Do not rely on Clockstretching for writes

This commit is contained in:
Olaf Rempel 2020-02-02 00:03:09 +01:00
parent 5bdbb430e7
commit 964c933bf3
2 changed files with 81 additions and 13 deletions

View File

@ -10,10 +10,10 @@ Currently the following AVR MCUs are supported:
AVR MCU | Flash bytes used (.text + .data) | Bootloader region size AVR MCU | Flash bytes used (.text + .data) | Bootloader region size
--- | --- | --- --- | --- | ---
atmega8 | 718 (0x2CE) | 512 words atmega8 | 802 (0x322) | 512 words
atmega88 | 740 (0x2E4) | 512 words atmega88 | 826 (0x33A) | 512 words
atmega168 | 740 (0x2E4) | 512 words atmega168 | 826 (0x33A) | 512 words
atmega328p | 740 (0x2E4) | 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) (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+ 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** | 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 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 **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 **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 The multiboot_tool repository contains a simple linux application that uses
this protocol to access the bootloader over linux i2c device. 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. 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 ## ## Development ##
Issue reports, feature requests, patches or simply success stories are much appreciated. Issue reports, feature requests, patches or simply success stories are much appreciated.
## Roadmap ## ## Roadmap ##
Some ideas that I want to investigate / implement in twiboot: 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) - support AVR TINYs (USI peripheral, no bootloader fuse, no Read-While-Write flash)

70
main.c
View File

@ -24,6 +24,7 @@
#define VERSION_STRING "TWIBOOT v2.1" #define VERSION_STRING "TWIBOOT v2.1"
#define EEPROM_SUPPORT 1 #define EEPROM_SUPPORT 1
#define LED_SUPPORT 1 #define LED_SUPPORT 1
#define USE_CLOCKSTRETCH 0
#define F_CPU 8000000ULL #define F_CPU 8000000ULL
#define TIMER_DIVISOR 1024 #define TIMER_DIVISOR 1024
@ -63,6 +64,8 @@
#define CMD_ACCESS_CHIPINFO (0x10 | CMD_ACCESS_MEMORY) #define CMD_ACCESS_CHIPINFO (0x10 | CMD_ACCESS_MEMORY)
#define CMD_ACCESS_FLASH (0x20 | CMD_ACCESS_MEMORY) #define CMD_ACCESS_FLASH (0x20 | CMD_ACCESS_MEMORY)
#define CMD_ACCESS_EEPROM (0x30 | 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 */ /* SLA+W */
#define CMD_SWITCH_APPLICATION CMD_READ_VERSION #define CMD_SWITCH_APPLICATION CMD_READ_VERSION
@ -198,6 +201,22 @@ static void write_eeprom_byte(uint8_t val)
eeprom_busy_wait(); eeprom_busy_wait();
} /* write_eeprom_byte */ } /* 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 */ #endif /* EEPROM_SUPPORT */
@ -279,6 +298,19 @@ static uint8_t TWI_data_write(uint8_t bcnt, uint8_t data)
default: default:
switch (cmd) 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: case CMD_ACCESS_FLASH:
{ {
uint8_t pos = bcnt -4; uint8_t pos = bcnt -4;
@ -289,19 +321,19 @@ static uint8_t TWI_data_write(uint8_t bcnt, uint8_t data)
ack = 0x00; ack = 0x00;
} }
if (pos >= (sizeof(buf) -1)) if ((cmd == CMD_ACCESS_FLASH) &&
(pos >= (sizeof(buf) -1))
)
{ {
#if (USE_CLOCKSTRETCH)
write_flash_page(); write_flash_page();
#else
cmd = CMD_WRITE_FLASH_PAGE;
#endif
} }
break; break;
} }
#if (EEPROM_SUPPORT)
case CMD_ACCESS_EEPROM:
write_eeprom_byte(data);
break;
#endif /* (EEPROM_SUPPORT) */
default: default:
ack = 0x00; ack = 0x00;
break; break;
@ -392,6 +424,30 @@ static void TWI_vect(void)
/* STOP or repeated START -> IDLE */ /* STOP or repeated START -> IDLE */
case 0xA0: 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<<TWEA);
TWCR = (1<<TWINT) | control;
#if (EEPROM_SUPPORT)
if (cmd == CMD_WRITE_EEPROM_PAGE)
{
write_eeprom_buffer(bcnt -4);
}
else
#endif /* (EEPROM_SUPPORT) */
{
write_flash_page();
}
}
#endif /* (USE_CLOCKSTRETCH) */
bcnt = 0; bcnt = 0;
/* fall through */ /* fall through */