From 49e5f2451c7e2d295aa4fefc6dd38c1833f5247d Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Thu, 25 Nov 2021 09:17:11 +0000 Subject: [PATCH] patch #9328: ft245r.c: add TPI support (patches 5-7) Submitted by David Mosberger-Tang: * ft245r.c (ft245r_set_bitclock): add workaround for FT245 hardware bugs in bitclock setting Correct baud rate calculation (multiplying with factor of 2 was wrong) and add compile-time workaround for FTDI chips suffering for the variable pulse-width errata. The workaround entails always running the chip at 3MHz and stuffing the channel with repeated bytes to achieve the desired baudrate. This has no effect on programming speed. Note, however, that now a baudrate option -b750000 has to be used to achieve maximum speed. (Option enabled by default now.) git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1488 81a1dc3b-b13d-400b-aceb-764788c761c2 --- ChangeLog | 7 ++++++ NEWS | 6 ++++- ft245r.c | 66 +++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index a6b12e6f..1a8691df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2021-11-25 Joerg Wunsch + + Submitted by David Mosberger-Tang: + patch #9328: ft245r.c: add TPI support (patches 5-7) + * ft245r.c (ft245r_set_bitclock): add workaround for + FT245 hardware bugs in bitclock setting + 2021-11-25 Joerg Wunsch Submitted by David Mosberger-Tang: diff --git a/NEWS b/NEWS index 426438b6..21021303 100644 --- a/NEWS +++ b/NEWS @@ -14,10 +14,12 @@ Current: debuggers (JTAGICE3 with firmware 3+, AtmelICE, EDBG, mEDBG) - UPDI support added (AVR8X family) - TPI support for USBtinyISP + - TPI support for ft245r - AVR Doper uses libhidapi rather than raw libusb (patch #9033) - -P net:host:port can use IPv6 now (Posix systems only) - New configure option: -disable-libusb_1_0 - extended UPDI device context (> 64 Ki flash) + - major overhaul of ft245r driver (patch #9327/#9328) * New devices supported: @@ -108,11 +110,13 @@ Current: patch #9110: Let reserved fuse bits to be read as *don't care* patch #9253: Fix for giving terminal_mode commands more than 20 arguments patch #9320: fix TPI RESET in bitbang.c - patch #9079: Fix ftdi_syncbb teardown (supersedes #9893) + patch #9079: Fix ftdi_syncbb teardown (supersedes #9893, superseded by #9328) patch #9122: Fixed MISO sampling in ftdi_syncbb patch #9123: ftdi_syncbb: use FT245R_CYCLES in ft245r_set_bitclock() patch #8719: Support Over-the-Air bootloading with XBeeBoot patch #9757: Fix ATtiny817 Xplained Mini programmer + patch #9327: ft245r.c: add TPI support (patches 1-4) + patch #9328: ft245r.c: add TPI support (patches 5-7) * Internals: - New avrdude.conf keyword "family_id", used to verify SIB attributes diff --git a/ft245r.c b/ft245r.c index 4c4ffa60..9c717324 100644 --- a/ft245r.c +++ b/ft245r.c @@ -59,6 +59,7 @@ #include #include #include +#include #include "avrdude.h" #include "libavrdude.h" @@ -113,9 +114,26 @@ void ft245r_initpgm(PROGRAMMER * pgm) { //#define USE_INLINE_WRITE_PAGE #define FT245R_DEBUG 0 +/* + Some revisions of the FTDI chips mess up the timing in bitbang mode + unless the bitclock is set to the max (3MHz). For example, see: + + http://www.ftdichip.com/Support/Documents/TechnicalNotes/TN_120_FT232R%20Errata%20Technical%20Note.pdf + + To work around this problem, set the macro below to 1 to always set + the bitclock to 3MHz and then issue the same byte repeatedly to get + the desired timing. + +*/ +#define FT245R_BITBANG_VARIABLE_PULSE_WIDTH_WORKAROUND 1 static struct ftdi_context *handle; +#if FT245R_BITBANG_VARIABLE_PULSE_WIDTH_WORKAROUND +static unsigned int baud_multiplier; +#else +# define baud_multiplier 1 // this let's C compiler optimize +#endif static unsigned char ft245r_ddr; static unsigned char ft245r_out; @@ -213,14 +231,16 @@ static int ft245r_flush(PROGRAMMER * pgm) { static int ft245r_send2(PROGRAMMER * pgm, unsigned char * buf, size_t len, bool discard_rx_data) { - int i; + int i, j; for (i = 0; i < len; ++i) { - if (discard_rx_data) - ++rx.discard; - tx.buf[tx.len++] = buf[i]; - if (tx.len >= FT245R_MIN_FIFO_SIZE) - ft245r_flush(pgm); + for (j = 0; j < baud_multiplier; ++j) { + if (discard_rx_data) + ++rx.discard; + tx.buf[tx.len++] = buf[i]; + if (tx.len >= FT245R_MIN_FIFO_SIZE) + ft245r_flush(pgm); + } } return 0; } @@ -235,7 +255,7 @@ static int ft245r_send_and_discard(PROGRAMMER * pgm, unsigned char * buf, } static int ft245r_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len) { - int i; + int i, j; ft245r_flush(pgm); ft245r_fill(pgm); @@ -249,8 +269,11 @@ static int ft245r_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len) { --rx.discard; } - for (i = 0; i < len; ++i) + for (i = 0; i < len; ++i) { buf[i] = ft245r_rx_buf_get(pgm); + for (j = 1; j < baud_multiplier; ++j) + ft245r_rx_buf_get(pgm); + } return 0; } @@ -298,23 +321,32 @@ static int ft245r_chip_erase(PROGRAMMER * pgm, AVRPART * p) { static int ft245r_set_bitclock(PROGRAMMER * pgm) { - int r; - int rate = 0; + // libftdi1 multiplies bitbang baudrate by 4: + int r, rate = 0, ftdi_rate = 3000000 / 4; /* bitclock is second. 1us = 0.000001. Max rate for ft232r 750000 */ if(pgm->bitclock) { - rate = (uint32_t)(1.0/pgm->bitclock) * FT245R_CYCLES; + rate = (uint32_t)(1.0/pgm->bitclock); } else if (pgm->baudrate) { - rate = pgm->baudrate * FT245R_CYCLES; + rate = pgm->baudrate; } else { rate = 150000; /* should work for all ftdi chips and the avr default internal clock of 1MHz */ } - if (FT245R_DEBUG) { - avrdude_message(MSG_NOTICE2, " ft245r: spi bitclk %d -> ft baudrate %d\n", - rate / FT245R_CYCLES, rate); - } - r = ftdi_set_baudrate(handle, rate); +#if FT245R_BITBANG_VARIABLE_PULSE_WIDTH_WORKAROUND + if (rate > 0 && rate < ftdi_rate) + baud_multiplier = round((ftdi_rate + rate - 1) / rate); + else + baud_multiplier = 1; +#else + ftdi_rate = rate; +#endif + + avrdude_message(MSG_NOTICE2, + "%s: bitclk %d -> FTDI rate %d, baud multiplier %d\n", + __func__, rate, ftdi_rate, baud_multiplier); + + r = ftdi_set_baudrate(handle, ftdi_rate); if (r) { avrdude_message(MSG_INFO, "Set baudrate (%d) failed with error '%s'.\n", rate, ftdi_get_error_string (handle));