From 964c933bf307c6d1f786c2342a03d3679ec72af9 Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Sun, 2 Feb 2020 00:03:09 +0100 Subject: [PATCH] Do not rely on Clockstretching for writes --- README.md | 24 ++++++++++++++----- main.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 147af8b..01c59b0 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ Currently the following AVR MCUs are supported: AVR MCU | Flash bytes used (.text + .data) | Bootloader region size --- | --- | --- -atmega8 | 718 (0x2CE) | 512 words -atmega88 | 740 (0x2E4) | 512 words -atmega168 | 740 (0x2E4) | 512 words -atmega328p | 740 (0x2E4) | 512 words +atmega8 | 802 (0x322) | 512 words +atmega88 | 826 (0x33A) | 512 words +atmega168 | 826 (0x33A) | 512 words +atmega328p | 826 (0x33A) | 512 words (Compiled on Ubuntu 18.04 LTS (gcc 5.4.0 / avr-libc 2.0.0) with EEPROM and LED support) @@ -74,7 +74,7 @@ Read chip info | **SLA+W**, 0x02, 0x00, 0x00, 0x00, **SLA+R**, {8 bytes}, **STO* Read 1+ flash bytes | **SLA+W**, 0x02, 0x01, addrh, addrl, **SLA+R**, {* bytes}, **STO** | Read 1+ eeprom bytes | **SLA+W**, 0x02, 0x02, addrh, addrl, **SLA+R**, {* bytes}, **STO** | Write one flash page | **SLA+W**, 0x02, 0x01, addrh, addrl, {* bytes}, **STO** | page size as indicated in chip info -Write 1+ eeprom bytes | **SLA+W**, 0x02, 0x02, addrh, addrl, {* bytes}, **STO** | +Write 1+ eeprom bytes | **SLA+W**, 0x02, 0x02, addrh, addrl, {* bytes}, **STO** | write 0 < n < page size bytes at once **SLA+R** means Start Condition, Slave Address, Read Access @@ -82,16 +82,28 @@ Write 1+ eeprom bytes | **SLA+W**, 0x02, 0x02, addrh, addrl, {* bytes}, **STO** **STO** means Stop Condition +A flash page / eeprom write is only triggered after the Stop Condition. +During the write process twiboot will NOT acknowledge its slave address. + The multiboot_tool repository contains a simple linux application that uses this protocol to access the bootloader over linux i2c device. The ispprog programming adapter can also be used as a avr910/butterfly to twiboot protocol bridge. + +## TWI/I2C Clockstretching ## +While a write is in progress twiboot will not respond on the TWI/I2C bus and the +TWI/I2C master needs to retry/poll the slave address until the write has completed. + +As a compile time option (USE_CLOCKSTRETCH) the previous behavior of twiboot can be restored: +TWI/I2C Clockstretching is then used to inform the master of the duration of the write. +Please note that there are some TWI/I2C masters that do not support clockstretching. + + ## Development ## Issue reports, feature requests, patches or simply success stories are much appreciated. ## Roadmap ## Some ideas that I want to investigate / implement in twiboot: -- find a way to not rely on TWI clock stretching during write access - support AVR TINYs (USI peripheral, no bootloader fuse, no Read-While-Write flash) diff --git a/main.c b/main.c index 427a982..4c4a9a8 100644 --- a/main.c +++ b/main.c @@ -24,6 +24,7 @@ #define VERSION_STRING "TWIBOOT v2.1" #define EEPROM_SUPPORT 1 #define LED_SUPPORT 1 +#define USE_CLOCKSTRETCH 0 #define F_CPU 8000000ULL #define TIMER_DIVISOR 1024 @@ -63,6 +64,8 @@ #define CMD_ACCESS_CHIPINFO (0x10 | CMD_ACCESS_MEMORY) #define CMD_ACCESS_FLASH (0x20 | CMD_ACCESS_MEMORY) #define CMD_ACCESS_EEPROM (0x30 | CMD_ACCESS_MEMORY) +#define CMD_WRITE_FLASH_PAGE (0x40 | CMD_ACCESS_MEMORY) +#define CMD_WRITE_EEPROM_PAGE (0x50 | CMD_ACCESS_MEMORY) /* SLA+W */ #define CMD_SWITCH_APPLICATION CMD_READ_VERSION @@ -198,6 +201,22 @@ static void write_eeprom_byte(uint8_t val) eeprom_busy_wait(); } /* write_eeprom_byte */ + + +#if (USE_CLOCKSTRETCH == 0) +/* ************************************************************************* + * write_eeprom_buffer + * ************************************************************************* */ +static void write_eeprom_buffer(uint8_t size) +{ + uint8_t *p = buf; + + while (size--) + { + write_eeprom_byte(*p++); + } +} /* write_eeprom_buffer */ +#endif /* (USE_CLOCKSTRETCH == 0) */ #endif /* EEPROM_SUPPORT */ @@ -279,6 +298,19 @@ static uint8_t TWI_data_write(uint8_t bcnt, uint8_t data) default: switch (cmd) { +#if (EEPROM_SUPPORT) +#if (USE_CLOCKSTRETCH) + case CMD_ACCESS_EEPROM: + write_eeprom_byte(data); + break; +#else + case CMD_ACCESS_EEPROM: + cmd = CMD_WRITE_EEPROM_PAGE; + /* fall through */ + + case CMD_WRITE_EEPROM_PAGE: +#endif /* (USE_CLOCKSTRETCH) */ +#endif /* (EEPROM_SUPPORT) */ case CMD_ACCESS_FLASH: { uint8_t pos = bcnt -4; @@ -289,19 +321,19 @@ static uint8_t TWI_data_write(uint8_t bcnt, uint8_t data) ack = 0x00; } - if (pos >= (sizeof(buf) -1)) + if ((cmd == CMD_ACCESS_FLASH) && + (pos >= (sizeof(buf) -1)) + ) { +#if (USE_CLOCKSTRETCH) write_flash_page(); +#else + cmd = CMD_WRITE_FLASH_PAGE; +#endif } break; } -#if (EEPROM_SUPPORT) - case CMD_ACCESS_EEPROM: - write_eeprom_byte(data); - break; -#endif /* (EEPROM_SUPPORT) */ - default: ack = 0x00; break; @@ -392,6 +424,30 @@ static void TWI_vect(void) /* STOP or repeated START -> IDLE */ case 0xA0: +#if (USE_CLOCKSTRETCH == 0) + if ((cmd == CMD_WRITE_FLASH_PAGE) +#if (EEPROM_SUPPORT) + || (cmd == CMD_WRITE_EEPROM_PAGE) +#endif + ) + { + /* disable ACK for now, re-enable after page write */ + control &= ~(1<