/* * avrftdi - extension for avrdude, Wolfgang Moser, Ville Voipio * Copyright (C) 2011 Hannes Weisbach, Doug Springer * * 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 . */ /* $Id$ */ /* * Interface to the MPSSE Engine of FTDI Chips using libftdi. */ #include "ac_cfg.h" #include #include #include #include #include #include #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_1_0 #ifdef HAVE_LIBFTDI1 #include #include enum { FTDI_SCK = 1, FTDI_MOSI, FTDI_MISO, FTDI_RESET }; enum { ERROR, WARN, INFO, DEBUG, TRACE }; #define __log(lvl, fmt, ...) \ do { \ avrftdi_log(lvl, __func__, __LINE__, fmt, ##__VA_ARGS__); \ } while(0) #define log_err(fmt, ...) __log(ERROR, fmt, ##__VA_ARGS__) #define log_warn(fmt, ...) __log(WARN, fmt, ##__VA_ARGS__) #define log_info(fmt, ...) __log(INFO, fmt, ##__VA_ARGS__) #define log_debug(fmt, ...) __log(DEBUG, fmt, ##__VA_ARGS__) #define log_trace(fmt, ...) __log(TRACE, fmt, ##__VA_ARGS__) #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 * doing. * If you think you know what you are doing: YOU DONT! */ //#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 *); /* * 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 function-name(line-number):" to identify were messages came * from. * This function is the backend of the log_*-macros, but it can be used * directly. */ static void avrftdi_log(int level, const char * func, int line, const char * fmt, ...) { static int skip_prefix = 0; const char *p = fmt; va_list ap; if(verbose >= level) { if(!skip_prefix) { switch(level) { case ERROR: fprintf(stderr, "E "); break; case WARN: fprintf(stderr, "W "); break; case INFO: fprintf(stderr, "I "); break; case DEBUG: fprintf(stderr, "D "); break; case TRACE: fprintf(stderr, "T "); break; default: fprintf(stderr, " "); } fprintf(stderr, "%s(%d): ", func, line); } va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } skip_prefix = 1; while(*p++) if(*p == '\n' && !(*(p+1))) skip_prefix = 0; } /* * 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) { int i; fprintf(stderr, "%s begin:\n", desc); for (i = 0; i < offset; i++) fprintf(stderr, "%02x ", buf[i]); fprintf(stderr, "\n"); for (i++; i <= len; i++) { fprintf(stderr, "%02x ", buf[i-1]); if((i-offset) != 0 && (i-offset)%width == 0) fprintf(stderr, "\n"); } 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; uint8_t buf[3]; /* divisor on 6000000 / freq - 1 */ divisor = (6000000 / freq) - 1; if (divisor < 0) { log_warn("Frequency too high (%u > 6 MHz)\n", freq); log_warn("Resetting Frequency to 6MHz\n"); divisor = 0; } if (divisor > 65535) { log_warn("Frequency too low (%u < 91.553 Hz)\n", freq); log_warn("Resetting Frequency to 91.553Hz\n"); divisor = 65535; } log_info("Using frequency: %d\n", 6000000/(divisor+1)); log_info("Clock divisor: 0x%04x\n", divisor); buf[0] = TCK_DIVISOR; buf[1] = (uint8_t)(divisor & 0xff); buf[2] = (uint8_t)((divisor >> 8) & 0xff); #ifndef DRYRUN E(ftdi_write_data(ftdi->ftdic, buf, 3) < 0, ftdi->ftdic); #endif return 0; } /* * 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, pin_mask, inverted, fail; avrftdi_t* pdata = to_pdata(pgm); fail = 0; pin = pgm->pinno[pinfunc] & PIN_MASK; inverted = pgm->pinno[pinfunc] & PIN_INVERSE; pin_mask = (1 << (pin - 1)); /* not configured */ if(!pin) { log_warn("Pin %s not configured\n", avr_pin_name(pinfunc)); return 0; } /* check that the pin number is in range */ if (pin > pdata->pin_limit) { log_warn("Invalid pin definition for pin %s.\n", avr_pin_name(pinfunc)); log_warn("Configured as pin %d, but highest pin is %d.\n", pin, pdata->pin_limit); fail = 1; } /* check if the pin is still available */ if (pdata->pin_direction & pin_mask) { log_warn("Pin %d (%s) is used twice. The second use is %s.\n", 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) { log_err("Aborting, since the reset pin is wrongly configured\n"); return -1; } else { log_warn("Ignoring wrongly configured pin.\n"); return 0; } } /* all checks passed - do actual work */ log_info("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 |= pin_mask; } return 0; } /* * 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 pin, inverted; uint32_t pin_mask, pin_bit; avrftdi_t* pdata = to_pdata(pgm); 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_mask) { log_warn("Pins for %s not configured.\n", avr_pin_name(pinfunc)); return 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; /* 0 is not a valid pin, see above, we use 1 << (pin - 1) to create pin_bit */ if(pin + 1 > pdata->pin_limit) { log_warn("Invalid pin definition for pin %s.\n", avr_pin_name(pinfunc)); log_warn("Configured as pin %d, but highest pin is %d.\n", pin + 1, pdata->pin_limit); log_warn("Ignoring wrongly configured pins.\n"); } if(pin_bit & pdata->pin_direction) { log_warn("Failure: pin %d (%s) is used twice. The second use is %s.\n", pin, ftdi_pin_name(pdata, pin), avr_pin_name(pinfunc)); log_warn("Ignoring wrongly configured pins.\n"); } } /* 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 */ log_info("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; return 0; } /* * 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) { 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; } if (value) value = pin_mask; log_debug("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 */ log_debug("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 ^= (-value ^ pdata->pin_value) & pin_mask; /*pdata->pin_value = (pdata->pin_value & (~pin_mask)) | value;*/ return write_flush(pdata); } /* these functions are callbacks, which go into the * PROGRAMMER data structure ("optional functions") */ static int set_led_pgm(struct programmer_t * pgm, int value) { return set_pin(pgm, PIN_LED_PGM, value); } static int set_led_rdy(struct programmer_t * pgm, int value) { return set_pin(pgm, PIN_LED_RDY, value); } static int set_led_err(struct programmer_t * pgm, int value) { return set_pin(pgm, PIN_LED_ERR, value); } static int set_led_vfy(struct programmer_t * pgm, int value) { return set_pin(pgm, PIN_LED_VFY, value); } /* Send 'buf_size' bytes from 'cmd' to device and return data from device in * buffer 'data'. * Write is only performed when mode contains MPSSE_DO_WRITE. * Read is only performed when mode contains MPSSE_DO_WRITE and MPSSE_DO_READ. */ static int avrftdi_transmit(avrftdi_t* pdata, unsigned char mode, unsigned char *buf, unsigned char *data, int buf_size) { size_t blocksize; size_t remaining = buf_size; size_t written = 0; unsigned char cmd[3]; // unsigned char si = SEND_IMMEDIATE; cmd[0] = mode | MPSSE_WRITE_NEG; cmd[1] = ((buf_size - 1) & 0xff); cmd[2] = (((buf_size - 1) >> 8) & 0xff); //if we are not reading back, we can just write the data out if(!(mode & MPSSE_DO_READ)) blocksize = buf_size; else blocksize = pdata->rx_buffer_size; #ifndef DRYRUN E(ftdi_write_data(pdata->ftdic, cmd, sizeof(cmd)) != sizeof(cmd), pdata->ftdic); #endif while(remaining) { size_t transfer_size = (remaining > blocksize) ? blocksize : remaining; #ifndef DRYRUN E(ftdi_write_data(pdata->ftdic, &buf[written], transfer_size) != transfer_size, pdata->ftdic); #endif #if 0 if(remaining < blocksize) E(ftdi_write_data(pdata->ftdic, &si, sizeof(si)) != sizeof(si), pdata->ftdic); #endif if (mode & MPSSE_DO_READ) { int n; int k = 0; do { #ifndef DRYRUN n = ftdi_read_data(pdata->ftdic, &data[written + k], transfer_size - k); E(n < 0, pdata->ftdic); #else n = transfer_size - k; #endif k += n; } while (k < transfer_size); } written += transfer_size; remaining -= transfer_size; } return written; } static int write_flush(avrftdi_t* pdata) { unsigned char buf[6]; log_debug("Setting pin direction (0x%04x) and value (0x%04x)\n", 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 log_trace("Set pins command: %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; 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, index, err; char * serial, *desc; avrftdi_t* pdata = to_pdata(pgm); /************************ * parameter validation * ************************/ /* use vid/pid in following priority: config, * defaults. cmd-line is currently not supported */ if (pgm->usbvid) vid = pgm->usbvid; else vid = 0x0403; if (pgm->usbpid) pid = pgm->usbpid; else pid = 0x6010; if (0 == pgm->usbsn[0]) /* we don't care about SN. Use first avail. */ serial = NULL; else serial = pgm->usbsn; /* not used yet, but i put them here, just in case someone does needs or * wants to implement this. */ desc = NULL; index = 0; if (pgm->usbdev[0] == 'a' || pgm->usbdev[0] == 'A') interface = INTERFACE_A; else if (pgm->usbdev[0] == 'b' || pgm->usbdev[0] == 'B') interface = INTERFACE_B; else { log_warn("Invalid interface '%s'. Setting to Interface A\n", pgm->usbdev); interface = INTERFACE_A; } /**************** * Device setup * ****************/ E(ftdi_set_interface(pdata->ftdic, interface) < 0, pdata->ftdic); err = ftdi_usb_open_desc_index(pdata->ftdic, vid, pid, desc, serial, index); if(err) { log_err("Error %d occured: %s\n", err, ftdi_get_error_string(pdata->ftdic)); //stupid hack, because avrdude calls pgm->close() even when pgm->open() fails //and usb_dev is intialized to the last usb device from probing pdata->ftdic->usb_dev = NULL; return err; } else { log_info("Using device VID:PID %04x:%04x and SN '%s' on interface %c.\n", vid, pid, serial, INTERFACE_A == interface? 'A': 'B'); } ftdi_set_latency_timer(pdata->ftdic, 1); /* 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); if (pgm->baudrate) { set_frequency(pdata, pgm->baudrate); } else if(pgm->bitclock) { set_frequency(pdata, (uint32_t)(1.0f/pgm->bitclock)); } else { set_frequency(pdata, pgm->baudrate ? pgm->baudrate : 150000); } /************* * pin setup * *************/ if ( FTDI_SCK != pgm->pinno[PIN_AVR_SCK] || FTDI_MOSI != pgm->pinno[PIN_AVR_MOSI] || FTDI_MISO != pgm->pinno[PIN_AVR_MISO]) { log_warn("Pin configuration for FTDI MPSSE must be:\n"); log_warn("%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]); log_warn("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; } log_info("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) { log_warn("RESET pin clashes with data pin or is not set.\n"); log_warn("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_AM: case TYPE_BM: case TYPE_R: log_err("Found unsupported device type AM, BM or R. avrftdi "); log_err("cannot work with your chip. Try the 'synbb' programmer.\n"); return -1; case TYPE_2232C: pdata->pin_limit = 11; pdata->rx_buffer_size = 384; break; case TYPE_2232H: pdata->pin_limit = 15; pdata->rx_buffer_size = 4096; break; case TYPE_232H: pdata->pin_limit = 15; pdata->rx_buffer_size = 1024; break; case TYPE_4232H: pdata->pin_limit = 7; pdata->rx_buffer_size = 2048; break; default: log_warn("Found unkown device %x. I will do my ", pdata->ftdic->type); log_warn("best to work with it, but no guarantees ...\n"); pdata->pin_limit = 7; pdata->rx_buffer_size = pdata->ftdic->max_packet_size; break; } /* 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; log_info("Pin direction mask: %04x\n", pdata->pin_direction); log_info("Pin value mask: %04x\n", pdata->pin_value); /********************************************** * set the ready LED and set our direction up * **********************************************/ set_led_rdy(pgm,0); set_led_pgm(pgm,1); return 0; } static void avrftdi_close(PROGRAMMER * pgm) { avrftdi_t* pdata = to_pdata(pgm); if(pdata->ftdic->usb_dev) { set_pins(pgm, PPI_AVR_BUFF, ON); set_pin(pgm, PIN_AVR_RESET, ON); /* Stop driving the pins - except for the LEDs */ log_info("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 } return; } 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); /* 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); return pgm->program_enable(pgm, p); } static void avrftdi_disable(PROGRAMMER * pgm) { return; } static void avrftdi_enable(PROGRAMMER * pgm) { return; } static void avrftdi_display(PROGRAMMER * pgm, const char *p) { return; } static int avrftdi_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res[4]) { /* 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), MPSSE_DO_READ | MPSSE_DO_WRITE, cmd, res, 4); } static int avrftdi_program_enable(PROGRAMMER * pgm, AVRPART * p) { int i; unsigned char buf[4]; memset(buf, 0, sizeof(buf)); if (p->op[AVR_OP_PGM_ENABLE] == NULL) { log_err("AVR_OP_PGM_ENABLE command not defined for %s\n", p->desc); return -1; } avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf); for(i = 0; i < 4; i++) { pgm->cmd(pgm, buf, buf); if (buf[p->pollindex-1] != p->pollvalue) { log_warn("Program enable command not successful. Retrying.\n"); set_pin(pgm, PIN_AVR_RESET, ON); usleep(20); set_pin(pgm, PIN_AVR_RESET, OFF); avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf); } else return 0; } log_err("Device is not responding to program enable. Check connection.\n"); #ifndef DRYRUN return -1; #else return 0; #endif } static int avrftdi_chip_erase(PROGRAMMER * pgm, AVRPART * p) { unsigned char cmd[4]; unsigned char res[4]; if (p->op[AVR_OP_CHIP_ERASE] == NULL) { log_err("AVR_OP_CHIP_ERASE command not defined for %s\n", p->desc); return -1; } 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); return 0; } /* Load extended address byte command */ static int avrftdi_lext(avrftdi_t* pdata, AVRPART *p, AVRMEM *m, unsigned int address) { 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); if(verbose > TRACE) buf_dump(buf, sizeof(buf), "load extended address command", 0, 16 * 3); #ifndef DRYRUN E(ftdi_write_data(pdata->ftdic, buf, sizeof(buf)) != sizeof(buf), pdata->ftdic); #endif return 0; } static int avrftdi_eeprom_write(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int len) { 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[3]); for (add = addr; add < addr + len; add++) { avr_set_addr(m->op[AVR_OP_WRITE], &cmd[3], add); avr_set_input(m->op[AVR_OP_WRITE], &cmd[3], *data++); E(ftdi_write_data(to_pdata(pgm)->ftdic, cmd, sizeof(cmd)) != sizeof(cmd), to_pdata(pgm)->ftdic); usleep((m->max_write_delay)); } return len; } static int avrftdi_eeprom_read(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, unsigned int page_size, unsigned int addr, unsigned int len) { unsigned char cmd[4]; unsigned char buffer[len], *bufptr = buffer; 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), MPSSE_DO_READ | MPSSE_DO_WRITE, cmd, cmd, 4); avr_get_output(m->op[AVR_OP_READ], cmd, bufptr++); } memcpy(m->buf + addr, buffer, len); return len; } static int avrftdi_flash_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned int page_size, unsigned int addr, unsigned int len) { int use_lext_address = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL; unsigned int word; unsigned int poll_index; unsigned int buf_size; unsigned char poll_byte; unsigned char *buffer = &m->buf[addr]; unsigned char buf[4*len+4], *bufptr = buf; memset(buf, 0, sizeof(buf)); /* pre-check opcodes */ if (m->op[AVR_OP_LOADPAGE_LO] == NULL) { log_err("AVR_OP_LOADPAGE_LO command not defined for %s\n", p->desc); return -1; } if (m->op[AVR_OP_LOADPAGE_HI] == NULL) { log_err("AVR_OP_LOADPAGE_HI command not defined for %s\n", p->desc); return -1; } if(page_size != m->page_size) { log_warn("Parameter page_size is %d, ", page_size); log_warn("but m->page_size is %d. Using the latter.\n", m->page_size); } page_size = m->page_size; /* 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++) { log_debug("-< 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) { log_err("AVR_OP_WRITEPAGE command not defined for %s\n", p->desc); return -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 > TRACE) buf_dump(buf, buf_size, "command buffer", 0, 16*2); log_info("Transmitting buffer of size: %d\n", 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) { log_info("Using m->buf[%d] = 0x%02x as polling value ", poll_index, m->buf[poll_index]); /* poll page write ready */ do { log_info("."); pgm->read_byte(pgm, p, m, poll_index, &poll_byte); } while (m->buf[poll_index] != poll_byte); log_info("\n"); } else { log_warn("No suitable byte (!=0xff) for polling found.\n"); log_warn("Trying to sleep instead, but programming errors may occur.\n"); log_warn("Be sure to verify programmed memory (no -V option)\n"); /* 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) { OPCODE * readop; int byte, word; int use_lext_address = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL; unsigned int address = addr/2; 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)); /* pre-check opcodes */ if (m->op[AVR_OP_READ_LO] == NULL) { log_err("AVR_OP_READ_LO command not defined for %s\n", p->desc); return -1; } if (m->op[AVR_OP_READ_HI] == NULL) { log_err("AVR_OP_READ_HI command not defined for %s\n", p->desc); return -1; } if(use_lext_address && ((address & 0xffff0000))) { avrftdi_lext(to_pdata(pgm), p, m, address); } /* 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 > TRACE) { 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 > TRACE) { 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 > TRACE) buf_dump(&m->buf[addr], page_size, "page:", 0, 32); return len; } static int avrftdi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned int page_size, unsigned int addr, unsigned int n_bytes) { if (strcmp(m->desc, "flash") == 0) return avrftdi_flash_write(pgm, p, m, page_size, addr, n_bytes); else if (strcmp(m->desc, "eeprom") == 0) return avrftdi_eeprom_write(pgm, p, m, page_size, addr, n_bytes); else return -2; } static int avrftdi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned int page_size, unsigned int addr, unsigned int n_bytes) { if (strcmp(m->desc, "flash") == 0) return avrftdi_flash_read(pgm, p, m, page_size, addr, n_bytes); else if(strcmp(m->desc, "eeprom") == 0) return avrftdi_eeprom_read(pgm, p, m, page_size, addr, n_bytes); else return -2; } static void avrftdi_setup(PROGRAMMER * pgm) { avrftdi_t* pdata; pgm->cookie = malloc(sizeof(avrftdi_t)); pdata = to_pdata(pgm); #ifndef DRYRUN pdata->ftdic = ftdi_new(); if(!pdata->ftdic) { log_err("Error allocating memory.\n"); exit(-ENOMEM); } E_VOID(ftdi_init(pdata->ftdic), pdata->ftdic); #endif pdata->pin_value = 0; pdata->pin_direction = 0; pdata->led_mask = 0; } static void avrftdi_teardown(PROGRAMMER * pgm) { avrftdi_t* pdata = to_pdata(pgm); if(pdata) { #ifndef DRYRUN ftdi_deinit(pdata->ftdic); ftdi_free(pdata->ftdic); #endif free(pdata); } } void avrftdi_initpgm(PROGRAMMER * pgm) { strcpy(pgm->type, "avrftdi"); /* * mandatory functions */ pgm->initialize = avrftdi_initialize; pgm->display = avrftdi_display; pgm->enable = avrftdi_enable; pgm->disable = avrftdi_disable; pgm->program_enable = avrftdi_program_enable; pgm->chip_erase = avrftdi_chip_erase; pgm->cmd = avrftdi_cmd; pgm->open = avrftdi_open; pgm->close = avrftdi_close; pgm->read_byte = avr_read_byte_default; pgm->write_byte = avr_write_byte_default; /* * optional functions */ pgm->paged_write = avrftdi_paged_write; pgm->paged_load = avrftdi_paged_load; pgm->setup = avrftdi_setup; pgm->teardown = avrftdi_teardown; pgm->rdy_led = set_led_rdy; pgm->err_led = set_led_err; pgm->pgm_led = set_led_pgm; pgm->vfy_led = set_led_vfy; } #else /*HAVE_LIBFTDI1*/ static int avrftdi_noftdi_open (struct programmer_t *pgm, char * name) { fprintf(stderr, "%s: Error: no libftdi1 support. Install libftdi1 and run configure/make again.\n", progname); exit(1); } void avrftdi_initpgm(PROGRAMMER * pgm) { strcpy(pgm->type, "avrftdi"); pgm->open = avrftdi_noftdi_open; } #endif /* HAVE_LIBFTDI1 */ #else /*HAVE_LIBUSB_1_0*/ static int avrftdi_nousb_open (struct programmer_t *pgm, char * name) { fprintf(stderr, "%s: Error: no USB support. Install libusb-1.0 and run configure/make again.\n", progname); exit(1); } void avrftdi_initpgm(PROGRAMMER * pgm) { strcpy(pgm->type, "avrftdi"); pgm->open = avrftdi_nousb_open; } #endif /*HAVE_LIBUSB_1_0*/ const char avrftdi_desc[] = "Interface to the MPSSE Engine of FTDI Chips using libftdi.";