patch #9327: ft245r.c: add TPI support (patches 1-4)

Submitted by David Mosberger-Tang:
* ft245r.c: add TPI support
* avrdude.conf.in (tc2030): New programmer




git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1483 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Joerg Wunsch 2021-11-24 21:25:45 +00:00
parent d947e5893f
commit 6de6c0ffce
3 changed files with 218 additions and 10 deletions

View File

@ -1,3 +1,10 @@
2021-11-24 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
Submitted by David Mosberger-Tang:
patch #9327: ft245r.c: add TPI support (patches 1-4)
* ft245r.c: add TPI support
* avrdude.conf.in (tc2030): New programmer
2021-11-24 Joerg Wunsch <j.gnu@uriah.heep.sax.de> 2021-11-24 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
* ft245r.c (ft245r_open): allow for picking a default * ft245r.c (ft245r_open): allow for picking a default

View File

@ -780,6 +780,18 @@ programmer
reset = 7; # RI X3(4) reset = 7; # RI X3(4)
; ;
programmer
id = "tc2030";
desc = "Tag-Connect TC2030";
type = "ftdi_syncbb";
connection_type = usb;
# FOR TPI devices:
mosi = 0; # TxD = D0 (wire to TPIDATA via 1k resistor)
miso = 1; # RxD = D1 (wire to TPIDATA directly)
sck = 2; # RTS = D2 (wire to SCK)
reset = 3; # CTS = D3 (wire to ~RESET)
;
# website mentioned above uses this id # website mentioned above uses this id
programmer parent "arduino-ft232r" programmer parent "arduino-ft232r"
id = "diecimila"; id = "diecimila";

209
ft245r.c
View File

