diff options
Diffstat (limited to 'xs/src/avrdude/bitbang.c')
-rw-r--r-- | xs/src/avrdude/bitbang.c | 655 |
1 files changed, 0 insertions, 655 deletions
diff --git a/xs/src/avrdude/bitbang.c b/xs/src/avrdude/bitbang.c deleted file mode 100644 index b943c3cea..000000000 --- a/xs/src/avrdude/bitbang.c +++ /dev/null @@ -1,655 +0,0 @@ -/* - * avrdude - A Downloader/Uploader for AVR device programmers - * Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com> - * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org> - * Copyright (C) 2011 Darell Tan <darell.tan@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -/* $Id$ */ - -#include "ac_cfg.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> - -#if !defined(WIN32NATIVE) -# include <signal.h> -# include <sys/time.h> -#endif - -#include "avrdude.h" -#include "libavrdude.h" - -#include "par.h" -#include "serbb.h" -#include "tpi.h" -#include "bitbang.h" - -static int delay_decrement; - -#if defined(WIN32NATIVE) -static int has_perfcount; -static LARGE_INTEGER freq; -#else -static volatile int done; - -typedef void (*mysighandler_t)(int); -static mysighandler_t saved_alarmhandler; - -static void alarmhandler(int signo) -{ - done = 1; - signal(SIGALRM, saved_alarmhandler); -} -#endif /* WIN32NATIVE */ - -/* - * Calibrate the microsecond delay loop below. - */ -static void bitbang_calibrate_delay(void) -{ -#if defined(WIN32NATIVE) - /* - * If the hardware supports a high-resolution performance counter, - * we ultimately prefer that one, as it gives quite accurate delays - * on modern high-speed CPUs. - */ - if (QueryPerformanceFrequency(&freq)) - { - has_perfcount = 1; - avrdude_message(MSG_NOTICE2, "%s: Using performance counter for bitbang delays\n", - progname); - } - else - { - /* - * If a high-resolution performance counter is not available, we - * don't have any Win32 implementation for setting up the - * per-microsecond delay count, so we can only run on a - * preconfigured delay stepping there. The figure below should at - * least be correct within an order of magnitude, judging from the - * auto-calibration figures seen on various Unix systems on - * comparable hardware. - */ - avrdude_message(MSG_NOTICE2, "%s: Using guessed per-microsecond delay count for bitbang delays\n", - progname); - delay_decrement = 100; - } -#else /* !WIN32NATIVE */ - struct itimerval itv; - volatile int i; - - avrdude_message(MSG_NOTICE2, "%s: Calibrating delay loop...", - progname); - i = 0; - done = 0; - saved_alarmhandler = signal(SIGALRM, alarmhandler); - /* - * Set ITIMER_REAL to 100 ms. All known systems have a timer - * granularity of 10 ms or better, so counting the delay cycles - * accumulating over 100 ms should give us a rather realistic - * picture, without annoying the user by a lengthy startup time (as - * an alarm(1) would do). Of course, if heavy system activity - * happens just during calibration but stops before the remaining - * part of AVRDUDE runs, this will yield wrong values. There's not - * much we can do about this. - */ - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 100000; - itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0; - setitimer(ITIMER_REAL, &itv, 0); - while (!done) - i--; - itv.it_value.tv_sec = itv.it_value.tv_usec = 0; - setitimer(ITIMER_REAL, &itv, 0); - /* - * Calculate back from 100 ms to 1 us. - */ - delay_decrement = -i / 100000; - avrdude_message(MSG_NOTICE2, " calibrated to %d cycles per us\n", - delay_decrement); -#endif /* WIN32NATIVE */ -} - -/* - * Delay for approximately the number of microseconds specified. - * usleep()'s granularity is usually like 1 ms or 10 ms, so it's not - * really suitable for short delays in bit-bang algorithms. - */ -void bitbang_delay(unsigned int us) -{ -#if defined(WIN32NATIVE) - LARGE_INTEGER countNow, countEnd; - - if (has_perfcount) - { - QueryPerformanceCounter(&countNow); - countEnd.QuadPart = countNow.QuadPart + freq.QuadPart * us / 1000000ll; - - while (countNow.QuadPart < countEnd.QuadPart) - QueryPerformanceCounter(&countNow); - } - else /* no performance counters -- run normal uncalibrated delay */ - { -#endif /* WIN32NATIVE */ - volatile unsigned int del = us * delay_decrement; - - while (del > 0) - del--; -#if defined(WIN32NATIVE) - } -#endif /* WIN32NATIVE */ -} - -/* - * transmit and receive a byte of data to/from the AVR device - */ -static unsigned char bitbang_txrx(PROGRAMMER * pgm, unsigned char byte) -{ - int i; - unsigned char r, b, rbyte; - - rbyte = 0; - for (i=7; i>=0; i--) { - /* - * Write and read one bit on SPI. - * Some notes on timing: Let T be the time it takes to do - * one pgm->setpin()-call resp. par clrpin()-call, then - * - SCK is high for 2T - * - SCK is low for 2T - * - MOSI setuptime is 1T - * - MOSI holdtime is 3T - * - SCK low to MISO read is 2T to 3T - * So we are within programming specs (expect for AT90S1200), - * if and only if T>t_CLCL (t_CLCL=clock period of target system). - * - * Due to the delay introduced by "IN" and "OUT"-commands, - * T is greater than 1us (more like 2us) on x86-architectures. - * So programming works safely down to 1MHz target clock. - */ - - b = (byte >> i) & 0x01; - - /* set the data input line as desired */ - pgm->setpin(pgm, PIN_AVR_MOSI, b); - - pgm->setpin(pgm, PIN_AVR_SCK, 1); - - /* - * read the result bit (it is either valid from a previous falling - * edge or it is ignored in the current context) - */ - r = pgm->getpin(pgm, PIN_AVR_MISO); - - pgm->setpin(pgm, PIN_AVR_SCK, 0); - - rbyte |= r << i; - } - - return rbyte; -} - -static int bitbang_tpi_clk(PROGRAMMER * pgm) -{ - unsigned char r = 0; - pgm->setpin(pgm, PIN_AVR_SCK, 1); - - r = pgm->getpin(pgm, PIN_AVR_MISO); - - pgm->setpin(pgm, PIN_AVR_SCK, 0); - - return r; -} - -void bitbang_tpi_tx(PROGRAMMER * pgm, unsigned char byte) -{ - int i; - unsigned char b, parity; - - /* start bit */ - pgm->setpin(pgm, PIN_AVR_MOSI, 0); - bitbang_tpi_clk(pgm); - - parity = 0; - for (i = 0; i <= 7; i++) { - b = (byte >> i) & 0x01; - parity ^= b; - - /* set the data input line as desired */ - pgm->setpin(pgm, PIN_AVR_MOSI, b); - bitbang_tpi_clk(pgm); - } - - /* parity bit */ - pgm->setpin(pgm, PIN_AVR_MOSI, parity); - bitbang_tpi_clk(pgm); - - /* 2 stop bits */ - pgm->setpin(pgm, PIN_AVR_MOSI, 1); - bitbang_tpi_clk(pgm); - bitbang_tpi_clk(pgm); -} - -int bitbang_tpi_rx(PROGRAMMER * pgm) -{ - int i; - unsigned char b, rbyte, parity; - - /* make sure pin is on for "pullup" */ - pgm->setpin(pgm, PIN_AVR_MOSI, 1); - - /* wait for start bit (up to 10 bits) */ - b = 1; - for (i = 0; i < 10; i++) { - b = bitbang_tpi_clk(pgm); - if (b == 0) - break; - } - if (b != 0) { - avrdude_message(MSG_INFO, "bitbang_tpi_rx: start bit not received correctly\n"); - return -1; - } - - rbyte = 0; - parity = 0; - for (i=0; i<=7; i++) { - b = bitbang_tpi_clk(pgm); - parity ^= b; - - rbyte |= b << i; - } - - /* parity bit */ - if (bitbang_tpi_clk(pgm) != parity) { - avrdude_message(MSG_INFO, "bitbang_tpi_rx: parity bit is wrong\n"); - return -1; - } - - /* 2 stop bits */ - b = 1; - b &= bitbang_tpi_clk(pgm); - b &= bitbang_tpi_clk(pgm); - if (b != 1) { - avrdude_message(MSG_INFO, "bitbang_tpi_rx: stop bits not received correctly\n"); - return -1; - } - - return rbyte; -} - -int bitbang_rdy_led(PROGRAMMER * pgm, int value) -{ - pgm->setpin(pgm, PIN_LED_RDY, !value); - return 0; -} - -int bitbang_err_led(PROGRAMMER * pgm, int value) -{ - pgm->setpin(pgm, PIN_LED_ERR, !value); - return 0; -} - -int bitbang_pgm_led(PROGRAMMER * pgm, int value) -{ - pgm->setpin(pgm, PIN_LED_PGM, !value); - return 0; -} - -int bitbang_vfy_led(PROGRAMMER * pgm, int value) -{ - pgm->setpin(pgm, PIN_LED_VFY, !value); - return 0; -} - - -/* - * transmit an AVR device command and return the results; 'cmd' and - * 'res' must point to at least a 4 byte data buffer - */ -int bitbang_cmd(PROGRAMMER * pgm, const unsigned char *cmd, - unsigned char *res) -{ - int i; - - for (i=0; i<4; i++) { - res[i] = bitbang_txrx(pgm, cmd[i]); - } - - if(verbose >= 2) - { - avrdude_message(MSG_NOTICE2, "bitbang_cmd(): [ "); - for(i = 0; i < 4; i++) - avrdude_message(MSG_NOTICE2, "%02X ", cmd[i]); - avrdude_message(MSG_NOTICE2, "] [ "); - for(i = 0; i < 4; i++) - { - avrdude_message(MSG_NOTICE2, "%02X ", res[i]); - } - avrdude_message(MSG_NOTICE2, "]\n"); - } - - return 0; -} - -int bitbang_cmd_tpi(PROGRAMMER * pgm, const unsigned char *cmd, - int cmd_len, unsigned char *res, int res_len) -{ - int i, r; - - pgm->pgm_led(pgm, ON); - - for (i=0; i<cmd_len; i++) { - bitbang_tpi_tx(pgm, cmd[i]); - } - - r = 0; - for (i=0; i<res_len; i++) { - r = bitbang_tpi_rx(pgm); - if (r == -1) - break; - res[i] = r; - } - - if(verbose >= 2) - { - avrdude_message(MSG_NOTICE2, "bitbang_cmd_tpi(): [ "); - for(i = 0; i < cmd_len; i++) - avrdude_message(MSG_NOTICE2, "%02X ", cmd[i]); - avrdude_message(MSG_NOTICE2, "] [ "); - for(i = 0; i < res_len; i++) - { - avrdude_message(MSG_NOTICE2, "%02X ", res[i]); - } - avrdude_message(MSG_NOTICE2, "]\n"); - } - - pgm->pgm_led(pgm, OFF); - if (r == -1) - return -1; - return 0; -} - -/* - * transmit bytes via SPI and return the results; 'cmd' and - * 'res' must point to data buffers - */ -int bitbang_spi(PROGRAMMER * pgm, const unsigned char *cmd, - unsigned char *res, int count) -{ - int i; - - pgm->setpin(pgm, PIN_LED_PGM, 0); - - for (i=0; i<count; i++) { - res[i] = bitbang_txrx(pgm, cmd[i]); - } - - pgm->setpin(pgm, PIN_LED_PGM, 1); - - if(verbose >= 2) - { - avrdude_message(MSG_NOTICE2, "bitbang_cmd(): [ "); - for(i = 0; i < count; i++) - avrdude_message(MSG_NOTICE2, "%02X ", cmd[i]); - avrdude_message(MSG_NOTICE2, "] [ "); - for(i = 0; i < count; i++) - { - avrdude_message(MSG_NOTICE2, "%02X ", res[i]); - } - avrdude_message(MSG_NOTICE2, "]\n"); - } - - return 0; -} - - -/* - * issue the 'chip erase' command to the AVR device - */ -int bitbang_chip_erase(PROGRAMMER * pgm, AVRPART * p) -{ - unsigned char cmd[4]; - unsigned char res[4]; - AVRMEM *mem; - - if (p->flags & AVRPART_HAS_TPI) { - pgm->pgm_led(pgm, ON); - - while (avr_tpi_poll_nvmbsy(pgm)); - - /* NVMCMD <- CHIP_ERASE */ - bitbang_tpi_tx(pgm, TPI_CMD_SOUT | TPI_SIO_ADDR(TPI_IOREG_NVMCMD)); - bitbang_tpi_tx(pgm, TPI_NVMCMD_CHIP_ERASE); /* CHIP_ERASE */ - - /* Set Pointer Register */ - mem = avr_locate_mem(p, "flash"); - if (mem == NULL) { - avrdude_message(MSG_INFO, "No flash memory to erase for part %s\n", - p->desc); - return -1; - } - bitbang_tpi_tx(pgm, TPI_CMD_SSTPR | 0); - bitbang_tpi_tx(pgm, (mem->offset & 0xFF) | 1); /* high byte */ - bitbang_tpi_tx(pgm, TPI_CMD_SSTPR | 1); - bitbang_tpi_tx(pgm, (mem->offset >> 8) & 0xFF); - - /* write dummy value to start erase */ - bitbang_tpi_tx(pgm, TPI_CMD_SST); - bitbang_tpi_tx(pgm, 0xFF); - - while (avr_tpi_poll_nvmbsy(pgm)); - - pgm->pgm_led(pgm, OFF); - - return 0; - } - - if (p->op[AVR_OP_CHIP_ERASE] == NULL) { - avrdude_message(MSG_INFO, "chip erase instruction not defined for part \"%s\"\n", - p->desc); - return -1; - } - - pgm->pgm_led(pgm, ON); - - memset(cmd, 0, sizeof(cmd)); - - avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); - pgm->cmd(pgm, cmd, res); - usleep(p->chip_erase_delay); - pgm->initialize(pgm, p); - - pgm->pgm_led(pgm, OFF); - - return 0; -} - -/* - * issue the 'program enable' command to the AVR device - */ -int bitbang_program_enable(PROGRAMMER * pgm, AVRPART * p) -{ - unsigned char cmd[4]; - unsigned char res[4]; - int i; - - if (p->flags & AVRPART_HAS_TPI) { - /* enable NVM programming */ - bitbang_tpi_tx(pgm, TPI_CMD_SKEY); - for (i = sizeof(tpi_skey) - 1; i >= 0; i--) - bitbang_tpi_tx(pgm, tpi_skey[i]); - - /* check NVMEN bit */ - bitbang_tpi_tx(pgm, TPI_CMD_SLDCS | TPI_REG_TPISR); - i = bitbang_tpi_rx(pgm); - return (i != -1 && (i & TPI_REG_TPISR_NVMEN)) ? 0 : -2; - } - - if (p->op[AVR_OP_PGM_ENABLE] == NULL) { - avrdude_message(MSG_INFO, "program enable instruction not defined for part \"%s\"\n", - p->desc); - return -1; - } - - memset(cmd, 0, sizeof(cmd)); - avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd); - pgm->cmd(pgm, cmd, res); - - if (res[2] != cmd[1]) - return -2; - - return 0; -} - -/* - * initialize the AVR device and prepare it to accept commands - */ -int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p) -{ - int rc; - int tries; - int i; - - bitbang_calibrate_delay(); - - pgm->powerup(pgm); - usleep(20000); - - /* TPIDATA is a single line, so MISO & MOSI should be connected */ - if (p->flags & AVRPART_HAS_TPI) { - /* make sure cmd_tpi() is defined */ - if (pgm->cmd_tpi == NULL) { - avrdude_message(MSG_INFO, "%s: Error: %s programmer does not support TPI\n", - progname, pgm->type); - return -1; - } - - /* bring RESET high first */ - pgm->setpin(pgm, PIN_AVR_RESET, 1); - usleep(1000); - - avrdude_message(MSG_NOTICE2, "doing MOSI-MISO link check\n"); - - pgm->setpin(pgm, PIN_AVR_MOSI, 0); - if (pgm->getpin(pgm, PIN_AVR_MISO) != 0) { - avrdude_message(MSG_INFO, "MOSI->MISO 0 failed\n"); - return -1; - } - pgm->setpin(pgm, PIN_AVR_MOSI, 1); - if (pgm->getpin(pgm, PIN_AVR_MISO) != 1) { - avrdude_message(MSG_INFO, "MOSI->MISO 1 failed\n"); - return -1; - } - - avrdude_message(MSG_NOTICE2, "MOSI-MISO link present\n"); - } - - pgm->setpin(pgm, PIN_AVR_SCK, 0); - pgm->setpin(pgm, PIN_AVR_RESET, 0); - usleep(20000); - - if (p->flags & AVRPART_HAS_TPI) { - /* keep TPIDATA high for 16 clock cycles */ - pgm->setpin(pgm, PIN_AVR_MOSI, 1); - for (i = 0; i < 16; i++) - pgm->highpulsepin(pgm, PIN_AVR_SCK); - - /* remove extra guard timing bits */ - bitbang_tpi_tx(pgm, TPI_CMD_SSTCS | TPI_REG_TPIPCR); - bitbang_tpi_tx(pgm, 0x7); - - /* read TPI ident reg */ - bitbang_tpi_tx(pgm, TPI_CMD_SLDCS | TPI_REG_TPIIR); - rc = bitbang_tpi_rx(pgm); - if (rc != 0x80) { - avrdude_message(MSG_INFO, "TPIIR not correct\n"); - return -1; - } - } else { - pgm->highpulsepin(pgm, PIN_AVR_RESET); - } - - usleep(20000); /* 20 ms XXX should be a per-chip parameter */ - - /* - * Enable programming mode. If we are programming an AT90S1200, we - * can only issue the command and hope it worked. If we are using - * one of the other chips, the chip will echo 0x53 when issuing the - * third byte of the command. In this case, try up to 32 times in - * order to possibly get back into sync with the chip if we are out - * of sync. - */ - if (p->flags & AVRPART_IS_AT90S1200) { - pgm->program_enable(pgm, p); - } - else { - tries = 0; - do { - rc = pgm->program_enable(pgm, p); - if ((rc == 0)||(rc == -1)) - break; - pgm->highpulsepin(pgm, p->retry_pulse/*PIN_AVR_SCK*/); - tries++; - } while (tries < 65); - - /* - * can't sync with the device, maybe it's not attached? - */ - if (rc) { - avrdude_message(MSG_INFO, "%s: AVR device not responding\n", progname); - return -1; - } - } - - return 0; -} - -static int verify_pin_assigned(PROGRAMMER * pgm, int pin, char * desc) -{ - if (pgm->pinno[pin] == 0) { - avrdude_message(MSG_INFO, "%s: error: no pin has been assigned for %s\n", - progname, desc); - return -1; - } - return 0; -} - - -/* - * Verify all prerequisites for a bit-bang programmer are present. - */ -int bitbang_check_prerequisites(PROGRAMMER *pgm) -{ - - if (verify_pin_assigned(pgm, PIN_AVR_RESET, "AVR RESET") < 0) - return -1; - if (verify_pin_assigned(pgm, PIN_AVR_SCK, "AVR SCK") < 0) - return -1; - if (verify_pin_assigned(pgm, PIN_AVR_MISO, "AVR MISO") < 0) - return -1; - if (verify_pin_assigned(pgm, PIN_AVR_MOSI, "AVR MOSI") < 0) - return -1; - - if (pgm->cmd == NULL) { - avrdude_message(MSG_INFO, "%s: error: no cmd() method defined for bitbang programmer\n", - progname); - return -1; - } - return 0; -} |