diff --git a/ChangeLog b/ChangeLog index 3d468759..d576dfcf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2012-02-01 Rene Liebscher + + bug #30559 Ft232 bit-bang support + * ft245r.[ch]: new programmer type implementation + * configure.ac: add pthread as link library + * avrdude.conf.in: added some new programmers + * Makefile.am: added new source files to compile + * pindefs.h: change PIN_MASK, PIN_INVERSE to highest bit of unsigned int + * pgm.[ch]: added generic function to print pin assignments (taken from par.c) + * par.c: moved pin assigment print function to pgm.c + 2012-02-01 Joerg Wunsch * lexer.l: Sort keyword tokens into alphabetic order. diff --git a/Makefile.am b/Makefile.am index f4ef4db3..4e05bb44 100644 --- a/Makefile.am +++ b/Makefile.am @@ -91,6 +91,8 @@ libavrdude_a_SOURCES = \ avr.h \ avr910.c \ avr910.h \ + ft245r.c \ + ft245r.h \ avrdude.h \ avrftdi.c \ avrftdi.h \ diff --git a/avrdude.conf.in b/avrdude.conf.in index 5f5c9532..a8d7da1e 100644 --- a/avrdude.conf.in +++ b/avrdude.conf.in @@ -16,13 +16,8 @@ # parent # optional parent # id = [, [, ] ...] ; # are quoted strings # desc = ; # quoted string -# type = par | stk500 | stk500v2 | stk500pp | stk500hvsp | stk500generic | -# stk600 | stk600pp | stk600hvsp | -# avr910 | butterfly | usbasp | -# jtagmki | jtagmkii | jtagmkii_isp | jtagmkii_dw | -# jtagmkII_avr32 | jtagmkii_pdi | -# dragon_dw | dragon_jtag | dragon_isp | dragon_pp | -# dragon_hvsp | dragon_pdi | arduino | wiring; # programmer type +# type = ; # programmer type, quoted string +# # supported programmer types can be listed by "-c ?type" # connection_type = parallel | serial | usb # baudrate = ; # baudrate for avr910-programmer # vcc = [, ... ] ; # pin number(s) @@ -576,6 +571,59 @@ programmer connection_type = serial; ; +programmer + id = "ft245r"; + desc = "FT245R Synchronous BitBang"; + type = "ftdi_syncbb"; + connection_type = usb; + miso = 2; # D1 + sck = 1; # D0 + mosi = 3; # D2 + reset = 5; # D4 +; + +programmer + id = "ft232r"; + desc = "FT232R Synchronous BitBang"; + type = "ftdi_syncbb"; + connection_type = usb; + miso = 2; # RxD + sck = 1; # RTS + mosi = 3; # TxD + reset = 5; # DTR +; + +# see http://www.bitwizard.nl/wiki/index.php/FTDI_ATmega +programmer + id = "bwmega"; + desc = "BitWizard ftdi_atmega builtin programmer"; + type = "ftdi_syncbb"; + connection_type = usb; + miso = 6; # DSR + sck = 7; # DCD + mosi = 4; # CTS + reset = 8; # RI +; + +# see http://www.geocities.jp/arduino_diecimila/bootloader/index_en.html +# Note: pins are numbered from 1! +programmer + id = "arduino-ft232r"; + desc = "Arduino: FT232R connected to ISP"; + type = "ftdi_syncbb"; + connection_type = usb; + miso = 4; # CTS X3(1) + sck = 6; # DSR X3(2) + mosi = 7; # DCD X3(3) + reset = 8; # RI X3(4) +; + +# website mentioned above uses this id +programmer parent "arduino-ft232r" + id = "diecimila"; + desc = "alias for arduino-ft232r"; +; + programmer id = "usbasp"; desc = "USBasp, http://www.fischl.de/usbasp/"; diff --git a/configure.ac b/configure.ac index fc36c85b..70c39674 100644 --- a/configure.ac +++ b/configure.ac @@ -135,7 +135,7 @@ AH_TEMPLATE([HAVE_LIBFTDI], [Define if FTDI support is enabled via libftdi]) AC_CHECK_LIB([ftdi], [ftdi_usb_get_strings], [have_libftdi=yes], [], [-lusb]) if test x$have_libftdi = xyes; then - LIBFTDI="-lftdi -lusb" + LIBFTDI="-lftdi -lusb -lpthread" AC_DEFINE([HAVE_LIBFTDI]) fi AC_SUBST(LIBFTDI, $LIBFTDI) diff --git a/ft245r.c b/ft245r.c new file mode 100644 index 00000000..bf14368c --- /dev/null +++ b/ft245r.c @@ -0,0 +1,831 @@ + +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2003-2004 Theodore A. Roth + * some code: + * Copyright (C) 2011-2012 Roger E. Wolff + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* $Id$ */ + +/* ft245r -- FT245R/FT232R Synchronous BitBangMode Programmer + default pin assign + FT232R / FT245R + miso = 2; # RxD / D1 + sck = 1; # RTS / D0 + mosi = 3; # TxD / D2 + reset = 5; # DTR / D4 +*/ + +/* + The ft232r is very similar, or even "identical" in the synchronous + bitbang mode that we use here. + + This allows boards that have an ft232r for communication and an avr + as the processor to function as their own "ICSP". Boards that fit + this description include the Arduino Duemilanove, Arduino Diecimila, + Arduino NG (http://arduino.cc/it/main/boards) and the BitWizard + ftdi_atmega board (http://www.bitwizard.nl/wiki/index.php/FTDI_ATmega) + + The Arduinos have to be patched to bring some of the control lines + to the ICSP header. The BitWizard board already has the neccessary + wiring on the PCB. + + How to add the wires to an arduino is documented here: + http://www.geocities.jp/arduino_diecimila/bootloader/index_en.html +*/ + + +#include "ac_cfg.h" + +#include +#include +#include +#include +#include +#include + +#include "avrdude.h" +#include "avr.h" +#include "avrpart.h" +#include "pindefs.h" +#include "pgm.h" +#include "config.h" +#include "bitbang.h" +#include "ft245r.h" + +#include +#include + +#ifdef HAVE_LIBFTDI + +#if defined(_WIN32) +#include +#endif + +#include + + +#define FT245R_CYCLES 2 +#define FT245R_FRAGMENT_SIZE 512 +#define REQ_OUTSTANDINGS 10 +//#define USE_INLINE_WRITE_PAGE + +#define FT245R_DEBUG 1 + +static struct ftdi_context *handle; + +static unsigned char ft245r_ddr; +static unsigned char ft245r_sck; +static unsigned char ft245r_mosi; +static unsigned char ft245r_reset; +static unsigned char ft245r_miso; + +#define BUFSIZE 0x2000 + +// libftdi / libftd2xx compatibility functions. + +static pthread_t readerthread; +static sem_t buf_data, buf_space; +static unsigned char buffer[BUFSIZE]; +static int head, tail; + +static void add_to_buf (unsigned char c) { + int nh; + + sem_wait (&buf_space); + if (head == (BUFSIZE -1)) nh = 0; + else nh = head + 1; + + if (nh == tail) { + fprintf (stderr, "buffer overflow. Cannot happen!\n"); + //exit (1); + } + buffer[head] = c; + head = nh; + sem_post (&buf_data); +} + +static void *reader (void *arg) { + struct ftdi_context *handle = (struct ftdi_context *)(arg); + unsigned char buf[0x1000]; + int br, i; + + while (1) { + br = ftdi_read_data (handle, buf, sizeof(buf)); + for (i=0; i> 1); + } else { + *data &= ~(pins >> 1); + } +} + +static inline void setmybit(unsigned char *data, int pinno, int v) { + if (v) { + *data |= (1 << (pinno-1)); + } else { + *data &= ~(1 <<(pinno-1)); + } +} + +static int ft245r_send(PROGRAMMER * pgm, unsigned char * buf, size_t len) { + int rv; + + rv = ftdi_write_data(handle, buf, len); + if (len != rv) return -1; + return 0; +} + +static int ft245r_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len) { + int i; + + // Copy over data from the circular buffer.. + // XXX This should timeout, and return error if there isn't enough + // data. + for (i=0; iop[AVR_OP_CHIP_ERASE] == NULL) { + fprintf(stderr, "chip erase instruction not defined for part \"%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; +} + +static unsigned char saved_signature[3]; + +static void ft245r_set_bitclock(PROGRAMMER * pgm) { + int r; + int rate = 0; + + /* bitclock is second. 1us = 0.000001. Max rate for ft232r 750000 */ + if(pgm->bitclock) { + rate = (uint32_t)(1.0/pgm->bitclock) * 2; + } else if (pgm->baudrate) { + rate = pgm->baudrate * 2; + } else { + rate = 150000; /* should work for all ftdi chips and the avr default internal clock of 1MHz */ + } + + if ((verbose>=1) || FT245R_DEBUG) { + fprintf(stderr," ft245r: spi bitclk %d -> ft baudrate %d\n", + rate / 2, rate); + } + r = ftdi_set_baudrate(handle, rate); + if (r) { + fprintf(stderr, "Set baudrate (%d) failed with error '%s'.\n", + rate, ftdi_get_error_string (handle)); + exit (1); + } +} + +static int set_reset(PROGRAMMER * pgm, int val) { + unsigned char buf[1]; + + buf[0] = 0; + if (val) buf[0] |= ft245r_reset; + + ft245r_send (pgm, buf, 1); + ft245r_recv (pgm, buf, 1); + return 0; +} + +static int ft245r_cmd(PROGRAMMER * pgm, unsigned char cmd[4], + unsigned char res[4]); +/* + * issue the 'program enable' command to the AVR device + */ +static int ft245r_program_enable(PROGRAMMER * pgm, AVRPART * p) { + int retry_count = 0; + unsigned char cmd[4]; + unsigned char res[4]; + int i,reset_ok; + + ft245r_set_bitclock(pgm); + +retry: + reset_ok = 0; + set_reset(pgm, 0); + usleep(5000); // 5ms + set_reset(pgm, 1); + usleep(5000); // 5ms + set_reset(pgm, 0); + usleep(5000); // 5ms + + cmd[0] = 0xAC; + cmd[1] = 0x53; + cmd[2] = 0; + cmd[3] = 0; + ft245r_cmd(pgm, cmd, res); + if (res[2] == 0x53 ) reset_ok = 1; + for (i=0; i<3; i++) { + cmd[0] = 0x30; + cmd[1] = 0; + cmd[2] = i; + cmd[3] = 0; + ft245r_cmd(pgm, cmd, res); + saved_signature[i] = res[3]; + } + if (reset_ok && (saved_signature[0] == 0x1e)) // success + return 0; + + if (retry_count < 5) { + if (retry_count == 3) { + ft245r_drain (pgm, 0); + tail = head; + } + retry_count++; + goto retry; + } + if ((verbose>=1) || FT245R_DEBUG) { + fprintf(stderr, + "%s: ft245r_program_enable: failed\n", progname); + fflush(stderr); + } + return -1; +} + +static int ft245r_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m) { + m->buf[0] = saved_signature[0]; + m->buf[1] = saved_signature[1]; + m->buf[2] = saved_signature[2]; + return 3; +} + +#define check_pin(s) {\ + if ((pgm->pinno[s] & PIN_MASK) == 0) {\ + fprintf(stderr,\ + "%s: pin %s is not set\n",\ + progname,#s);\ + exit(1);\ + }\ + if ((pgm->pinno[s] & PIN_INVERSE) != 0) {\ + fprintf(stderr,\ + "%s: pin %s inverse is not supported.\n",\ + progname,#s);\ + exit(1);\ + }\ +} + +/* + * initialize the AVR device and prepare it to accept commands + */ +static int ft245r_initialize(PROGRAMMER * pgm, AVRPART * p) { + check_pin(PIN_AVR_SCK); + check_pin(PIN_AVR_MOSI); + check_pin(PIN_AVR_MISO); + check_pin(PIN_AVR_RESET); + return ft245r_program_enable(pgm, p); +} + +static void ft245r_disable(PROGRAMMER * pgm) { + return; +} + + +static void ft245r_enable(PROGRAMMER * pgm) { + /* Do nothing. */ + return; +} + +static inline int set_data(unsigned char *buf, unsigned char data) { + int j; + int buf_pos = 0; + unsigned char bit = 0x80; + + for (j=0; j<8; j++) { + buf[buf_pos] = 0; + if (data & bit) buf[buf_pos] |= ft245r_mosi; + buf_pos++; + + buf[buf_pos] = 0; + if (data & bit) buf[buf_pos] |= ft245r_mosi; + buf[buf_pos] |= ft245r_sck; + buf_pos++; + + bit >>= 1; + } + return buf_pos; +} + +static inline unsigned char extract_data(unsigned char *buf, int offset) { + int j; + int buf_pos = 1; + unsigned char bit = 0x80; + unsigned char r = 0; + + buf += offset * (8 * FT245R_CYCLES); + for (j=0; j<8; j++) { + if (buf[buf_pos] & ft245r_miso) { + r |= bit; + } + buf_pos += FT245R_CYCLES; + bit >>= 1; + } + return r; +} + +/* to check data */ +static inline unsigned char extract_data_out(unsigned char *buf, int offset) { + int j; + int buf_pos = 1; + unsigned char bit = 0x80; + unsigned char r = 0; + + buf += offset * (8 * FT245R_CYCLES); + for (j=0; j<8; j++) { + if (buf[buf_pos] & ft245r_mosi) { + r |= bit; + } + buf_pos += FT245R_CYCLES; + bit >>= 1; + } + return r; +} + + +/* + * transmit an AVR device command and return the results; 'cmd' and + * 'res' must point to at least a 4 byte data buffer + */ +static int ft245r_cmd(PROGRAMMER * pgm, unsigned char cmd[4], + unsigned char res[4]) { + int i,buf_pos; + unsigned char buf[128]; + + buf_pos = 0; + for (i=0; i<4; i++) { + buf_pos += set_data(buf+buf_pos, cmd[i]); + } + buf[buf_pos] = 0; + buf_pos++; + + ft245r_send (pgm, buf, buf_pos); + ft245r_recv (pgm, buf, buf_pos); + res[0] = extract_data(buf, 0); + res[1] = extract_data(buf, 1); + res[2] = extract_data(buf, 2); + res[3] = extract_data(buf, 3); + + return 0; +} + + +static int ft245r_open(PROGRAMMER * pgm, char * port) { + int rv; + int devnum = -1; + strcpy(pgm->port, port); + + if (strcmp(port,DEFAULT_USB) != 0) { + if (strncasecmp("ft", port, 2) == 0) { + char *startptr = port + 2; + char *endptr = NULL; + devnum = strtol(startptr,&endptr,10); + if ((startptr==endptr) || (*endptr != '\0')) { + devnum = -1; + } + } + if (devnum < 0) { + fprintf(stderr, + "%s: invalid portname '%s': use 'ft[0-9]+'\n", + progname,port); + exit(1); + } + } else { + devnum = 0; + } + + handle = malloc (sizeof (struct ftdi_context)); + ftdi_init(handle); + rv = ftdi_usb_open_desc_index(handle, + pgm->usbvid?pgm->usbvid:0x0403, + pgm->usbpid?pgm->usbpid:0x6001, + pgm->usbproduct[0]?pgm->usbproduct:NULL, + pgm->usbsn[0]?pgm->usbsn:NULL, + devnum); + if (rv) { + fprintf (stderr, "can't open ftdi device %d. (%s)\n", devnum, ftdi_get_error_string(handle)); + ftdi_deinit (handle); + free(handle); + exit (1); + } + + /* We start a new thread to read the output from the FTDI. This is + * necessary because otherwise we'll deadlock. We cannot finish + * writing because the ftdi cannot send the results because we + * haven't provided a read buffer yet. */ + + sem_init (&buf_data, 0, 0); + sem_init (&buf_space, 0, BUFSIZE); + pthread_create (&readerthread, NULL, reader, handle); + + ft245r_ddr = 0; + setmybit(&ft245r_ddr, pgm->pinno[PIN_AVR_SCK], 1); + setmybit(&ft245r_ddr, pgm->pinno[PIN_AVR_MOSI], 1); + setmybit(&ft245r_ddr, pgm->pinno[PIN_AVR_RESET], 1); + + ft245r_sck = 0; + setmybit(&ft245r_sck, pgm->pinno[PIN_AVR_SCK], 1); + ft245r_mosi = 0; + setmybit(&ft245r_mosi, pgm->pinno[PIN_AVR_MOSI], 1); + ft245r_reset = 0; + setmybit(&ft245r_reset, pgm->pinno[PIN_AVR_RESET], 1); + ft245r_miso = 0; + setmybit(&ft245r_miso, pgm->pinno[PIN_AVR_MISO], 1); + + rv = ftdi_set_bitmode(handle, ft245r_ddr, BITMODE_SYNCBB); // set Synchronous BitBang + + if (rv) { + fprintf(stderr, + "%s: Synchronous BitBangMode is not supported (%s)\n", + progname, ftdi_get_error_string(handle)); + ftdi_usb_close(handle); + ftdi_deinit (handle); + free(handle); + exit(1); + } + /* + * drain any extraneous input + */ + ft245r_drain (pgm, 0); + + return 0; +} + + +static void ft245r_close(PROGRAMMER * pgm) { + // I think the switch to BB mode and back flushes the buffer. + ftdi_set_bitmode(handle, 0, BITMODE_SYNCBB); // set Synchronous BitBang, all in puts + ftdi_set_bitmode(handle, 0, BITMODE_RESET); // disable Synchronous BitBang + ftdi_usb_close(handle); + ftdi_deinit (handle); + free(handle); +} + +static void ft245r_display(PROGRAMMER * pgm, const char * p) { + fprintf(stderr, "%sPin assignment : 1..8 = DBUS0..7, 9..12 = GPIO0..3\n",p); + pgm_display_generic_mask(pgm, p, SHOW_AVR_PINS); +} + +static int ft245r_paged_write_gen(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + unsigned int page_size, unsigned int addr, + unsigned int n_bytes) { + unsigned long i, pa; + int rc; + + for (i=0; ibuf[addr]); + if (rc != 0) { + return -2; + } + + if (m->paged) { + // Can this piece of code ever be activated?? Do AVRs exist that + // have paged non-flash memories? -- REW + // XXX Untested code below. + /* + * check to see if it is time to flush the page with a page + * write + */ + + if (((addr % m->page_size) == m->page_size-1) || (i == n_bytes-1)) { + pa = addr - (addr % m->page_size); + + rc = avr_write_page(pgm, p, m, pa); + if (rc != 0) { + return -2; + } + } + } + } + return i; +} + +static struct ft245r_request { + int addr; + int bytes; + int n; + struct ft245r_request *next; +} *req_head,*req_tail,*req_pool; + +static void put_request(int addr, int bytes, int n) { + struct ft245r_request *p; + if (req_pool) { + p = req_pool; + req_pool = p->next; + } else { + p = malloc(sizeof(struct ft245r_request)); + if (!p) { + fprintf(stderr, "can't alloc memory\n"); + exit(1); + } + } + memset(p, 0, sizeof(struct ft245r_request)); + p->addr = addr; + p->bytes = bytes; + p->n = n; + if (req_tail) { + req_tail->next = p; + req_tail = p; + } else { + req_head = req_tail = p; + } +} + +static int do_request(PROGRAMMER * pgm, AVRMEM *m) { + struct ft245r_request *p; + int addr, bytes, j, n; + unsigned char buf[FT245R_FRAGMENT_SIZE+1+128]; + + if (!req_head) return 0; + p = req_head; + req_head = p->next; + if (!req_head) req_tail = req_head; + + addr = p->addr; + bytes = p->bytes; + n = p->n; + memset(p, 0, sizeof(struct ft245r_request)); + p->next = req_pool; + req_pool = p; + + ft245r_recv(pgm, buf, bytes); + for (j=0; jbuf[addr++] = extract_data(buf , (j * 4 + 3)); + } + return 1; +} + +static int ft245r_paged_write_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + int page_size, int addr, int n_bytes) { + unsigned int i,j; + int addr_save,buf_pos,do_page_write,req_count; + unsigned char buf[FT245R_FRAGMENT_SIZE+1+128]; + + req_count = 0; + for (i=0; i> 9) & 0xff ); + buf_pos += set_data(buf+buf_pos, (addr >> 1) & 0xff ); + buf_pos += set_data(buf+buf_pos, m->buf[addr]); + addr ++; + i++; + if ( (m->paged) && + (((i % m->page_size) == 0) || (i == n_bytes))) { + do_page_write = 1; + break; + } + } +#if defined(USE_INLINE_WRITE_PAGE) + if (do_page_write) { + int addr_wk = addr_save - (addr_save % m->page_size); + /* If this device has a "load extended address" command, issue it. */ + if (m->op[AVR_OP_LOAD_EXT_ADDR]) { + unsigned char cmd[4]; + OPCODE *lext = m->op[AVR_OP_LOAD_EXT_ADDR]; + + memset(cmd, 0, 4); + avr_set_bits(lext, cmd); + avr_set_addr(lext, cmd, addr_wk/2); + buf_pos += set_data(buf+buf_pos, cmd[0]); + buf_pos += set_data(buf+buf_pos, cmd[1]); + buf_pos += set_data(buf+buf_pos, cmd[2]); + buf_pos += set_data(buf+buf_pos, cmd[3]); + } + buf_pos += set_data(buf+buf_pos, 0x4C); /* Issue Page Write */ + buf_pos += set_data(buf+buf_pos,(addr_wk >> 9) & 0xff); + buf_pos += set_data(buf+buf_pos,(addr_wk >> 1) & 0xff); + buf_pos += set_data(buf+buf_pos, 0); + } +#endif + if (i >= n_bytes) { + buf[buf_pos++] = 0; // sck down + } + ft245r_send(pgm, buf, buf_pos); + put_request(addr_save, buf_pos, 0); + //ft245r_sync(pgm); +#if 0 + fprintf(stderr, "send addr 0x%04x bufsize %d [%02x %02x] page_write %d\n", + addr_save,buf_pos, + extract_data_out(buf , (0*4 + 3) ), + extract_data_out(buf , (1*4 + 3) ), + do_page_write); +#endif + req_count++; + if (req_count > REQ_OUTSTANDINGS) + do_request(pgm, m); + if (do_page_write) { +#if defined(USE_INLINE_WRITE_PAGE) + while (do_request(pgm, m)) + ; + usleep(m->max_write_delay); +#else + int addr_wk = addr_save - (addr_save % m->page_size); + int rc; + while (do_request(pgm, m)) + ; + rc = avr_write_page(pgm, p, m, addr_wk); + if (rc != 0) { + return -2; + } +#endif + req_count = 0; + } + } + while (do_request(pgm, m)) + ; + return i; +} + + +static int ft245r_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 ft245r_paged_write_flash(pgm, p, m, page_size, addr, n_bytes); + } else if (strcmp(m->desc, "eeprom") == 0) { + return ft245r_paged_write_gen(pgm, p, m, page_size, addr, n_bytes); + } else { + return -2; + } +} + +static int ft245r_paged_load_gen(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + unsigned int page_size, unsigned int addr, + int n_bytes) { + unsigned char rbyte; + unsigned long i; + int rc; + + for (i=0; ibuf[i+addr] = rbyte; + } + return 0; +} + +static int ft245r_paged_load_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + unsigned int page_size, unsigned int addr, + unsigned int n_bytes) { + unsigned long i,j,n; + int addr_save,buf_pos; + int req_count = 0; + unsigned char buf[FT245R_FRAGMENT_SIZE+1]; + + for (i=0; i= n_bytes) break; + buf_pos += set_data(buf+buf_pos, (addr & 1)?0x28:0x20 ); + buf_pos += set_data(buf+buf_pos, (addr >> 9) & 0xff ); + buf_pos += set_data(buf+buf_pos, (addr >> 1) & 0xff ); + buf_pos += set_data(buf+buf_pos, 0); + addr ++; + i++; + } + if (i >= n_bytes) { + buf[buf_pos++] = 0; // sck down + } + n = j; + ft245r_send(pgm, buf, buf_pos); + put_request(addr_save, buf_pos, n); + req_count++; + if (req_count > REQ_OUTSTANDINGS) + do_request(pgm, m); + + } + while (do_request(pgm, m)) + ; + return 0; +} + +static int ft245r_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 ft245r_paged_load_flash(pgm, p, m, page_size, addr, n_bytes); + } else if (strcmp(m->desc, "eeprom") == 0) { + return ft245r_paged_load_gen(pgm, p, m, page_size, addr, n_bytes); + } else { + return -2; + } +} + +void ft245r_initpgm(PROGRAMMER * pgm) { + strcpy(pgm->type, "ftdi_syncbb"); + + /* + * mandatory functions + */ + pgm->initialize = ft245r_initialize; + pgm->display = ft245r_display; + pgm->enable = ft245r_enable; + pgm->disable = ft245r_disable; + pgm->program_enable = ft245r_program_enable; + pgm->chip_erase = ft245r_chip_erase; + pgm->cmd = ft245r_cmd; + pgm->open = ft245r_open; + pgm->close = ft245r_close; + pgm->read_byte = avr_read_byte_default; + pgm->write_byte = avr_write_byte_default; + + /* + * optional functions + */ + pgm->paged_write = ft245r_paged_write; + pgm->paged_load = ft245r_paged_load; + + pgm->read_sig_bytes = ft245r_read_sig_bytes; +} + +#else +static int ft245r_noftdi_open (struct programmer_t *pgm, char * name) { + fprintf(stderr, + "%s: error: no ftdi support. Please compile again with libftdi installed.\n", + progname); + + exit(1); +} + +void ft245r_initpgm(PROGRAMMER * pgm) { + strcpy(pgm->type, "ftdi_syncbb"); + pgm->open = ft245r_noftdi_open; +} +#endif + +const char ft245r_desc[] = "FT245R/FT232R Synchronous BitBangMode Programmer"; diff --git a/ft245r.h b/ft245r.h new file mode 100644 index 00000000..81479496 --- /dev/null +++ b/ft245r.h @@ -0,0 +1,10 @@ +#ifndef ft245r_h +#define ft245r_h + +#include "pgm.h" + +extern const char ft245r_desc[]; +void ft245r_initpgm (PROGRAMMER * pgm); + + +#endif /* ft245r_h */ diff --git a/par.c b/par.c index 37f640cc..2f669966 100644 --- a/par.c +++ b/par.c @@ -178,25 +178,6 @@ static int par_highpulsepin(PROGRAMMER * pgm, int pin) return 0; } -static char * pins_to_str(unsigned int pmask) -{ - static char buf[64]; - int pin; - char b2[8]; - - buf[0] = 0; - for (pin = 1; pin <= 17; pin++) { - if (pmask & (1 << pin)) { - sprintf(b2, "%d", pin); - if (buf[0] != 0) - strcat(buf, ","); - strcat(buf, b2); - } - } - - return buf; -} - /* * apply power to the AVR processor */ @@ -337,52 +318,6 @@ static void par_close(PROGRAMMER * pgm) pgm->fd.ifd = -1; } -static void par_display(PROGRAMMER * pgm, const char * p) -{ - char vccpins[64]; - char buffpins[64]; - - if (pgm->pinno[PPI_AVR_VCC]) { - snprintf(vccpins, sizeof(vccpins), "%s", - pins_to_str(pgm->pinno[PPI_AVR_VCC])); - } - else { - strcpy(vccpins, " (not used)"); - } - - if (pgm->pinno[PPI_AVR_BUFF]) { - snprintf(buffpins, sizeof(buffpins), "%s", - pins_to_str(pgm->pinno[PPI_AVR_BUFF])); - } - else { - strcpy(buffpins, " (not used)"); - } - - fprintf(stderr, - "%s VCC = %s\n" - "%s BUFF = %s\n" - "%s RESET = %d\n" - "%s SCK = %d\n" - "%s MOSI = %d\n" - "%s MISO = %d\n" - "%s ERR LED = %d\n" - "%s RDY LED = %d\n" - "%s PGM LED = %d\n" - "%s VFY LED = %d\n", - - p, vccpins, - p, buffpins, - p, pgm->pinno[PIN_AVR_RESET], - p, pgm->pinno[PIN_AVR_SCK], - p, pgm->pinno[PIN_AVR_MOSI], - p, pgm->pinno[PIN_AVR_MISO], - p, pgm->pinno[PIN_LED_ERR], - p, pgm->pinno[PIN_LED_RDY], - p, pgm->pinno[PIN_LED_PGM], - p, pgm->pinno[PIN_LED_VFY]); -} - - /* * parse the -E string */ @@ -433,7 +368,7 @@ void par_initpgm(PROGRAMMER * pgm) pgm->pgm_led = bitbang_pgm_led; pgm->vfy_led = bitbang_vfy_led; pgm->initialize = bitbang_initialize; - pgm->display = par_display; + pgm->display = pgm_display_generic; pgm->enable = par_enable; pgm->disable = par_disable; pgm->powerup = par_powerup; diff --git a/pgm.c b/pgm.c index f0e3b5b3..eaa0ead1 100644 --- a/pgm.c +++ b/pgm.c @@ -212,6 +212,72 @@ void programmer_display(PROGRAMMER * pgm, const char * p) pgm->display(pgm, p); } +static char * pins_to_str(unsigned int pmask) +{ + static char buf[64]; + int pin; + char b2[8]; + + if ((pmask & PIN_MASK) == 0) + return " (not used)"; + + buf[0] = ' '; + buf[1] = 0; + for (pin = 0; pin <= 17; pin++) { + if (pmask & (1 << pin)) { + sprintf(b2, "%d", pin); + if (buf[1] != 0) + strcat(buf, ","); + strcat(buf, b2); + } + } + + return buf; +} + +static char * pin_to_str(unsigned int pin) +{ + static char buf[12]; + + if ((pin & PIN_MASK) == 0) + return " (not used)"; + + buf[0] = (pin & PIN_INVERSE)?'~':' '; + buf[1] = 0; + sprintf(buf+1, "%d", pin & PIN_MASK); + + return buf; +} + +void pgm_display_generic_mask(PROGRAMMER * pgm, const char * p, unsigned int show) +{ + if(show & (1<pinno[PPI_AVR_VCC])); + if(show & (1<pinno[PPI_AVR_BUFF])); + if(show & (1<pinno[PIN_AVR_RESET])); + if(show & (1<pinno[PIN_AVR_SCK])); + if(show & (1<pinno[PIN_AVR_MOSI])); + if(show & (1<pinno[PIN_AVR_MISO])); + if(show & (1<pinno[PIN_LED_ERR])); + if(show & (1<pinno[PIN_LED_RDY])); + if(show & (1<pinno[PIN_LED_PGM])); + if(show & (1<pinno[PIN_LED_VFY])); +} + +void pgm_display_generic(PROGRAMMER * pgm, const char * p) +{ + pgm_display_generic_mask(pgm, p, SHOW_ALL_PINS); +} + PROGRAMMER * locate_programmer(LISTID programmers, const char * configid) { LNODEID ln1, ln2; diff --git a/pgm.h b/pgm.h index c8097980..784a32f4 100644 --- a/pgm.h +++ b/pgm.h @@ -143,6 +143,15 @@ PROGRAMMER * pgm_dup(const PROGRAMMER const * src); void pgm_free(PROGRAMMER * const p); void programmer_display(PROGRAMMER * pgm, const char * p); + +/* show is a mask like this (1< + enum { PPI_AVR_VCC=1, PPI_AVR_BUFF, @@ -35,8 +37,8 @@ enum { PIN_LED_VFY, N_PINS }; -#define PIN_INVERSE 0x80 /* flag for inverted pin in serbb */ -#define PIN_MASK 0x7f +#define PIN_MASK (UINT_MAX>>1) +#define PIN_INVERSE (~(PIN_MASK)) /* flag for inverted pin in serbb */ #define LED_ON(fd,pin) ppi_setpin(fd,pin,0) #define LED_OFF(fd,pin) ppi_setpin(fd,pin,1)