@ -67,6 +67,11 @@
#include "ft245r.h" #include "ft245r.h"
#include "usbdevs.h" #include "usbdevs.h"
#include "tpi.h"
#define TPIPCR_GT_0b 0x07
#define TPI_STOP_BITS 0x03
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h> #include <windows.h>
#endif #endif
@ -241,6 +246,9 @@ static int ft245r_chip_erase(PROGRAMMER * pgm, AVRPART * p) {
unsigned char cmd[4] = {0,0,0,0}; unsigned char cmd[4] = {0,0,0,0};
unsigned char res[4]; unsigned char res[4];
if (p->flags & AVRPART_HAS_TPI)
return avr_tpi_chip_erase(pgm, p);
if (p->op[AVR_OP_CHIP_ERASE] == NULL) { if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
avrdude_message(MSG_INFO, "chip erase instruction not defined for part \"%s\"\n", avrdude_message(MSG_INFO, "chip erase instruction not defined for part \"%s\"\n",
p->desc); p->desc);
@ -280,6 +288,16 @@ static int ft245r_set_bitclock(PROGRAMMER * pgm) {
return 0; return 0;
} }
static int get_pin(PROGRAMMER *pgm, int pinname) {
uint8_t byte;
if (ftdi_read_pins(handle, &byte) != 0)
return -1;
if (FT245R_DEBUG)
avrdude_message(MSG_INFO, "%s: in 0x%02x\n", __func__, byte);
return GET_BITS_0(byte, pgm, pinname) != 0;
}
static int set_pin(PROGRAMMER * pgm, int pinname, int val) { static int set_pin(PROGRAMMER * pgm, int pinname, int val) {
unsigned char buf[1]; unsigned char buf[1];
@ -375,6 +393,8 @@ static void ft245r_enable(PROGRAMMER * pgm) {
static int ft245r_cmd(PROGRAMMER * pgm, const unsigned char *cmd, static int ft245r_cmd(PROGRAMMER * pgm, const unsigned char *cmd,
unsigned char *res); unsigned char *res);
static int ft245r_tpi_tx(PROGRAMMER * pgm, uint8_t byte);
static int ft245r_tpi_rx(PROGRAMMER * pgm, uint8_t *bytep);
/* /*
* issue the 'program enable' command to the AVR device * issue the 'program enable' command to the AVR device
*/ */
@ -383,6 +403,9 @@ static int ft245r_program_enable(PROGRAMMER * pgm, AVRPART * p) {
unsigned char res[4]; unsigned char res[4];
int i; int i;
if (p->flags & AVRPART_HAS_TPI)
return avr_tpi_program_enable(pgm, p, TPIPCR_GT_0b);
if (p->op[AVR_OP_PGM_ENABLE] == NULL) { if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
avrdude_message(MSG_INFO, "%s: AVR_OP_PGM_ENABLE command not defined for %s\n", avrdude_message(MSG_INFO, "%s: AVR_OP_PGM_ENABLE command not defined for %s\n",
progname, p->desc); progname, p->desc);
@ -443,25 +466,73 @@ static int ft245r_initialize(PROGRAMMER * pgm, AVRPART * p) {
*/ */
usleep(20000); // 20ms usleep(20000); // 20ms
if (p->flags & AVRPART_HAS_TPI) {
bool io_link_ok = true;
uint8_t byte;
int i;
/* Since there is a single TPIDATA line, MOSI and MISO must be
linked together through a 1kOhm resistor. Verify that
everything we send on MOSI gets mirrored back on MISO. */
set_pin(pgm, PIN_AVR_MOSI, 0);
if (get_pin(pgm, PIN_AVR_MISO) != 0) {
io_link_ok = false;
avrdude_message(MSG_INFO, "MOSI->MISO 0 failed\n");
if (!ovsigck)
return -1;
}
set_pin(pgm, PIN_AVR_MOSI, 1);
if (get_pin(pgm, PIN_AVR_MISO) != 1) {
io_link_ok = false;
avrdude_message(MSG_INFO, "MOSI->MISO 1 failed\n");
if (!ovsigck)
return -1;
}
if (io_link_ok)
avrdude_message(MSG_NOTICE2, "MOSI-MISO link present\n");
/* keep TPIDATA high for 16 clock cycles */
set_pin(pgm, PIN_AVR_MOSI, 1);
for (i = 0; i < 16; i++) {
set_sck(pgm, 1);
set_sck(pgm, 0);
}
/* remove extra guard timing bits */
ft245r_tpi_tx(pgm, TPI_CMD_SSTCS | TPI_REG_TPIPCR);
ft245r_tpi_tx(pgm, 0x7);
/* read TPI ident reg */
ft245r_tpi_tx(pgm, TPI_CMD_SLDCS | TPI_REG_TPIIR);
ft245r_tpi_rx(pgm, &byte);
if (byte != 0x80) {
avrdude_message(MSG_INFO, "TPIIR 0x%02x not correct\n", byte);
return -1;
}
}
return ft245r_program_enable(pgm, p); return ft245r_program_enable(pgm, p);
} }
static inline void add_bit(PROGRAMMER * pgm, unsigned char *buf, int *buf_pos,
uint8_t bit) {
ft245r_out = SET_BITS_0(ft245r_out,pgm,PIN_AVR_MOSI, bit);
ft245r_out = SET_BITS_0(ft245r_out,pgm,PIN_AVR_SCK,0);
buf[*buf_pos] = ft245r_out;
(*buf_pos)++;
ft245r_out = SET_BITS_0(ft245r_out,pgm,PIN_AVR_SCK,1);
buf[*buf_pos] = ft245r_out;
(*buf_pos)++;
}
static inline int set_data(PROGRAMMER * pgm, unsigned char *buf, unsigned char data) { static inline int set_data(PROGRAMMER * pgm, unsigned char *buf, unsigned char data) {
int j; int j;
int buf_pos = 0; int buf_pos = 0;
unsigned char bit = 0x80; unsigned char bit = 0x80;
for (j=0; j<8; j++) { for (j=0; j<8; j++) {
ft245r_out = SET_BITS_0(ft245r_out,pgm,PIN_AVR_MOSI,data & bit); add_bit(pgm, buf, &buf_pos, (data & bit) != 0);
ft245r_out = SET_BITS_0(ft245r_out,pgm,PIN_AVR_SCK,0);
buf[buf_pos] = ft245r_out;
buf_pos++;
ft245r_out = SET_BITS_0(ft245r_out,pgm,PIN_AVR_SCK,1);
buf[buf_pos] = ft245r_out;
buf_pos++;
bit >>= 1; bit >>= 1;
} }
return buf_pos; return buf_pos;
@ -532,6 +603,123 @@ static int ft245r_cmd(PROGRAMMER * pgm, const unsigned char *cmd,
return 0; return 0;
} }
static inline uint8_t extract_tpi_data(PROGRAMMER * pgm, unsigned char *buf,
int *buf_pos) {
uint8_t bit = 0x1, byte = 0;
int j;
for (j = 0; j < 8; j++) {
(*buf_pos)++; // skip over falling clock edge
if (GET_BITS_0(buf[(*buf_pos)++], pgm, PIN_AVR_MISO))
byte |= bit;
bit <<= 1;
}
return byte;
}
static inline int set_tpi_data(PROGRAMMER * pgm, unsigned char *buf,
uint8_t byte) {
uint8_t bit = 0x1, parity = 0;
int j, buf_pos = 0;
// start bit:
add_bit(pgm, buf, &buf_pos, 0);
// 8 data bits:
for (j = 0; j < 8; j++) {
add_bit(pgm, buf, &buf_pos, (byte & bit) != 0);
parity ^= (byte & bit) != 0;
bit <<= 1;
}
// parity bit:
add_bit(pgm, buf, &buf_pos, parity);
// stop bits:
add_bit(pgm, buf, &buf_pos, 1);
add_bit(pgm, buf, &buf_pos, 1);
return buf_pos;
}
static int ft245r_tpi_tx(PROGRAMMER * pgm, uint8_t byte) {
uint8_t buf[128];
int len;
len = set_tpi_data(pgm, buf, byte);
ft245r_send(pgm, buf, len);
ft245r_recv(pgm, buf, len);
return 0;
}
static int ft245r_tpi_rx(PROGRAMMER * pgm, uint8_t *bytep) {
uint8_t buf[128], bit, parity;
int i, buf_pos = 0, len = 0;
uint32_t res, m, byte;
/* Allow for up to 4 bits before we must see start bit; during
that time, we must keep the MOSI line high. */
for (i = 0; i < 2; ++i)
len += set_data(pgm, &buf[len], 0xff);
ft245r_send(pgm, buf, len);
ft245r_recv(pgm, buf, len);
res = (extract_tpi_data(pgm, buf, &buf_pos)
| ((uint32_t) extract_tpi_data(pgm, buf, &buf_pos) << 8));
/* Look for start bit: */
m = 0x1;
while (m & res)
m <<= 1;
if (m >= 0x10) {
avrdude_message(MSG_INFO, "%s: start bit missing (res=0x%04x)\n",
__func__, res);
return -1;
}
byte = parity = 0;
for (i = 0; i < 8; ++i) {
m <<= 1;
bit = (res & m) != 0;
parity ^= bit;
byte |= bit << i;
}
m <<= 1;
if (((res & m) != 0) != parity) {
avrdude_message(MSG_INFO, "%s: parity bit wrong\n", __func__);
return -1;
}
if (((res & (m << 1)) == 0) || ((res & (m << 2))) == 0) {
avrdude_message(MSG_INFO, "%s: stop bits wrong\n", __func__);
return -1;
}
*bytep = (uint8_t) byte;
return 0;
}
static int ft245r_cmd_tpi(PROGRAMMER * pgm, const unsigned char *cmd,
int cmd_len, unsigned char *res, int res_len) {
int i, ret = 0;
pgm->pgm_led(pgm, ON);
for (i = 0; i < cmd_len; ++i)
ft245r_tpi_tx(pgm, cmd[i]);
for (i = 0; i < res_len; ++i)
if ((ret = ft245r_tpi_rx(pgm, &res[i])) < 0)
break;
if (verbose >= 2) {
avrdude_message(MSG_NOTICE2, "%s: [ ", __func__);
for (i = 0; i < cmd_len; i++)
avrdude_message(MSG_NOTICE2, "%02X ", cmd[i]);
avrdude_message(MSG_NOTICE2, "] [ ");
for(i = 0; i < res_len; i++)
avrdude_message(MSG_NOTICE2, "%02X ", res[i]);
avrdude_message(MSG_NOTICE2, "]\n");
}
pgm->pgm_led(pgm, OFF);
return ret;
}
/* lower 8 pins are accepted, they might be also inverted */ /* lower 8 pins are accepted, they might be also inverted */
static const struct pindef_t valid_pins = {{0xff},{0xff}} ; static const struct pindef_t valid_pins = {{0xff},{0xff}} ;
@ -985,6 +1173,7 @@ void ft245r_initpgm(PROGRAMMER * pgm) {
pgm->program_enable = ft245r_program_enable; pgm->program_enable = ft245r_program_enable;
pgm->chip_erase = ft245r_chip_erase; pgm->chip_erase = ft245r_chip_erase;
pgm->cmd = ft245r_cmd; pgm->cmd = ft245r_cmd;
pgm->cmd_tpi = ft245r_cmd_tpi;
pgm->open = ft245r_open; pgm->open = ft245r_open;
pgm->close = ft245r_close; pgm->close = ft245r_close;
pgm->read_byte = avr_read_byte_default; pgm->read_byte = avr_read_byte_default;