From 008ff9bb978e375293912bb7324e98b9635efa62 Mon Sep 17 00:00:00 2001 From: Hannes Weisbach Date: Thu, 2 May 2013 11:06:15 +0000 Subject: [PATCH] Adds initial avrftdi TPI support. Device identification is possible tested under OS X 10.6.8 with an FT4232H and ATtiny10. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1145 81a1dc3b-b13d-400b-aceb-764788c761c2 --- Makefile.am | 2 + avrftdi.c | 176 +++++++++++++++-------- avrftdi_private.h | 63 +++++++++ avrftdi_tpi.c | 352 ++++++++++++++++++++++++++++++++++++++++++++++ avrftdi_tpi.h | 14 ++ 5 files changed, 550 insertions(+), 57 deletions(-) create mode 100644 avrftdi_private.h create mode 100644 avrftdi_tpi.c create mode 100644 avrftdi_tpi.h diff --git a/Makefile.am b/Makefile.am index b94318ed..4d3a3e21 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,6 +96,8 @@ libavrdude_a_SOURCES = \ avrdude.h \ avrftdi.c \ avrftdi.h \ + avrftdi_tpi.c \ + avrftdi_tpi.h \ avrpart.c \ avrpart.h \ bitbang.c \ diff --git a/avrftdi.c b/avrftdi.c index 670e8dc4..effc18dc 100644 --- a/avrftdi.c +++ b/avrftdi.c @@ -38,8 +38,8 @@ #include "pgm.h" #include "avrftdi.h" #include "avrpart.h" -#include "tpi.h" -#include "usbasp.h" +#include "avrftdi_tpi.h" +#include "avrftdi_private.h" #ifdef HAVE_LIBUSB_1_0 #ifdef HAVE_LIBFTDI1 @@ -64,26 +64,6 @@ enum { ERR, WARN, INFO, DEBUG, TRACE }; #define FTDI_DEFAULT_MASK ( (1 << (FTDI_SCK - 1)) | (1 << (FTDI_MOSI - 1)) ) -#define E(x, ftdi) \ - do { \ - if ((x)) { \ - log_err("%s: %s (%d) %s", \ - #x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \ - return -1; \ - } \ - } while(0) - -#define E_VOID(x, ftdi) \ - do { \ - if ((x)) { \ - log_err("%s: %s (%d) %s", \ - #x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \ - } \ - } while(0) - -#define to_pdata(pgm) \ - ((avrftdi_t *)((pgm)->cookie)) - /* This is for running the code without having a FTDI-device. * The generated code is useless! For debugging purposes only. * This should never be defined, unless you know what you are @@ -92,22 +72,6 @@ enum { ERR, WARN, INFO, DEBUG, TRACE }; */ //#define DRYRUN -typedef struct avrftdi_s { - /* pointer to struct maintained by libftdi to identify the device */ - struct ftdi_context* ftdic; - /* bitmask of values for pins. bit 0 represents pin 0 ([A|B]DBUS0) */ - uint16_t pin_value; - /* bitmask of pin direction. a '1' make a pin an output. - * bit 0 corresponds to pin 0. */ - uint16_t pin_direction; - /* don't know. not useful. someone put it in. */ - uint16_t led_mask; - /* total number of pins supported by a programmer. varies with FTDI chips */ - int pin_limit; - /* internal RX buffer of the device. needed for INOUT transfers */ - int rx_buffer_size; -} avrftdi_t; - static int write_flush(avrftdi_t *); /* @@ -419,12 +383,12 @@ static int set_pin(PROGRAMMER * pgm, int pinfunc, int value) pin = pgm->pinno[pinfunc] & PIN_MASK; inverted = pgm->pinno[pinfunc] & PIN_INVERSE; - + pin_mask = 1 << (pin - 1); - + /* make value 0 or 1 and invert, if necessary */ value = (inverted) ? !value : !!value; - + if (!pin) { /* this error message is really annoying, maybe use a ratelimit? */ /* @@ -586,6 +550,71 @@ static int avrftdi_transmit(avrftdi_t* pdata, unsigned char mode, unsigned char return written; } +/* this function tries to sync up with the FTDI. See FTDI application note AN_129. + * AN_135 uses 0xab as bad command and enables/disables loopback around synchronisation. + * This may fail if data is left in the buffer (i.e. avrdude aborted with ctrl-c) + * or the device is in an illegal state (i.e. a previous program). + * If the FTDI is out of sync, the buffers are cleared ("purged") and the + * sync is re-tried. + * if it still fails, we return an error code. higher level code may than abort. + * the device may be reset by unplugging the device and plugging it back in. + * resetting the device did not always help for me. + */ +static int ftdi_sync(avrftdi_t* pdata) +{ + unsigned char illegal_cmd[] = {0xaa}; + unsigned char reply[2]; + unsigned int i, n; + unsigned int retry = 0; + unsigned char latency; + + ftdi_get_latency_timer(pdata->ftdic, &latency); + fprintf(stderr, "Latency: %d\n", latency); + + do{ + n = ftdi_read_data(pdata->ftdic, reply, 1); + } while(n > 0); +retry: + /* send command "0xaa", which is an illegal command. */ + E(ftdi_write_data(pdata->ftdic, illegal_cmd, sizeof(illegal_cmd)) != sizeof(illegal_cmd), pdata->ftdic); + + i = 0; + do { +#ifndef DRYRUN + n = ftdi_read_data(pdata->ftdic, &reply[i], sizeof(reply) - i); + E(n < 0, pdata->ftdic); + //fprintf(stderr, "%s\n", ftdi_get_error_string(pdata->ftdic)); +#else + n = sizeof(reply) - i; +#endif + i += n; + } while (i < sizeof(reply)); + + /* 0xfa is return code for illegal command - we expect that, since we issued an + * illegal command (0xaa) + * the next byte will be the illegal command, the FTDI is complaining about. + */ + if(reply[0] == 0xfa && reply[1] == illegal_cmd[0]) + { + /* if the FTDI is complaining about the right thing, everything is fine */ + fprintf(stderr, "FTDI is in sync.\n"); + return 0; + } + else + { + fprintf(stderr, "FTDI out of sync. Received 0x%02x 0x%02x\n", reply[0], reply[1]); + if(retry < 4) + { + fprintf(stderr, "Trying to re-sync by purging buffers. Attempt\n"); + E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic); + retry++; + goto retry; + } else + fprintf(stderr, "Aborting. Try resetting or unplugging the device.\n"); + } + return -1; +} + static int write_flush(avrftdi_t* pdata) { unsigned char buf[6]; @@ -615,23 +644,36 @@ static int write_flush(avrftdi_t* pdata) * * Add.: purge does NOT flush. It clears. Also, it is unkown, when the purge * command actually arrives at the chip. - * Use read-pin-status command as sync. + * Use read pin status command as sync. */ #ifndef DRYRUN //E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic); unsigned char cmd[] = { GET_BITS_LOW, SEND_IMMEDIATE }; unsigned int n; + int retries = 0; + int num = 0; E(ftdi_write_data(pdata->ftdic, cmd, sizeof(cmd)) != sizeof(cmd), pdata->ftdic); do { n = ftdi_read_data(pdata->ftdic, cmd, 1); + if(n > 0) + { + avrftdi_print(0, "Low byte lines: 0x%02x\n", cmd[0]); + num += n; + } + if(!n) + { + retries++; + } E(n < 0, pdata->ftdic); - } while(n < 1); + } while(retries < 1/*n < 1*/); + avrftdi_print(0, "Read %d extra bytes\n", num-1); #endif return 0; + } @@ -698,12 +740,21 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port) } ftdi_set_latency_timer(pdata->ftdic, 1); + //ftdi_write_data_set_chunksize(pdata->ftdic, 16); + //ftdi_read_data_set_chunksize(pdata->ftdic, 16); /* set SPI mode */ E(ftdi_set_bitmode(pdata->ftdic, 0, BITMODE_RESET) < 0, pdata->ftdic); E(ftdi_set_bitmode(pdata->ftdic, pdata->pin_direction & 0xff, BITMODE_MPSSE) < 0, pdata->ftdic); E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic); +/* + ret = ftdi_sync(pdata); + if(ret < 0) + return ret; +*/ + write_flush(pdata); + if (pgm->baudrate) { set_frequency(pdata, pgm->baudrate); } else if(pgm->bitclock) { @@ -781,7 +832,6 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port) if (add_pin(pgm, PIN_AVR_MOSI)) return -1; if (add_pin(pgm, PIN_AVR_RESET)) return -1; - /* gather the rest of the pins */ if (add_pins(pgm, PPI_AVR_VCC)) return -1; if (add_pins(pgm, PPI_AVR_BUFF)) return -1; @@ -830,21 +880,29 @@ static void avrftdi_close(PROGRAMMER * pgm) static int avrftdi_initialize(PROGRAMMER * pgm, AVRPART * p) { - set_pin(pgm, PIN_AVR_RESET, OFF); - set_pins(pgm, PPI_AVR_BUFF, OFF); - set_pin(pgm, PIN_AVR_SCK, OFF); - /*use speed optimization with CAUTION*/ - usleep(20 * 1000); + if(p->flags & AVRPART_HAS_TPI) + { + /* see avrftdi_tpi.c */ + avrftdi_tpi_initialize(pgm, p); + } + else + { + set_pin(pgm, PIN_AVR_RESET, OFF); + set_pins(pgm, PPI_AVR_BUFF, OFF); + set_pin(pgm, PIN_AVR_SCK, OFF); + /*use speed optimization with CAUTION*/ + usleep(20 * 1000); - /* giving rst-pulse of at least 2 avr-clock-cycles, for - * security (2us @ 1MHz) */ - set_pin(pgm, PIN_AVR_RESET, ON); - usleep(20 * 1000); + /* giving rst-pulse of at least 2 avr-clock-cycles, for + * security (2us @ 1MHz) */ + set_pin(pgm, PIN_AVR_RESET, ON); + usleep(20 * 1000); - /*setting rst back to 0 */ - set_pin(pgm, PIN_AVR_RESET, OFF); - /*wait at least 20ms bevor issuing spi commands to avr */ - usleep(20 * 1000); + /*setting rst back to 0 */ + set_pin(pgm, PIN_AVR_RESET, OFF); + /*wait at least 20ms bevor issuing spi commands to avr */ + usleep(20 * 1000); + } return pgm->program_enable(pgm, p); } @@ -965,6 +1023,7 @@ static int avrftdi_eeprom_write(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, avr_set_addr(m->op[AVR_OP_WRITE], &cmd[3], add); avr_set_input(m->op[AVR_OP_WRITE], &cmd[3], *data++); + //avrftdi_transmit(to_pdata(pgm), MPSSE_DO_WRITE, cmd, cmd, 4); E(ftdi_write_data(to_pdata(pgm)->ftdic, cmd, sizeof(cmd)) != sizeof(cmd), to_pdata(pgm)->ftdic); @@ -1237,11 +1296,14 @@ avrftdi_setup(PROGRAMMER * pgm) pdata->pin_value = 0; pdata->pin_direction = 0; pdata->led_mask = 0; + pdata->guard_bits = 128 + 2; + pdata->set_pin = &set_pin; } static void avrftdi_teardown(PROGRAMMER * pgm) { + fprintf(stderr, "\n%s: Unintializing programmer.\n", progname); avrftdi_t* pdata = to_pdata(pgm); if(pdata) { diff --git a/avrftdi_private.h b/avrftdi_private.h new file mode 100644 index 00000000..a620747e --- /dev/null +++ b/avrftdi_private.h @@ -0,0 +1,63 @@ +#pragma once +#include "ac_cfg.h" + +#include + +#ifdef HAVE_LIBFTDI1 +# include +#else +# error "libftdi1 required for avrftdi." +#endif + +#include "pgm.h" + +#define E(x, ftdi) \ + do { \ + if ((x)) \ + { \ + fprintf(stderr, "%s:%d %s() %s: %s (%d)\n\t%s\n", \ + __FILE__, __LINE__, __FUNCTION__, \ + #x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \ + return -1; \ + } \ + } while(0) + +#define E_VOID(x, ftdi) \ + do { \ + if ((x)) \ + { \ + fprintf(stderr, "%s:%d %s() %s: %s (%d)\n\t%s\n", \ + __FILE__, __LINE__, __FUNCTION__, \ + #x, strerror(errno), errno, ftdi_get_error_string(ftdi)); \ + } \ + } while(0) + + +#define to_pdata(pgm) \ + ((avrftdi_t *)((pgm)->cookie)) + +typedef struct avrftdi_s { + /* pointer to struct maintained by libftdi to identify the device */ + struct ftdi_context* ftdic; + /* bitmask of values for pins. bit 0 represents pin 0 ([A|B]DBUS0) */ + uint16_t pin_value; + /* bitmask of pin direction. a '1' make a pin an output. + * bit 0 corresponds to pin 0. */ + uint16_t pin_direction; + /* don't know. not useful. someone put it in. */ + uint16_t led_mask; + /* total number of pins supported by a programmer. varies with FTDI chips */ + int pin_limit; + /* internal RX buffer of the device. needed for INOUT transfers */ + int rx_buffer_size; + /* number of guard bits for TPI. should be moved to struct PROGRAMMER */ + int guard_bits; + /* function pointer to the set_pin function, so that we do not have to drag + * it into global scope. it's a hack, but i think it's slightly better than + * the alternative. + */ + int (*set_pin)(PROGRAMMER *, int, int); +} avrftdi_t; + +void avrftdi_print(int level, const char * fmt, ...); + diff --git a/avrftdi_tpi.c b/avrftdi_tpi.c new file mode 100644 index 00000000..91ebebdf --- /dev/null +++ b/avrftdi_tpi.c @@ -0,0 +1,352 @@ +#include "ac_cfg.h" + +#include +#include +#include +#include + +#include "pgm.h" +#include "avrpart.h" +#include "pindefs.h" +#include "tpi.h" +#include "usbasp.h" + +#include "avrftdi_tpi.h" +#include "avrftdi_private.h" + +#ifdef HAVE_LIBUSB_1_0 +#ifdef HAVE_LIBFTDI1 + +#include +#include + +static void +avrftdi_debug_frame(uint16_t frame) +{ + static char bit_name[] = "IDLES01234567PSS"; + //static char bit_name[] = "SSP76543210SELDI"; + char line0[34], line1[34], line2[34]; + int bit, pos; + + for(bit = 0; bit < 16; bit++) + { + pos = 16 - bit - 1; + if(frame & (1 << pos)) + { + line0[2*pos] = '_'; + line0[2*pos+1] = ' '; + + line2[2*pos] = ' '; + line2[2*pos+1] = ' '; + } + else + { + line0[2*pos] = ' '; + line0[2*pos+1] = ' '; + + line2[2*pos] = '-'; + line2[2*pos+1] = ' '; + } + + line1[2*pos] = bit_name[pos]; + line1[2*pos+1] = ' '; + + } + + line0[32] = 0; + line1[32] = 0; + line2[32] = 0; + + avrftdi_print(0, "%s\n", line0); + avrftdi_print(0, "%s\n", line1); + //avrftdi_print(0, "%s\n", line2); +} + +int +avrftdi_tpi_initialize(PROGRAMMER * pgm, AVRPART * p) +{ + int ret; + + avrftdi_t* pdata = to_pdata(pgm); + unsigned char buf[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 0x01, 0x00, 0xff, 0xff }; + + avrftdi_print(0, "Using TPI interface\n"); + + pgm->program_enable = avrftdi_tpi_program_enable; + pgm->cmd_tpi = avrftdi_cmd_tpi; + pgm->chip_erase = avrftdi_tpi_chip_erase; + //pgm->read_byte = avrftdi_tpi_read_byte; + //pgm->write_byte = avrftdi_tpi_write_byte; + + avrftdi_print(0, "Setting /Reset pin low\n"); + pdata->set_pin(pgm, PIN_AVR_RESET, OFF); + pdata->set_pin(pgm, PIN_AVR_SCK, OFF); + pdata->set_pin(pgm, PIN_AVR_MOSI, ON); + usleep(20 * 1000); + + pdata->set_pin(pgm, PIN_AVR_RESET, ON); + /* worst case 128ms */ + usleep(2 * 128 * 1000); + + /*setting rst back to 0 */ + pdata->set_pin(pgm, PIN_AVR_RESET, OFF); + /*wait at least 20ms bevor issuing spi commands to avr */ + usleep(20 * 1000); + + avrftdi_print(0, "Sending 16 init clock cycles ... "); + ret = ftdi_write_data(pdata->ftdic, buf, sizeof(buf)); + avrftdi_print(0, "Done.\n"); + + return ret; +} + +#define TPI_BIT_PAR 0x2000 + +static uint16_t +tpi_byte2frame(uint8_t byte) +{ + uint16_t frame = 0xc00f; + int parity = __builtin_popcount(byte) & 1; + + frame |= ((byte << 5) & 0x1fe0); + + if(parity) + frame |= TPI_BIT_PAR; + + return frame; +} + +static int +tpi_frame2byte(uint16_t frame, uint8_t * byte) +{ + /* drop partity + 2 stop bits */ + *byte = (frame >> 1) & 0xff; + + int parity = __builtin_popcount(*byte) & 1; + int parity_rcvd = (frame & 0x200) ? 1 : 0; + + avrftdi_print(1, "Recevied frame with payload 0x%02x and parity %d.\n", *byte, parity); + + return parity != parity_rcvd; +} + +#define TPI_FRAME_SIZE 2 + +static int +avrftdi_tpi_break(PROGRAMMER * pgm) +{ + unsigned char buffer[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 1, 0, 0x80, 0x01 }; + E(ftdi_write_data(to_pdata(pgm)->ftdic, buffer, sizeof(buffer)) != sizeof(buffer), to_pdata(pgm)->ftdic); + + return 0; +} + +static int +avrftdi_tpi_write_byte(PROGRAMMER * pgm, unsigned char byte) +{ + uint16_t frame; + + struct ftdi_context* ftdic = to_pdata(pgm)->ftdic; + + unsigned char buffer[] = { MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB, 1, 0, 0, 0 }; + + frame = tpi_byte2frame(byte); + + buffer[3] = frame & 0xff; + buffer[4] = frame >> 8; + + avrftdi_print(1, "TPI frame: 0x%02x 0x%02x, data byte 0x%02x\n", + buffer[6], buffer[7], byte); + avrftdi_print(2, "FTDI raw data: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4] /*, buffer[5], buffer[6], buffer[7]*/); + + avrftdi_debug_frame(frame); + + E(ftdi_write_data(ftdic, buffer, sizeof(buffer)) != sizeof(buffer), ftdic); + + return 0; +} + +static int +avrftdi_tpi_read_byte(PROGRAMMER * pgm, unsigned char * byte) +{ + uint16_t frame; + + int guard_bits = to_pdata(pgm)->guard_bits; + int bytes = ((guard_bits + 7) / 8) + 2; + int i = 0, n = 0; + + /* worst case size: + * - 128 guard bits + * - 2 default idle bits + * - 12 frame bits + * = 142 bits + */ + unsigned char buffer[bytes]; + + if(bytes > sizeof(buffer)) + avrftdi_print(0, "Requested more bytes (%d) than available buffer space (%d)\n", bytes, sizeof(buffer)); + + avrftdi_print(1, "Guard bit size (incl. default idle bits) is %d\n", guard_bits); + avrftdi_print(1, "Reading %d bytes for guard bits + frame\n", bytes); + + /* set it high, so the PDI won't detect we're driving the line */ + to_pdata(pgm)->set_pin(pgm, PIN_AVR_MOSI, ON); + + buffer[0] = MPSSE_DO_READ | MPSSE_WRITE_NEG | MPSSE_LSB; + buffer[1] = (bytes-1) & 0xff; + buffer[2] = ((bytes-1) >> 8) & 0xff; + buffer[3] = SEND_IMMEDIATE; + + avrftdi_print(3, "Read request: 0x%02x 0x%02x 0x%02x 0x%02x\n", + buffer[0], buffer[1], buffer[2], buffer[3]); + + ftdi_write_data(to_pdata(pgm)->ftdic, buffer, 4); + + memset(buffer, 0, sizeof(buffer)); + + i = 0; + do { + n = ftdi_read_data(to_pdata(pgm)->ftdic, &buffer[i], bytes - i); + E(n < 0, to_pdata(pgm)->ftdic); + i += n; + } while(i < bytes); + + /* dismiss at least (guard_bits / 8) bytes */ + i = guard_bits / 8; + frame = buffer[i] | (buffer[i+1] << 8); + + /* now shift the rest of guard bits out */ + i = guard_bits - (i*8); + frame >>= i; + + avrftdi_print(1, "Received frame 0x%04x (LSB first)\n", frame); + + return tpi_frame2byte(frame, byte); +} + +int +avrftdi_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p) +{ + int retry; + int err; + int i; + unsigned char byte = 0; + + avrftdi_print(0, "TPI program enable\n"); + + //TODO determine guard time: + //-disable output possible -> guard time + //-else: minimum guard time + /* set guard time */ + //avrftdi_tpi_write_byte(pgm, TPI_OP_SSTCS(TPIPCR)); + //avrftdi_tpi_write_byte(pgm, TPIPCR_GT_2b); + + /* send SKEY */ + avrftdi_tpi_write_byte(pgm, TPI_CMD_SKEY); + for(i = sizeof(tpi_skey) - 1; i >= 0; --i) + avrftdi_tpi_write_byte(pgm, tpi_skey[i]); + + /* check if device is ready */ + for(retry = 0; retry < 10; retry++) + { + avrftdi_print(0, "Reading Identification register\n"); + avrftdi_tpi_write_byte(pgm, TPI_OP_SLDCS(TPIIR)); + err = avrftdi_tpi_read_byte(pgm, &byte); + if(err || byte != 0x80) + { + avrftdi_print(0, "Error. Sending break.\n"); + avrftdi_tpi_break(pgm); + avrftdi_tpi_break(pgm); + continue; + } + + avrftdi_print(0, "Reading Status register\n"); + avrftdi_tpi_write_byte(pgm, TPI_OP_SLDCS(TPISR)); + err = avrftdi_tpi_read_byte(pgm, &byte); + if(err || !(byte & TPISR_NVMEN)) + { + avrftdi_print(0, "Error. Sending break.\n"); + avrftdi_tpi_break(pgm); + avrftdi_tpi_break(pgm); + continue; + } + + return 0; + } + + avrftdi_print(0, "error connecting to target\n"); + return -1; +} + +static int +avrftdi_tpi_nvm_waitbusy(PROGRAMMER * pgm) +{ + unsigned char byte; + int err; + int retry; + + for(retry = 50; retry > 0; retry--) + { + avrftdi_tpi_write_byte(pgm, TPI_OP_SIN(NVMCSR)); + err = avrftdi_tpi_read_byte(pgm, &byte); + if(err || (byte & NVMCSR_BSY)) + continue; + return 0; + } + + return -1; +} + +int +avrftdi_cmd_tpi(PROGRAMMER * pgm, unsigned char cmd[], int cmd_len, + unsigned char res[], int res_len) +{ + int i, err = 0; + + for(i = 0; i < cmd_len; i++) + { + err = avrftdi_tpi_write_byte(pgm, cmd[i]); + if(err) + return err; + } + + for(i = 0; i < res_len; i++) + { + err = avrftdi_tpi_read_byte(pgm, &res[i]); + if(err) + return err; + } + + return 0; +} + +int +avrftdi_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p) +{ + /* Set PR to flash */ + avrftdi_tpi_write_byte(pgm, TPI_OP_SSTPR(0)); + avrftdi_tpi_write_byte(pgm, 0x01); + avrftdi_tpi_write_byte(pgm, TPI_OP_SSTPR(1)); + avrftdi_tpi_write_byte(pgm, 0x40); + /* select ERASE */ + avrftdi_tpi_write_byte(pgm, TPI_OP_SOUT(NVMCMD)); + avrftdi_tpi_write_byte(pgm, NVMCMD_CHIP_ERASE); + /* dummy write */ + avrftdi_tpi_write_byte(pgm, TPI_OP_SST_INC); + avrftdi_tpi_write_byte(pgm, 0x00); + avrftdi_tpi_nvm_waitbusy(pgm); + + usleep(p->chip_erase_delay); + pgm->initialize(pgm, p); + + return 0; +} + +#else /*HAVE_LIBFTDI*/ +#endif /* HAVE_LIBFTDI */ + +#else /*HAVE_LIBUSB*/ + +#endif /*HAVE_LIBUSB*/ + diff --git a/avrftdi_tpi.h b/avrftdi_tpi.h new file mode 100644 index 00000000..d38fa887 --- /dev/null +++ b/avrftdi_tpi.h @@ -0,0 +1,14 @@ +#pragma once + +#include "pgm.h" +#include "avrpart.h" + +//int avrftdi_tpi_write_byte(PROGRAMMER * pgm, unsigned char byte); +//int avrftdi_tpi_read_byte(PROGRAMMER * pgm, unsigned char * byte); +int avrftdi_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p); +int avrftdi_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p); +int avrftdi_cmd_tpi(PROGRAMMER * pgm, unsigned char cmd[], int cmd_len, + unsigned char res[], int res_len); +int avrftdi_tpi_initialize(PROGRAMMER * pgm, AVRPART * p); + +