1 --- /dev/null 2009-08-02 22:44:47.000000000 +0200
2 +++ ft245r.c 2009-08-02 21:56:45.000000000 +0200
5 + * avrdude - A Downloader/Uploader for AVR device programmers
6 + * Copyright (C) 2003-2004 Theodore A. Roth <troth@openavr.org>
8 + * This program is free software; you can redistribute it and/or modify
9 + * it under the terms of the GNU General Public License as published by
10 + * the Free Software Foundation; either version 2 of the License, or
11 + * (at your option) any later version.
13 + * This program is distributed in the hope that it will be useful,
14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 + * GNU General Public License for more details.
18 + * You should have received a copy of the GNU General Public License
19 + * along with this program; if not, write to the Free Software
20 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 +/* ft245r -- FT245R/FT232R Synchronous BitBangMode Programmer
28 + miso = 1; # RxD / D1
30 + mosi = 2; # TxD / D2
31 + reset = 4; # DTR / D4
40 +#include <sys/time.h>
49 +#if defined(_WIN32) || defined(SUPPORT_FT245R)
57 +#define FT245R_CYCLES 2
58 +#define FT245R_FRAGMENT_SIZE 512
59 +#define REQ_OUTSTANDINGS 10
60 +//#define USE_INLINE_WRITE_PAGE
62 +#define FT245R_DEBUG 1
64 +extern char * progname;
65 +extern int do_cycles;
69 +static FT_HANDLE handle;
71 +static unsigned char ft245r_ddr;
72 +static unsigned char ft245r_sck;
73 +static unsigned char ft245r_mosi;
74 +static unsigned char ft245r_reset;
75 +static unsigned char ft245r_miso;
77 +static inline void setbit(UCHAR *data, int pinno, int v)
80 + *data |= (1 << (pinno));
82 + *data &= ~(1 <<(pinno));
86 +static int ft245r_send(PROGRAMMER * pgm, char * buf, size_t len)
90 + r = FT_Write(handle, buf, len, &rlen);
91 + if (r == FT_OK) return 0;
92 + if (len != rlen) return -1;
97 +static int ft245r_recv(PROGRAMMER * pgm, char * buf, size_t len)
102 + r = FT_Read(handle, buf, len, &rlen);
104 + if (r != FT_OK || len != rlen) {
106 + "%s: ft245r_recv(): programmer is not responding\n",
114 +static int ft245r_drain(PROGRAMMER * pgm, int display)
118 + r = FT_SetBitMode(handle, 0, 0x0); // reset
119 + if (r != FT_OK) return -1;
120 + r = FT_SetBitMode(handle, ft245r_ddr, 0x4); // set Synchronuse BitBang
121 + if (r != FT_OK) return -1;
123 + r = FT_GetQueueStatus(handle, &n);
124 + if (r != FT_OK) return -1;
126 + fprintf(stderr, "ft245r_drain called but queue is not empty %d \n",
132 +static inline int ft245r_sync(PROGRAMMER * pgm)
136 + r = FT_GetBitMode(handle, &ch);
137 + if (r != FT_OK) return -1;
141 +static int ft245r_chip_erase(PROGRAMMER * pgm, AVRPART * p)
143 + unsigned char cmd[4];
144 + unsigned char res[4];
146 + if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
147 + fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
152 + memset(cmd, 0, sizeof(cmd));
154 + avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
155 + pgm->cmd(pgm, cmd, res);
156 + usleep(p->chip_erase_delay);
157 + pgm->initialize(pgm, p);
162 +static unsigned char saved_signature[3];
164 +static int valid_rates[] = {
165 + 2400, 4800, 9600, 14400, 19200, 38400, 57600,
166 + 115200, 230400, 460800, 921600, 3000000
169 +static void ft245r_set_bitclock(PROGRAMMER * pgm) {
174 + if (pgm->bitclock == 0.0) { // using default
175 + rate = 235000.0 /2;
176 + } else if (pgm->bitclock >= 0.50 ) {
177 + rate = 500000.0 /2;
178 + } else if (pgm->bitclock < 0.01) {
181 + rate = pgm->bitclock * 1000000.0 /2;
183 + for (i= sizeof(valid_rates)/sizeof(valid_rates[0]) -1; i>=0; --i)
185 + if (valid_rates[i] <= rate) {
186 + rate = valid_rates[i];
190 + if (i<0) rate = valid_rates[0];
192 + r = FT_SetBaudRate(handle, rate);
193 + if ((verbose>=1) || FT245R_DEBUG) {
194 + fprintf(stderr," ft245r: bitclk %d -> ft baud %d\n",
199 +static int set_reset(PROGRAMMER * pgm, int val)
201 + unsigned char buf[1];
204 + if (val) buf[0] |= ft245r_reset;
206 + ft245r_send (pgm, buf, 1);
207 + ft245r_recv (pgm, buf, 1);
211 +static int ft245r_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
212 + unsigned char res[4]);
214 + * issue the 'program enable' command to the AVR device
216 +static int ft245r_program_enable(PROGRAMMER * pgm, AVRPART * p)
218 + int retry_count = 0;
219 + unsigned char cmd[4];
220 + unsigned char res[4];
223 + ft245r_set_bitclock(pgm);
228 + usleep(5000); // 5ms
230 + usleep(5000); // 5ms
232 + usleep(5000); // 5ms
238 + ft245r_cmd(pgm, cmd, res);
239 + if (res[2] == 0x53 ) reset_ok = 1;
240 + for (i=0; i<3; i++) {
245 + ft245r_cmd(pgm, cmd, res);
246 + saved_signature[i] = res[3];
249 + if (reset_ok && (saved_signature[0] == 0x1e)) // success
252 + if (retry_count < 5) {
256 + if ((verbose>=1) || FT245R_DEBUG) {
258 + "%s: ft245r_program_enable: failed\n", progname);
264 +static int ft245r_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
266 + m->buf[0] = saved_signature[0];
267 + m->buf[1] = saved_signature[1];
268 + m->buf[2] = saved_signature[2];
273 + * initialize the AVR device and prepare it to accept commands
275 +static int ft245r_initialize(PROGRAMMER * pgm, AVRPART * p)
277 + return ft245r_program_enable(pgm, p);
280 +static void ft245r_disable(PROGRAMMER * pgm)
286 +static void ft245r_enable(PROGRAMMER * pgm)
293 +static inline int set_data(unsigned char *buf, unsigned char data)
297 + unsigned char bit = 0x80;
299 + for (j=0; j<8; j++) {
301 + if (data & bit) buf[buf_pos] |= ft245r_mosi;
305 + if (data & bit) buf[buf_pos] |= ft245r_mosi;
306 + buf[buf_pos] |= ft245r_sck;
314 +static inline unsigned char extract_data(unsigned char *buf, int offset)
318 + unsigned char bit = 0x80;
319 + unsigned char r = 0;
321 + buf += offset * (8 * FT245R_CYCLES);
322 + for (j=0; j<8; j++) {
323 + if (buf[buf_pos] & ft245r_miso) {
326 + buf_pos += FT245R_CYCLES;
333 +static inline unsigned char extract_data_out(unsigned char *buf, int offset)
337 + unsigned char bit = 0x80;
338 + unsigned char r = 0;
340 + buf += offset * (8 * FT245R_CYCLES);
341 + for (j=0; j<8; j++) {
342 + if (buf[buf_pos] & ft245r_mosi) {
345 + buf_pos += FT245R_CYCLES;
353 + * transmit an AVR device command and return the results; 'cmd' and
354 + * 'res' must point to at least a 4 byte data buffer
356 +static int ft245r_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
357 + unsigned char res[4])
360 + unsigned char buf[128];
363 + for (i=0; i<4; i++) {
364 + buf_pos += set_data(buf+buf_pos, cmd[i]);
369 + ft245r_send (pgm, buf, buf_pos);
370 + ft245r_recv (pgm, buf, buf_pos);
371 + res[0] = extract_data(buf, 0);
372 + res[1] = extract_data(buf, 1);
373 + res[2] = extract_data(buf, 2);
374 + res[3] = extract_data(buf, 3);
379 +static int ft245r_open(PROGRAMMER * pgm, char * port)
383 + strcpy(pgm->port, port);
386 + if (!strncasecmp("ft", port, 2) && '0' <= port[2] && port[2] <= '9') {
387 + devnum = port[2] - '0';
390 + "%s: invalid portname %s: use ft0 - ft9\n",
394 + r = FT_Open(devnum, &handle);
396 + for (devnum=0; devnum<9; devnum++) {
397 + r = FT_Open(devnum, &handle);
398 + if (r == FT_OK) break;
403 + "%s: %s open failed \n",
407 + r = FT_SetBitMode(handle, 0, 0x4); // set Synchronuse BitBang
410 + "%s: Synchronuse BitBangMode is not supported\n",
415 + fprintf(stderr, "%s: BitBang OK \n", progname);
420 + setbit(&ft245r_ddr, pgm->pinno[PIN_AVR_SCK], 1);
421 + setbit(&ft245r_ddr, pgm->pinno[PIN_AVR_MOSI], 1);
422 + setbit(&ft245r_ddr, pgm->pinno[PIN_AVR_RESET], 1);
424 + setbit(&ft245r_sck, pgm->pinno[PIN_AVR_SCK], 1);
426 + setbit(&ft245r_mosi, pgm->pinno[PIN_AVR_MOSI], 1);
428 + setbit(&ft245r_reset, pgm->pinno[PIN_AVR_RESET], 1);
430 + setbit(&ft245r_miso, pgm->pinno[PIN_AVR_MISO], 1);
431 + if ((verbose>=1) || FT245R_DEBUG) {
433 + "%s: pin assign miso %d sck %d mosi %d reset %d\n",
435 + pgm->pinno[PIN_AVR_MISO],
436 + pgm->pinno[PIN_AVR_SCK],
437 + pgm->pinno[PIN_AVR_MOSI],
438 + pgm->pinno[PIN_AVR_RESET]);
442 + * drain any extraneous input
444 + ft245r_drain (pgm, 0);
446 + fprintf(stderr, "%s: drain OK \n", progname);
453 +static void ft245r_close(PROGRAMMER * pgm)
458 +static void ft245r_display(PROGRAMMER * pgm, char * p)
463 +static int ft245r_paged_write_gen(PROGRAMMER * pgm, AVRPART * p,
464 + AVRMEM * m, int page_size, int n_bytes)
468 + for (i=0; i<n_bytes; i++) {
469 + report_progress(i, n_bytes, NULL);
471 + rc = avr_write_byte_default(pgm, p, m, i, m->buf[i]);
478 + * check to see if it is time to flush the page with a page
481 + if (((i % m->page_size) == m->page_size-1) || (i == n_bytes-1)) {
482 + rc = avr_write_page(pgm, p, m, i);
492 +static struct ft245r_request {
496 + struct ft245r_request *next;
497 +} *req_head,*req_tail,*req_pool;
499 +static void put_request(int addr, int bytes, int n)
501 + struct ft245r_request *p;
504 + req_pool = p->next;
506 + p = malloc(sizeof(struct ft245r_request));
508 + fprintf(stderr, "can't alloc memory\n");
512 + memset(p, 0, sizeof(struct ft245r_request));
517 + req_tail->next = p;
520 + req_head = req_tail = p;
524 +static int do_request(PROGRAMMER * pgm, AVRMEM *m)
526 + struct ft245r_request *p;
527 + int addr, bytes, j, n;
528 + char buf[FT245R_FRAGMENT_SIZE+1+128];
530 + if (!req_head) return 0;
532 + req_head = p->next;
533 + if (!req_head) req_tail = req_head;
538 + memset(p, 0, sizeof(struct ft245r_request));
539 + p->next = req_pool;
542 + ft245r_recv(pgm, buf, bytes);
543 + for (j=0; j<n; j++) {
544 + m->buf[addr++] = extract_data(buf , (j * 4 + 3));
547 +if (n == 0) // paged_write
548 +fprintf(stderr, "recv addr 0x%04x buf size %d \n",addr, bytes);
553 +static int ft245r_paged_write_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
554 + int page_size, int n_bytes)
557 + int addr,addr_save,buf_pos,do_page_write,req_count;
558 + char buf[FT245R_FRAGMENT_SIZE+1+128];
562 + for (i=0; i<n_bytes; ) {
566 + for (j=0; j< FT245R_FRAGMENT_SIZE/8/FT245R_CYCLES/4; j++) {
567 + buf_pos += set_data(buf+buf_pos, (addr & 1)?0x48:0x40 );
568 + buf_pos += set_data(buf+buf_pos, (addr >> 9) & 0xff );
569 + buf_pos += set_data(buf+buf_pos, (addr >> 1) & 0xff );
570 + buf_pos += set_data(buf+buf_pos, m->buf[i]);
574 + (((i % m->page_size) == 0) || (i == n_bytes))) {
579 +#if defined(USE_INLINE_WRITE_PAGE)
580 + if (do_page_write) {
581 + int addr_wk = addr_save - (addr_save % m->page_size);
582 + /* If this device has a "load extended address" command, issue it. */
583 + if (m->op[AVR_OP_LOAD_EXT_ADDR]) {
584 + unsigned char cmd[4];
585 + OPCODE *lext = m->op[AVR_OP_LOAD_EXT_ADDR];
588 + avr_set_bits(lext, cmd);
589 + avr_set_addr(lext, cmd, addr_wk/2);
590 + buf_pos += set_data(buf+buf_pos, cmd[0]);
591 + buf_pos += set_data(buf+buf_pos, cmd[1]);
592 + buf_pos += set_data(buf+buf_pos, cmd[2]);
593 + buf_pos += set_data(buf+buf_pos, cmd[3]);
595 + buf_pos += set_data(buf+buf_pos, 0x4C); /* Issue Page Write */
596 + buf_pos += set_data(buf+buf_pos,(addr_wk >> 9) & 0xff);
597 + buf_pos += set_data(buf+buf_pos,(addr_wk >> 1) & 0xff);
598 + buf_pos += set_data(buf+buf_pos, 0);
601 + if (i >= n_bytes) {
602 + buf[buf_pos++] = 0; // sck down
604 + ft245r_send(pgm, buf, buf_pos);
605 + put_request(addr_save, buf_pos, 0);
606 + //ft245r_sync(pgm);
608 +fprintf(stderr, "send addr 0x%04x bufsize %d [%02x %02x] page_write %d\n",
610 + extract_data_out(buf , (0*4 + 3) ),
611 + extract_data_out(buf , (1*4 + 3) ),
615 + if (req_count > REQ_OUTSTANDINGS)
616 + do_request(pgm, m);
617 + if (do_page_write) {
618 +#if defined(USE_INLINE_WRITE_PAGE)
619 + while (do_request(pgm, m))
621 + usleep(m->max_write_delay);
623 + int addr_wk = addr_save - (addr_save % m->page_size);
625 + while (do_request(pgm, m))
627 + rc = avr_write_page(pgm, p, m, addr_wk);
634 + report_progress(i, n_bytes, NULL);
636 + while (do_request(pgm, m))
642 +static int ft245r_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
643 + int page_size, int n_bytes)
645 + if (strcmp(m->desc, "flash") == 0) {
646 + return ft245r_paged_write_flash(pgm, p, m, page_size, n_bytes);
648 + else if (strcmp(m->desc, "eeprom") == 0) {
649 + return ft245r_paged_write_gen(pgm, p, m, page_size, n_bytes);
656 +static int ft245r_paged_load_gen(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
657 + int page_size, int n_bytes)
659 + unsigned char rbyte;
663 + for (i=0; i<n_bytes; i++) {
664 + rc = avr_read_byte_default(pgm, p, m, i, &rbyte);
669 + report_progress(i, n_bytes, NULL);
675 +static int ft245r_paged_load_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
676 + int page_size, int n_bytes)
678 + unsigned long i,j,n;
680 + int addr,addr_save,buf_pos;
682 + char buf[FT245R_FRAGMENT_SIZE+1];
685 + for (i=0; i<n_bytes; ) {
688 + for (j=0; j< FT245R_FRAGMENT_SIZE/8/FT245R_CYCLES/4; j++) {
689 + if (i >= n_bytes) break;
690 + buf_pos += set_data(buf+buf_pos, (addr & 1)?0x28:0x20 );
691 + buf_pos += set_data(buf+buf_pos, (addr >> 9) & 0xff );
692 + buf_pos += set_data(buf+buf_pos, (addr >> 1) & 0xff );
693 + buf_pos += set_data(buf+buf_pos, 0);
697 + if (i >= n_bytes) {
698 + buf[buf_pos++] = 0; // sck down
701 + ft245r_send(pgm, buf, buf_pos);
702 + put_request(addr_save, buf_pos, n);
704 + if (req_count > REQ_OUTSTANDINGS)
705 + do_request(pgm, m);
706 + report_progress(i, n_bytes, NULL);
708 + while (do_request(pgm, m))
713 +static int ft245r_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
714 + int page_size, int n_bytes)
716 + if (strcmp(m->desc, "flash") == 0) {
717 + return ft245r_paged_load_flash(pgm, p, m, page_size, n_bytes);
719 + else if (strcmp(m->desc, "eeprom") == 0) {
720 + return ft245r_paged_load_gen(pgm, p, m, page_size, n_bytes);
727 +void ft245r_initpgm(PROGRAMMER * pgm)
729 + strcpy(pgm->type, "ft245r");
732 + * mandatory functions
734 + pgm->initialize = ft245r_initialize;
735 + pgm->display = ft245r_display;
736 + pgm->enable = ft245r_enable;
737 + pgm->disable = ft245r_disable;
738 + pgm->program_enable = ft245r_program_enable;
739 + pgm->chip_erase = ft245r_chip_erase;
740 + pgm->cmd = ft245r_cmd;
741 + pgm->open = ft245r_open;
742 + pgm->close = ft245r_close;
743 + pgm->read_byte = avr_read_byte_default;
744 + pgm->write_byte = avr_write_byte_default;
747 + * optional functions
749 + pgm->paged_write = ft245r_paged_write;
750 + pgm->paged_load = ft245r_paged_load;
752 + pgm->read_sig_bytes = ft245r_read_sig_bytes;
755 +static int ft245r_initialize(PROGRAMMER * pgm, AVRPART * p)
760 +void ft245r_initpgm(PROGRAMMER * pgm)
762 + pgm->initialize = ft245r_initialize;