From 30d9f67ed42d8068357550a84acfb634caac4894 Mon Sep 17 00:00:00 2001 From: Funkeleinhorn Date: Sat, 6 Apr 2024 18:40:49 +0200 Subject: [PATCH 01/12] Add serprog programmer This commit adds support to program AVRs via programmers speaking the serprog protocol used by flashrom. A programmer implementing this is for example: https://github.com/stacksmashing/pico-serprog --- src/CMakeLists.txt | 2 + src/Makefile.am | 2 + src/avrdude.conf.in | 18 ++ src/pgm_type.c | 2 + src/serprog.c | 485 ++++++++++++++++++++++++++++++++++++++++++++ src/serprog.h | 35 ++++ 6 files changed, 544 insertions(+) create mode 100644 src/serprog.c create mode 100644 src/serprog.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f9ddb59d..7d8a2669 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -231,6 +231,8 @@ add_library(libavrdude serialadapter.c serialupdi.c serialupdi.h + serprog.c + serprog.h solaris_ecpp.h stk500.c stk500.h diff --git a/src/Makefile.am b/src/Makefile.am index f90b82c8..f67ac711 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -185,6 +185,8 @@ libavrdude_a_SOURCES = \ usbasp.h \ serialupdi.c \ serialupdi.h \ + serprog.c \ + serprog.h \ updi_constants.h \ updi_link.c \ updi_link.h \ diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 10513680..968962f3 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -1479,6 +1479,24 @@ programmer # serialupdi hvupdi_support = 1; ; +#------------------------------------------------------------ +# serprog +#------------------------------------------------------------ + +# The Serprog programmer implementation allows programming +# with programmers using the serprog protocol from flashrom. +# See https://flashrom.org/classic_cli_manpage.html#serprog-programmer +# and https://wiki.flashrom.org/Serprog +# for details. + +programmer # serprog + id = "serprog"; + desc = "Serprog"; + type = "serprog"; + prog_modes = PM_ISP; + connection_type = serial; +; + #------------------------------------------------------------ # avrisp #------------------------------------------------------------ diff --git a/src/pgm_type.c b/src/pgm_type.c index 945f816f..56639eb8 100644 --- a/src/pgm_type.c +++ b/src/pgm_type.c @@ -49,6 +49,7 @@ #include "ppi.h" #include "serbb.h" #include "serialupdi.h" +#include "serprog.h" #include "stk500.h" #include "stk500generic.h" #include "stk500v2.h" @@ -100,6 +101,7 @@ const PROGRAMMER_TYPE programmers_types[] = { // Name(s) the programmers call th {"pickit2", pickit2_initpgm, pickit2_desc}, // "pickit2" {"serbb", serbb_initpgm, serbb_desc}, // "SERBB" {"serialupdi", serialupdi_initpgm, serialupdi_desc}, // "serialupdi" + {"serprog", serprog_initpgm, serprog_desc}, // "serprog" {"stk500", stk500_initpgm, stk500_desc}, // "STK500" {"stk500generic", stk500generic_initpgm, stk500generic_desc}, // "STK500GENERIC" {"stk500v2", stk500v2_initpgm, stk500v2_desc}, // "STK500V2" diff --git a/src/serprog.c b/src/serprog.c new file mode 100644 index 00000000..03cb1ad0 --- /dev/null +++ b/src/serprog.c @@ -0,0 +1,485 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Support for using serprog programmers to program over ISP + * + * Copyright (C) 2024 Sydney Louisa Wilke + * used linuxspi.c as a template: + * Copyright (C) 2013 Kevin Cuzner + * Copyright (C) 2018 Ralf Ramsauer + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ac_cfg.h" + +#include "avrdude.h" +#include "libavrdude.h" + +#include "serprog.h" + +#include +#include + +#include +#include +#include +#include + +#define serprog "serprog" + +const char serprog_desc[] = "Programmer using the serprog protocol"; + +/* + * Private data for this programmer. + */ +struct pdata { + unsigned char cmd_bitmap[32]; +}; + +#define my (*(struct pdata *)(pgm->cookie)) + +// serprog protocol specification + +/* According to Serial Flasher Protocol Specification - version 1 */ +#define S_ACK 0x06 +#define S_NAK 0x15 +#define S_CMD_NOP 0x00 /* No operation */ +#define S_CMD_Q_IFACE 0x01 /* Query interface version */ +#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */ +#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */ +#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */ +#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */ +#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */ +#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */ +#define S_CMD_Q_WRNMAXLEN 0x08 /* Query Write to opbuf: Write-N maximum length */ +#define S_CMD_R_BYTE 0x09 /* Read a single byte */ +#define S_CMD_R_NBYTES 0x0A /* Read n bytes */ +#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */ +#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */ +#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */ +#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */ +#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */ +#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */ +#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */ +#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */ +#define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */ +#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */ +#define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */ +#define S_CMD_S_SPI_CS 0x16 /* Set SPI chip select to use */ +#define S_CMD_S_SPI_MODE 0x17 /* Sets the spi mode used by S_CMD_O_SPIOP */ +#define S_CMD_S_CS_MODE 0x18 /* Sets the way the CS is controlled */ + +enum spi_mode { + SPI_MODE_HALF_DUPLEX = 0, + SPI_MODE_FULL_DUPLEX = 1, + SPI_MODE_MAX = SPI_MODE_FULL_DUPLEX, +}; + +enum cs_mode { + CS_MODE_AUTO = 0, + CS_MODE_SELECTED = 1, + CS_MODE_DESELECTED = 2, + CS_MODE_MAX = CS_MODE_DESELECTED, +}; + +// little endian helper functions + +static uint16_t read_le16(unsigned char* buf) { + return buf[0] | (buf[1] << 8); +} + +static uint32_t read_le32(unsigned char* buf) { + return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); +} + +static void write_le24(unsigned char* buf, uint32_t val) { + buf[0] = val; + buf[1] = val >> 8; + buf[2] = val >> 16; +} + +static void write_le32(unsigned char* buf, uint32_t val) { + buf[0] = val; + buf[1] = val >> 8; + buf[2] = val >> 16; + buf[3] = val >> 24; +} + +// serprog communication functions + +static int perform_serprog_cmd_full(const PROGRAMMER *pgm, uint8_t cmd, + const unsigned char* params, int params_len, + const unsigned char* send_buf, int send_len, + unsigned char* recv_buf, int recv_len) { + unsigned char resp_status_code = 0; + + serial_send(&pgm->fd, &cmd, 1); + if (params_len > 0) + serial_send(&pgm->fd, params, params_len); + if (send_len > 0) + serial_send(&pgm->fd, send_buf, send_len); + + if (serial_recv(&pgm->fd, &resp_status_code, 1) < 0 || serial_recv(&pgm->fd, recv_buf, recv_len) < 0) + return -1; + if (resp_status_code == S_ACK) + return 0; + else if (resp_status_code == S_NAK) + return 1; + else + return -1; +} + +static int perform_serprog_cmd(const PROGRAMMER *pgm, uint8_t cmd, + const unsigned char* params, int params_len, + unsigned char* recv_buf, int recv_len) { + return perform_serprog_cmd_full(pgm, cmd, params, params_len, NULL, 0, recv_buf, recv_len); +} + +/** + * @brief Sends/receives a message to the AVR in full duplex mode + * @return -1 on failure, otherwise number of bytes sent/received + */ +static int serprog_spi_duplex(const PROGRAMMER *pgm, const unsigned char *tx, unsigned char *rx, int len) { + unsigned char params[6]; + write_le24(params, len); + write_le24(params + 3, len); + if (perform_serprog_cmd_full(pgm, S_CMD_O_SPIOP, params, sizeof(params), tx, len, rx, len) != 0) { + return -1; + } + + return len; +} + +static bool is_serprog_cmd_supported(unsigned char *cmd_bitmap, unsigned char cmd) { + return (cmd_bitmap[cmd / 8] >> (cmd % 8)) & 1; +} + +// programmer lifecycle handlers + +static int serprog_open(PROGRAMMER *pgm, const char *pt) { + const char *port_error = + "unknown port specification, " + "please use the format /dev/ttyACM0,cs=0\n"; + char port_default[] = "/dev/ttyACM0"; + char *serialdev; + char *port = mmt_strdup(pt); + + if (str_eq(port, "unknown")) { + port = port_default; + } + + serialdev = strtok(port, ","); + if (!serialdev) { + pmsg_error("%s", port_error); + return -1; + } + + // parse chip select if specified + uint8_t cs = 0; + char *option_str = strtok(NULL, ","); + if (option_str) { + char *option_name = strtok(option_str, "="); + if (strcmp(option_name, "cs") != 0) { + pmsg_error("unkown parameter: %s\n", option_name); + return -1; + } + char *option_value = strtok(NULL, "="); + if (option_value) { + cs = atoi(option_value); + } + } + + union pinfo pinfo; + pgm->port = port; + pinfo.serialinfo.baud = pgm->baudrate? pgm->baudrate: 115200; + pinfo.serialinfo.cflags = SERIAL_8N1; + if (serial_open(port, pinfo, &pgm->fd)==-1) { + return -1; + } + + unsigned char buf[32]; + + // sync + memset(buf, 0, sizeof(buf)); + if (perform_serprog_cmd(pgm, S_CMD_SYNCNOP, NULL, 0, buf, 1) != 1 || buf[0] != S_ACK) { + pmsg_error("can not sync. is this a serprog programmer?\n"); + return -1; + } + + // get command bitmap + memset(my.cmd_bitmap, 0, sizeof(my.cmd_bitmap)); + if (perform_serprog_cmd(pgm, S_CMD_Q_CMDMAP, NULL, 0, my.cmd_bitmap, 32) != 0) { + pmsg_error("can not get list of supported serprog commands.\n"); + return -1; + } + + // get protocol version + memset(buf, 0, sizeof(buf)); + if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_IFACE) + || perform_serprog_cmd(pgm, S_CMD_Q_IFACE, NULL, 0, buf, 2) != 0) { + pmsg_error("can not get serprog protocol version.\n"); + return -1; + } + if (read_le16(buf) != 0x01) { + pmsg_error("unsupported serprog protocol version: %d\n", read_le16(buf)); + return -1; + } + + pmsg_info("serprog protocol version: %d\n", read_le16(buf)); + + // get programmer name + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_PGMNAME)) { + memset(buf, 0, sizeof(buf)); + if (perform_serprog_cmd(pgm, S_CMD_Q_PGMNAME, NULL, 0, buf, 16) != 0) { + pmsg_error("can not get programmer name.\n"); + return -1; + } + pmsg_info("programmer name: %s\n", buf); + } + + // check if required commands are supported + if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_O_SPIOP)) { + pmsg_error("this programmer does not support SPI operations.\n"); + return -1; + } + + if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_CS_MODE)) { + pmsg_error("this programmer does not support setting the CS mode.\n"); + return -1; + } + + if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_MODE)) { + pmsg_error("this programmer does not support setting the SPI mode.\n"); + return -1; + } + + // set SPI clock frequency + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) { + memset(buf, 0, sizeof(buf)); + write_le32(buf, 115200); + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) { + pmsg_error("can not set SPI frequency.\n"); + return -1; + } + if (read_le32(buf) != 115200) { + pmsg_error("set SPI frequency differs from requested.\n"); + return -1; + } + } + + // set active chip select + if (option_str != NULL) { + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { + memset(buf, 0, sizeof(buf)); + buf[0] = cs; + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { + pmsg_error("can not change CS.\n"); + return -1; + } + } else { + pmsg_error("changing the CS is not supported by the programmer.\n"); + return -1; + } + } + + // set full duplex + memset(buf, 0, sizeof(buf)); + buf[0] = SPI_MODE_FULL_DUPLEX; + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { + pmsg_error("can not set SPI full duplex mode.\n"); + return -1; + } + + // set output + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) { + memset(buf, 0, sizeof(buf)); + buf[0] = 1; // Pin state enable + if (perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { + pmsg_error("can not enable pin state.\n"); + return -1; + } + } + + // enable the CS / reset pin + const unsigned char cs_mode = CS_MODE_SELECTED; + if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { + pmsg_error("can not enable the reset pin.\n"); + return -1; + } + return 0; +} + +static void serprog_close(PROGRAMMER *pgm) { + unsigned char buf[32]; + // switch cs to auto + const unsigned char cs_mode = CS_MODE_AUTO; + if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { + pmsg_error("can not reset the CS mode to auto.\n"); + } + // disable output + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) { + memset(buf, 0, sizeof(buf)); + buf[0] = 0; // Pin state disable + if (perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { + pmsg_error("can not disable pin state.\n"); + } + } + // restore half duplex + memset(buf, 0, sizeof(buf)); + buf[0] = SPI_MODE_HALF_DUPLEX; + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { + pmsg_error("can not reset SPI half duplex mode.\n"); + } + // reset CS to CS_0 + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { + memset(buf, 0, sizeof(buf)); + buf[0] = 0; + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { + pmsg_error("can not reset CS to CS_0.\n"); + } + } + + serial_close(&pgm->fd); +} + +static int serprog_cmd(const PROGRAMMER *pgm, const unsigned char *cmd, unsigned char *res) { + return serprog_spi_duplex(pgm, cmd, res, 4); +} + +static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *p) { + int tries, ret; + + if (p->prog_modes & PM_TPI) { + /* We do not support TPI. This is a dedicated SPI thing */ + pmsg_error("programmer " serprog " does not support TPI\n"); + return -1; + } + + //enable programming on the part + tries = 0; + do { + ret = pgm->program_enable(pgm, p); + if (ret == 0 || ret == -1) + break; + } while(tries++ < 65); + + if (ret) + pmsg_error("AVR device not responding\n"); + + return ret; +} + +static int serprog_program_enable(const PROGRAMMER *pgm, const AVRPART *p) { + unsigned char cmd[4], res[4]; + + if (!p->op[AVR_OP_PGM_ENABLE]) { + pmsg_error("program enable instruction not defined for part %s\n", p->desc); + return -1; + } + + memset(cmd, 0, sizeof(cmd)); + avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd); //set the cmd + pgm->cmd(pgm, cmd, res); + + if (res[2] != cmd[1]) { + /** From ATtiny441 datasheet: + * + * In some systems, the programmer can not guarantee that SCK is held low + * during power-up. In this case, RESET must be given a positive pulse after + * SCK has been set to '0'. The duration of the pulse must be at least t RST + * plus two CPU clock cycles. See Table 25-5 on page 240 for definition of + * minimum pulse width on RESET pin, t RST + * 2. Wait for at least 20 ms and then enable serial programming by sending + * the Programming Enable serial instruction to the SDO pin + * 3. The serial programming instructions will not work if the communication + * is out of synchronization. When in sync, the second byte (0x53) will echo + * back when issuing the third byte of the Programming Enable instruction + * ... + * If the 0x53 did not echo back, give RESET a positive pulse and issue a + * new Programming Enable command + */ + unsigned char cs_mode = CS_MODE_DESELECTED; + if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { + return -1; + } + usleep(5); + cs_mode = CS_MODE_SELECTED; + if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { + return -1; + } + usleep(20000); + + return -2; + } + + return 0; +} + +static int serprog_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { + unsigned char cmd[4], res[4]; + + if (!p->op[AVR_OP_CHIP_ERASE]) { + pmsg_error("chip erase instruction not defined for part %s\n", p->desc); + return -1; + } + + memset(cmd, 0, sizeof(cmd)); + avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); + pgm->cmd(pgm, cmd, res); + usleep(p->chip_erase_delay); + pgm->initialize(pgm, p); + + return 0; +} + +static void serprog_disable(const PROGRAMMER* pgm) { +} + +static void serprog_enable(PROGRAMMER *pgm, const AVRPART *p) { +} + +static void serprog_display(const PROGRAMMER* pgm, const char* p) { +} + +static void serprog_setup(PROGRAMMER *pgm) { + pgm->cookie = mmt_malloc(sizeof(struct pdata)); +} + +static void serprog_teardown(PROGRAMMER* pgm) { + mmt_free(pgm->cookie); + pgm->cookie = NULL; +} + +void serprog_initpgm(PROGRAMMER *pgm) { + strcpy(pgm->type, serprog); + + // required fields + pgm->initialize = serprog_initialize; + pgm->display = serprog_display; + pgm->enable = serprog_enable; + pgm->disable = serprog_disable; + pgm->program_enable = serprog_program_enable; + pgm->chip_erase = serprog_chip_erase; + pgm->cmd = serprog_cmd; + pgm->open = serprog_open; + pgm->close = serprog_close; + pgm->read_byte = avr_read_byte_default; + pgm->write_byte = avr_write_byte_default; + + // optional fields + pgm->setup = serprog_setup; + pgm->teardown = serprog_teardown; +} + diff --git a/src/serprog.h b/src/serprog.h new file mode 100644 index 00000000..092dd95b --- /dev/null +++ b/src/serprog.h @@ -0,0 +1,35 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2013 Kevin Cuzner + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef serprog_h +#define serprog_h + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char serprog_desc[]; +void serprog_initpgm(PROGRAMMER *pgm); + +#ifdef __cplusplus +} +#endif + +#endif //serprog_h + From 14e32f49c4adea44ff38e476faf844c0548b65f4 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 5 May 2024 22:57:24 +0100 Subject: [PATCH 02/12] Adapt messages to AVRDUDE style --- src/serprog.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/serprog.c b/src/serprog.c index 03cb1ad0..f0e80c7b 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -214,14 +214,14 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { // sync memset(buf, 0, sizeof(buf)); if (perform_serprog_cmd(pgm, S_CMD_SYNCNOP, NULL, 0, buf, 1) != 1 || buf[0] != S_ACK) { - pmsg_error("can not sync. is this a serprog programmer?\n"); + pmsg_error("cannot sync; is this a serprog programmer?\n"); return -1; } // get command bitmap memset(my.cmd_bitmap, 0, sizeof(my.cmd_bitmap)); if (perform_serprog_cmd(pgm, S_CMD_Q_CMDMAP, NULL, 0, my.cmd_bitmap, 32) != 0) { - pmsg_error("can not get list of supported serprog commands.\n"); + pmsg_error("cannot get list of supported serprog commands\n"); return -1; } @@ -229,7 +229,7 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { memset(buf, 0, sizeof(buf)); if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_IFACE) || perform_serprog_cmd(pgm, S_CMD_Q_IFACE, NULL, 0, buf, 2) != 0) { - pmsg_error("can not get serprog protocol version.\n"); + pmsg_error("cannot get serprog protocol version\n"); return -1; } if (read_le16(buf) != 0x01) { @@ -243,7 +243,7 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_PGMNAME)) { memset(buf, 0, sizeof(buf)); if (perform_serprog_cmd(pgm, S_CMD_Q_PGMNAME, NULL, 0, buf, 16) != 0) { - pmsg_error("can not get programmer name.\n"); + pmsg_error("cannot get programmer name\n"); return -1; } pmsg_info("programmer name: %s\n", buf); @@ -251,17 +251,17 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { // check if required commands are supported if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_O_SPIOP)) { - pmsg_error("this programmer does not support SPI operations.\n"); + pmsg_error("this programmer does not support SPI operations\n"); return -1; } if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_CS_MODE)) { - pmsg_error("this programmer does not support setting the CS mode.\n"); + pmsg_error("this programmer does not support setting the CS mode\n"); return -1; } if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_MODE)) { - pmsg_error("this programmer does not support setting the SPI mode.\n"); + pmsg_error("this programmer does not support setting the SPI mode\n"); return -1; } @@ -270,11 +270,11 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { memset(buf, 0, sizeof(buf)); write_le32(buf, 115200); if (perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) { - pmsg_error("can not set SPI frequency.\n"); + pmsg_error("cannot set SPI frequency\n"); return -1; } if (read_le32(buf) != 115200) { - pmsg_error("set SPI frequency differs from requested.\n"); + pmsg_error("set SPI frequency differs from the requested one\n"); return -1; } } @@ -285,11 +285,11 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { memset(buf, 0, sizeof(buf)); buf[0] = cs; if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { - pmsg_error("can not change CS.\n"); + pmsg_error("cannot change CS\n"); return -1; } } else { - pmsg_error("changing the CS is not supported by the programmer.\n"); + pmsg_error("changing the CS is not supported by the programmer\n"); return -1; } } @@ -298,7 +298,7 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { memset(buf, 0, sizeof(buf)); buf[0] = SPI_MODE_FULL_DUPLEX; if (perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { - pmsg_error("can not set SPI full duplex mode.\n"); + pmsg_error("cannot set SPI full duplex mode\n"); return -1; } @@ -307,7 +307,7 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { memset(buf, 0, sizeof(buf)); buf[0] = 1; // Pin state enable if (perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { - pmsg_error("can not enable pin state.\n"); + pmsg_error("cannot enable pin state\n"); return -1; } } @@ -315,7 +315,7 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { // enable the CS / reset pin const unsigned char cs_mode = CS_MODE_SELECTED; if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { - pmsg_error("can not enable the reset pin.\n"); + pmsg_error("cannot enable the reset pin\n"); return -1; } return 0; @@ -326,28 +326,28 @@ static void serprog_close(PROGRAMMER *pgm) { // switch cs to auto const unsigned char cs_mode = CS_MODE_AUTO; if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { - pmsg_error("can not reset the CS mode to auto.\n"); + pmsg_error("cannot reset the CS mode to auto\n"); } // disable output if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) { memset(buf, 0, sizeof(buf)); buf[0] = 0; // Pin state disable if (perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { - pmsg_error("can not disable pin state.\n"); + pmsg_error("cannot disable pin state\n"); } } // restore half duplex memset(buf, 0, sizeof(buf)); buf[0] = SPI_MODE_HALF_DUPLEX; if (perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { - pmsg_error("can not reset SPI half duplex mode.\n"); + pmsg_error("cannot reset SPI half duplex mode\n"); } // reset CS to CS_0 if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { memset(buf, 0, sizeof(buf)); buf[0] = 0; if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { - pmsg_error("can not reset CS to CS_0.\n"); + pmsg_error("cannot reset CS to CS_0\n"); } } @@ -396,7 +396,7 @@ static int serprog_program_enable(const PROGRAMMER *pgm, const AVRPART *p) { if (res[2] != cmd[1]) { /** From ATtiny441 datasheet: * - * In some systems, the programmer can not guarantee that SCK is held low + * In some systems, the programmer cannot guarantee that SCK is held low * during power-up. In this case, RESET must be given a positive pulse after * SCK has been set to '0'. The duration of the pulse must be at least t RST * plus two CPU clock cycles. See Table 25-5 on page 240 for definition of From 59edcd8c78ecf4e913a01e28e3309d4a2624ab3c Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 5 May 2024 23:00:47 +0100 Subject: [PATCH 03/12] Use command line programmer name in messages --- src/serprog.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/serprog.c b/src/serprog.c index f0e80c7b..95fbd4fb 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -37,8 +37,6 @@ #include #include -#define serprog "serprog" - const char serprog_desc[] = "Programmer using the serprog protocol"; /* @@ -251,17 +249,17 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { // check if required commands are supported if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_O_SPIOP)) { - pmsg_error("this programmer does not support SPI operations\n"); + pmsg_error("the %s programmer does not support SPI operations\n", pgmid); return -1; } if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_CS_MODE)) { - pmsg_error("this programmer does not support setting the CS mode\n"); + pmsg_error("the %s programmer does not support setting the CS mode\n", pgmid); return -1; } if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_MODE)) { - pmsg_error("this programmer does not support setting the SPI mode\n"); + pmsg_error("the %s programmer does not support setting the SPI mode\n", pgmid); return -1; } @@ -289,7 +287,7 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { return -1; } } else { - pmsg_error("changing the CS is not supported by the programmer\n"); + pmsg_error("changing the CS is not supported by the %s programmer\n", pgmid); return -1; } } @@ -363,7 +361,7 @@ static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *p) { if (p->prog_modes & PM_TPI) { /* We do not support TPI. This is a dedicated SPI thing */ - pmsg_error("programmer " serprog " does not support TPI\n"); + pmsg_error("the %s programmer does not support TPI\n", pgmid); return -1; } @@ -463,7 +461,7 @@ static void serprog_teardown(PROGRAMMER* pgm) { } void serprog_initpgm(PROGRAMMER *pgm) { - strcpy(pgm->type, serprog); + strcpy(pgm->type, "serprog"); // required fields pgm->initialize = serprog_initialize; From 5cf001f045da0ed935ac5b32c40b927e2315e773 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 5 May 2024 23:03:41 +0100 Subject: [PATCH 04/12] Space pointer declarations consistently --- src/serprog.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/serprog.c b/src/serprog.c index 95fbd4fb..d05f8dd2 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -94,21 +94,21 @@ enum cs_mode { // little endian helper functions -static uint16_t read_le16(unsigned char* buf) { +static uint16_t read_le16(unsigned char *buf) { return buf[0] | (buf[1] << 8); } -static uint32_t read_le32(unsigned char* buf) { +static uint32_t read_le32(unsigned char *buf) { return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); } -static void write_le24(unsigned char* buf, uint32_t val) { +static void write_le24(unsigned char *buf, uint32_t val) { buf[0] = val; buf[1] = val >> 8; buf[2] = val >> 16; } -static void write_le32(unsigned char* buf, uint32_t val) { +static void write_le32(unsigned char *buf, uint32_t val) { buf[0] = val; buf[1] = val >> 8; buf[2] = val >> 16; @@ -118,9 +118,9 @@ static void write_le32(unsigned char* buf, uint32_t val) { // serprog communication functions static int perform_serprog_cmd_full(const PROGRAMMER *pgm, uint8_t cmd, - const unsigned char* params, int params_len, - const unsigned char* send_buf, int send_len, - unsigned char* recv_buf, int recv_len) { + const unsigned char *params, int params_len, + const unsigned char *send_buf, int send_len, + unsigned char *recv_buf, int recv_len) { unsigned char resp_status_code = 0; serial_send(&pgm->fd, &cmd, 1); @@ -140,8 +140,8 @@ static int perform_serprog_cmd_full(const PROGRAMMER *pgm, uint8_t cmd, } static int perform_serprog_cmd(const PROGRAMMER *pgm, uint8_t cmd, - const unsigned char* params, int params_len, - unsigned char* recv_buf, int recv_len) { + const unsigned char *params, int params_len, + unsigned char *recv_buf, int recv_len) { return perform_serprog_cmd_full(pgm, cmd, params, params_len, NULL, 0, recv_buf, recv_len); } @@ -442,20 +442,20 @@ static int serprog_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { return 0; } -static void serprog_disable(const PROGRAMMER* pgm) { +static void serprog_disable(const PROGRAMMER *pgm) { } static void serprog_enable(PROGRAMMER *pgm, const AVRPART *p) { } -static void serprog_display(const PROGRAMMER* pgm, const char* p) { +static void serprog_display(const PROGRAMMER *pgm, const char *p) { } static void serprog_setup(PROGRAMMER *pgm) { pgm->cookie = mmt_malloc(sizeof(struct pdata)); } -static void serprog_teardown(PROGRAMMER* pgm) { +static void serprog_teardown(PROGRAMMER *pgm) { mmt_free(pgm->cookie); pgm->cookie = NULL; } From 638a429337cd9a62bfc67316843027807d30e517 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Sun, 5 May 2024 23:06:38 +0100 Subject: [PATCH 05/12] Add const to pointer argument where possible --- src/serprog.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/serprog.c b/src/serprog.c index d05f8dd2..3eb39f32 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -94,11 +94,11 @@ enum cs_mode { // little endian helper functions -static uint16_t read_le16(unsigned char *buf) { +static uint16_t read_le16(const unsigned char *buf) { return buf[0] | (buf[1] << 8); } -static uint32_t read_le32(unsigned char *buf) { +static uint32_t read_le32(const unsigned char *buf) { return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); } @@ -160,7 +160,7 @@ static int serprog_spi_duplex(const PROGRAMMER *pgm, const unsigned char *tx, un return len; } -static bool is_serprog_cmd_supported(unsigned char *cmd_bitmap, unsigned char cmd) { +static bool is_serprog_cmd_supported(const unsigned char *cmd_bitmap, unsigned char cmd) { return (cmd_bitmap[cmd / 8] >> (cmd % 8)) & 1; } From b84b2728d03c26d911e9ad325ec8f8361b259ad5 Mon Sep 17 00:00:00 2001 From: Funkeleinhorn Date: Wed, 8 May 2024 15:52:30 +0200 Subject: [PATCH 06/12] Make CS an extended parameter --- src/serprog.c | 125 +++++++++++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 52 deletions(-) diff --git a/src/serprog.c b/src/serprog.c index 3eb39f32..05d69ee7 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -20,6 +20,10 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * known limitations: + * - performance is suboptimal + * - connecting over TCP/IP to programmers is not implemented yet */ #include "ac_cfg.h" @@ -44,40 +48,41 @@ const char serprog_desc[] = "Programmer using the serprog protocol"; */ struct pdata { unsigned char cmd_bitmap[32]; + unsigned int cs; }; #define my (*(struct pdata *)(pgm->cookie)) // serprog protocol specification -/* According to Serial Flasher Protocol Specification - version 1 */ +// According to Serial Flasher Protocol Specification - version 1 #define S_ACK 0x06 #define S_NAK 0x15 -#define S_CMD_NOP 0x00 /* No operation */ -#define S_CMD_Q_IFACE 0x01 /* Query interface version */ -#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */ -#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */ -#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */ -#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */ -#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */ -#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */ -#define S_CMD_Q_WRNMAXLEN 0x08 /* Query Write to opbuf: Write-N maximum length */ -#define S_CMD_R_BYTE 0x09 /* Read a single byte */ -#define S_CMD_R_NBYTES 0x0A /* Read n bytes */ -#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */ -#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */ -#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */ -#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */ -#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */ -#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */ -#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */ -#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */ -#define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */ -#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */ -#define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */ -#define S_CMD_S_SPI_CS 0x16 /* Set SPI chip select to use */ -#define S_CMD_S_SPI_MODE 0x17 /* Sets the spi mode used by S_CMD_O_SPIOP */ -#define S_CMD_S_CS_MODE 0x18 /* Sets the way the CS is controlled */ +#define S_CMD_NOP 0x00 // No operation +#define S_CMD_Q_IFACE 0x01 // Query interface version +#define S_CMD_Q_CMDMAP 0x02 // Query supported commands bitmap +#define S_CMD_Q_PGMNAME 0x03 // Query programmer name +#define S_CMD_Q_SERBUF 0x04 // Query Serial Buffer Size +#define S_CMD_Q_BUSTYPE 0x05 // Query supported bustypes +#define S_CMD_Q_CHIPSIZE 0x06 // Query supported chipsize (2^n format) +#define S_CMD_Q_OPBUF 0x07 // Query operation buffer size +#define S_CMD_Q_WRNMAXLEN 0x08 // Query Write to opbuf: Write-N maximum length +#define S_CMD_R_BYTE 0x09 // Read a single byte +#define S_CMD_R_NBYTES 0x0A // Read n bytes +#define S_CMD_O_INIT 0x0B // Initialize operation buffer +#define S_CMD_O_WRITEB 0x0C // Write opbuf: Write byte with address +#define S_CMD_O_WRITEN 0x0D // Write to opbuf: Write-N +#define S_CMD_O_DELAY 0x0E // Write opbuf: udelay +#define S_CMD_O_EXEC 0x0F // Execute operation buffer +#define S_CMD_SYNCNOP 0x10 // Special no-operation that returns NAK+ACK +#define S_CMD_Q_RDNMAXLEN 0x11 // Query read-n maximum length +#define S_CMD_S_BUSTYPE 0x12 // Set used bustype(s). +#define S_CMD_O_SPIOP 0x13 // Perform SPI operation. +#define S_CMD_S_SPI_FREQ 0x14 // Set SPI clock frequency +#define S_CMD_S_PIN_STATE 0x15 // Enable/disable output drivers +#define S_CMD_S_SPI_CS 0x16 // Set SPI chip select to use +#define S_CMD_S_SPI_MODE 0x17 // Sets the spi mode used by S_CMD_O_SPIOP +#define S_CMD_S_CS_MODE 0x18 // Sets the way the CS is controlled enum spi_mode { SPI_MODE_HALF_DUPLEX = 0, @@ -169,7 +174,7 @@ static bool is_serprog_cmd_supported(const unsigned char *cmd_bitmap, unsigned c static int serprog_open(PROGRAMMER *pgm, const char *pt) { const char *port_error = "unknown port specification, " - "please use the format /dev/ttyACM0,cs=0\n"; + "please use the format /dev/ttyACM0\n"; char port_default[] = "/dev/ttyACM0"; char *serialdev; char *port = mmt_strdup(pt); @@ -184,21 +189,6 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { return -1; } - // parse chip select if specified - uint8_t cs = 0; - char *option_str = strtok(NULL, ","); - if (option_str) { - char *option_name = strtok(option_str, "="); - if (strcmp(option_name, "cs") != 0) { - pmsg_error("unkown parameter: %s\n", option_name); - return -1; - } - char *option_value = strtok(NULL, "="); - if (option_value) { - cs = atoi(option_value); - } - } - union pinfo pinfo; pgm->port = port; pinfo.serialinfo.baud = pgm->baudrate? pgm->baudrate: 115200; @@ -278,18 +268,16 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { } // set active chip select - if (option_str != NULL) { - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { - memset(buf, 0, sizeof(buf)); - buf[0] = cs; - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot change CS\n"); - return -1; - } - } else { - pmsg_error("changing the CS is not supported by the %s programmer\n", pgmid); + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { + memset(buf, 0, sizeof(buf)); + buf[0] = my.cs; + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { + pmsg_error("cannot change CS\n"); return -1; } + } else if (my.cs > 0) { + pmsg_error("changing the CS is not supported by the programmer\n"); + return -1; } // set full duplex @@ -460,6 +448,38 @@ static void serprog_teardown(PROGRAMMER *pgm) { pgm->cookie = NULL; } +static int serprog_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) { + LNODEID ln; + const char *extended_param; + int rv = 0; + + for (ln = lfirst(extparms); ln; ln = lnext(ln)) { + extended_param = ldata(ln); + + if (str_starts(extended_param, "cs=")) { + unsigned int cs; + if (sscanf(extended_param, "cs=%u", &cs) != 1) { + pmsg_error("invalid chip select '%s'\n", extended_param); + rv = -1; + } + my.cs = cs; + continue; + } + + if (str_eq(extended_param, "help")) { + msg_error("%s -c %s extended options:\n", progname, pgmid); + msg_error(" -xcs=cs_num Set the chip select to use\n"); + msg_error(" -xhelp Show this help menu and exit\n"); + return LIBAVRDUDE_EXIT; + } + + pmsg_error("invalid extended parameter '%s'\n", extended_param); + rv = -1; + } + + return rv; +} + void serprog_initpgm(PROGRAMMER *pgm) { strcpy(pgm->type, "serprog"); @@ -479,5 +499,6 @@ void serprog_initpgm(PROGRAMMER *pgm) { // optional fields pgm->setup = serprog_setup; pgm->teardown = serprog_teardown; + pgm->parseextparams = serprog_parseextparams; } From 2266a0fe9c1ccfac3717a179cac2f2b9e81b1a30 Mon Sep 17 00:00:00 2001 From: Funkeleinhorn Date: Wed, 8 May 2024 16:42:30 +0200 Subject: [PATCH 07/12] Do enable/disable in correct functions instead of in open/close --- src/serprog.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/serprog.c b/src/serprog.c index 05d69ee7..8a17f1ee 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -253,6 +253,11 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { return -1; } + if (my.cs > 0 && !is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { + pmsg_error("the %s programmer does not support changing the CS\n", pgmid); + return -1; + } + // set SPI clock frequency if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) { memset(buf, 0, sizeof(buf)); @@ -267,17 +272,18 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { } } + return 0; +} + +static void serprog_enable(PROGRAMMER *pgm, const AVRPART *p) { + unsigned char buf[32]; // set active chip select if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { memset(buf, 0, sizeof(buf)); buf[0] = my.cs; if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { pmsg_error("cannot change CS\n"); - return -1; } - } else if (my.cs > 0) { - pmsg_error("changing the CS is not supported by the programmer\n"); - return -1; } // set full duplex @@ -285,7 +291,6 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { buf[0] = SPI_MODE_FULL_DUPLEX; if (perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { pmsg_error("cannot set SPI full duplex mode\n"); - return -1; } // set output @@ -294,7 +299,6 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { buf[0] = 1; // Pin state enable if (perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { pmsg_error("cannot enable pin state\n"); - return -1; } } @@ -302,12 +306,10 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { const unsigned char cs_mode = CS_MODE_SELECTED; if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { pmsg_error("cannot enable the reset pin\n"); - return -1; } - return 0; } -static void serprog_close(PROGRAMMER *pgm) { +static void serprog_disable(const PROGRAMMER *pgm) { unsigned char buf[32]; // switch cs to auto const unsigned char cs_mode = CS_MODE_AUTO; @@ -336,7 +338,9 @@ static void serprog_close(PROGRAMMER *pgm) { pmsg_error("cannot reset CS to CS_0\n"); } } +} +static void serprog_close(PROGRAMMER *pgm) { serial_close(&pgm->fd); } @@ -430,12 +434,6 @@ static int serprog_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { return 0; } -static void serprog_disable(const PROGRAMMER *pgm) { -} - -static void serprog_enable(PROGRAMMER *pgm, const AVRPART *p) { -} - static void serprog_display(const PROGRAMMER *pgm, const char *p) { } From 43e998b5c412e46ae24ff15a1ddfbaa9b916669f Mon Sep 17 00:00:00 2001 From: Funkeleinhorn Date: Wed, 8 May 2024 18:05:17 +0200 Subject: [PATCH 08/12] Add documentation and clean up code --- src/avrdude.1 | 11 +++++++++++ src/avrdude.conf.in | 4 ++-- src/doc/avrdude.texi | 15 +++++++++++++++ src/serprog.c | 18 ++++++++++-------- src/serprog.h | 4 +++- 5 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index f5ed848d..28de8edb 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -1988,6 +1988,17 @@ the CS line being managed outside the application. .It Ar help Show help menu and exit. .El +.It Ar serprog +.Bl -tag -offset indent -width indent +.It Ar cs +Sets the chip select (CS) to use on supported programmers. +Programmers supporting the 0x16 serprog command can have more than the default CS (0). +This option allows to choose this additional CS's (1,2,3,...) for programming the AVR. +Here you can find the addition to the serprog spec enabling that: +https://review.coreboot.org/c/flashrom/+/80498 +.It Ar help +Show help menu and exit. +.El .El .Sh FILES .Bl -tag -offset indent -width /dev/ppi0XXX diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 968962f3..314b7ab7 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -1485,8 +1485,8 @@ programmer # serialupdi # The Serprog programmer implementation allows programming # with programmers using the serprog protocol from flashrom. -# See https://flashrom.org/classic_cli_manpage.html#serprog-programmer -# and https://wiki.flashrom.org/Serprog +# See https://flashrom.org/supported_hw/supported_prog/serprog/overview.html +# and https://flashrom.org/supported_hw/supported_prog/serprog/serprog-protocol.html # for details. programmer # serprog diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 68486c9c..83213daa 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -1645,6 +1645,21 @@ the CS line being managed outside the application. Show help menu and exit. @end table +@cindex Option @code{-x} serprog +@item serprog + +The serprog programmer type accepts the following extended parameter: +@table @code +@item @samp{cs} +Sets the chip select (CS) to use on supported programmers. +Programmers supporting the 0x16 serprog command can have more than the default CS (0). +This option allows to choose this additional CS's (1,2,3,...) for programming the AVR. +Here you can find the addition to the serprog spec enabling that: +https://review.coreboot.org/c/flashrom/+/80498 +@item @samp{help} +Show help menu and exit. +@end table + @end table @page diff --git a/src/serprog.c b/src/serprog.c index 8a17f1ee..66ec8762 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -1,6 +1,8 @@ /* * avrdude - A Downloader/Uploader for AVR device programmers - * Support for using serprog programmers to program over ISP + * Support for using serprog programmers to program over ISP. + * For information on serprog see: + * https://flashrom.org/supported_hw/supported_prog/serprog/index.html * * Copyright (C) 2024 Sydney Louisa Wilke * used linuxspi.c as a template: @@ -136,12 +138,8 @@ static int perform_serprog_cmd_full(const PROGRAMMER *pgm, uint8_t cmd, if (serial_recv(&pgm->fd, &resp_status_code, 1) < 0 || serial_recv(&pgm->fd, recv_buf, recv_len) < 0) return -1; - if (resp_status_code == S_ACK) - return 0; - else if (resp_status_code == S_NAK) - return 1; - else - return -1; + + return resp_status_code == S_ACK? 0: resp_status_code == S_NAK? 1: -1; } static int perform_serprog_cmd(const PROGRAMMER *pgm, uint8_t cmd, @@ -466,7 +464,11 @@ static int serprog_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) if (str_eq(extended_param, "help")) { msg_error("%s -c %s extended options:\n", progname, pgmid); - msg_error(" -xcs=cs_num Set the chip select to use\n"); + msg_error(" -xcs=cs_num Sets the chip select (CS) to use on supported programmers.\n"); + msg_error(" Programmers supporting the 0x16 serprog command can have more than the default CS (0).\n"); + msg_error(" This option allows to choose this additional CS's (1,2,3,...) for programming the AVR.\n"); + msg_error(" Here you can find the addition to the serprog spec enabling that:\n"); + msg_error(" https://review.coreboot.org/c/flashrom/+/80498\n"); msg_error(" -xhelp Show this help menu and exit\n"); return LIBAVRDUDE_EXIT; } diff --git a/src/serprog.h b/src/serprog.h index 092dd95b..5de51452 100644 --- a/src/serprog.h +++ b/src/serprog.h @@ -1,6 +1,8 @@ /* * avrdude - A Downloader/Uploader for AVR device programmers - * Copyright (C) 2013 Kevin Cuzner + * Copyright (C) 2024 Sydney Louisa Wilke + * used linuxspi.h as a template: + * Copyright (C) 2013 Kevin Cuzner * * 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 From e72d67285959ff5f7bc9b9f0071ccb90fa43b422 Mon Sep 17 00:00:00 2001 From: Funkeleinhorn Date: Thu, 9 May 2024 22:46:39 +0200 Subject: [PATCH 09/12] Move serprog enable logic to pgm->initialize() This commits moves the logic to enable the serprog programmer to be ready for programming to the initalize() function as it seems to be the counterpart of disable() and is called directly before programming starts. This allows to open() a serprog programmer without blocking the SPI bus as 0x15 S_PIN_STATE and 0x18 S_CS_MODE is only called in initalize before the actual programming starts. --- src/serprog.c | 78 +++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/serprog.c b/src/serprog.c index 66ec8762..e40321d6 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -273,40 +273,6 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { return 0; } -static void serprog_enable(PROGRAMMER *pgm, const AVRPART *p) { - unsigned char buf[32]; - // set active chip select - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { - memset(buf, 0, sizeof(buf)); - buf[0] = my.cs; - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot change CS\n"); - } - } - - // set full duplex - memset(buf, 0, sizeof(buf)); - buf[0] = SPI_MODE_FULL_DUPLEX; - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot set SPI full duplex mode\n"); - } - - // set output - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) { - memset(buf, 0, sizeof(buf)); - buf[0] = 1; // Pin state enable - if (perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot enable pin state\n"); - } - } - - // enable the CS / reset pin - const unsigned char cs_mode = CS_MODE_SELECTED; - if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { - pmsg_error("cannot enable the reset pin\n"); - } -} - static void serprog_disable(const PROGRAMMER *pgm) { unsigned char buf[32]; // switch cs to auto @@ -347,14 +313,51 @@ static int serprog_cmd(const PROGRAMMER *pgm, const unsigned char *cmd, unsigned } static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *p) { - int tries, ret; - if (p->prog_modes & PM_TPI) { /* We do not support TPI. This is a dedicated SPI thing */ pmsg_error("the %s programmer does not support TPI\n", pgmid); return -1; } + unsigned char buf[32]; + + // set active chip select + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { + memset(buf, 0, sizeof(buf)); + buf[0] = my.cs; + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { + pmsg_error("cannot change CS\n"); + return -1; + } + } + + // set full duplex + memset(buf, 0, sizeof(buf)); + buf[0] = SPI_MODE_FULL_DUPLEX; + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { + pmsg_error("cannot set SPI full duplex mode\n"); + return -1; + } + + // set output + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) { + memset(buf, 0, sizeof(buf)); + buf[0] = 1; // Pin state enable + if (perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { + pmsg_error("cannot enable pin state\n"); + return -1; + } + } + + // enable the CS / reset pin + const unsigned char cs_mode = CS_MODE_SELECTED; + if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { + pmsg_error("cannot enable the reset pin\n"); + return -1; + } + + int tries, ret; + //enable programming on the part tries = 0; do { @@ -435,6 +438,9 @@ static int serprog_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { static void serprog_display(const PROGRAMMER *pgm, const char *p) { } +static void serprog_enable(PROGRAMMER *pgm, const AVRPART *p) { +} + static void serprog_setup(PROGRAMMER *pgm) { pgm->cookie = mmt_malloc(sizeof(struct pdata)); } From 5ae58ff728fc7bec35b6879799aff1b14c4330ea Mon Sep 17 00:00:00 2001 From: Funkeleinhorn Date: Tue, 14 May 2024 01:18:39 +0200 Subject: [PATCH 10/12] Address code review and add set/get_sck_period() --- src/avrdude.1 | 4 +- src/avrdude.conf.in | 2 +- src/doc/avrdude.texi | 4 +- src/serprog.c | 107 ++++++++++++++++++++++++------------------- src/serprog.h | 3 +- 5 files changed, 63 insertions(+), 57 deletions(-) diff --git a/src/avrdude.1 b/src/avrdude.1 index 28de8edb..3a859781 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -1993,9 +1993,7 @@ Show help menu and exit. .It Ar cs Sets the chip select (CS) to use on supported programmers. Programmers supporting the 0x16 serprog command can have more than the default CS (0). -This option allows to choose this additional CS's (1,2,3,...) for programming the AVR. -Here you can find the addition to the serprog spec enabling that: -https://review.coreboot.org/c/flashrom/+/80498 +This option allows to choose these additional CSes (1, 2, ...) for programming the AVR. .It Ar help Show help menu and exit. .El diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in index 314b7ab7..516fed49 100644 --- a/src/avrdude.conf.in +++ b/src/avrdude.conf.in @@ -1491,7 +1491,7 @@ programmer # serialupdi programmer # serprog id = "serprog"; - desc = "Serprog"; + desc = "Program via the Serprog protocol from Flashrom"; type = "serprog"; prog_modes = PM_ISP; connection_type = serial; diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 83213daa..b9b9dacf 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -1653,9 +1653,7 @@ The serprog programmer type accepts the following extended parameter: @item @samp{cs} Sets the chip select (CS) to use on supported programmers. Programmers supporting the 0x16 serprog command can have more than the default CS (0). -This option allows to choose this additional CS's (1,2,3,...) for programming the AVR. -Here you can find the addition to the serprog spec enabling that: -https://review.coreboot.org/c/flashrom/+/80498 +This option allows to choose these additional CSes (1, 2, ...) for programming the AVR. @item @samp{help} Show help menu and exit. @end table diff --git a/src/serprog.c b/src/serprog.c index e40321d6..90fec7df 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -5,9 +5,6 @@ * https://flashrom.org/supported_hw/supported_prog/serprog/index.html * * Copyright (C) 2024 Sydney Louisa Wilke - * used linuxspi.c as a template: - * Copyright (C) 2013 Kevin Cuzner - * Copyright (C) 2018 Ralf Ramsauer * * 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 @@ -23,7 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * known limitations: + * Known limitations: * - performance is suboptimal * - connecting over TCP/IP to programmers is not implemented yet */ @@ -43,7 +40,7 @@ #include #include -const char serprog_desc[] = "Programmer using the serprog protocol"; +const char serprog_desc[] = "Program via the Serprog protocol from Flashrom"; /* * Private data for this programmer. @@ -51,6 +48,7 @@ const char serprog_desc[] = "Programmer using the serprog protocol"; struct pdata { unsigned char cmd_bitmap[32]; unsigned int cs; + uint32_t actual_frequency; }; #define my (*(struct pdata *)(pgm->cookie)) @@ -130,11 +128,14 @@ static int perform_serprog_cmd_full(const PROGRAMMER *pgm, uint8_t cmd, unsigned char *recv_buf, int recv_len) { unsigned char resp_status_code = 0; - serial_send(&pgm->fd, &cmd, 1); + if(serial_send(&pgm->fd, &cmd, 1) < 0) + return -1; if (params_len > 0) - serial_send(&pgm->fd, params, params_len); + if(serial_send(&pgm->fd, params, params_len) < 0) + return -1; if (send_len > 0) - serial_send(&pgm->fd, send_buf, send_len); + if(serial_send(&pgm->fd, send_buf, send_len) < 0) + return -1; if (serial_recv(&pgm->fd, &resp_status_code, 1) < 0 || serial_recv(&pgm->fd, recv_buf, recv_len) < 0) return -1; @@ -169,24 +170,7 @@ static bool is_serprog_cmd_supported(const unsigned char *cmd_bitmap, unsigned c // programmer lifecycle handlers -static int serprog_open(PROGRAMMER *pgm, const char *pt) { - const char *port_error = - "unknown port specification, " - "please use the format /dev/ttyACM0\n"; - char port_default[] = "/dev/ttyACM0"; - char *serialdev; - char *port = mmt_strdup(pt); - - if (str_eq(port, "unknown")) { - port = port_default; - } - - serialdev = strtok(port, ","); - if (!serialdev) { - pmsg_error("%s", port_error); - return -1; - } - +static int serprog_open(PROGRAMMER *pgm, const char *port) { union pinfo pinfo; pgm->port = port; pinfo.serialinfo.baud = pgm->baudrate? pgm->baudrate: 115200; @@ -256,20 +240,6 @@ static int serprog_open(PROGRAMMER *pgm, const char *pt) { return -1; } - // set SPI clock frequency - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) { - memset(buf, 0, sizeof(buf)); - write_le32(buf, 115200); - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) { - pmsg_error("cannot set SPI frequency\n"); - return -1; - } - if (read_le32(buf) != 115200) { - pmsg_error("set SPI frequency differs from the requested one\n"); - return -1; - } - } - return 0; } @@ -312,8 +282,8 @@ static int serprog_cmd(const PROGRAMMER *pgm, const unsigned char *cmd, unsigned return serprog_spi_duplex(pgm, cmd, res, 4); } -static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *p) { - if (p->prog_modes & PM_TPI) { +static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *part) { + if (part->prog_modes & PM_TPI) { /* We do not support TPI. This is a dedicated SPI thing */ pmsg_error("the %s programmer does not support TPI\n", pgmid); return -1; @@ -321,6 +291,25 @@ static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *p) { unsigned char buf[32]; + // set SPI clock frequency + if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) { + memset(buf, 0, sizeof(buf)); + uint32_t frequency; + if (pgm->bitclock > 0) { + frequency = pgm->bitclock; + } else if (part->factory_fcpu > 0) { + frequency = (part->factory_fcpu / 4); + } else { + frequency = 250000; + } + write_le32(buf, frequency); + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) { + pmsg_error("cannot set SPI frequency\n"); + return -1; + } + my.actual_frequency = read_le32(buf); + } + // set active chip select if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { memset(buf, 0, sizeof(buf)); @@ -361,7 +350,7 @@ static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *p) { //enable programming on the part tries = 0; do { - ret = pgm->program_enable(pgm, p); + ret = pgm->program_enable(pgm, part); if (ret == 0 || ret == -1) break; } while(tries++ < 65); @@ -372,6 +361,10 @@ static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *p) { return ret; } +/* used linuxspi.c as a template: + * Copyright (C) 2013 Kevin Cuzner + * Copyright (C) 2018 Ralf Ramsauer + */ static int serprog_program_enable(const PROGRAMMER *pgm, const AVRPART *p) { unsigned char cmd[4], res[4]; @@ -450,6 +443,26 @@ static void serprog_teardown(PROGRAMMER *pgm) { pgm->cookie = NULL; } +static int serprog_set_sck_period(const PROGRAMMER *pgm, double v) { + if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) { + return -1; + } + unsigned char buf[8]; + memset(buf, 0, sizeof(buf)); + write_le32(buf, v); + if (perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) { + pmsg_error("cannot set SPI frequency\n"); + return -1; + } + my.actual_frequency = read_le32(buf); + return 0; +} + +static int serprog_get_sck_period(const PROGRAMMER *pgm, double *v) { + *v = my.actual_frequency; + return 0; +} + static int serprog_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) { LNODEID ln; const char *extended_param; @@ -470,11 +483,7 @@ static int serprog_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) if (str_eq(extended_param, "help")) { msg_error("%s -c %s extended options:\n", progname, pgmid); - msg_error(" -xcs=cs_num Sets the chip select (CS) to use on supported programmers.\n"); - msg_error(" Programmers supporting the 0x16 serprog command can have more than the default CS (0).\n"); - msg_error(" This option allows to choose this additional CS's (1,2,3,...) for programming the AVR.\n"); - msg_error(" Here you can find the addition to the serprog spec enabling that:\n"); - msg_error(" https://review.coreboot.org/c/flashrom/+/80498\n"); + msg_error(" -xcs=cs_num Sets the chip select (CS) to use on supported programmers\n"); msg_error(" -xhelp Show this help menu and exit\n"); return LIBAVRDUDE_EXIT; } @@ -506,5 +515,7 @@ void serprog_initpgm(PROGRAMMER *pgm) { pgm->setup = serprog_setup; pgm->teardown = serprog_teardown; pgm->parseextparams = serprog_parseextparams; + pgm->get_sck_period = serprog_get_sck_period; + pgm->set_sck_period = serprog_set_sck_period; } diff --git a/src/serprog.h b/src/serprog.h index 5de51452..99ec9401 100644 --- a/src/serprog.h +++ b/src/serprog.h @@ -1,8 +1,7 @@ /* * avrdude - A Downloader/Uploader for AVR device programmers + * * Copyright (C) 2024 Sydney Louisa Wilke - * used linuxspi.h as a template: - * Copyright (C) 2013 Kevin Cuzner * * 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 From a98630522914a4eaa109c69c9d6ccdc2570a17fd Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 21 May 2024 23:18:41 +0100 Subject: [PATCH 11/12] Format source code in new AVRDUDE style (and minor changes) --- src/serprog.c | 686 +++++++++++++++++++++++++------------------------- src/serprog.h | 5 +- 2 files changed, 344 insertions(+), 347 deletions(-) diff --git a/src/serprog.c b/src/serprog.c index 90fec7df..240eac90 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -42,111 +42,108 @@ const char serprog_desc[] = "Program via the Serprog protocol from Flashrom"; -/* - * Private data for this programmer. - */ +// Private data for this programmer struct pdata { - unsigned char cmd_bitmap[32]; - unsigned int cs; - uint32_t actual_frequency; + unsigned char cmd_bitmap[32]; + unsigned int cs; + uint32_t actual_frequency; }; #define my (*(struct pdata *)(pgm->cookie)) -// serprog protocol specification +// Serprog protocol specification // According to Serial Flasher Protocol Specification - version 1 #define S_ACK 0x06 #define S_NAK 0x15 -#define S_CMD_NOP 0x00 // No operation -#define S_CMD_Q_IFACE 0x01 // Query interface version -#define S_CMD_Q_CMDMAP 0x02 // Query supported commands bitmap -#define S_CMD_Q_PGMNAME 0x03 // Query programmer name -#define S_CMD_Q_SERBUF 0x04 // Query Serial Buffer Size -#define S_CMD_Q_BUSTYPE 0x05 // Query supported bustypes -#define S_CMD_Q_CHIPSIZE 0x06 // Query supported chipsize (2^n format) -#define S_CMD_Q_OPBUF 0x07 // Query operation buffer size -#define S_CMD_Q_WRNMAXLEN 0x08 // Query Write to opbuf: Write-N maximum length -#define S_CMD_R_BYTE 0x09 // Read a single byte -#define S_CMD_R_NBYTES 0x0A // Read n bytes -#define S_CMD_O_INIT 0x0B // Initialize operation buffer -#define S_CMD_O_WRITEB 0x0C // Write opbuf: Write byte with address -#define S_CMD_O_WRITEN 0x0D // Write to opbuf: Write-N -#define S_CMD_O_DELAY 0x0E // Write opbuf: udelay -#define S_CMD_O_EXEC 0x0F // Execute operation buffer -#define S_CMD_SYNCNOP 0x10 // Special no-operation that returns NAK+ACK -#define S_CMD_Q_RDNMAXLEN 0x11 // Query read-n maximum length -#define S_CMD_S_BUSTYPE 0x12 // Set used bustype(s). -#define S_CMD_O_SPIOP 0x13 // Perform SPI operation. -#define S_CMD_S_SPI_FREQ 0x14 // Set SPI clock frequency -#define S_CMD_S_PIN_STATE 0x15 // Enable/disable output drivers -#define S_CMD_S_SPI_CS 0x16 // Set SPI chip select to use -#define S_CMD_S_SPI_MODE 0x17 // Sets the spi mode used by S_CMD_O_SPIOP -#define S_CMD_S_CS_MODE 0x18 // Sets the way the CS is controlled +#define S_CMD_NOP 0x00 // No operation +#define S_CMD_Q_IFACE 0x01 // Query interface version +#define S_CMD_Q_CMDMAP 0x02 // Query supported commands bitmap +#define S_CMD_Q_PGMNAME 0x03 // Query programmer name +#define S_CMD_Q_SERBUF 0x04 // Query Serial Buffer Size +#define S_CMD_Q_BUSTYPE 0x05 // Query supported bustypes +#define S_CMD_Q_CHIPSIZE 0x06 // Query supported chipsize (2^n format) +#define S_CMD_Q_OPBUF 0x07 // Query operation buffer size +#define S_CMD_Q_WRNMAXLEN 0x08 // Query Write to opbuf: Write-N maximum length +#define S_CMD_R_BYTE 0x09 // Read a single byte +#define S_CMD_R_NBYTES 0x0A // Read n bytes +#define S_CMD_O_INIT 0x0B // Initialize operation buffer +#define S_CMD_O_WRITEB 0x0C // Write opbuf: Write byte with address +#define S_CMD_O_WRITEN 0x0D // Write to opbuf: Write-N +#define S_CMD_O_DELAY 0x0E // Write opbuf: udelay +#define S_CMD_O_EXEC 0x0F // Execute operation buffer +#define S_CMD_SYNCNOP 0x10 // Special no-operation that returns NAK+ACK +#define S_CMD_Q_RDNMAXLEN 0x11 // Query read-n maximum length +#define S_CMD_S_BUSTYPE 0x12 // Set used bustype(s). +#define S_CMD_O_SPIOP 0x13 // Perform SPI operation. +#define S_CMD_S_SPI_FREQ 0x14 // Set SPI clock frequency +#define S_CMD_S_PIN_STATE 0x15 // Enable/disable output drivers +#define S_CMD_S_SPI_CS 0x16 // Set SPI chip select to use +#define S_CMD_S_SPI_MODE 0x17 // Sets the SPI mode used by S_CMD_O_SPIOP +#define S_CMD_S_CS_MODE 0x18 // Sets the way the CS is controlled enum spi_mode { - SPI_MODE_HALF_DUPLEX = 0, - SPI_MODE_FULL_DUPLEX = 1, - SPI_MODE_MAX = SPI_MODE_FULL_DUPLEX, + SPI_MODE_HALF_DUPLEX = 0, + SPI_MODE_FULL_DUPLEX = 1, + SPI_MODE_MAX = SPI_MODE_FULL_DUPLEX, }; enum cs_mode { - CS_MODE_AUTO = 0, - CS_MODE_SELECTED = 1, - CS_MODE_DESELECTED = 2, - CS_MODE_MAX = CS_MODE_DESELECTED, + CS_MODE_AUTO = 0, + CS_MODE_SELECTED = 1, + CS_MODE_DESELECTED = 2, + CS_MODE_MAX = CS_MODE_DESELECTED, }; -// little endian helper functions +// Little endian helper functions static uint16_t read_le16(const unsigned char *buf) { - return buf[0] | (buf[1] << 8); + return buf[0] | (buf[1] << 8); } static uint32_t read_le32(const unsigned char *buf) { - return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); + return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); } static void write_le24(unsigned char *buf, uint32_t val) { - buf[0] = val; - buf[1] = val >> 8; - buf[2] = val >> 16; + buf[0] = val; + buf[1] = val >> 8; + buf[2] = val >> 16; } static void write_le32(unsigned char *buf, uint32_t val) { - buf[0] = val; - buf[1] = val >> 8; - buf[2] = val >> 16; - buf[3] = val >> 24; + buf[0] = val; + buf[1] = val >> 8; + buf[2] = val >> 16; + buf[3] = val >> 24; } -// serprog communication functions +// Serprog communication functions static int perform_serprog_cmd_full(const PROGRAMMER *pgm, uint8_t cmd, - const unsigned char *params, int params_len, - const unsigned char *send_buf, int send_len, - unsigned char *recv_buf, int recv_len) { - unsigned char resp_status_code = 0; + const unsigned char *params, int params_len, + const unsigned char *send_buf, int send_len, unsigned char *recv_buf, int recv_len) { - if(serial_send(&pgm->fd, &cmd, 1) < 0) - return -1; - if (params_len > 0) - if(serial_send(&pgm->fd, params, params_len) < 0) - return -1; - if (send_len > 0) - if(serial_send(&pgm->fd, send_buf, send_len) < 0) - return -1; + unsigned char resp_status_code = 0; - if (serial_recv(&pgm->fd, &resp_status_code, 1) < 0 || serial_recv(&pgm->fd, recv_buf, recv_len) < 0) - return -1; + if(serial_send(&pgm->fd, &cmd, 1) < 0) + return -1; + if(params_len > 0) + if(serial_send(&pgm->fd, params, params_len) < 0) + return -1; + if(send_len > 0) + if(serial_send(&pgm->fd, send_buf, send_len) < 0) + return -1; - return resp_status_code == S_ACK? 0: resp_status_code == S_NAK? 1: -1; + if(serial_recv(&pgm->fd, &resp_status_code, 1) < 0 || serial_recv(&pgm->fd, recv_buf, recv_len) < 0) + return -1; + + return resp_status_code == S_ACK? 0: resp_status_code == S_NAK? 1: -1; } static int perform_serprog_cmd(const PROGRAMMER *pgm, uint8_t cmd, - const unsigned char *params, int params_len, - unsigned char *recv_buf, int recv_len) { - return perform_serprog_cmd_full(pgm, cmd, params, params_len, NULL, 0, recv_buf, recv_len); + const unsigned char *params, int params_len, unsigned char *recv_buf, int recv_len) { + return perform_serprog_cmd_full(pgm, cmd, params, params_len, NULL, 0, recv_buf, recv_len); } /** @@ -154,211 +151,209 @@ static int perform_serprog_cmd(const PROGRAMMER *pgm, uint8_t cmd, * @return -1 on failure, otherwise number of bytes sent/received */ static int serprog_spi_duplex(const PROGRAMMER *pgm, const unsigned char *tx, unsigned char *rx, int len) { - unsigned char params[6]; - write_le24(params, len); - write_le24(params + 3, len); - if (perform_serprog_cmd_full(pgm, S_CMD_O_SPIOP, params, sizeof(params), tx, len, rx, len) != 0) { - return -1; - } + unsigned char params[6]; - return len; + write_le24(params, len); + write_le24(params + 3, len); + if(perform_serprog_cmd_full(pgm, S_CMD_O_SPIOP, params, sizeof params, tx, len, rx, len) != 0) + return -1; + + return len; } static bool is_serprog_cmd_supported(const unsigned char *cmd_bitmap, unsigned char cmd) { - return (cmd_bitmap[cmd / 8] >> (cmd % 8)) & 1; + return (cmd_bitmap[cmd / 8] >> (cmd % 8)) & 1; } -// programmer lifecycle handlers +// Programmer lifecycle handlers static int serprog_open(PROGRAMMER *pgm, const char *port) { - union pinfo pinfo; - pgm->port = port; - pinfo.serialinfo.baud = pgm->baudrate? pgm->baudrate: 115200; - pinfo.serialinfo.cflags = SERIAL_8N1; - if (serial_open(port, pinfo, &pgm->fd)==-1) { - return -1; + union pinfo pinfo; + + pgm->port = port; + pinfo.serialinfo.baud = pgm->baudrate? pgm->baudrate: 115200; + pinfo.serialinfo.cflags = SERIAL_8N1; + if(serial_open(port, pinfo, &pgm->fd) == -1) + return -1; + + unsigned char buf[32]; + + // Sync + memset(buf, 0, sizeof buf); + if(perform_serprog_cmd(pgm, S_CMD_SYNCNOP, NULL, 0, buf, 1) != 1 || buf[0] != S_ACK) { + pmsg_error("cannot sync; is this a serprog programmer?\n"); + return -1; + } + + // Get command bitmap + memset(my.cmd_bitmap, 0, sizeof my.cmd_bitmap); + if(perform_serprog_cmd(pgm, S_CMD_Q_CMDMAP, NULL, 0, my.cmd_bitmap, 32) != 0) { + pmsg_error("cannot get list of supported serprog commands\n"); + return -1; + } + + // Get protocol version + memset(buf, 0, sizeof buf); + if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_IFACE) + || perform_serprog_cmd(pgm, S_CMD_Q_IFACE, NULL, 0, buf, 2) != 0) { + pmsg_error("cannot get serprog protocol version\n"); + return -1; + } + if(read_le16(buf) != 0x01) { + pmsg_error("unsupported serprog protocol version: %d\n", read_le16(buf)); + return -1; + } + + pmsg_info("serprog protocol version: %d\n", read_le16(buf)); + + // Get programmer name + if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_PGMNAME)) { + memset(buf, 0, sizeof buf); + if(perform_serprog_cmd(pgm, S_CMD_Q_PGMNAME, NULL, 0, buf, 16) != 0) { + pmsg_error("cannot get programmer name\n"); + return -1; } + pmsg_info("programmer name: %s\n", buf); + } - unsigned char buf[32]; + // Check if required commands are supported + if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_O_SPIOP)) { + pmsg_error("the %s programmer does not support SPI operations\n", pgmid); + return -1; + } - // sync - memset(buf, 0, sizeof(buf)); - if (perform_serprog_cmd(pgm, S_CMD_SYNCNOP, NULL, 0, buf, 1) != 1 || buf[0] != S_ACK) { - pmsg_error("cannot sync; is this a serprog programmer?\n"); - return -1; - } + if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_CS_MODE)) { + pmsg_error("the %s programmer does not support setting the CS mode\n", pgmid); + return -1; + } - // get command bitmap - memset(my.cmd_bitmap, 0, sizeof(my.cmd_bitmap)); - if (perform_serprog_cmd(pgm, S_CMD_Q_CMDMAP, NULL, 0, my.cmd_bitmap, 32) != 0) { - pmsg_error("cannot get list of supported serprog commands\n"); - return -1; - } + if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_MODE)) { + pmsg_error("the %s programmer does not support setting the SPI mode\n", pgmid); + return -1; + } - // get protocol version - memset(buf, 0, sizeof(buf)); - if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_IFACE) - || perform_serprog_cmd(pgm, S_CMD_Q_IFACE, NULL, 0, buf, 2) != 0) { - pmsg_error("cannot get serprog protocol version\n"); - return -1; - } - if (read_le16(buf) != 0x01) { - pmsg_error("unsupported serprog protocol version: %d\n", read_le16(buf)); - return -1; - } + if(my.cs > 0 && !is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { + pmsg_error("the %s programmer does not support changing the CS\n", pgmid); + return -1; + } - pmsg_info("serprog protocol version: %d\n", read_le16(buf)); - - // get programmer name - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_Q_PGMNAME)) { - memset(buf, 0, sizeof(buf)); - if (perform_serprog_cmd(pgm, S_CMD_Q_PGMNAME, NULL, 0, buf, 16) != 0) { - pmsg_error("cannot get programmer name\n"); - return -1; - } - pmsg_info("programmer name: %s\n", buf); - } - - // check if required commands are supported - if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_O_SPIOP)) { - pmsg_error("the %s programmer does not support SPI operations\n", pgmid); - return -1; - } - - if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_CS_MODE)) { - pmsg_error("the %s programmer does not support setting the CS mode\n", pgmid); - return -1; - } - - if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_MODE)) { - pmsg_error("the %s programmer does not support setting the SPI mode\n", pgmid); - return -1; - } - - if (my.cs > 0 && !is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { - pmsg_error("the %s programmer does not support changing the CS\n", pgmid); - return -1; - } - - return 0; + return 0; } static void serprog_disable(const PROGRAMMER *pgm) { - unsigned char buf[32]; - // switch cs to auto - const unsigned char cs_mode = CS_MODE_AUTO; - if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { - pmsg_error("cannot reset the CS mode to auto\n"); - } - // disable output - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) { - memset(buf, 0, sizeof(buf)); - buf[0] = 0; // Pin state disable - if (perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot disable pin state\n"); - } - } - // restore half duplex - memset(buf, 0, sizeof(buf)); - buf[0] = SPI_MODE_HALF_DUPLEX; - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot reset SPI half duplex mode\n"); - } - // reset CS to CS_0 - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { - memset(buf, 0, sizeof(buf)); - buf[0] = 0; - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot reset CS to CS_0\n"); - } + unsigned char buf[32]; + + // Switch CS to auto + const unsigned char cs_mode = CS_MODE_AUTO; + + if(perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { + pmsg_error("cannot reset the CS mode to auto\n"); + } + // Disable output + if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) { + memset(buf, 0, sizeof buf); + buf[0] = 0; // Pin state disable + if(perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { + pmsg_error("cannot disable pin state\n"); } + } + // Restore half duplex + memset(buf, 0, sizeof buf); + buf[0] = SPI_MODE_HALF_DUPLEX; + if(perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) + pmsg_error("cannot reset SPI half duplex mode\n"); + + // Reset CS to CS_0 + if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { + memset(buf, 0, sizeof buf); + buf[0] = 0; + if(perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) + pmsg_error("cannot reset CS to CS_0\n"); + } } static void serprog_close(PROGRAMMER *pgm) { - serial_close(&pgm->fd); + serial_close(&pgm->fd); } static int serprog_cmd(const PROGRAMMER *pgm, const unsigned char *cmd, unsigned char *res) { - return serprog_spi_duplex(pgm, cmd, res, 4); + return serprog_spi_duplex(pgm, cmd, res, 4); } static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *part) { - if (part->prog_modes & PM_TPI) { - /* We do not support TPI. This is a dedicated SPI thing */ - pmsg_error("the %s programmer does not support TPI\n", pgmid); - return -1; + if(part->prog_modes & PM_TPI) { + // We do not support TPI; this is a dedicated SPI thing + pmsg_error("the %s programmer does not support TPI\n", pgmid); + return -1; + } + + unsigned char buf[32]; + + // Set SPI clock frequency + if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) { + memset(buf, 0, sizeof buf); + uint32_t frequency = + pgm->bitclock > 0? pgm->bitclock: + part->factory_fcpu > 0? part->factory_fcpu/4: + 250000; + write_le32(buf, frequency); + if(perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) { + pmsg_error("cannot set SPI frequency %u Hz\n", (unsigned) frequency); + return -1; } + my.actual_frequency = read_le32(buf); + } - unsigned char buf[32]; - - // set SPI clock frequency - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) { - memset(buf, 0, sizeof(buf)); - uint32_t frequency; - if (pgm->bitclock > 0) { - frequency = pgm->bitclock; - } else if (part->factory_fcpu > 0) { - frequency = (part->factory_fcpu / 4); - } else { - frequency = 250000; - } - write_le32(buf, frequency); - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) { - pmsg_error("cannot set SPI frequency\n"); - return -1; - } - my.actual_frequency = read_le32(buf); + // Set active chip select + if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { + memset(buf, 0, sizeof buf); + buf[0] = my.cs; + if(perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { + pmsg_error("cannot change CS\n"); + return -1; } + } - // set active chip select - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_CS)) { - memset(buf, 0, sizeof(buf)); - buf[0] = my.cs; - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_CS, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot change CS\n"); - return -1; - } + // Set full duplex + memset(buf, 0, sizeof buf); + buf[0] = SPI_MODE_FULL_DUPLEX; + if(perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { + pmsg_error("cannot set SPI full duplex mode\n"); + return -1; + } + + // Set output + if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) { + memset(buf, 0, sizeof buf); + buf[0] = 1; // Pin state enable + if(perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { + pmsg_error("cannot enable pin state\n"); + return -1; } + } - // set full duplex - memset(buf, 0, sizeof(buf)); - buf[0] = SPI_MODE_FULL_DUPLEX; - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_MODE, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot set SPI full duplex mode\n"); - return -1; - } + // Enable the CS/reset pin + const unsigned char cs_mode = CS_MODE_SELECTED; - // set output - if (is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_PIN_STATE)) { - memset(buf, 0, sizeof(buf)); - buf[0] = 1; // Pin state enable - if (perform_serprog_cmd(pgm, S_CMD_S_PIN_STATE, buf, 1, NULL, 0) != 0) { - pmsg_error("cannot enable pin state\n"); - return -1; - } - } + if(perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { + pmsg_error("cannot enable the reset pin\n"); + return -1; + } - // enable the CS / reset pin - const unsigned char cs_mode = CS_MODE_SELECTED; - if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { - pmsg_error("cannot enable the reset pin\n"); - return -1; - } + int tries, ret; - int tries, ret; + // Enable programming on the part + tries = 0; + do { + ret = pgm->program_enable(pgm, part); + if(ret == 0 || ret == -1) + break; + } while(tries++ < 65); - //enable programming on the part - tries = 0; - do { - ret = pgm->program_enable(pgm, part); - if (ret == 0 || ret == -1) - break; - } while(tries++ < 65); + if(ret) + pmsg_error("AVR device not responding\n"); - if (ret) - pmsg_error("AVR device not responding\n"); - - return ret; + return ret; } /* used linuxspi.c as a template: @@ -366,66 +361,68 @@ static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *part) { * Copyright (C) 2018 Ralf Ramsauer */ static int serprog_program_enable(const PROGRAMMER *pgm, const AVRPART *p) { - unsigned char cmd[4], res[4]; + unsigned char cmd[4], res[4]; - if (!p->op[AVR_OP_PGM_ENABLE]) { - pmsg_error("program enable instruction not defined for part %s\n", p->desc); - return -1; - } + if(!p->op[AVR_OP_PGM_ENABLE]) { + pmsg_error("program enable instruction not defined for part %s\n", p->desc); + return -1; + } - memset(cmd, 0, sizeof(cmd)); - avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd); //set the cmd - pgm->cmd(pgm, cmd, res); + memset(cmd, 0, sizeof cmd); + avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd); // Set the cmd + pgm->cmd(pgm, cmd, res); - if (res[2] != cmd[1]) { - /** From ATtiny441 datasheet: - * - * In some systems, the programmer cannot guarantee that SCK is held low - * during power-up. In this case, RESET must be given a positive pulse after - * SCK has been set to '0'. The duration of the pulse must be at least t RST - * plus two CPU clock cycles. See Table 25-5 on page 240 for definition of - * minimum pulse width on RESET pin, t RST - * 2. Wait for at least 20 ms and then enable serial programming by sending - * the Programming Enable serial instruction to the SDO pin - * 3. The serial programming instructions will not work if the communication - * is out of synchronization. When in sync, the second byte (0x53) will echo - * back when issuing the third byte of the Programming Enable instruction - * ... - * If the 0x53 did not echo back, give RESET a positive pulse and issue a - * new Programming Enable command - */ - unsigned char cs_mode = CS_MODE_DESELECTED; - if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { - return -1; - } - usleep(5); - cs_mode = CS_MODE_SELECTED; - if (perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) { - return -1; - } - usleep(20000); + if(res[2] != cmd[1]) { - return -2; - } + /** From ATtiny441 datasheet: + * + * In some systems, the programmer cannot guarantee that SCK is held low + * during power-up. In this case, RESET must be given a positive pulse after + * SCK has been set to '0'. The duration of the pulse must be at least t RST + * plus two CPU clock cycles. See Table 25-5 on page 240 for definition of + * minimum pulse width on RESET pin, t RST + * 2. Wait for at least 20 ms and then enable serial programming by sending + * the Programming Enable serial instruction to the SDO pin + * 3. The serial programming instructions will not work if the communication + * is out of synchronization. When in sync, the second byte (0x53) will echo + * back when issuing the third byte of the Programming Enable instruction + * ... + * If the 0x53 did not echo back, give RESET a positive pulse and issue a + * new Programming Enable command + */ - return 0; + unsigned char cs_mode = CS_MODE_DESELECTED; + if(perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) + return -1; + + usleep(5); + cs_mode = CS_MODE_SELECTED; + if(perform_serprog_cmd(pgm, S_CMD_S_CS_MODE, &cs_mode, 1, NULL, 0) != 0) + return -1; + + usleep(20000); + + return -2; + } + + return 0; } static int serprog_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) { - unsigned char cmd[4], res[4]; + unsigned char cmd[4], res[4]; - if (!p->op[AVR_OP_CHIP_ERASE]) { - pmsg_error("chip erase instruction not defined for part %s\n", p->desc); - return -1; - } + if(!p->op[AVR_OP_CHIP_ERASE]) { + pmsg_error("chip erase instruction not defined for part %s\n", p->desc); + return -1; + } - memset(cmd, 0, sizeof(cmd)); - avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); - pgm->cmd(pgm, cmd, res); - usleep(p->chip_erase_delay); - pgm->initialize(pgm, p); + memset(cmd, 0, sizeof cmd); + avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); + pgm->cmd(pgm, cmd, res); + usleep(p->chip_erase_delay); + pgm->initialize(pgm, p); - return 0; + return 0; } static void serprog_display(const PROGRAMMER *pgm, const char *p) { @@ -435,87 +432,88 @@ static void serprog_enable(PROGRAMMER *pgm, const AVRPART *p) { } static void serprog_setup(PROGRAMMER *pgm) { - pgm->cookie = mmt_malloc(sizeof(struct pdata)); + pgm->cookie = mmt_malloc(sizeof(struct pdata)); } static void serprog_teardown(PROGRAMMER *pgm) { - mmt_free(pgm->cookie); - pgm->cookie = NULL; + mmt_free(pgm->cookie); + pgm->cookie = NULL; } static int serprog_set_sck_period(const PROGRAMMER *pgm, double v) { - if (!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) { - return -1; - } - unsigned char buf[8]; - memset(buf, 0, sizeof(buf)); - write_le32(buf, v); - if (perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) { - pmsg_error("cannot set SPI frequency\n"); - return -1; - } - my.actual_frequency = read_le32(buf); - return 0; + if(!is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) + return -1; + + unsigned char buf[8]; + + memset(buf, 0, sizeof buf); + write_le32(buf, v); + if(perform_serprog_cmd(pgm, S_CMD_S_SPI_FREQ, buf, 4, buf, 4) != 0) { + pmsg_error("cannot set SPI frequency\n"); + return -1; + } + my.actual_frequency = read_le32(buf); + return 0; } static int serprog_get_sck_period(const PROGRAMMER *pgm, double *v) { - *v = my.actual_frequency; - return 0; + *v = my.actual_frequency; + return 0; } static int serprog_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) { - LNODEID ln; - const char *extended_param; - int rv = 0; + LNODEID ln; + const char *extended_param; + int rv = 0; - for (ln = lfirst(extparms); ln; ln = lnext(ln)) { - extended_param = ldata(ln); + for(ln = lfirst(extparms); ln; ln = lnext(ln)) { + extended_param = ldata(ln); - if (str_starts(extended_param, "cs=")) { - unsigned int cs; - if (sscanf(extended_param, "cs=%u", &cs) != 1) { - pmsg_error("invalid chip select '%s'\n", extended_param); - rv = -1; - } - my.cs = cs; - continue; - } + if(str_starts(extended_param, "cs=")) { + unsigned int cs; - if (str_eq(extended_param, "help")) { - msg_error("%s -c %s extended options:\n", progname, pgmid); - msg_error(" -xcs=cs_num Sets the chip select (CS) to use on supported programmers\n"); - msg_error(" -xhelp Show this help menu and exit\n"); - return LIBAVRDUDE_EXIT; - } - - pmsg_error("invalid extended parameter '%s'\n", extended_param); + if(sscanf(extended_param, "cs=%u", &cs) != 1) { + pmsg_error("invalid chip select '%s'\n", extended_param); rv = -1; + } + my.cs = cs; + continue; } - return rv; + if(str_eq(extended_param, "help")) { + msg_error("%s -c %s extended options:\n", progname, pgmid); + msg_error(" -xcs=cs_num Sets the chip select (CS) to use on supported programmers\n"); + msg_error(" -xhelp Show this help menu and exit\n"); + return LIBAVRDUDE_EXIT; + } + + pmsg_error("invalid extended parameter '%s'\n", extended_param); + rv = -1; + } + + return rv; } void serprog_initpgm(PROGRAMMER *pgm) { - strcpy(pgm->type, "serprog"); + strcpy(pgm->type, "serprog"); - // required fields - pgm->initialize = serprog_initialize; - pgm->display = serprog_display; - pgm->enable = serprog_enable; - pgm->disable = serprog_disable; - pgm->program_enable = serprog_program_enable; - pgm->chip_erase = serprog_chip_erase; - pgm->cmd = serprog_cmd; - pgm->open = serprog_open; - pgm->close = serprog_close; - pgm->read_byte = avr_read_byte_default; - pgm->write_byte = avr_write_byte_default; + // Required fields + pgm->initialize = serprog_initialize; + pgm->display = serprog_display; + pgm->enable = serprog_enable; + pgm->disable = serprog_disable; + pgm->program_enable = serprog_program_enable; + pgm->chip_erase = serprog_chip_erase; + pgm->cmd = serprog_cmd; + pgm->open = serprog_open; + pgm->close = serprog_close; + pgm->read_byte = avr_read_byte_default; + pgm->write_byte = avr_write_byte_default; - // optional fields - pgm->setup = serprog_setup; - pgm->teardown = serprog_teardown; - pgm->parseextparams = serprog_parseextparams; - pgm->get_sck_period = serprog_get_sck_period; - pgm->set_sck_period = serprog_set_sck_period; + // Optional fields + pgm->setup = serprog_setup; + pgm->teardown = serprog_teardown; + pgm->parseextparams = serprog_parseextparams; + pgm->get_sck_period = serprog_get_sck_period; + pgm->set_sck_period = serprog_set_sck_period; } - diff --git a/src/serprog.h b/src/serprog.h index 99ec9401..587f66f8 100644 --- a/src/serprog.h +++ b/src/serprog.h @@ -1,3 +1,4 @@ + /* * avrdude - A Downloader/Uploader for AVR device programmers * @@ -31,6 +32,4 @@ void serprog_initpgm(PROGRAMMER *pgm); #ifdef __cplusplus } #endif - -#endif //serprog_h - +#endif // serprog_h From acf59cb61c86b49dd13118e571784141f7cdd35e Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Tue, 21 May 2024 23:19:46 +0100 Subject: [PATCH 12/12] Convert bitclock period to frequency --- src/serprog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serprog.c b/src/serprog.c index 240eac90..739790b2 100644 --- a/src/serprog.c +++ b/src/serprog.c @@ -293,7 +293,7 @@ static int serprog_initialize(const PROGRAMMER *pgm, const AVRPART *part) { if(is_serprog_cmd_supported(my.cmd_bitmap, S_CMD_S_SPI_FREQ)) { memset(buf, 0, sizeof buf); uint32_t frequency = - pgm->bitclock > 0? pgm->bitclock: + pgm->bitclock > 0? 1/pgm->bitclock: part->factory_fcpu > 0? part->factory_fcpu/4: 250000; write_le32(buf, frequency);