From 35cd1d0b4fe5e914ecd75c6962abcd9736c6607c Mon Sep 17 00:00:00 2001 From: Jeff Kent Date: Sat, 18 Mar 2023 19:48:58 -0500 Subject: [PATCH 1/8] add pindefs for JTAG --- src/avrdude.conf.in | 4 ++++ src/config_gram.y | 8 ++++++++ src/lexer.l | 4 ++++ src/libavrdude.h | 5 +++++ src/pgm.c | 8 ++++++++ src/pindefs.c | 16 ++++++++++++++++ 6 files changed, 45 insertions(+) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 1cc82043..d3beacf2 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -32,6 +32,10 @@ # sck = ; # pin number # sdo = ; # pin number # sdi = ; # pin number +# tck = ; # pin number +# tdi = ; # pin number +# tdo = ; # pin number +# tms = ; # pin number # errled = ; # pin number # rdyled = ; # pin number # pgmled = ; # pin number diff --git a/src/config_gram.y b/src/config_gram.y index 93379ca6..787a742d 100644 --- a/src/config_gram.y +++ b/src/config_gram.y @@ -108,6 +108,10 @@ static int pin_name; %token K_SCK %token K_SIGNATURE %token K_SIZE +%token K_TCK +%token K_TDI +%token K_TDO +%token K_TMS %token K_USB %token K_USBPID %token K_TYPE @@ -557,6 +561,10 @@ prog_parm_pins: K_SCK TKN_EQUAL {pin_name = PIN_AVR_SCK; clear_pin(pin_name); } pin_number { free_token($1); } | K_SDO TKN_EQUAL {pin_name = PIN_AVR_SDO; clear_pin(pin_name); } pin_number | K_SDI TKN_EQUAL {pin_name = PIN_AVR_SDI; clear_pin(pin_name); } pin_number | + K_TCK TKN_EQUAL {pin_name = PIN_JTAG_TCK; clear_pin(pin_name); } pin_number | + K_TDI TKN_EQUAL {pin_name = PIN_JTAG_TDI; clear_pin(pin_name); } pin_number | + K_TDO TKN_EQUAL {pin_name = PIN_JTAG_TDO; clear_pin(pin_name); } pin_number | + K_TMS TKN_EQUAL {pin_name = PIN_JTAG_TMS; clear_pin(pin_name); } pin_number | K_ERRLED TKN_EQUAL {pin_name = PIN_LED_ERR; clear_pin(pin_name); } pin_number | K_RDYLED TKN_EQUAL {pin_name = PIN_LED_RDY; clear_pin(pin_name); } pin_number | K_PGMLED TKN_EQUAL {pin_name = PIN_LED_PGM; clear_pin(pin_name); } pin_number | diff --git a/src/lexer.l b/src/lexer.l index 1aae32ee..36787433 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -237,6 +237,10 @@ sdo { yylval=NULL; ccap(); return K_SDO; } serial { yylval=NULL; ccap(); return K_SERIAL; } signature { yylval=NULL; ccap(); return K_SIGNATURE; } spi { yylval=NULL; return K_SPI; } +tck { yylval=NULL; ccap(); return K_TCK; } +tdi { yylval=NULL; ccap(); return K_TDI; } +tdo { yylval=NULL; ccap(); return K_TDO; } +tms { yylval=NULL; ccap(); return K_TMS; } type { yylval=NULL; ccap(); return K_TYPE; } usb { yylval=NULL; return K_USB; } usbpid { yylval=NULL; ccap(); return K_USBPID; } diff --git a/src/libavrdude.h b/src/libavrdude.h index 44ae0f7c..deb400e0 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -424,6 +424,10 @@ enum { PIN_AVR_SCK, PIN_AVR_SDO, PIN_AVR_SDI, + PIN_JTAG_TCK, + PIN_JTAG_TDI, + PIN_JTAG_TDO, + PIN_JTAG_TMS, PIN_LED_ERR, PIN_LED_RDY, PIN_LED_PGM, @@ -860,6 +864,7 @@ void programmer_display(PROGRAMMER * pgm, const char * p); #define SHOW_ALL_PINS (~0u) #define SHOW_PPI_PINS ((1<pin[PIN_AVR_SDO])); if(show & (1<pin[PIN_AVR_SDI])); + if(show & (1<pin[PIN_JTAG_TCK])); + if(show & (1<pin[PIN_JTAG_TDI])); + if(show & (1<pin[PIN_JTAG_TDO])); + if(show & (1<pin[PIN_JTAG_TMS])); if(show & (1<pin[PIN_LED_ERR])); if(show & (1<pin[PIN_AVR_SDI]), &(pgm->pinno[PIN_AVR_SDI])) < 0) return -1; + if (pin_fill_old_pinno(&(pgm->pin[PIN_JTAG_TCK]), &(pgm->pinno[PIN_JTAG_TCK])) < 0) + return -1; + if (pin_fill_old_pinno(&(pgm->pin[PIN_JTAG_TDI]), &(pgm->pinno[PIN_JTAG_TDI])) < 0) + return -1; + if (pin_fill_old_pinno(&(pgm->pin[PIN_JTAG_TDO]), &(pgm->pinno[PIN_JTAG_TDO])) < 0) + return -1; + if (pin_fill_old_pinno(&(pgm->pin[PIN_JTAG_TMS]), &(pgm->pinno[PIN_JTAG_TMS])) < 0) + return -1; if (pin_fill_old_pinno(&(pgm->pin[PIN_LED_ERR]), &(pgm->pinno[PIN_LED_ERR])) < 0) return -1; if (pin_fill_old_pinno(&(pgm->pin[PIN_LED_RDY]), &(pgm->pinno[PIN_LED_RDY])) < 0) @@ -377,6 +385,10 @@ const char * avr_pin_name(int pinname) { case PIN_AVR_SCK : return "SCK"; case PIN_AVR_SDO : return "SDO"; case PIN_AVR_SDI : return "SDI"; + case PIN_JTAG_TCK : return "TCK"; + case PIN_JTAG_TDI : return "TDI"; + case PIN_JTAG_TDO : return "TDO"; + case PIN_JTAG_TMS : return "TMS"; case PIN_LED_ERR : return "ERRLED"; case PIN_LED_RDY : return "RDYLED"; case PIN_LED_PGM : return "PGMLED"; @@ -400,6 +412,10 @@ const char * avr_pin_lcname(int pinname) { case PIN_AVR_SCK : return "sck"; case PIN_AVR_SDO : return "sdo"; case PIN_AVR_SDI : return "sdi"; + case PIN_JTAG_TCK : return "tck"; + case PIN_JTAG_TDI : return "tdi"; + case PIN_JTAG_TDO : return "tdo"; + case PIN_JTAG_TMS : return "tms"; case PIN_LED_ERR : return "errled"; case PIN_LED_RDY : return "rdyled"; case PIN_LED_PGM : return "pgmled"; From ecd416917de6519ae47695b6ed2df64d4e8d56a6 Mon Sep 17 00:00:00 2001 From: Jeff Kent Date: Sun, 19 Mar 2023 11:23:02 -0500 Subject: [PATCH 2/8] add FTDI MPSSE jtag support --- src/avrdude.conf.in | 20 ++ src/avrftdi.c | 697 +++++++++++++++++++++++++++++++++++++++--- src/avrftdi.h | 2 + src/avrftdi_private.h | 27 ++ src/pgm_type.c | 1 + 5 files changed, 706 insertions(+), 41 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index d3beacf2..f94e185e 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -1135,6 +1135,26 @@ programmer sdi = 2; # TDO 13 ; +#------------------------------------------------------------ +# tumpa-jtag +#------------------------------------------------------------ + +programmer parent "tumpa" + id = "tumpa-jtag"; + desc = "TIAO USB Multi-Protocol Adapter (JTAG)"; + type = "avrftdi_jtag"; + sck = ; + sdo = ; + sdi = ; + tck = 0; # TCK 9 + tdi = 1; # TDI 5 + tdo = 2; # TDO 13 + tms = 3; # TMS 7 + reset = ; #4; # RST 15 + buff = ~11; + prog_modes = PM_JTAG; +; + #------------------------------------------------------------ # ktlink #------------------------------------------------------------ diff --git a/src/avrftdi.c b/src/avrftdi.c index b255c395..9bed0015 100644 --- a/src/avrftdi.c +++ b/src/avrftdi.c @@ -1,6 +1,7 @@ /* * avrftdi - extension for avrdude, Wolfgang Moser, Ville Voipio * Copyright (C) 2011 Hannes Weisbach, Doug Springer + * Copyright (C) 2023 Jeff Kent * * 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 @@ -60,9 +61,27 @@ void avrftdi_initpgm(PROGRAMMER *pgm) { pgm->open = avrftdi_noftdi_open; } +void avrftdi_jtag_initpgm(PROGRAMMER *pgm) { + strcpy(pgm->type, "avrftdi_jtag"); + pgm->open = avrftdi_noftdi_open; +} + #else -enum { FTDI_SCK = 0, FTDI_SDO, FTDI_SDI, FTDI_RESET }; +#define PGM_FL_IS_DW (0x0001) +#define PGM_FL_IS_PDI (0x0002) +#define PGM_FL_IS_JTAG (0x0004) +#define PGM_FL_IS_EDBG (0x0008) +#define PGM_FL_IS_UPDI (0x0010) +#define PGM_FL_IS_TPI (0x0020) + +/* MPSSE pins */ +enum { + FTDI_TCK_SCK = 0, + FTDI_TDI_SDO, + FTDI_TDO_SDI, + FTDI_TMS_CS, +}; static int write_flush(avrftdi_t *); @@ -186,37 +205,60 @@ static void buf_dump(const unsigned char *buf, int len, char *desc, */ static int set_frequency(avrftdi_t* ftdi, uint32_t freq) { - int32_t divisor; - uint8_t buf[3]; + int32_t clock, divisor; + float hs_error, ls_error; + uint8_t buf[4], *ptr = buf; + + if (ftdi->ftdic->type == TYPE_232H || + ftdi->ftdic->type == TYPE_2232H || + ftdi->ftdic->type == TYPE_4232H) { + + clock = 60000000; + divisor = ((clock / 2) / freq) - 1; + hs_error = (float)(clock / 2) / (divisor + 1) / freq; + + clock = 12000000; + divisor = ((clock / 2) / freq) - 1; + ls_error = (float)(clock / 2) / (divisor + 1) / freq; + + if (ls_error <= hs_error) { + *ptr++ = EN_DIV_5; + } else { + clock = 60000000; + divisor = ((clock / 2) / freq) - 1; + *ptr++ = DIS_DIV_5; + } + } else { + clock = 12000000; + divisor = ((clock / 2) / freq) - 1; + } - /* divisor on 6000000 / freq - 1 */ - divisor = (6000000 / freq) - 1; if (divisor < 0) { - log_warn("Frequency too high (%u > 6 MHz)\n", freq); - log_warn("Resetting Frequency to 6MHz\n"); + log_warn("Frequency too high (%u > %u MHz)\n", freq, clock / 2000000); + log_warn("Resetting Frequency to %uMHz\n", clock / 2000000); divisor = 0; } if (divisor > 65535) { - log_warn("Frequency too low (%u < 91.553 Hz)\n", freq); - log_warn("Resetting Frequency to 91.553Hz\n"); + log_warn("Frequency too low (%u < %.3f Hz)\n", freq, (float) clock / 2 / 65535); + log_warn("Resetting Frequency to %.3fHz\n", (float) clock / 2 / 65535); divisor = 65535; } - log_info("Using frequency: %d\n", 6000000/(divisor+1)); + log_info("Using frequency: %d\n", clock / 2 / (divisor + 1)); log_info("Clock divisor: 0x%04x\n", divisor); - buf[0] = TCK_DIVISOR; - buf[1] = (uint8_t)(divisor & 0xff); - buf[2] = (uint8_t)((divisor >> 8) & 0xff); + *ptr++ = TCK_DIVISOR; + *ptr++ = (uint8_t)(divisor & 0xff); + *ptr++ = (uint8_t)(divisor >> 8) & 0xff; - E(ftdi_write_data(ftdi->ftdic, buf, 3) < 0, ftdi->ftdic); + E(ftdi_write_data(ftdi->ftdic, buf, ptr - buf) < 0, ftdi->ftdic); return 0; } /* - * This function sets or clears any pin, except SCK, SDI and SDO. Depending + * This function sets or clears any pin, except mandatory pins. Depending * on the pin configuration, a non-zero value sets the pin in the 'active' * state (high active, low active) and a zero value sets the pin in the * inactive state. @@ -550,14 +592,21 @@ static int avrftdi_check_pins_mpsse(const PROGRAMMER *pgm, bool output) { /* SCK/SDO/SDI are fixed and not invertible? */ /* TODO: inverted SCK/SDI/SDO */ - static const struct pindef_t valid_pins_SCK = {{0x01},{0x00}}; - static const struct pindef_t valid_pins_SDO = {{0x02},{0x00}}; - static const struct pindef_t valid_pins_SDI = {{0x04},{0x00}}; + static const struct pindef_t valid_pins[4] = { + {{0x01}, {0x00}}, + {{0x02}, {0x00}}, + {{0x04}, {0x00}}, + {{0x08}, {0x00}}, + }; /* value for 8/12/16 bit wide interface for other pins */ int valid_mask = ((1 << pdata->pin_limit) - 1); - /* mask out SCK/SDI/SDO */ - valid_mask &= ~((1 << FTDI_SCK) | (1 << FTDI_SDO) | (1 << FTDI_SDI)); + + /* mask MPSSE pins */ + valid_mask &= ~((1 << FTDI_TCK_SCK) | (1 << FTDI_TDI_SDO) | (1 << FTDI_TDO_SDI)); + if (pgm->flag == PGM_FL_IS_JTAG) { + valid_mask &= ~(1 << FTDI_TMS_CS); + } log_debug("Using valid mask mpsse: 0x%08x\n", valid_mask); static struct pindef_t valid_pins_others; @@ -572,13 +621,24 @@ static int avrftdi_check_pins_mpsse(const PROGRAMMER *pgm, bool output) { } /* now set mpsse specific pins */ + if (pgm->flag == PGM_FL_IS_JTAG) { + pin_checklist[PIN_JTAG_TCK].mandatory = 1; + pin_checklist[PIN_JTAG_TCK].valid_pins = &valid_pins[FTDI_TCK_SCK]; + pin_checklist[PIN_JTAG_TDI].mandatory = 1; + pin_checklist[PIN_JTAG_TDI].valid_pins = &valid_pins[FTDI_TDI_SDO]; + pin_checklist[PIN_JTAG_TDO].mandatory = 1; + pin_checklist[PIN_JTAG_TDO].valid_pins = &valid_pins[FTDI_TDO_SDI]; + pin_checklist[PIN_JTAG_TMS].mandatory = 1; + pin_checklist[PIN_JTAG_TMS].valid_pins = &valid_pins[FTDI_TMS_CS]; + } else { pin_checklist[PIN_AVR_SCK].mandatory = 1; - pin_checklist[PIN_AVR_SCK].valid_pins = &valid_pins_SCK; - pin_checklist[PIN_AVR_SDO].mandatory = 1; - pin_checklist[PIN_AVR_SDO].valid_pins = &valid_pins_SDO; - pin_checklist[PIN_AVR_SDI].mandatory = 1; - pin_checklist[PIN_AVR_SDI].valid_pins = &valid_pins_SDI; - pin_checklist[PIN_AVR_RESET].mandatory = 1; + pin_checklist[PIN_AVR_SCK].valid_pins = &valid_pins[FTDI_TCK_SCK]; + pin_checklist[PIN_AVR_SDO].mandatory = 1; + pin_checklist[PIN_AVR_SDO].valid_pins = &valid_pins[FTDI_TDI_SDO]; + pin_checklist[PIN_AVR_SDI].mandatory = 1; + pin_checklist[PIN_AVR_SDI].valid_pins = &valid_pins[FTDI_TDO_SDI]; + pin_checklist[PIN_AVR_RESET].mandatory = 1; + } /* assumes all checklists above have same number of entries */ return pins_check(pgm, pin_checklist, N_PINS, output); @@ -601,11 +661,23 @@ static int avrftdi_pin_setup(const PROGRAMMER *pgm) { log_err("No valid pin configuration found.\n"); avrftdi_check_pins_bb(pgm, true); log_err("Pin configuration for FTDI MPSSE must be:\n"); - log_err("%s: 0, %s: 1, %s: 2 (is: %s, %s, %s)\n", avr_pin_name(PIN_AVR_SCK), - avr_pin_name(PIN_AVR_SDO), avr_pin_name(PIN_AVR_SDI), - pins_to_str(&pgm->pin[PIN_AVR_SCK]), - pins_to_str(&pgm->pin[PIN_AVR_SDO]), - pins_to_str(&pgm->pin[PIN_AVR_SDI])); + if (pgm->flag == PGM_FL_IS_JTAG) { + log_err("%s: 0, %s: 1, %s: 2, %s :3 (is: %s, %s, %s, %s)\n", + avr_pin_name(PIN_JTAG_TCK), avr_pin_name(PIN_JTAG_TDI), + avr_pin_name(PIN_JTAG_TDO), avr_pin_name(PIN_JTAG_TMS), + pins_to_str(&pgm->pin[PIN_JTAG_TCK]), + pins_to_str(&pgm->pin[PIN_JTAG_TDI]), + pins_to_str(&pgm->pin[PIN_JTAG_TDO]), + pins_to_str(&pgm->pin[PIN_JTAG_TMS])); + } else { + log_err("%s: 0, %s: 1, %s: 2 (is: %s, %s, %s)\n", + avr_pin_name(PIN_AVR_SCK), + avr_pin_name(PIN_AVR_SDO), + avr_pin_name(PIN_AVR_SDI), + pins_to_str(&pgm->pin[PIN_AVR_SCK]), + pins_to_str(&pgm->pin[PIN_AVR_SDO]), + pins_to_str(&pgm->pin[PIN_AVR_SDI])); + } log_err("If other pin configuration is used, fallback to slower bitbanging mode is used.\n"); return -1; @@ -628,6 +700,20 @@ static int avrftdi_pin_setup(const PROGRAMMER *pgm) { } pdata->pin_direction &= ~pgm->pin[PIN_AVR_SDI].mask[0]; + if (pgm->flag & PGM_FL_IS_JTAG) { + if (!pdata->use_bitbanging) { + pdata->pin_value &= ~pgm->pin[PIN_JTAG_TCK].mask[0]; + pdata->pin_value |= pgm->pin[PIN_JTAG_TCK].inverse[0]; + } + pdata->pin_direction &= ~pgm->pin[PIN_JTAG_TDO].mask[0]; + } else { + if (!pdata->use_bitbanging) { + pdata->pin_value &= ~pgm->pin[PIN_AVR_SCK].mask[0]; + pdata->pin_value |= pgm->pin[PIN_AVR_SCK].inverse[0]; + } + pdata->pin_direction &= ~pgm->pin[PIN_AVR_SDI].mask[0]; + } + for(pin = PIN_LED_ERR; pin < N_PINS; ++pin) { pdata->led_mask |= pgm->pin[pin].mask[0]; } @@ -835,9 +921,10 @@ static int avrftdi_initialize(const PROGRAMMER *pgm, const AVRPART *p) { return pgm->program_enable(pgm, p); } -static void avrftdi_display(const PROGRAMMER *pgm, const char *p) { - // print the full pin definitions as in ft245r ? - return; +static void avrftdi_display(const PROGRAMMER *pgm, const char *p) +{ + msg_info("%sPin assignment : 0..7 = DBUS0..7, 8..15 = CBUS0..7\n", p); + pgm_display_generic_mask(pgm, p, SHOW_ALL_PINS); } @@ -1219,13 +1306,511 @@ avrftdi_teardown(PROGRAMMER * pgm) } } -void avrftdi_initpgm(PROGRAMMER *pgm) { +/******************/ +/* JTAG functions */ +/******************/ + +static int avrftdi_jtag_reset(const PROGRAMMER *pgm) +{ + avrftdi_t *pdata = to_pdata(pgm); + unsigned char buf[3], *ptr = buf; + + /* Unknown -> Reset -> Run-Test/Idle */ + *ptr++ = MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 5; + *ptr++ = 0x1f; + + E(ftdi_write_data(pdata->ftdic, buf, ptr - buf) != ptr - buf, pdata->ftdic); + + return 0; +} + +static int avrftdi_jtag_ir_out(const PROGRAMMER *pgm, unsigned char ir) +{ + avrftdi_t *pdata = to_pdata(pgm); + unsigned char buf[9], *ptr = buf; + + /* Idle -> Select-DR -> Select-IR -> Capture-IR -> Shift-IR */ + *ptr++ = MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 3; + *ptr++ = 0x03; + + /* Clock out first 3 bits */ + *ptr++ = MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 2; + *ptr++ = ir & 0x7; + + /* Clock out 4th bit and Shift-IR -> Exit1-IR -> Update-IR -> Idle */ + *ptr++ = MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 2; + *ptr++ = (ir & 0x8) << 4 | 0x03; + + E(ftdi_write_data(pdata->ftdic, buf, ptr - buf) != ptr - buf, pdata->ftdic); + + return 0; +} + +static int avrftdi_jtag_dr_out(const PROGRAMMER *pgm, unsigned int dr, int bits) +{ + avrftdi_t *pdata = to_pdata(pgm); + unsigned char buf[18], *ptr = buf; + + if (bits <= 0 || bits > 31) { + return -1; + } + + /* Idle -> Select-DR -> Capture-DR -> Shift-DR */ + *ptr++ = MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 2; + *ptr++ = 0x01; + + while (bits > 8) { + /* Write bits */ + *ptr++ = MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 7; + *ptr++ = dr & 0xff; + bits -= 8; + dr >>= 8; + } + + if (bits > 1) { + /* Write */ + *ptr++ = MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = bits - 2; + *ptr++ = dr & ((1 << (bits - 1)) - 1); + } + dr <<= 8 - bits; + + /* Write MSB and Shift-DR -> Exit1-DR -> Update-DR -> Idle */ + *ptr++ = MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 2; + *ptr++ = (dr & 0x80) | 0x03; + + E(ftdi_write_data(pdata->ftdic, buf, ptr - buf) != ptr - buf, pdata->ftdic); + + return 0; +} + +static int avrftdi_jtag_dr_inout(const PROGRAMMER *pgm, unsigned int dr, + int bits) +{ + avrftdi_t *pdata = to_pdata(pgm); + unsigned char buf[19], *ptr = buf; + unsigned char bytes = 1, pos; + unsigned int dr_in; + + if (bits <= 0 || bits > 31) { + return -1; + } + + /* Run-Test/Idle -> Select-DR -> Capture-DR -> Shift-DR */ + *ptr++ = MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 2; + *ptr++ = 0x01; + + while (bits > 8) { + /* Read/write bits */ + *ptr++ = MPSSE_DO_READ | MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 7; + *ptr++ = dr & 0xff; + bits -= 8; + bytes++; + dr >>= 8; + } + + if (bits > 1) { + /* Read/write */ + *ptr++ = MPSSE_DO_READ | MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = bits - 2; + *ptr++ = dr & ((1 << (bits - 1)) - 1); + bytes++; + } + dr <<= 8 - bits; + + /* Read/write MSB and Shift-DR -> Exit1-DR -> Update-DR -> Run-Test/Idle */ + *ptr++ = MPSSE_WRITE_TMS | MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 2; + *ptr++ = (dr & 0x80) | 0x03; + *ptr++ = SEND_IMMEDIATE; + + E(ftdi_write_data(pdata->ftdic, buf, ptr - buf) != ptr - buf, pdata->ftdic); + + pos = 0; + do { + int n = ftdi_read_data(pdata->ftdic, &buf[pos], bytes - pos); + E(n < 0, pdata->ftdic); + pos += n; + } while (pos < bytes); + + dr_in = 0; + ptr = buf; + pos = 0; + while (bytes - (ptr - buf) > 2) { + dr_in |= *ptr++ << pos; + pos += 8; + } + if (bytes >= 1) { + dr_in |= *ptr++ << (pos - 8 + bits - 1); + pos += bits - 1; + } + dr_in |= (*ptr++ & 0x20) << (pos - 5); + + return dr_in; +} + +static int avrftdi_jtag_initialize(const PROGRAMMER *pgm, const AVRPART *p) +{ + pgm->powerup(pgm); + + set_pin(pgm, PIN_AVR_RESET, OFF); + set_pin(pgm, PIN_JTAG_TCK, OFF); + usleep(20 * 1000); + + set_pin(pgm, PIN_AVR_RESET, ON); + usleep(20 * 1000); + + return 0; +} + +static void avrftdi_jtag_enable(PROGRAMMER *pgm, const AVRPART *p) +{ + set_pin(pgm, PPI_AVR_BUFF, ON); + + avrftdi_jtag_reset(pgm); + + /* Set RESET */ + avrftdi_jtag_ir_out(pgm, JTAG_IR_AVR_RESET); + avrftdi_jtag_dr_out(pgm, 1, 1); + + /* Write program enable magic */ + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_ENABLE); + avrftdi_jtag_dr_out(pgm, 0xa370, 16); +} + +static void avrftdi_jtag_disable(const PROGRAMMER *pgm) +{ + avrftdi_t *pdata = to_pdata(pgm); + + /* NOP command */ + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300, 15); + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + + /* Clear program enable */ + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_ENABLE); + avrftdi_jtag_dr_out(pgm, 0x0000, 16); + + /* Disable RESET */ + avrftdi_jtag_ir_out(pgm, JTAG_IR_AVR_RESET); + avrftdi_jtag_dr_out(pgm, 0, 1); + + write_flush(pdata); + + set_pin(pgm, PPI_AVR_BUFF, OFF); +} + +static int avrftdi_jtag_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) +{ + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2380, 15); + avrftdi_jtag_dr_out(pgm, 0x3180, 15); + avrftdi_jtag_dr_out(pgm, 0x3380, 15); + avrftdi_jtag_dr_out(pgm, 0x3380, 15); + while (!(avrftdi_jtag_dr_inout(pgm, 0x3380, 15) & 0x0200)) + ; + + return 0; +} + +static int avrftdi_jtag_read_byte(const PROGRAMMER *pgm, const AVRPART *p, + const AVRMEM *m, unsigned long addr, unsigned char *value) +{ + if (strcmp(m->desc, "lfuse") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_FUSE_READ, 15); + + /* Read fuse low byte */ + avrftdi_jtag_dr_out(pgm, 0x3200, 15); + *value = avrftdi_jtag_dr_inout(pgm, 0x3300, 15) & 0xff; + + } else if (strcmp(m->desc, "hfuse") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_FUSE_READ, 15); + + /* Read fuse high byte */ + avrftdi_jtag_dr_out(pgm, 0x3e00, 15); + *value = avrftdi_jtag_dr_inout(pgm, 0x3f00, 15) & 0xff; + + } else if (strcmp(m->desc, "efuse") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_FUSE_READ, 15); + + /* Read fuse extended byte */ + avrftdi_jtag_dr_out(pgm, 0x3a00, 15); + *value = avrftdi_jtag_dr_inout(pgm, 0x3b00, 15) & 0xff; + + } else if (strcmp(m->desc, "lock") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_FUSE_READ, 15); + + /* Read lock bits byte */ + avrftdi_jtag_dr_out(pgm, 0x3600, 15); + *value = avrftdi_jtag_dr_inout(pgm, 0x3700, 15) & 0xff; + + } else if (strcmp(m->desc, "signature") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_SIGCAL_READ, 15); + avrftdi_jtag_dr_out(pgm, 0x0300 | (addr & 0xff), 15); + + /* Read signature byte */ + avrftdi_jtag_dr_out(pgm, 0x3200, 15); + *value = avrftdi_jtag_dr_inout(pgm, 0x3300, 15) & 0xff; + + } else if (strcmp(m->desc, "calibration") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_SIGCAL_READ, 15); + avrftdi_jtag_dr_out(pgm, 0x0300 | (addr & 0xff), 15); + + /* Read calibration byte */ + avrftdi_jtag_dr_out(pgm, 0x3600, 15); + *value = avrftdi_jtag_dr_inout(pgm, 0x3700, 15) & 0xff; + + } else { + return -1; + } + + return 0; +} + +static int avrftdi_jtag_write_byte(const PROGRAMMER *pgm, const AVRPART *p, + const AVRMEM *m, unsigned long addr, unsigned char value) +{ + if (strcmp(m->desc, "lfuse") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_FUSE_WRITE, 15); + + /* Load data low byte */ + avrftdi_jtag_dr_out(pgm, 0x1300 | value, 15); + + /* Write fuse low byte */ + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + avrftdi_jtag_dr_out(pgm, 0x3100, 15); + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + + /* Poll for fuse write complete */ + while (!(avrftdi_jtag_dr_inout(pgm, 0x3300, 15) & 0x0200)) + ; + + } else if (strcmp(m->desc, "hfuse") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_FUSE_WRITE, 15); + + /* Load data low byte */ + avrftdi_jtag_dr_out(pgm, 0x1300 | value, 15); + + /* Write fuse low byte */ + avrftdi_jtag_dr_out(pgm, 0x3700, 15); + avrftdi_jtag_dr_out(pgm, 0x3500, 15); + avrftdi_jtag_dr_out(pgm, 0x3700, 15); + avrftdi_jtag_dr_out(pgm, 0x3700, 15); + + /* Poll for fuse write complete */ + while (!(avrftdi_jtag_dr_inout(pgm, 0x3700, 15) & 0x0200)) + ; + + } else if (strcmp(m->desc, "efuse") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_FUSE_WRITE, 15); + + /* Load data low byte */ + avrftdi_jtag_dr_out(pgm, 0x1300 | value, 15); + + /* Write fuse low byte */ + avrftdi_jtag_dr_out(pgm, 0x3b00, 15); + avrftdi_jtag_dr_out(pgm, 0x3900, 15); + avrftdi_jtag_dr_out(pgm, 0x3b00, 15); + avrftdi_jtag_dr_out(pgm, 0x3b00, 15); + + /* Poll for fuse write complete */ + while (!(avrftdi_jtag_dr_inout(pgm, 0x3b00, 15) & 0x0200)) + ; + + } else if (strcmp(m->desc, "lock") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_LOCK_WRITE, 15); + + /* Load data low byte */ + avrftdi_jtag_dr_out(pgm, 0x1300 | value | 0xc0, 15); + + /* Write fuse low byte */ + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + avrftdi_jtag_dr_out(pgm, 0x3100, 15); + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + + /* Poll for fuse write complete */ + while (!(avrftdi_jtag_dr_inout(pgm, 0x3300, 15) & 0x0200)) + ; + + } else { + return -1; + } + + return 0; +} + +static int avrftdi_jtag_paged_write(const PROGRAMMER *pgm, const AVRPART *p, + const AVRMEM *m, unsigned int page_size, unsigned int addr, + unsigned int n_bytes) +{ + unsigned int maxaddr = addr + n_bytes; + unsigned char byte; + + if (strcmp(m->desc, "flash") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_FLASH_WRITE, 15); + + /* Load address */ + avrftdi_jtag_dr_out(pgm, 0x0b00 | ((addr >> 17) & 0xff), 15); + avrftdi_jtag_dr_out(pgm, 0x0700 | ((addr >> 9) & 0xff), 15); + avrftdi_jtag_dr_out(pgm, 0x0300 | ((addr >> 1) & 0xff), 15); + + /* Load page data */ + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_PAGELOAD); + for (unsigned int i = 0; i < page_size; i++) { + byte = i < (maxaddr - addr) ? m->buf[addr + i] : 0xff; + avrftdi_jtag_dr_out(pgm, byte, 8); + } + + /* Write Flash page */ + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x3700, 15); + avrftdi_jtag_dr_out(pgm, 0x3500, 15); + avrftdi_jtag_dr_out(pgm, 0x3700, 15); + avrftdi_jtag_dr_out(pgm, 0x3700, 15); + + /* Wait for completion */ + while (!(avrftdi_jtag_dr_inout(pgm, 0x3700, 15) & 0x0200)) + ; + + } else if (strcmp(m->desc, "eeprom") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_EEPROM_WRITE, 15); + + for (; addr < maxaddr; addr += page_size) { + for (unsigned int i = 0; i < page_size; i++) { + /* Load address */ + avrftdi_jtag_dr_out(pgm, 0x0700 | ((addr >> 8) & 0xff), 15); + avrftdi_jtag_dr_out(pgm, 0x0300 | ((addr + i) & 0xff), 15); + + /* Load data byte */ + avrftdi_jtag_dr_out(pgm, 0x1300 | m->buf[addr + i], 15); + + /* Latch data */ + avrftdi_jtag_dr_out(pgm, 0x3700, 15); + avrftdi_jtag_dr_out(pgm, 0x7700, 15); + avrftdi_jtag_dr_out(pgm, 0x3700, 15); + } + + /* Write EEPROM page */ + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + avrftdi_jtag_dr_out(pgm, 0x3100, 15); + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + avrftdi_jtag_dr_out(pgm, 0x3300, 15); + + /* Wait for completion */ + while (!(avrftdi_jtag_dr_inout(pgm, 0x3300, 15) & 0x0200)) + ; + } + } else { + return -1; + } + + return n_bytes; +} + +static int avrftdi_jtag_paged_read(const PROGRAMMER *pgm, const AVRPART *p, + const AVRMEM *m, unsigned int page_size, unsigned int addr, + unsigned int n_bytes) +{ + avrftdi_t *pdata = to_pdata(pgm); + unsigned int maxaddr = addr + n_bytes; + unsigned char *buf, *ptr; + unsigned int bytes; + + buf = alloca(n_bytes * 8 + 1); + ptr = buf; + + if (strcmp(m->desc, "flash") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_FLASH_READ, 15); + + /* Load address */ + avrftdi_jtag_dr_out(pgm, 0x0b00 | ((addr >> 17) & 0xff), 15); + avrftdi_jtag_dr_out(pgm, 0x0700 | ((addr >> 9) & 0xff), 15); + avrftdi_jtag_dr_out(pgm, 0x0300 | ((addr >> 1) & 0xff), 15); + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_PAGEREAD); + + for (unsigned int i = addr; i < maxaddr; i++) { + /* Run-Test/Idle -> Select-DR -> Capture-DR -> Shift-DR */ + *ptr++ = MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 2; + *ptr++ = 0x01; + + /* Read byte */ + *ptr++ = MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE; + *ptr++ = 6; + + /* Shift-DR -> Exit1-DR -> Update-DR -> Run-Test/Idle */ + *ptr++ = MPSSE_WRITE_TMS | MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + *ptr++ = 2; + *ptr++ = 0x03; + } + + *ptr++ = SEND_IMMEDIATE; + E(ftdi_write_data(pdata->ftdic, buf, ptr - buf) != ptr - buf, pdata->ftdic); + + bytes = 0; + do { + int n = ftdi_read_data(pdata->ftdic, &buf[bytes], n_bytes * 2 - bytes); + E(n < 0, pdata->ftdic); + bytes += n; + } while (bytes < n_bytes * 2); + + for (unsigned int i = 0; i < n_bytes; i++) { + m->buf[addr + i] = (buf[i * 2] >> 1) | (buf[(i * 2) + 1] << 2); + } + + } else if (strcmp(m->desc, "eeprom") == 0) { + avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_COMMANDS); + avrftdi_jtag_dr_out(pgm, 0x2300 | JTAG_DR_PROG_EEPROM_READ, 15); + + for (; addr < maxaddr; addr++) { + /* Load address */ + avrftdi_jtag_dr_out(pgm, 0x0700 | ((addr >> 8) & 0xff), 15); + avrftdi_jtag_dr_out(pgm, 0x0300 | (addr & 0xff), 15); + + /* Read data byte */ + avrftdi_jtag_dr_out(pgm, 0x3300 | (addr & 0xff), 15); + avrftdi_jtag_dr_out(pgm, 0x3200, 15); + m->buf[addr] = avrftdi_jtag_dr_inout(pgm, 0x3300, 15) & 0xff; + } + + } else { + return -1; + } + + return n_bytes; +} + +void avrftdi_initpgm(PROGRAMMER *pgm) +{ strcpy(pgm->type, "avrftdi"); /* * mandatory functions */ - pgm->initialize = avrftdi_initialize; pgm->display = avrftdi_display; pgm->enable = avrftdi_enable; @@ -1243,23 +1828,53 @@ void avrftdi_initpgm(PROGRAMMER *pgm) { /* * optional functions */ - pgm->paged_write = avrftdi_paged_write; pgm->paged_load = avrftdi_paged_load; - pgm->setpin = set_pin; - pgm->setup = avrftdi_setup; pgm->teardown = avrftdi_teardown; - pgm->rdy_led = set_led_rdy; pgm->err_led = set_led_err; pgm->pgm_led = set_led_pgm; pgm->vfy_led = set_led_vfy; } +void avrftdi_jtag_initpgm(PROGRAMMER *pgm) +{ + strcpy(pgm->type, "avrftdi_jtag"); + + /* + * mandatory functions + */ + pgm->initialize = avrftdi_jtag_initialize; + pgm->display = avrftdi_display; + pgm->enable = avrftdi_jtag_enable; + pgm->disable = avrftdi_jtag_disable; + pgm->powerup = avrftdi_powerup; + pgm->powerdown = avrftdi_powerdown; + pgm->chip_erase = avrftdi_jtag_chip_erase; + pgm->open = avrftdi_open; + pgm->close = avrftdi_close; + pgm->read_byte = avrftdi_jtag_read_byte; + pgm->write_byte = avrftdi_jtag_write_byte; + + /* + * optional functions + */ + pgm->paged_write = avrftdi_jtag_paged_write; + pgm->paged_load = avrftdi_jtag_paged_read; + pgm->setup = avrftdi_setup; + pgm->teardown = avrftdi_teardown; + pgm->rdy_led = set_led_rdy; + pgm->err_led = set_led_err; + pgm->pgm_led = set_led_pgm; + pgm->vfy_led = set_led_vfy; + pgm->page_size = 256; + pgm->flag = PGM_FL_IS_JTAG; +} + #endif /* DO_NOT_BUILD_AVRFTDI */ - const char avrftdi_desc[] = "Interface to the MPSSE Engine of FTDI Chips using libftdi."; +const char avrftdi_jtag_desc[] = "libftdi JTAG interface"; diff --git a/src/avrftdi.h b/src/avrftdi.h index 167264df..3c3a4983 100644 --- a/src/avrftdi.h +++ b/src/avrftdi.h @@ -29,7 +29,9 @@ extern "C" { extern const char avrftdi_desc[]; +extern const char avrftdi_jtag_desc[]; void avrftdi_initpgm(PROGRAMMER *pgm); +void avrftdi_jtag_initpgm(PROGRAMMER *pgm); #ifdef __cplusplus } diff --git a/src/avrftdi_private.h b/src/avrftdi_private.h index 6fd973ca..e26d502e 100644 --- a/src/avrftdi_private.h +++ b/src/avrftdi_private.h @@ -61,6 +61,33 @@ enum { ERR, WARN, INFO, DEBUG, TRACE }; } \ } while(0) +enum { + JTAG_IR_EXTEST = 0, + JTAG_IR_IDCODE = 1, + JTAG_IR_SAMPLE_PRELOAD = 2, + JTAG_IR_PROG_ENABLE = 4, + JTAG_IR_PROG_COMMANDS = 5, + JTAG_IR_PROG_PAGELOAD = 6, + JTAG_IR_PROG_PAGEREAD = 7, + JTAG_IR_PRIVATE0 = 8, + JTAG_IR_PRIVATE1 = 9, + JTAG_IR_PRIVATE2 = 10, + JTAG_IR_PRIVATE3 = 11, + JTAG_IR_AVR_RESET = 12, + JTAG_IR_BYPASS = 15, +}; + +enum jtag_cmd { + JTAG_DR_PROG_NONE = 0x00, + JTAG_DR_PROG_FLASH_READ = 0x02, + JTAG_DR_PROG_EEPROM_READ = 0x03, + JTAG_DR_PROG_FUSE_READ = 0x04, + JTAG_DR_PROG_SIGCAL_READ = 0x08, + JTAG_DR_PROG_FLASH_WRITE = 0x10, + JTAG_DR_PROG_EEPROM_WRITE = 0x11, + JTAG_DR_PROG_LOCK_WRITE = 0x20, + JTAG_DR_PROG_FUSE_WRITE = 0x40, +}; #define to_pdata(pgm) \ ((avrftdi_t *)((pgm)->cookie)) diff --git a/src/pgm_type.c b/src/pgm_type.c index a7408c70..be3a8071 100644 --- a/src/pgm_type.c +++ b/src/pgm_type.c @@ -64,6 +64,7 @@ const PROGRAMMER_TYPE programmers_types[] = { // Name(s) the programmers call th {"arduino", arduino_initpgm, arduino_desc}, // "Arduino" {"avr910", avr910_initpgm, avr910_desc}, // "avr910" {"avrftdi", avrftdi_initpgm, avrftdi_desc}, // "avrftdi" + {"avrftdi_jtag", avrftdi_jtag_initpgm, avrftdi_jtag_desc}, // "avrftdi_jtag" {"buspirate", buspirate_initpgm, buspirate_desc}, // "BusPirate" {"buspirate_bb", buspirate_bb_initpgm, buspirate_bb_desc}, // "BusPirate_BB" {"butterfly", butterfly_initpgm, butterfly_desc}, // "butterfly" From ada5f3bd5be5a2bd617bdccc061f16b726434fe0 Mon Sep 17 00:00:00 2001 From: Jeff Kent Date: Sun, 19 Mar 2023 13:18:41 -0500 Subject: [PATCH 3/8] add tumpa-b configuration for convenience --- src/avrdude.conf.in | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index f94e185e..b0098db0 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -1135,6 +1135,15 @@ programmer sdi = 2; # TDO 13 ; +#------------------------------------------------------------ +# tumpa-b +#------------------------------------------------------------ + +programmer parent "tumpa" + id = "tumpa-b"; + usbdev = "B"; +; + #------------------------------------------------------------ # tumpa-jtag #------------------------------------------------------------ From 366467b750a4cb15ac4303f4078585a3812ca34c Mon Sep 17 00:00:00 2001 From: Jeff Kent Date: Mon, 20 Mar 2023 20:10:07 -0500 Subject: [PATCH 4/8] add ft232h_jtag and ft2232h_jtag programmer conf * add link to TUMPA manual * clean up TUMPA programmer confs --- src/avrdude.conf.in | 75 +++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index b0098db0..ce8fa3f4 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -880,6 +880,26 @@ programmer sdi = 2; # AD2 (TDO) ; +#------------------------------------------------------------ +# ft2232h_jtag +#------------------------------------------------------------ + +programmer + id = "ft2232h_jtag"; + desc = "FT2232H based generic programmer"; + type = "avrftdi_jtag"; + prog_modes = PM_JTAG; + connection_type = usb; + usbvid = 0x0403; + usbpid = 0x6010; + usbdev = "A"; +# JTAG-signals - lower ADBUS-Nibble (default) + tck = 0; # AD0 (TCK) + tdi = 1; # AD1 (TDI) + tdo = 2; # AD2 (TDO) + tms = 3; # AD3 (TMS) +; + #------------------------------------------------------------ # avrftdi #------------------------------------------------------------ @@ -1005,6 +1025,26 @@ programmer sdi = 2; # AD2 (TDO) ; +#------------------------------------------------------------ +# ft232h_jtag +#------------------------------------------------------------ + +programmer + id = "ft232h_jtag"; + desc = "FT232H based generic JTAG programmer"; + type = "avrftdi_jtag"; + prog_modes = PM_JTAG; + connection_type = usb; + usbvid = 0x0403; + usbpid = 0x6014; + usbdev = "A"; +# JTAG-signals + tck = 0; # AD0 (TCK) + tdi = 1; # AD1 (TDI) + tdo = 2; # AD2 (TDO) + tms = 3; # AD3 (TMS) +; + #------------------------------------------------------------ # um232h #------------------------------------------------------------ @@ -1117,51 +1157,40 @@ programmer # tumpa #------------------------------------------------------------ -# submitted as bug #46020 +# First SPI connector +# User manual: https://www.tiaowiki.com/w/TIAO_USB_Multi_Protocol_Adapter_User%27s_Manual -programmer +programmer parent "ft2232h" id = "tumpa"; desc = "TIAO USB Multi-Protocol Adapter"; - type = "avrftdi"; - prog_modes = PM_TPI | PM_ISP; - connection_type = usb; - usbvid = 0x0403; usbpid = 0x8a98; usbdev = "A"; usbvendor = "TIAO"; - reset = 3; # TMS 7 - sck = 0; # TCK 9 - sdo = 1; # TDI 5 - sdi = 2; # TDO 13 ; #------------------------------------------------------------ # tumpa-b #------------------------------------------------------------ +# Second SPI connector + programmer parent "tumpa" id = "tumpa-b"; usbdev = "B"; ; #------------------------------------------------------------ -# tumpa-jtag +# tumpa_jtag #------------------------------------------------------------ -programmer parent "tumpa" - id = "tumpa-jtag"; +programmer parent "ft2232h_jtag" + id = "tumpa_jtag"; desc = "TIAO USB Multi-Protocol Adapter (JTAG)"; - type = "avrftdi_jtag"; - sck = ; - sdo = ; - sdi = ; - tck = 0; # TCK 9 - tdi = 1; # TDI 5 - tdo = 2; # TDO 13 - tms = 3; # TMS 7 - reset = ; #4; # RST 15 - buff = ~11; prog_modes = PM_JTAG; + usbpid = 0x8a98; + usbvendor = "TIAO"; + buff = ~11; + reset = 4; # RST AD4 (Pin 15) ; #------------------------------------------------------------ From 4cf8f296cca1be73b7e6dbf19800afdc1e503efb Mon Sep 17 00:00:00 2001 From: Jeff Kent Date: Mon, 20 Mar 2023 20:21:53 -0500 Subject: [PATCH 5/8] make avrftdi_display output not show other interface pins --- src/avrftdi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/avrftdi.c b/src/avrftdi.c index 9bed0015..0bd191ce 100644 --- a/src/avrftdi.c +++ b/src/avrftdi.c @@ -924,7 +924,11 @@ static int avrftdi_initialize(const PROGRAMMER *pgm, const AVRPART *p) { static void avrftdi_display(const PROGRAMMER *pgm, const char *p) { msg_info("%sPin assignment : 0..7 = DBUS0..7, 8..15 = CBUS0..7\n", p); - pgm_display_generic_mask(pgm, p, SHOW_ALL_PINS); + if (pgm->flag & PGM_FL_IS_JTAG) { + pgm_display_generic_mask(pgm, p, SHOW_ALL_PINS & ~SHOW_AVR_PINS); + } else { + pgm_display_generic_mask(pgm, p, SHOW_ALL_PINS & ~SHOW_JTAG_PINS); + } } From ca1f270329e70a3babcaab7b7bef357f6e38e7c5 Mon Sep 17 00:00:00 2001 From: Jeff Kent Date: Wed, 24 May 2023 12:50:24 -0500 Subject: [PATCH 6/8] avrftdi jtag: swap enable and initialize functions --- src/avrftdi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/avrftdi.c b/src/avrftdi.c index 0bd191ce..22acf971 100644 --- a/src/avrftdi.c +++ b/src/avrftdi.c @@ -1462,7 +1462,7 @@ static int avrftdi_jtag_dr_inout(const PROGRAMMER *pgm, unsigned int dr, return dr_in; } -static int avrftdi_jtag_initialize(const PROGRAMMER *pgm, const AVRPART *p) +static void avrftdi_jtag_enable(PROGRAMMER *pgm, const AVRPART *p) { pgm->powerup(pgm); @@ -1472,11 +1472,9 @@ static int avrftdi_jtag_initialize(const PROGRAMMER *pgm, const AVRPART *p) set_pin(pgm, PIN_AVR_RESET, ON); usleep(20 * 1000); - - return 0; } -static void avrftdi_jtag_enable(PROGRAMMER *pgm, const AVRPART *p) +static int avrftdi_jtag_initialize(const PROGRAMMER *pgm, const AVRPART *p) { set_pin(pgm, PPI_AVR_BUFF, ON); @@ -1489,6 +1487,8 @@ static void avrftdi_jtag_enable(PROGRAMMER *pgm, const AVRPART *p) /* Write program enable magic */ avrftdi_jtag_ir_out(pgm, JTAG_IR_PROG_ENABLE); avrftdi_jtag_dr_out(pgm, 0xa370, 16); + + return 0; } static void avrftdi_jtag_disable(const PROGRAMMER *pgm) From fb63b289c5fc3a4e85d94299618932d3b751adfe Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Mon, 31 Jul 2023 12:57:29 +0100 Subject: [PATCH 7/8] Remove not needed inherited properties --- src/avrdude.conf.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index bc319417..020864bf 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -1207,7 +1207,6 @@ programmer parent "ft2232h" id = "tumpa"; desc = "TIAO USB Multi-Protocol Adapter"; usbpid = 0x8a98; - usbdev = "A"; usbvendor = "TIAO"; ; @@ -1229,7 +1228,6 @@ programmer parent "tumpa" programmer parent "ft2232h_jtag" id = "tumpa_jtag"; desc = "TIAO USB Multi-Protocol Adapter (JTAG)"; - prog_modes = PM_JTAG; usbpid = 0x8a98; usbvendor = "TIAO"; buff = ~11; From c1d7f919be803ea7b0af9e3b7a9934a307288f77 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Mon, 31 Jul 2023 13:11:57 +0100 Subject: [PATCH 8/8] Exit avrftdi_jtag_enable() when encountering incompatible chip The use of exit() is brought about by the fact that, unlike all other programming functions, pgm->enable() is of type void, ie, cannot easily tell the caller something went wrong. --- src/avrftdi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/avrftdi.c b/src/avrftdi.c index 22acf971..95dded4e 100644 --- a/src/avrftdi.c +++ b/src/avrftdi.c @@ -1464,6 +1464,18 @@ static int avrftdi_jtag_dr_inout(const PROGRAMMER *pgm, unsigned int dr, static void avrftdi_jtag_enable(PROGRAMMER *pgm, const AVRPART *p) { + if(!ovsigck) { + if(str_eq(p->id, "m128a") || str_eq(p->id, "m128") || + str_eq(p->id, "m64a") || str_eq(p->id, "m64") || + str_eq(p->id, "m32a") || str_eq(p->id, "m32") || + str_eq(p->id, "m16a") || str_eq(p->id, "m16") || + str_eq(p->id, "m162")) { + pmsg_error("programmer type %s is known not to work for %s\n", pgm->type, p->desc); + imsg_error("exiting; use -F to carry on regardless\n"); + exit(1); + } + } + pgm->powerup(pgm); set_pin(pgm, PIN_AVR_RESET, OFF);