Skip to content

Commit 2015a87

Browse files
committed
patch #9328: ft245r.c: add TPI support (patches 5-7)
Submitted by David Mosberger-Tang: * ft245r.c: Remove the reader thread (also removes patch #9079) Eliminate separate reader thread by tracking how many bytes are queued in the FTDI chip's RX FIFO and reading those bytes when it fills up (since in synchronous bitbang mode, the chip won't send any more bytes until it has space in the RX FIFO). This reduces TPI programming time by another 33%. Since write data is now queued as much as possible, we need flush this queued data (a) before reading and (b) before sleeping. For the latter case, a new helper function ft245r_usleep() is introduced. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1487 81a1dc3b-b13d-400b-aceb-764788c761c2
1 parent 5bf24e4 commit 2015a87

File tree

2 files changed

+135
-114
lines changed

2 files changed

+135
-114
lines changed

ChangeLog

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
2021-11-25 Joerg Wunsch <[email protected]>
2+
3+
Submitted by David Mosberger-Tang:
4+
patch #9328: ft245r.c: add TPI support (patches 5-7)
5+
* ft245r.c: Remove the reader thread (also removes
6+
patch #9079)
7+
18
2021-11-24 Joerg Wunsch <[email protected]>
29

310
Submitted by David Mosberger-Tang:

ft245r.c

Lines changed: 128 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,7 @@
9191
#define DO_NOT_BUILD_FT245R
9292
#endif
9393

94-
#ifndef HAVE_PTHREAD_H
95-
96-
static int ft245r_nopthread_open (struct programmer_t *pgm, char * name) {
97-
avrdude_message(MSG_INFO, "%s: error: no pthread support. Please compile again with pthread installed."
98-
#if defined(_WIN32)
99-
" See http://sourceware.org/pthreads-win32/."
100-
#endif
101-
"\n",
102-
progname);
103-
104-
return -1;
105-
}
106-
107-
void ft245r_initpgm(PROGRAMMER * pgm) {
108-
strcpy(pgm->type, "ftdi_syncbb");
109-
pgm->open = ft245r_nopthread_open;
110-
}
111-
112-
#elif defined(DO_NOT_BUILD_FT245R)
94+
#if defined(DO_NOT_BUILD_FT245R)
11395

11496
static int ft245r_noftdi_open (struct programmer_t *pgm, char * name) {
11597
avrdude_message(MSG_INFO, "%s: error: no libftdi or libusb support. Install libftdi1/libusb-1.0 or libftdi/libusb and run configure/make again.\n",
@@ -125,21 +107,6 @@ void ft245r_initpgm(PROGRAMMER * pgm) {
125107

126108
#else
127109

128-
#include <pthread.h>
129-
130-
#ifdef __APPLE__
131-
/* Mac OS X defines sem_init but actually does not implement them */
132-
#include <dispatch/dispatch.h>
133-
134-
typedef dispatch_semaphore_t sem_t;
135-
136-
#define sem_init(psem,x,val) *psem = dispatch_semaphore_create(val)
137-
#define sem_post(psem) dispatch_semaphore_signal(*psem)
138-
#define sem_wait(psem) dispatch_semaphore_wait(*psem, DISPATCH_TIME_FOREVER)
139-
#else
140-
#include <semaphore.h>
141-
#endif
142-
143110
#define FT245R_CYCLES 2
144111
#define FT245R_FRAGMENT_SIZE 512
145112
#define REQ_OUTSTANDINGS 10
@@ -152,92 +119,144 @@ static struct ftdi_context *handle;
152119
static unsigned char ft245r_ddr;
153120
static unsigned char ft245r_out;
154121

155-
#define BUFSIZE 0x2000
122+
#define FT245R_BUFSIZE 0x2000 // receive buffer size
123+
#define FT245R_MIN_FIFO_SIZE 128 // min of FTDI RX/TX FIFO size
156124

157-
// libftdi / libftd2xx compatibility functions.
125+
static struct {
126+
int len; // # of bytes in transmit buffer
127+
uint8_t buf[FT245R_MIN_FIFO_SIZE]; // transmit buffer
128+
} tx;
158129

159-
static pthread_t readerthread;
160-
static sem_t buf_data, buf_space;
161-
static unsigned char buffer[BUFSIZE];
162-
static int head, tail;
163130
static struct {
164131
int discard; // # of bytes to discard during read
132+
int pending; // # of bytes that have been written since last read
133+
int wr; // write pointer
134+
int rd; // read pointer
135+
uint8_t buf[FT245R_BUFSIZE]; // receive ring buffer
165136
} rx;
166137

167-
static void add_to_buf (unsigned char c) {
168-
int nh;
138+
// Discard all data from the receive buffer.
139+
static void ft245r_rx_buf_purge(PROGRAMMER * pgm) {
140+
rx.rd = rx.wr = 0;
141+
}
169142

170-
sem_wait (&buf_space);
171-
if (head == (BUFSIZE -1)) nh = 0;
172-
else nh = head + 1;
143+
static void ft245r_rx_buf_put(PROGRAMMER * pgm, uint8_t byte) {
144+
rx.buf[rx.wr++] = byte;
145+
if (rx.wr >= sizeof(rx.buf))
146+
rx.wr = 0;
147+
}
173148

174-
if (nh == tail) {
175-
avrdude_message(MSG_INFO, "buffer overflow. Cannot happen!\n");
176-
}
177-
buffer[head] = c;
178-
head = nh;
179-
sem_post (&buf_data);
149+
static uint8_t ft245r_rx_buf_get(PROGRAMMER * pgm) {
150+
uint8_t byte = rx.buf[rx.rd++];
151+
if (rx.rd >= sizeof(rx.buf))
152+
rx.rd = 0;
153+
return byte;
154+
}
155+
156+
/* Fill receive buffer with data from the FTDI receive FIFO. */
157+
static int ft245r_fill(PROGRAMMER * pgm) {
158+
uint8_t raw[FT245R_MIN_FIFO_SIZE];
159+
int i, nread;
160+
161+
nread = ftdi_read_data(handle, raw, rx.pending);
162+
if (nread < 0)
163+
return -1;
164+
rx.pending -= nread;
165+
#if FT245R_DEBUG
166+
avrdude_message(MSG_INFO, "%s: read %d bytes (pending=%d)\n",
167+
__func__, nread, rx.pending);
168+
#endif
169+
for (i = 0; i < nread; ++i)
170+
ft245r_rx_buf_put(pgm, raw[i]);
171+
return nread;
180172
}
181173

182-
static void *reader (void *arg) {
183-
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
184-
struct ftdi_context *handle = (struct ftdi_context *)(arg);
185-
unsigned char buf[0x1000];
186-
int br, i;
187-
188-
while (1) {
189-
/* 'old_cancel_state' added for portability reasons,
190-
* see pthread_setcancelstate() manual */
191-
int old_cancel_state;
192-
pthread_testcancel();
193-
/* isolate libftdi and libusb from cancellation requests to prevent unhandled behavior */
194-
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancel_state);
195-
br = ftdi_read_data (handle, buf, sizeof(buf));
196-
for (i=0; i<br; i++)
197-
add_to_buf (buf[i]);
198-
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state);
174+
/* Flush pending TX data to the FTDI send FIFO. */
175+
static int ft245r_flush(PROGRAMMER * pgm) {
176+
int rv, len = tx.len, avail;
177+
uint8_t *src = tx.buf;
178+
179+
if (!len)
180+
return 0;
181+
182+
while (len > 0) {
183+
avail = FT245R_MIN_FIFO_SIZE - rx.pending;
184+
if (avail <= 0) {
185+
avail = ft245r_fill(pgm);
186+
if (avail < 0) {
187+
avrdude_message(MSG_INFO,
188+
"%s: fill returned %d: %s\n",
189+
__func__, avail, ftdi_get_error_string(handle));
190+
return -1;
191+
}
192+
}
193+
if (avail > len)
194+
avail = len;
195+
196+
#if FT245R_DEBUG
197+
avrdude_message(MSG_INFO, "%s: writing %d bytes\n", __func__, avail);
198+
#endif
199+
rv = ftdi_write_data(handle, src, avail);
200+
if (rv != avail) {
201+
avrdude_message(MSG_INFO,
202+
"%s: write returned %d (expected %d): %s\n",
203+
__func__, rv, avail, ftdi_get_error_string(handle));
204+
return -1;
205+
}
206+
src += avail;
207+
len -= avail;
208+
rx.pending += avail;
199209
}
200-
return NULL;
210+
tx.len = 0;
211+
return 0;
201212
}
202213

203-
static int ft245r_send(PROGRAMMER * pgm, unsigned char * buf, size_t len) {
204-
int rv;
214+
static int ft245r_send2(PROGRAMMER * pgm, unsigned char * buf, size_t len,
215+
bool discard_rx_data) {
216+
int i;
205217

206-
rv = ftdi_write_data(handle, buf, len);
207-
if (len != rv) return -1;
218+
for (i = 0; i < len; ++i) {
219+
if (discard_rx_data)
220+
++rx.discard;
221+
tx.buf[tx.len++] = buf[i];
222+
if (tx.len >= FT245R_MIN_FIFO_SIZE)
223+
ft245r_flush(pgm);
224+
}
208225
return 0;
209226
}
210227

228+
static int ft245r_send(PROGRAMMER * pgm, unsigned char * buf, size_t len) {
229+
return ft245r_send2(pgm, buf, len, false);
230+
}
231+
211232
static int ft245r_send_and_discard(PROGRAMMER * pgm, unsigned char * buf,
212233
size_t len) {
213-
rx.discard += len;
214-
return ft245r_send(pgm, buf, len);
234+
return ft245r_send2(pgm, buf, len, true);
215235
}
216236

217237
static int ft245r_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len) {
218-
int i = 0;
219-
220-
// Copy over data from the circular buffer..
221-
// XXX This should timeout, and return error if there isn't enough
222-
// data.
223-
while (i < len) {
224-
sem_wait (&buf_data);
225-
if (rx.discard > 0)
226-
--rx.discard;
227-
else
228-
buf[i++] = buffer[tail];
229-
if (tail == (BUFSIZE -1)) tail = 0;
230-
else tail++;
231-
sem_post (&buf_space);
238+
int i;
239+
240+
ft245r_flush(pgm);
241+
ft245r_fill(pgm);
242+
243+
#if FT245R_DEBUG
244+
avrdude_message(MSG_INFO, "%s: discarding %d, consuming %zu bytes\n",
245+
__func__, rx.discard, len);
246+
#endif
247+
while (rx.discard > 0) {
248+
ft245r_rx_buf_get(pgm);
249+
--rx.discard;
232250
}
233251

252+
for (i = 0; i < len; ++i)
253+
buf[i] = ft245r_rx_buf_get(pgm);
234254
return 0;
235255
}
236256

237257

238258
static int ft245r_drain(PROGRAMMER * pgm, int display) {
239259
int r;
240-
unsigned char t;
241260

242261
// flush the buffer in the chip by changing the mode.....
243262
r = ftdi_set_bitmode(handle, 0, BITMODE_RESET); // reset
@@ -246,13 +265,18 @@ static int ft245r_drain(PROGRAMMER * pgm, int display) {
246265
if (r) return -1;
247266

248267
// drain our buffer.
249-
while (head != tail) {
250-
ft245r_recv (pgm, &t, 1);
251-
}
268+
ft245r_rx_buf_purge(pgm);
252269
return 0;
253270
}
254271

255272

273+
/* Ensure any pending writes are sent to the FTDI chip before sleeping. */
274+
static void ft245r_usleep(PROGRAMMER * pgm, useconds_t usec) {
275+
ft245r_flush(pgm);
276+
usleep(usec);
277+
}
278+
279+
256280
static int ft245r_chip_erase(PROGRAMMER * pgm, AVRPART * p) {
257281
unsigned char cmd[4] = {0,0,0,0};
258282
unsigned char res[4];
@@ -268,7 +292,7 @@ static int ft245r_chip_erase(PROGRAMMER * pgm, AVRPART * p) {
268292

269293
avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
270294
pgm->cmd(pgm, cmd, res);
271-
usleep(p->chip_erase_delay);
295+
ft245r_usleep(pgm, p->chip_erase_delay);
272296
return pgm->initialize(pgm, p);
273297
}
274298

@@ -302,6 +326,8 @@ static int ft245r_set_bitclock(PROGRAMMER * pgm) {
302326
static int get_pin(PROGRAMMER *pgm, int pinname) {
303327
uint8_t byte;
304328

329+
ft245r_flush(pgm);
330+
305331
if (ftdi_read_pins(handle, &byte) != 0)
306332
return -1;
307333
if (FT245R_DEBUG)
@@ -365,7 +391,7 @@ static int set_led_vfy(struct programmer_t * pgm, int value) {
365391
static void ft245r_powerup(PROGRAMMER * pgm)
366392
{
367393
set_vcc(pgm, ON); /* power up */
368-
usleep(100);
394+
ft245r_usleep(pgm, 100);
369395
}
370396

371397

@@ -395,7 +421,7 @@ static void ft245r_enable(PROGRAMMER * pgm) {
395421
* and not via the buffer chip.
396422
*/
397423
set_reset(pgm, OFF);
398-
usleep(1);
424+
ft245r_usleep(pgm, 1);
399425
set_buff(pgm, ON);
400426
}
401427

@@ -434,12 +460,12 @@ static int ft245r_program_enable(PROGRAMMER * pgm, AVRPART * p) {
434460
fflush(stderr);
435461
}
436462
set_pin(pgm, PIN_AVR_RESET, ON);
437-
usleep(20);
463+
ft245r_usleep(pgm, 20);
438464
set_pin(pgm, PIN_AVR_RESET, OFF);
439465

440466
if (i == 3) {
441467
ft245r_drain(pgm, 0);
442-
tail = head;
468+
ft245r_rx_buf_purge(pgm);
443469
}
444470
}
445471

@@ -464,15 +490,15 @@ static int ft245r_initialize(PROGRAMMER * pgm, AVRPART * p) {
464490
ft245r_powerup(pgm);
465491

466492
set_reset(pgm, OFF);
467-
usleep(5000); // 5ms
493+
ft245r_usleep(pgm, 5000); // 5ms
468494
set_reset(pgm, ON);
469-
usleep(5000); // 5ms
495+
ft245r_usleep(pgm, 5000); // 5ms
470496
set_reset(pgm, OFF);
471497

472498
/* Wait for at least 20 ms and enable serial programming by sending the Programming
473499
* Enable serial instruction to pin MOSI.
474500
*/
475-
usleep(20000); // 20ms
501+
ft245r_usleep(pgm, 20000); // 20ms
476502

477503
if (p->flags & AVRPART_HAS_TPI) {
478504
bool io_link_ok = true;
@@ -862,15 +888,6 @@ static int ft245r_open(PROGRAMMER * pgm, char * port) {
862888
goto cleanup;
863889
}
864890

865-
/* We start a new thread to read the output from the FTDI. This is
866-
* necessary because otherwise we'll deadlock. We cannot finish
867-
* writing because the ftdi cannot send the results because we
868-
* haven't provided a read buffer yet. */
869-
870-
sem_init (&buf_data, 0, 0);
871-
sem_init (&buf_space, 0, BUFSIZE);
872-
pthread_create (&readerthread, NULL, reader, handle);
873-
874891
/*
875892
* drain any extraneous input
876893
*/
@@ -892,9 +909,6 @@ static int ft245r_open(PROGRAMMER * pgm, char * port) {
892909

893910
static void ft245r_close(PROGRAMMER * pgm) {
894911
if (handle) {
895-
/* reader thread must be stopped before libftdi de-initialization */
896-
pthread_cancel(readerthread);
897-
pthread_join(readerthread, NULL);
898912
// I think the switch to BB mode and back flushes the buffer.
899913
ftdi_set_bitmode(handle, 0, BITMODE_SYNCBB); // set Synchronous BitBang, all in puts
900914
ftdi_set_bitmode(handle, 0, BITMODE_RESET); // disable Synchronous BitBang
@@ -1071,7 +1085,7 @@ static int ft245r_paged_write_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
10711085
#if defined(USE_INLINE_WRITE_PAGE)
10721086
while (do_request(pgm, m))
10731087
;
1074-
usleep(m->max_write_delay);
1088+
ft245r_usleep(pgm, m->max_write_delay);
10751089
#else
10761090
int addr_wk = addr_save - (addr_save % m->page_size);
10771091
int rc;

0 commit comments

Comments
 (0)