From 086b4c329e1ca7e926716febf415e553d4910511 Mon Sep 17 00:00:00 2001 From: hweisbach Date: Sun, 29 Jul 2012 12:29:39 +0000 Subject: [PATCH] Adds bugfixes and maintenance for avrftdi Bugfixes: -remove ftdi_usb_purge_buffers(), since it does not flush, but clear buffers -fix bad polling in avrftdi_flash_write() where it was possible to poll a 0xff value. Maintenance: -use #defines from libftdi for MPSSE commands where applicable -reformat E() and E_VOID() macros -remove TYPE_* macros -clean up private structure (remove pin_inversion, type and ftype) -adds ftdi_pin_name() to turn a (FTDI) pin number to a human readable string -adds avrftdi_print to encapsulate "if(verbose > c) fprintf()"-idiom -nicer / better understandable (I hope) output -removes pin_limit() and adds a member in the private data structure. TYPE_* macros can be removed; decision is made from (struct ftdi_context).type -add_pin(s)() functions reworked. parameters are validated first, if everything is alright, pin_value is modified. pin_inversion mask is not needed; use PIN_INVERTED instead -change set_pin(s)(), so that it gets the pin value used by avrdude (and not a bit mask). This way, PIN_INVERTED is usable and pin_inversion is not needed. Plus, the interface is consistent with the add_pin() signature. Also move parameter validation to the start of the function. I also commented out the warning, that a pin is not defined, because it is annoying. -clean up avrftdi_open(): first parameter validation, then USB lookup, interface initialization then pin setup -avrftdi_eeprom_read/write() and avrftdi_flash_read/write(): convert to new calling scheme, where every paged_* function is called once for every page git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1098 81a1dc3b-b13d-400b-aceb-764788c761c2 --- ChangeLog | 5 + avrftdi.c | 1180 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 693 insertions(+), 492 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2c1225ef..4f3930aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-07-29 Hannes Weisbach + + * avrftdi.c: bugfixes (synchronisation) and maintenance (paged programming, + nicer output, separation of parameter checking and actual code) + 2012-07-25 Joerg Wunsch * jtagmkII.c (jtagmkII_memtype): return MTYPE_FLASH rather than diff --git a/avrftdi.c b/avrftdi.c index fdfa7077..2d32e2bf 100644 --- a/avrftdi.c +++ b/avrftdi.c @@ -32,11 +32,15 @@ #include #include #include +#include #include "avrdude.h" #include "avr.h" #include "pgm.h" #include "avrftdi.h" +#include "avrpart.h" +#include "tpi.h" +#include "usbasp.h" #ifdef HAVE_LIBUSB #ifdef HAVE_LIBFTDI @@ -50,37 +54,33 @@ # error "libusb needs either or " #endif -#define SCK 0x01 -#define SDO 0x02 -#define SDI 0x04 +enum { FTDI_SCK = 1, FTDI_MOSI, FTDI_MISO, FTDI_RESET }; +#define FTDI_DEFAULT_MASK ( (1 << (FTDI_SCK - 1)) | (1 << (FTDI_MOSI - 1)) ) -#define RX 0x20 -#define TX 0x11 +#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 TRX (RX | TX) +#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 TYPE_C_D 0x500 -#define TYPE_H 0x700 -#define TYPE_4H 0x800 - -#define E(x, ftdi) if ((x)) { fprintf(stdout, "%s:%d %s() %s: %s (%d)\n\t%s\n", __FILE__, __LINE__, __FUNCTION__, \ - #x, strerror(errno), errno, ftdi_get_error_string(ftdi)); return -1; } - -#define E_VOID(x, ftdi) if ((x)) { fprintf(stdout, "%s:%d %s() %s: %s (%d)\n\t%s\n", __FILE__, __LINE__, __FUNCTION__, \ - #x, strerror(errno), errno, ftdi_get_error_string(ftdi)); } - -typedef struct avrftdi_s { - struct ftdi_context* ftdic; - uint16_t pin_value; - uint16_t pin_direction; - uint16_t pin_inversion; - uint16_t led_mask; - int type; /**type is bcdDevice. C/D is 0x500 H is 0x700 4H is 0x800*/ - int ftype; /** is from FTDI. Use TYPE_2232C, TYPE_2232H, or TYPE_4232H*/ -} avrftdi_t; #define to_pdata(pgm) \ - (avrftdi_t *)((pgm)->cookie) + ((avrftdi_t *)((pgm)->cookie)) /* This is for running the code without having a FTDI-device. * The generated code is useless! For debugging purposes only. @@ -90,6 +90,79 @@ typedef struct avrftdi_s { */ //#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; +} avrftdi_t; + +static int write_flush(avrftdi_t *); + +/* + * returns a human-readable name for a pin number. the name should match with + * the pin names used in FTDI datasheets. + */ +static char* +ftdi_pin_name(avrftdi_t* pdata, int pin) +{ + static char pin_name[16]; + + char interface = '@'; + char port; + + /* INTERFACE_ANY is zero, so @ is used + * INTERFACE_A is one, so '@' + 1 = 'A' + * and so forth ... + * be aware, there is an 'interface' member in ftdi_context, + * however, we really want the 'index' member here. + */ + interface += pdata->ftdic->index; + + /* This is FTDI's naming scheme. + * probably 'D' is for data and 'C' for control + */ + if(pin < 8) + port = 'D'; + else + port = 'C'; + + snprintf(pin_name, sizeof(pin_name), "%c%cBUS%d", interface, port, pin-1); + + return pin_name; +} + +/* + * output function, to save if(vebose>level)-constructs. also prefixes output + * with "avrftdi" to identify were messages came from. + * TODO: make this a macro, so that __LINE_ and __func__ macros can be used. + */ +static void +avrftdi_print(int level, const char * fmt, ...) +{ + va_list ap; + if(verbose > level) + { + fprintf(stderr, "avrftdi: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + } +} + +/* + * helper function to print a binary buffer *buf of size len. begin and end of + * the dump are enclosed in the string contained in *desc. offset denotes the + * number of bytes which are printed on the first line (may be 0). after that + * width bytes are printed on each line + */ static void buf_dump(unsigned char *buf, int len, char *desc, int offset, int width) { @@ -106,6 +179,10 @@ static void buf_dump(unsigned char *buf, int len, char *desc, fprintf(stderr, "%s end\n", desc); } +/* + * calculates the so-called 'divisor'-value from a given frequency. + * the divisor is sent to the chip. + */ static int set_frequency(avrftdi_t* ftdi, uint32_t freq) { uint32_t divisor; @@ -131,12 +208,10 @@ static int set_frequency(avrftdi_t* ftdi, uint32_t freq) divisor = 65535; } - if(verbose) - fprintf(stderr, - "%s info: clock divisor: 0x%04x\n", - progname, divisor); + avrftdi_print(0, "frequency: %d\n", 6000000/(divisor+1)); + avrftdi_print(1, "clock divisor: 0x%04x\n", divisor); - buf[0] = 0x86; + buf[0] = TCK_DIVISOR; buf[1] = (uint8_t)(divisor & 0xff); buf[2] = (uint8_t)((divisor >> 8) & 0xff); @@ -147,232 +222,275 @@ static int set_frequency(avrftdi_t* ftdi, uint32_t freq) return 0; } -static int -pin_limit(avrftdi_t* pdata) -{ - if(TYPE_4232H == pdata->ftype) - return 7; - else if(TYPE_2232C==pdata->ftype) - return 11; - else if(TYPE_2232H == pdata->ftype) - return 15; - else{ - fprintf(stderr, "Unknown type %d (0x%x)\n", - pdata->ftype, pdata->ftype); - return 15; - } - -} - -/* Add a single pin (by pin number) to the pin masks (or to pins), - * update pinmask[pinfunc] */ +/* + * Adds a single pin to the direction mask and sets the pin state inactive in + * the value mask. the value of 'inactive' is chosen according to the pin + * configuration (high or low active). + */ static int add_pin(PROGRAMMER *pgm, int pinfunc) { - int pin, inversion_mask, mlim; + int pin, pin_mask, inverted, fail; avrftdi_t* pdata = to_pdata(pgm); - - pin = pgm->pinno[pinfunc]; - if (verbose) - fprintf(stderr, - "add_pin: %d: bit 0x%04x inv=0x%04x\n", - pinfunc, pin, - (pin & PIN_INVERSE)? (1<< ((pin&PIN_MASK) - 1)): 0); - - /* non-existent definitions, go away */ - if (pin == 0) - return 0; - - /* see if pin should be inverted */ - if(pin & PIN_INVERSE) { - pin &= PIN_MASK; - inversion_mask = 1 << (pin - 1); - } else { - inversion_mask = 0; - } - mlim = pin_limit(pdata); + fail = 0; + pin = pgm->pinno[pinfunc] & PIN_MASK; + inverted = pgm->pinno[pinfunc] & PIN_INVERSE; + pin_mask = (1 << (pin - 1)); + + /* not configured */ + if(!pin) + { + avrftdi_print(0, "Pin %s not configured\n", avr_pin_name(pinfunc)); + return 0; + } /* check that the pin number is in range */ - if (pin > mlim) { + if (pin > pdata->pin_limit) + { fprintf(stderr, - "%s failure: invalid pin definition (pin no > %d) in config file\n", - progname, mlim); - fprintf(stderr, - "pin function no %d, pin no: 0x%x\n", - pinfunc, pin); - return -1; + "%s invalid pin definition for pin %s. Configured as pin %d, but highest pin is %d.\n", + progname, avr_pin_name(pinfunc), pin, pdata->pin_limit); + fail = 1; } - /* create the mask and check that the pin is available */ - if (pdata->pin_direction & (1 << (pin -1)) ) { + /* check if the pin is still available */ + if (pdata->pin_direction & pin_mask) + { fprintf(stderr, - "%s failure: pin %d has two definitions in config file\n", - progname, pin); - return -1; - } else { - pdata->pin_direction |= (1 << (pin - 1)); - pdata->pin_inversion |= inversion_mask; + "%s failure: pin %d (%s) is used twice. The second use is %s.\n", + progname, pin, ftdi_pin_name(pdata, pin), avr_pin_name(pinfunc)); + fail = 1; } + + /* + * No need to fail for a wrongly configured led. + * MISO, MOSI and SCK are fixed and correctly set during setup. + * Maybe we should fail for wrongly configured VCC or BUFF pins? + */ + if(fail) + { + if(pinfunc == PIN_AVR_RESET) + { + fprintf(stderr, "Aborting, since the reset pin is wrongly configured\n"); + return -1; + } + else + { + fprintf(stdout, "Ignoring wrongly configured pin.\n"); + return 0; + } + } + + /* all checks passed - do actual work */ + avrftdi_print(0, "Configure pin %d (%s) as %s (%s active)\n", + pin, ftdi_pin_name(pdata, pin), + avr_pin_name(pinfunc), (inverted) ? "low": "high"); + + { + /* create mask */ + pdata->pin_direction |= pin_mask; + /* and set default value */ + if(inverted) + pdata->pin_value |= pin_mask; + else + pdata->pin_value &= ~(pin_mask); + } + if(PIN_LED_ERR == pinfunc || - PIN_LED_VFY == pinfunc || - PIN_LED_RDY == pinfunc || - PIN_LED_PGM == pinfunc) { - pdata->led_mask|=(1 << (pin - 1)); + PIN_LED_VFY == pinfunc || + PIN_LED_RDY == pinfunc || + PIN_LED_PGM == pinfunc) { + pdata->led_mask |= pin_mask; } - + return 0; } -/* Add pins by pin mask */ - +/* + * Add pins by pin mask + * Check an entire mask for correctness and plausibility. Performed checks are + * the pin number is lower that the total number of pins and the pin is not + * configured yet. + * If at least one test fails, the entire mask is discarded. + * These basic tests could possibly moved to avrdude core, since it does not + * contain any tests (as far as I can tell). + */ static int add_pins(PROGRAMMER *pgm, int pinfunc) { - int i, pin, mlim; - uint32_t mask, inversion_mask=0; + int pin, inverted, fail; + uint32_t pin_mask, pin_bit; avrftdi_t* pdata = to_pdata(pgm); - pin = pgm->pinno[pinfunc]; + pin_mask = (pgm->pinno[pinfunc] & PIN_MASK) >> 1; + /* FIXME: I think you cannot inverse these multi-pin options */ + inverted = pgm->pinno[pinfunc] & PIN_INVERSE; - if(pin & PIN_INVERSE){ - pin &= PIN_MASK; - inversion_mask = pin >>1; - } - pin >>= 1; - if (verbose) - fprintf(stderr, - "add_pins: %d: 0x%04x, inv=0x%04x\n", - pinfunc, pin, inversion_mask); - mask = pin; - - mlim = pin_limit(pdata); - - if (mask >= 1 << mlim) { - fprintf(stderr, - "%s failure: pin list has pins out of range (%x>%x): ", - progname, mask, 1 << mlim); - mask &= ~(1 << mlim) - 1; - } - else if (mask & pdata->pin_direction) { - fprintf(stderr, - "%s failure: conflicting pins in pin list: ", - progname); - mask &= pdata->pin_direction; - } - else { - pdata->pin_direction |= (uint16_t)mask; - pdata->pin_inversion |= inversion_mask; + if(!pin_mask) + { + avrftdi_print(0, "Pins for %s not configured.\n", avr_pin_name(pinfunc)); return 0; } - /* print the list of pins, if needed */ - i = 0; - while (mask > 1) { - if (mask & 1) - fprintf(stderr, "%d, ", i); - mask >>= 1; - i++; - } - if (mask > 0) - fprintf(stderr, "%d\n", i); - return -1; -} + fail = 0; + /* check every configured pin */ + for(pin = 0; (1 << pin) & (PIN_MASK); pin++) + { + pin_bit = 1 << pin; + + /* skip, if this pin is not in the mask to be configured */ + if(!(pin_bit & pin_mask)) + continue; + - -static int write_flush(avrftdi_t* pdata) -{ - unsigned char buf[6]; - if(verbose > 2) - fprintf(stderr, - "%s info: direction: 0x%04x, value: 0x%04x, inversion: 0x%04x\n", - progname, pdata->pin_direction, pdata->pin_value, pdata->pin_inversion); - - buf[0] = 0x80; - buf[1] = (pdata->pin_value) & 0xff; - buf[2] = (pdata->pin_direction) & 0xff; - buf[3] = 0x82; - buf[4] = ((pdata->pin_value) >> 8) & 0xff; - buf[5] = ((pdata->pin_direction) >> 8) & 0xff; - -#ifndef DRYRUN - E(ftdi_write_data(pdata->ftdic, buf, 6) != 6, pdata->ftdic); - -#endif - - if (verbose > 3) - fprintf(stderr, "FTDI LOG: %02x %02x %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); - - /* we need to flush here, because set_pin is used as reset. - * if we want to sleep reset periods, we must be certain the - * avr has got the reset signal when we start sleeping. - * (it may be stuck in the USB stack or some USB hub) - */ -#ifndef DRYRUN - E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic); -#endif - - return 0; - -} - -/* this function sets or clears a GPIO pin */ -static int set_pin(avrftdi_t* pdata, int pin, int value) -{ - int bit; - uint16_t tval; - if (0 == pin){ - if(verbose > 2) + /* 0 is not a valid pin, see above, we use 1 << (pin - 1) to create pin_bit */ + if(pin + 1 > pdata->pin_limit) + { fprintf(stderr, - "%s info: Pin is zero val %d!\n", - progname, value); - return 1; - } - --pin; - bit= 1 << (pin); - if (pdata->pin_inversion & bit) { - value = !value; - } - if (value) - value = bit; + "%s invalid pin definition for pin %s. Configured as pin %d, but highest pin is %d.\n", + progname, avr_pin_name(pinfunc), pin + 1, pdata->pin_limit); + fail = 1; + } + + if(pin_bit & pdata->pin_direction) + { + fprintf(stderr, + "%s failure: pin %d (%s) is used twice. The second use is %s.\n", + progname, pin, ftdi_pin_name(pdata, pin), avr_pin_name(pinfunc)); + fail = 1; + } + + } + + /* we can ignore those, because only VCC and BUFF pins, can have multiples. + * VCC and BUFF are not essential + */ + if(fail) + { + fprintf(stdout, "Ignoring wrongly configured pins.\n"); + return 0; + } + + /* conditional output */ + for(pin = 0; (1 << pin) & (PIN_MASK); pin++) + { + pin_bit = 1 << pin; + + /* skip if pin is not set */ + if(!(pin_bit & pin_mask)) + continue; + + /* remember, we count from 1, not 0 */ + avrftdi_print(0, "Configured pin %d (%s) as %s (%s active)\n", + pin+1, ftdi_pin_name(pdata, pin+1), + avr_pin_name(pinfunc), (inverted) ? "low": "high"); + } + + /* do the work */ + pdata->pin_direction |= (uint16_t)pin_mask; + if(inverted) + pdata->pin_value |= pin_mask; + else + pdata->pin_value &= ~pin_mask; - if (verbose > 1) - fprintf(stderr, - "%s info: pin %04x bit %04x value 0x%04x\n", - progname, pin + 1, bit, value); - /* set bits depending on value */ - /*pin_value ^= (-value ^ pin_value) & (1 << (pin - 1)); */ - tval = (pdata->pin_value & (~bit)) | value; - if (tval != pdata->pin_value) { - pdata->pin_value = tval; - return write_flush(pdata); - } else if (verbose > 1) - fprintf(stderr, "SameVal\n"); return 0; - } -/* this function sets or clears one or more GPIO pin these are bit-mapped */ -static int set_pins(avrftdi_t* pdata, int pin, int value) +/* + * This function sets or clears any pin, except SCK, MISO and MOSI. Depending + * on the pin configuration, a non-zero value sets the pin in the 'active' + * state (high active, low active) and a zero value sets the pin in the + * inactive state. + * Because we configured the pin direction mask earlier, nothing bad can happen + * here. + */ +static int set_pin(PROGRAMMER * pgm, int pinfunc, int value) { - if (0 == pin) { - if(verbose > 2) - fprintf(stderr,"%s info: Pins is zero!\n",progname); + + int pin, pin_mask; + int inverted; + + avrftdi_t* pdata = to_pdata(pgm); + + 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? */ + /* + avrftdi_print(2, "%s info: Pin is zero, value: %d!\n", + progname, value); + */ return 1; } - pin >>=1; - if (pdata->pin_inversion & pin) { - value = !value; - } - if (value) - value = pin; - if (verbose) - fprintf(stderr, - "%s info: pin %04x value %d\n", - progname, pin, value); + if (value) + value = pin_mask; + + avrftdi_print(1, "Setting pin %d (%s) as %s: %s (%s active)\n", pin, + ftdi_pin_name(pdata, pin), avr_pin_name(pinfunc), + (value) ? "high" : "low", (inverted) ? "low" : "high"); + + /* set bits depending on value */ + //tval = (pdata->pin_value & (~pin_mask)) | pin_mask; + pdata->pin_value ^= (-value ^ pdata->pin_value) & pin_mask; + //fprintf(stderr, "%x %x\n", tval, pdata->pin_value); + + return write_flush(pdata); +} + +/* + * This function sets or clears a group of pins - VCC or BUFF. + * the semantics are the same as for single pins, described above. + */ +static int set_pins(PROGRAMMER * pgm, int pinfunc, int value) +{ + int pin, pin_mask; + int inverted; + int pin_bit; + + avrftdi_t* pdata = to_pdata(pgm); + + pin = pgm->pinno[pinfunc] & PIN_MASK; + inverted = pgm->pinno[pinfunc] & PIN_INVERSE; + + pin_mask = pin >> 1; + + value = (inverted) ? !value : !!value; + + if (!pin) { + /* dito above */ + return 1; + } + + if(value) + value = pin_mask; + + /* conditional output */ + for(pin = 0; (1 << pin) & (PIN_MASK); pin++) + { + pin_bit = 1 << pin; + + /* skip if pin is not set */ + if(!(pin_bit & pin_mask)) + continue; + + /* remember, we count from 1, not 0 */ + avrftdi_print(0, "Setting pin %d (%s) as %s: %s (%s active)\n", + pin+1, ftdi_pin_name(pdata, pin+1), avr_pin_name(pinfunc), + (value) ? "high" : "low", (inverted) ? "low": "high"); + } + /* set bits depending on value */ /*pin_value ^= (-value ^ pin_value) & (1 << (pin - 1)); */ - pdata->pin_value = (pdata->pin_value & (~pin)) | value; + pdata->pin_value ^= (-value ^ pdata->pin_value) & pin_mask; + + /*pdata->pin_value = (pdata->pin_value & (~pin_mask)) | value;*/ + return write_flush(pdata); } @@ -381,22 +499,22 @@ static int set_pins(avrftdi_t* pdata, int pin, int value) */ static int set_led_pgm(struct programmer_t * pgm, int value) { - return set_pin(to_pdata(pgm), pgm->pinno[PIN_LED_PGM], value); + return set_pin(pgm, PIN_LED_PGM, value); } static int set_led_rdy(struct programmer_t * pgm, int value) { - return set_pin(to_pdata(pgm), pgm->pinno[PIN_LED_RDY], value); + return set_pin(pgm, PIN_LED_RDY, value); } static int set_led_err(struct programmer_t * pgm, int value) { - return set_pin(to_pdata(pgm), pgm->pinno[PIN_LED_ERR], value); + return set_pin(pgm, PIN_LED_ERR, value); } static int set_led_vfy(struct programmer_t * pgm, int value) { - return set_pin(to_pdata(pgm), pgm->pinno[PIN_LED_VFY], value); + return set_pin(pgm, PIN_LED_VFY, value); } static int avrftdi_transmit(avrftdi_t* pdata, unsigned char mode, unsigned char *cmd, @@ -406,8 +524,8 @@ static int avrftdi_transmit(avrftdi_t* pdata, unsigned char mode, unsigned char int n; unsigned char buf[4 + buf_size]; - if (mode & TX) { - buf[0] = mode; + if (mode & MPSSE_DO_WRITE) { + buf[0] = mode | MPSSE_WRITE_NEG; buf[1] = ((buf_size - 1) & 0xff); buf[2] = (((buf_size - 1) >> 8) & 0xff); @@ -419,7 +537,7 @@ static int avrftdi_transmit(avrftdi_t* pdata, unsigned char mode, unsigned char #endif } - if (mode & RX) { + if (mode & MPSSE_DO_READ) { memset(buf, 0, sizeof(buf)); do { #ifndef DRYRUN @@ -437,6 +555,57 @@ static int avrftdi_transmit(avrftdi_t* pdata, unsigned char mode, unsigned char return k; } +static int write_flush(avrftdi_t* pdata) +{ + unsigned char buf[6]; + + avrftdi_print(2, + "%s info: direction: 0x%04x, value: 0x%04x\n", + progname, pdata->pin_direction, pdata->pin_value); + + buf[0] = SET_BITS_LOW; + buf[1] = (pdata->pin_value) & 0xff; + buf[2] = (pdata->pin_direction) & 0xff; + buf[3] = SET_BITS_HIGH; + buf[4] = ((pdata->pin_value) >> 8) & 0xff; + buf[5] = ((pdata->pin_direction) >> 8) & 0xff; + +#ifndef DRYRUN + E(ftdi_write_data(pdata->ftdic, buf, 6) != 6, pdata->ftdic); + +#endif + + avrftdi_print(3, "FTDI LOG: %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + /* we need to flush here, because set_pin is used as reset. + * if we want to sleep reset periods, we must be certain the + * avr has got the reset signal when we start sleeping. + * (it may be stuck in the USB stack or some USB hub) + * + * 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. + */ +#ifndef DRYRUN + //E(ftdi_usb_purge_buffers(pdata->ftdic), pdata->ftdic); + + unsigned char cmd[] = { GET_BITS_LOW, SEND_IMMEDIATE }; + unsigned int n; + 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); + E(n < 0, pdata->ftdic); + } while(n < 1); + +#endif + + return 0; +} + + static int avrftdi_open(PROGRAMMER * pgm, char *port) { int vid, pid, interface, snfound; @@ -447,10 +616,15 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port) avrftdi_t* pdata = to_pdata(pgm); + /************************ + * parameter validation * + ************************/ + /* use vid/pid in following priority: config, * defaults. cmd-line is currently not supported */ snfound = 0; foundsn = NULL; + memset(serial, 0, sizeof(serial)); if (pgm->usbvid) vid = pgm->usbvid; @@ -475,30 +649,30 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port) progname, pgm->usbdev); interface = INTERFACE_A; } + + /************** + * USB lookup * + **************/ + #ifndef DRYRUN found_dev = NULL; if (ftdi_usb_find_all(pdata->ftdic, &devlist, vid, pid)) { devlist_ptr = devlist; do { ftdi_usb_get_strings(pdata->ftdic, devlist_ptr->dev, - NULL, 0, NULL, 0, serial, 255); + NULL, 0, NULL, 0, serial, sizeof(serial)); - if (verbose) - fprintf(stderr, - "%s: device: %s, serial number: %s type 0x%04x found\n", - progname, devlist_ptr->dev->filename, - serial, devlist_ptr->dev->descriptor.bcdDevice); + avrftdi_print(1, "%s: device: %s, serial number: %s type 0x%04x found\n", + progname, devlist_ptr->dev->filename, serial, + devlist_ptr->dev->descriptor.bcdDevice); if (!snfound) { if (strcmp(pgm->usbsn, serial) == 0){ foundsn = strdup(serial); snfound = 1; found_dev = devlist_ptr->dev; - pdata->type = devlist_ptr->dev->descriptor.bcdDevice; } }else { - if (0 == pdata->type) /**we assume it will attach to first found. */ - pdata->type = devlist_ptr->dev->descriptor.bcdDevice; if (NULL == found_dev) found_dev = devlist_ptr->dev; if (NULL == foundsn) @@ -521,87 +695,30 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port) progname, vid, pid, pgm->usbsn); return -1; } - if (verbose) { - fprintf(stderr, - "%s: Using device VID:PID %04x:%04x type 0x%04x(", - progname, vid, pid, pdata->type); - switch (pdata->type) { - case TYPE_C_D: - fprintf(stderr,"C/D"); break; - case TYPE_H: - fprintf(stderr,"H"); break; - case TYPE_4H: - fprintf(stderr,"4H"); break; - default: - fprintf(stderr,"unknown %04x",pdata->type); break; - } - fprintf(stderr,") and SN '%s'.\n", foundsn); - } - if (pdata->type == TYPE_C_D && INTERFACE_B == interface){ - fprintf(stderr, - "%s: Type C/D found. Setting interface to A\n", - progname); - interface = INTERFACE_A; - } - /*must be A for mpsse if C/D, can be A/B for H */ - if (verbose) - fprintf(stderr, - "%s: Using USB Interface %c\n", - progname, INTERFACE_A == interface? 'A': 'B'); + avrftdi_print(1, + "%s: Using device VID:PID %04x:%04x and SN '%s' on interface %c.\n", + progname, vid, pid, foundsn, INTERFACE_A == interface? 'A': 'B'); + free(foundsn); +#endif + + /**************** + * Device setup * + ****************/ + E(ftdi_set_interface(pdata->ftdic, interface) < 0, pdata->ftdic); E(ftdi_usb_open_dev(pdata->ftdic,found_dev) <0, pdata->ftdic); -/* E(ftdi_usb_open_desc(&ftdic, vid,pid,NULL,0==pgm->usbsn[0]?NULL:pgm->usbsn) < 0); */ - pdata->ftype=pdata->ftdic->type; -#endif + E(ftdi_usb_reset(pdata->ftdic) < 0, pdata->ftdic); + ftdi_set_latency_timer(pdata->ftdic, 1); - - if (SCK != (1 << (pgm->pinno[PIN_AVR_SCK] - 1)) - || SDO != (1 << (pgm->pinno[PIN_AVR_MOSI] - 1)) - || SDI != (1 << (pgm->pinno[PIN_AVR_MISO] - 1))) { - fprintf(stderr, - "%s failure: pinning for FTDI MPSSE must be:\n" - "\tSCK: 1, SDO: 2, SDI: 3(is: %d,%d,%d)\n", - progname, - pgm->pinno[PIN_AVR_SCK], - pgm->pinno[PIN_AVR_MOSI], - pgm->pinno[PIN_AVR_MISO]); - fprintf(stderr, "Setting pins accordingly ...\n"); - pgm->pinno[PIN_AVR_SCK] = 1; - pgm->pinno[PIN_AVR_MOSI] = 2; - pgm->pinno[PIN_AVR_MISO] = 3; - - } - if(verbose) - fprintf(stderr, - "%s info: reset pin value: %x\n", - progname, pgm->pinno[PIN_AVR_RESET]-1); - if (pgm->pinno[PIN_AVR_RESET] < 4 || pgm->pinno[PIN_AVR_RESET] == 0) { - fprintf(stderr, - "%s failure: RESET pin clashes with data pin or is not set.\n", - progname); - fprintf(stderr, "Setting to default-value 4\n"); - pgm->pinno[PIN_AVR_RESET] = 4; - } - - pdata->pin_direction = (0x3 | (1 << (pgm->pinno[PIN_AVR_RESET] - 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; - if (add_pin(pgm, PIN_LED_ERR)) return -1; - if (add_pin(pgm, PIN_LED_RDY)) return -1; - if (add_pin(pgm, PIN_LED_PGM)) return -1; - if (add_pin(pgm, PIN_LED_VFY)) return -1; #ifndef DRYRUN - E(ftdi_set_bitmode(pdata->ftdic, pdata->pin_direction & 0xff, BITMODE_MPSSE) < 0, pdata->ftdic); /*set SPI */ - write_flush(pdata); + /* 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); + #endif - if (verbose > 1) { - fprintf(stderr, "pin direction mask: %04x\n", pdata->pin_direction); - fprintf(stderr, "pin value mask: %04x\n", pdata->pin_value); - } if (pgm->baudrate) { set_frequency(pdata, pgm->baudrate); @@ -610,9 +727,78 @@ static int avrftdi_open(PROGRAMMER * pgm, char *port) } else { set_frequency(pdata, pgm->baudrate ? pgm->baudrate : 150000); } - /**set the ready LED, if we have one .. and set our direction up */ + + /************* + * pin setup * + *************/ + + if ( FTDI_SCK != pgm->pinno[PIN_AVR_SCK] + || FTDI_MOSI != pgm->pinno[PIN_AVR_MOSI] + || FTDI_MISO != pgm->pinno[PIN_AVR_MISO]) + { + fprintf(stderr, "%s failure: pinning for FTDI MPSSE must be:\n", progname); + fprintf(stderr, "\t%s: 1, %s: 2, %s: 3(is: %d,%d,%d)\n", + avr_pin_name(PIN_AVR_SCK), avr_pin_name(PIN_AVR_MOSI), + avr_pin_name(PIN_AVR_MISO), pgm->pinno[PIN_AVR_SCK], + pgm->pinno[PIN_AVR_MOSI], pgm->pinno[PIN_AVR_MISO]); + + fprintf(stderr, "Setting pins accordingly ...\n"); + pgm->pinno[PIN_AVR_SCK] = FTDI_SCK; + pgm->pinno[PIN_AVR_MOSI] = FTDI_MOSI; + pgm->pinno[PIN_AVR_MISO] = FTDI_MISO; + } + + avrftdi_print(1, "reset pin value: %x\n", pgm->pinno[PIN_AVR_RESET]-1); + + if ( pgm->pinno[PIN_AVR_RESET] < FTDI_RESET + || pgm->pinno[PIN_AVR_RESET] == 0) + { + fprintf(stderr, + "%s failure: RESET pin clashes with data pin or is not set.\n", + progname); + fprintf(stderr, "Setting to default-value 4\n"); + pgm->pinno[PIN_AVR_RESET] = FTDI_RESET; + } + + //pdata->pin_direction = (0x3 | (1 << (pgm->pinno[PIN_AVR_RESET] - 1))); + + /* set pin limit depending on chip type */ + switch(pdata->ftdic->type) { + case TYPE_2232C: + pdata->pin_limit = 15; + break; + case TYPE_2232H: + pdata->pin_limit = 11; + break; + case TYPE_4232H: + default: + pdata->pin_limit = 7; + } + + /* add SCK, MOSI and RESET as output pins - MISO needs no configuration */ + if (add_pin(pgm, PIN_AVR_SCK)) return -1; + 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; + if (add_pin(pgm, PIN_LED_ERR)) return -1; + if (add_pin(pgm, PIN_LED_RDY)) return -1; + if (add_pin(pgm, PIN_LED_PGM)) return -1; + if (add_pin(pgm, PIN_LED_VFY)) return -1; + + avrftdi_print(1, "pin direction mask: %04x\n", pdata->pin_direction); + avrftdi_print(1, "pin value mask: %04x\n", pdata->pin_value); + + /********************************************** + * set the ready LED and set our direction up * + **********************************************/ + set_led_rdy(pgm,0); - set_led_rdy(pgm,1); + set_led_pgm(pgm,1); + return 0; } @@ -621,17 +807,19 @@ static void avrftdi_close(PROGRAMMER * pgm) avrftdi_t* pdata = to_pdata(pgm); if(pdata->ftdic->usb_dev) { - set_pins(pdata, pgm->pinno[PPI_AVR_BUFF], ON); - set_pin(pdata, pgm->pinno[PIN_AVR_RESET], ON); + set_pins(pgm, PPI_AVR_BUFF, ON); + set_pin(pgm, PIN_AVR_RESET, ON); /**Stop driving the pins - except for the LEDs */ - if (verbose > 1) - fprintf(stderr, - "LED Mask=0x%04x value =0x%04x &=0x%04x\n", + + avrftdi_print(1, "LED Mask=0x%04x value =0x%04x &=0x%04x\n", pdata->led_mask, pdata->pin_value, pdata->led_mask & pdata->pin_value); + pdata->pin_direction = pdata->led_mask; pdata->pin_value &= pdata->led_mask; write_flush(pdata); #ifndef DRYRUN + /* reset state recommended by FTDI */ + ftdi_set_bitmode(pdata->ftdic, 0, BITMODE_RESET); E_VOID(ftdi_usb_close(pdata->ftdic), pdata->ftdic); #endif } @@ -639,24 +827,23 @@ static void avrftdi_close(PROGRAMMER * pgm) return; } - static int avrftdi_initialize(PROGRAMMER * pgm, AVRPART * p) { avrftdi_t* pdata = to_pdata(pgm); - set_pin(pdata, pgm->pinno[PIN_AVR_RESET], OFF); - set_pins(pdata, pgm->pinno[PPI_AVR_BUFF], OFF); - set_pin(pdata, pgm->pinno[PIN_AVR_SCK], OFF); + 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(pdata, pgm->pinno[PIN_AVR_RESET], ON); + set_pin(pgm, PIN_AVR_RESET, ON); usleep(20 * 1000); /*setting rst back to 0 */ - set_pin(pdata, pgm->pinno[PIN_AVR_RESET], OFF); + set_pin(pgm, PIN_AVR_RESET, OFF); /*wait at least 20ms bevor issuing spi commands to avr */ usleep(20 * 1000); @@ -683,7 +870,7 @@ static int avrftdi_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res { /* Do not use 'sizeof(cmd)'. => message from cppcheck: Using sizeof for array given as function argument returns the size of pointer. */ - return avrftdi_transmit(to_pdata(pgm), TRX, cmd, res, 4); + return avrftdi_transmit(to_pdata(pgm), MPSSE_DO_READ | MPSSE_DO_WRITE, cmd, res, 4); } @@ -691,7 +878,6 @@ static int avrftdi_program_enable(PROGRAMMER * pgm, AVRPART * p) { int i; unsigned char buf[4]; - avrftdi_t* pdata = to_pdata(pgm); memset(buf, 0, sizeof(buf)); @@ -708,9 +894,9 @@ static int avrftdi_program_enable(PROGRAMMER * pgm, AVRPART * p) pgm->cmd(pgm, buf, buf); if (buf[p->pollindex-1] != p->pollvalue) { //try resetting - set_pin(pdata, pgm->pinno[PIN_AVR_RESET], ON); + set_pin(pgm, PIN_AVR_RESET, ON); usleep(20); - set_pin(pdata, pgm->pinno[PIN_AVR_RESET], OFF); + set_pin(pgm, PIN_AVR_RESET, OFF); avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf); } else return 0; @@ -747,9 +933,11 @@ static int avrftdi_chip_erase(PROGRAMMER * pgm, AVRPART * p) /* Load extended address byte command */ -static int avrftdi_lext(avrftdi_t* pdata, AVRPART *p, AVRMEM *m, unsigned int address) +static int +avrftdi_lext(avrftdi_t* pdata, AVRPART *p, AVRMEM *m, unsigned int address) { - unsigned char buf[] = {0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}; + unsigned char buf[] = + { MPSSE_DO_WRITE | MPSSE_WRITE_NEG, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }; avr_set_bits(m->op[AVR_OP_LOAD_EXT_ADDR], &buf[3]); avr_set_addr(m->op[AVR_OP_LOAD_EXT_ADDR], &buf[3], address); @@ -759,7 +947,8 @@ static int avrftdi_lext(avrftdi_t* pdata, AVRPART *p, AVRMEM *m, unsigned int ad "load extended address command", 0, 16 * 3); #ifndef DRYRUN - E(ftdi_write_data(pdata->ftdic, buf, sizeof(buf)) != sizeof(buf), pdata->ftdic); + E(ftdi_write_data(pdata->ftdic, buf, sizeof(buf)) != sizeof(buf), + pdata->ftdic); #endif return 0; } @@ -767,18 +956,20 @@ static int avrftdi_lext(avrftdi_t* pdata, AVRPART *p, AVRMEM *m, unsigned int ad static int avrftdi_eeprom_write(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int len) { - unsigned char cmd[4]; + unsigned char cmd[] = + { MPSSE_DO_WRITE | MPSSE_WRITE_NEG, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned char *data = &m->buf[addr]; unsigned int add; - avr_set_bits(m->op[AVR_OP_WRITE], cmd); + avr_set_bits(m->op[AVR_OP_WRITE], &cmd[3]); for (add = addr; add < addr + len; add++) { - avr_set_addr(m->op[AVR_OP_WRITE], cmd, add); - avr_set_input(m->op[AVR_OP_WRITE], cmd, *data++); + 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), TX, cmd, cmd, 4); + E(ftdi_write_data(to_pdata(pgm)->ftdic, cmd, sizeof(cmd)) != sizeof(cmd), + to_pdata(pgm)->ftdic); usleep((m->max_write_delay)); } @@ -793,13 +984,13 @@ static int avrftdi_eeprom_read(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, unsigned int add; memset(buffer, 0, sizeof(buffer)); - for (add = addr; add < addr + len; add++) { + memset(cmd, 0, sizeof(cmd)); avr_set_bits(m->op[AVR_OP_READ], cmd); avr_set_addr(m->op[AVR_OP_READ], cmd, add); - avrftdi_transmit(to_pdata(pgm), TRX, cmd, cmd, 4); + avrftdi_transmit(to_pdata(pgm), MPSSE_DO_READ | MPSSE_DO_WRITE, cmd, cmd, 4); avr_get_output(m->op[AVR_OP_READ], cmd, bufptr++); } @@ -811,16 +1002,17 @@ static int avrftdi_eeprom_read(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, static int avrftdi_flash_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned int page_size, unsigned int addr, unsigned int len) { - int i; - unsigned int address = addr/2, buf_size; - unsigned int address_prev_block = ~address; /* start address of previous block, - init to different than address */ - unsigned int bytes = len; - unsigned int blocksize; int use_lext_address = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL; - unsigned char buf[4*len+4], *bufptr = buf; + + unsigned int word; + unsigned int poll_index; + unsigned int buf_size; + + unsigned char poll_byte; unsigned char *buffer = &m->buf[addr]; - unsigned char byte; + unsigned char buf[4*len+4], *bufptr = buf; + + memset(buf, 0, sizeof(buf)); /* pre-check opcodes */ if (m->op[AVR_OP_LOADPAGE_LO] == NULL) { @@ -836,113 +1028,121 @@ static int avrftdi_flash_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, return -1; } - //page_size = (page_size > m->page_size) ? m->page_size : page_size - 8; + if(page_size != m->page_size) { + fprintf(stderr, + "%s: Something funny is going on. Parameter" + "page_size is %d, buf m->page_size is %d. Using" + "the latter.\n", progname, page_size, m->page_size); + } + page_size = m->page_size; - while (bytes) { - if (bytes > page_size) { - blocksize = (page_size)/2; - bytes -= (page_size); - } else { - blocksize = bytes/2; - bytes = 0; - } - - if(verbose > 2) - fprintf(stderr, - "-< bytes = %d of %d, blocksize = %d of %d\n", - len - bytes, len, blocksize, m->page_size / 2); - - /* if we do cross a 64k word boundary (or write the - * first page), we need to issue a 'load extended - * address byte' command, which is defined as 0x4d - * 0x00
0x00. As far as i know, this - * is only available on 256k parts. 64k word is 128k - * bytes. - */ - if(use_lext_address && ((address & 0xffff0000) != (address_prev_block & 0xffff0000))) { - avrftdi_lext(to_pdata(pgm), p, m, address); - } - address_prev_block = address; - - for (i = 0; i < blocksize; i++) { - /*setting word*/ - avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], bufptr); - avr_set_addr(m->op[AVR_OP_LOADPAGE_LO], bufptr, address); - avr_set_input(m->op[AVR_OP_LOADPAGE_LO], bufptr, *buffer++); - bufptr += 4; - avr_set_bits(m->op[AVR_OP_LOADPAGE_HI], bufptr); - avr_set_addr(m->op[AVR_OP_LOADPAGE_HI], bufptr, address); - avr_set_input(m->op[AVR_OP_LOADPAGE_HI], bufptr, *buffer++); - bufptr += 4; - address++; - } - - if (verbose > 2) - fprintf(stderr, - "address = %d, page_size = %d\n", - address, m->page_size); - - if (((address * 2) % m->page_size) == 0 || bytes == 0) { - if (m->op[AVR_OP_WRITEPAGE] == NULL) { - fprintf(stderr, - "%s failure: Write Page (WRITEPAGE) command not defined for %s\n", - progname, p->desc); - exit(1); - } else { - avr_set_bits(m->op[AVR_OP_WRITEPAGE], bufptr); - } - /* setting page address highbyte */ - avr_set_addr(m->op[AVR_OP_WRITEPAGE], - bufptr, address - 1); - bufptr += 4; - } - - buf_size = bufptr - buf; - - if(verbose > 3) - buf_dump(buf, buf_size, "command buffer", 0, 16*3); - if(verbose > 2) - fprintf(stderr, - "%s info: buffer size: %d\n", - progname, buf_size); - - avrftdi_transmit(to_pdata(pgm), TX, buf, buf, buf_size); - - bufptr = buf; - if (((address * 2) % m->page_size) == 0 || bytes == 0) { - do { - pgm->read_byte(pgm, p, m, - (address * 2) - 1, &byte); - } while (m->buf[(address*2) - 1] != byte); - } - - if (verbose < 3) - report_progress(2 * address - addr, len, NULL); + /* if we do cross a 64k word boundary (or write the + * first page), we need to issue a 'load extended + * address byte' command, which is defined as 0x4d + * 0x00
0x00. As far as i know, this + * is only available on 256k parts. 64k word is 128k + * bytes. + * write the command only once. + */ + if(use_lext_address && (((addr/2) & 0xffff0000))) { + avrftdi_lext(to_pdata(pgm), p, m, addr/2); } + + /* prepare the command stream for the whole page */ + /* addr is in bytes, but we program in words. addr/2 should be something + * like addr >> WORD_SHIFT, though */ + for(word = addr/2; word < (len + addr)/2; word++) + { + avrftdi_print(2, "-< bytes = %d of %d\n", word * 2, len + addr); + + /*setting word*/ + avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], bufptr); + /* here is the second byte increment, just if you're wondering */ + avr_set_addr(m->op[AVR_OP_LOADPAGE_LO], bufptr, word); + avr_set_input(m->op[AVR_OP_LOADPAGE_LO], bufptr, *buffer++); + bufptr += 4; + avr_set_bits(m->op[AVR_OP_LOADPAGE_HI], bufptr); + avr_set_addr(m->op[AVR_OP_LOADPAGE_HI], bufptr, word); + avr_set_input(m->op[AVR_OP_LOADPAGE_HI], bufptr, *buffer++); + bufptr += 4; + } + + /* issue write page command, if available */ + if (m->op[AVR_OP_WRITEPAGE] == NULL) { + fprintf(stderr, + "%s failure: Write Page (WRITEPAGE) command not defined for %s\n", + progname, p->desc); + //FIXME: maybe not exit but return error code + exit(1); + } else { + avr_set_bits(m->op[AVR_OP_WRITEPAGE], bufptr); + /* setting page address highbyte */ + avr_set_addr(m->op[AVR_OP_WRITEPAGE], + bufptr, addr/2); + bufptr += 4; + } + + buf_size = bufptr - buf; + + if(verbose > 3) + buf_dump(buf, buf_size, "command buffer", 0, 16*2); + + avrftdi_print(2, "%s info: buffer size: %d\n", progname, buf_size); + + avrftdi_transmit(to_pdata(pgm), MPSSE_DO_WRITE, buf, buf, buf_size); + + bufptr = buf; + /* find a poll byte. we cannot poll a value of 0xff, so look + * for a value != 0xff + */ + for(poll_index = addr+len-1; poll_index > addr-1; poll_index--) + if(m->buf[poll_index] != 0xff) + break; + + if((poll_index < addr + len) && m->buf[poll_index] != 0xff) + { + avrftdi_print(2, "%s: using m->buf[%d] = 0x%02x as polling value ", + progname, poll_index, m->buf[poll_index]); + /* poll page write ready */ + do { + avrftdi_print(2, "."); + + pgm->read_byte(pgm, p, m, poll_index, &poll_byte); + } while (m->buf[poll_index] != poll_byte); + + avrftdi_print(2, "\n"); + } + else + { + fprintf(stderr, "%s: no suitable byte (!=0xff) for polling found.\n", progname); + fprintf(stderr, "%s: trying to sleep, but programming errors may occur.\n", progname); + fprintf(stderr, "%s: be sure to verify programmed memory (no -V option)\n", progname); + /* TODO sync write */ + /* sleep */ + usleep((m->max_write_delay)); + } + return len; } +/* + *Reading from flash + */ static int avrftdi_flash_read(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned int page_size, unsigned int addr, unsigned int len) { - /* - *Reading from flash - */ + OPCODE * readop; + int byte, word; int use_lext_address = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL; - int i, buf_index, buf_size = 0, psize = m->page_size; - unsigned char o_buf[4*len+4], *o_ptr = o_buf; - unsigned char i_buf[4*len+4]; unsigned int address = addr/2; - unsigned int address_prev_block = ~address; /* start address of previous block, - init to different than address */ - unsigned int bytes = len; - unsigned int blocksize; - unsigned char buffer[m->size], *bufptr = buffer; + + unsigned char o_buf[4*len+4]; + unsigned char i_buf[4*len+4]; + unsigned int index; memset(o_buf, 0, sizeof(o_buf)); memset(i_buf, 0, sizeof(i_buf)); - memset(buffer, 0, sizeof(buffer)); /* pre-check opcodes */ if (m->op[AVR_OP_READ_LO] == NULL) { @@ -957,55 +1157,56 @@ static int avrftdi_flash_read(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, progname, "AVR_OP_READ_HI", p->desc); return -1; } - - while (bytes) { - if (bytes > psize) { - blocksize = psize/2; - bytes -= psize; - } else { - blocksize = bytes/2; - bytes = 0; - } - - if(use_lext_address && ((address & 0xffff0000) != (address_prev_block & 0xffff0000))) { - avrftdi_lext(to_pdata(pgm), p, m, address); - } - address_prev_block = address; - - for(i = 0; i < blocksize; i++) { - if(verbose > 3) - fprintf(stderr, - "bufsize: %d, i: %d, add: %d\n", - buf_size, i, address); - avr_set_bits(m->op[AVR_OP_READ_LO], o_ptr); - avr_set_addr(m->op[AVR_OP_READ_LO], o_ptr, address); - o_ptr += 4; - avr_set_bits(m->op[AVR_OP_READ_HI], o_ptr); - avr_set_addr(m->op[AVR_OP_READ_HI], o_ptr, address); - o_ptr += 4; - - address++; - - //FIXME: why not program on per-page basis? - //maybe this covered a timing error in an earlier version? - buf_size = o_ptr - o_buf; - - if((buf_size >= (page_size - 8)) || ( i == blocksize-1)) { - avrftdi_transmit(to_pdata(pgm), TRX, o_buf, i_buf, buf_size); - - for(buf_index = 0; buf_index < buf_size; buf_index+=8) { - avr_get_output(m->op[AVR_OP_READ_LO], i_buf+buf_index, bufptr++); - avr_get_output(m->op[AVR_OP_READ_HI], i_buf+buf_index+4, bufptr++); - } - - if(verbose > 3) { - buf_dump(i_buf, buf_size, "i_buf", 0, 16); - } - o_ptr = o_buf; - } - } + + if(use_lext_address && ((address & 0xffff0000))) { + avrftdi_lext(to_pdata(pgm), p, m, address); } - memcpy(m->buf + addr, buffer, len); + + /* word addressing! */ + for(word = addr/2, index = 0; word < (addr + len)/2; word++) + { + /* one byte is transferred via a 4-byte opcode. + * TODO: reduce magic numbers + */ + avr_set_bits(m->op[AVR_OP_READ_LO], &o_buf[index*4]); + avr_set_addr(m->op[AVR_OP_READ_LO], &o_buf[index*4], word); + index++; + avr_set_bits(m->op[AVR_OP_READ_HI], &o_buf[index*4]); + avr_set_addr(m->op[AVR_OP_READ_HI], &o_buf[index*4], word); + index++; + } + + /* transmit, + * if there was an error, we did not see, memory validation will + * subsequently fail. + */ + if(verbose > 2) { + buf_dump(o_buf, sizeof(o_buf), "o_buf", 0, 32); + } + + avrftdi_transmit(to_pdata(pgm), MPSSE_DO_READ | MPSSE_DO_WRITE, o_buf, i_buf, len * 4); + + if(verbose > 2) { + buf_dump(i_buf, sizeof(i_buf), "i_buf", 0, 32); + } + + memset(&m->buf[addr], 0, page_size); + + /* every (read) op is 4 bytes in size and yields one byte of memory data */ + for(byte = 0; byte < page_size; byte++) { + if(byte & 1) + readop = m->op[AVR_OP_READ_HI]; + else + readop = m->op[AVR_OP_READ_LO]; + + /* take 4 bytes and put the memory byte in the buffer at + * offset addr + offset of the current byte + */ + avr_get_output(readop, &i_buf[byte*4], &m->buf[addr+byte]); + } + + if(verbose > 2) + buf_dump(&m->buf[addr], page_size, "page:", 0, 32); return len; } @@ -1052,10 +1253,7 @@ avrftdi_setup(PROGRAMMER * pgm) pdata->pin_value = 0; pdata->pin_direction = 0; - pdata->pin_inversion = 0; pdata->led_mask = 0; - pdata->type = 0; - pdata->ftype = 0; } static void @@ -1063,8 +1261,6 @@ avrftdi_teardown(PROGRAMMER * pgm) { avrftdi_t* pdata = to_pdata(pgm); - /* reset state recommended by FTDI */ - ftdi_set_bitmode(pdata->ftdic, 0, BITMODE_MPSSE); #ifndef DRYRUN ftdi_deinit(pdata->ftdic); ftdi_free(pdata->ftdic);