Do not rely on Clockstretching for writes
This commit is contained in:
parent
5bdbb430e7
commit
964c933bf3
24
README.md
24
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)
|
||||
|
70
main.c
70
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<<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;
|
||||
/* fall through */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user