Skip to content
This repository was archived by the owner on Oct 5, 2021. It is now read-only.

Commit ae96dba

Browse files
committed
i2c: add warning if failure on i2c clock stretching
Bootloader v1.0 for i2c only implements host "wait" through i2c "clock stretching". Some i2c host controller could timeout after just few ms of clock stretching. Since the i2c transaction cannot be retryed, stm32flash can only quit. Detect this case and rise a warning to the user. Add document to better explain the issue. Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
1 parent 56c5096 commit ae96dba

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

i2c.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ static struct varlen_cmd i2c_cmd_get_reply[] = {
176176

177177
struct port_interface port_i2c = {
178178
.name = "i2c",
179-
.flags = 0,
179+
.flags = PORT_STRETCH_W,
180180
.open = i2c_open,
181181
.close = i2c_close,
182182
.read = i2c_read,

port.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ typedef enum {
3333
#define PORT_GVR_ETX (1 << 1) /* cmd GVR returns protection status */
3434
#define PORT_CMD_INIT (1 << 2) /* use INIT cmd to autodetect speed */
3535
#define PORT_RETRY (1 << 3) /* allowed read() retry after timeout */
36+
#define PORT_STRETCH_W (1 << 4) /* warning for no-stretching commands */
3637

3738
/* all options and flags used to open and configure an interface */
3839
struct port_options {

stm32.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,15 @@ static const uint32_t stm_reset_code_length = sizeof(stm_reset_code);
9494

9595
extern const stm32_dev_t devices[];
9696

97+
static void stm32_warn_stretching(const char *f)
98+
{
99+
fprintf(stderr, "Attention !!!\n");
100+
fprintf(stderr, "\tThis %s error could be caused by your I2C\n", f);
101+
fprintf(stderr, "\tcontroller not accepting \"clock stretching\"\n");
102+
fprintf(stderr, "\tas required by bootloader.\n");
103+
fprintf(stderr, "\tCheck \"I2C.txt\" in stm32flash source code.\n");
104+
}
105+
97106
static stm32_err_t stm32_get_ack_timeout(const stm32_t *stm, time_t timeout)
98107
{
99108
struct port_interface *port = stm->port;
@@ -575,8 +584,12 @@ stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address,
575584
return STM32_ERR_UNKNOWN;
576585

577586
s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT);
578-
if (s_err != STM32_ERR_OK)
587+
if (s_err != STM32_ERR_OK) {
588+
if (port->flags & PORT_STRETCH_W
589+
&& stm->cmd->wm != STM32_CMD_WM_NS)
590+
stm32_warn_stretching("write");
579591
return STM32_ERR_UNKNOWN;
592+
}
580593
return STM32_ERR_OK;
581594
}
582595

@@ -666,6 +679,9 @@ stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages)
666679
s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT);
667680
if (s_err != STM32_ERR_OK) {
668681
fprintf(stderr, "Mass erase failed. Try specifying the number of pages to be erased.\n");
682+
if (port->flags & PORT_STRETCH_W
683+
&& stm->cmd->er != STM32_CMD_EE_NS)
684+
stm32_warn_stretching("erase");
669685
return STM32_ERR_UNKNOWN;
670686
}
671687
return STM32_ERR_OK;
@@ -708,6 +724,9 @@ stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages)
708724
s_err = stm32_get_ack_timeout(stm, STM32_SECTERASE_TIMEOUT);
709725
if (s_err != STM32_ERR_OK) {
710726
fprintf(stderr, "Page-by-page erase failed. Check the maximum pages your device supports.\n");
727+
if (port->flags & PORT_STRETCH_W
728+
&& stm->cmd->er != STM32_CMD_EE_NS)
729+
stm32_warn_stretching("erase");
711730
return STM32_ERR_UNKNOWN;
712731
}
713732

@@ -716,7 +735,13 @@ stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages)
716735

717736
/* And now the regular erase (0x43) for all other chips */
718737
if (pages == 0xFF) {
719-
return stm32_send_command_timeout(stm, 0xFF, STM32_MASSERASE_TIMEOUT);
738+
s_err = stm32_send_command_timeout(stm, 0xFF, STM32_MASSERASE_TIMEOUT);
739+
if (s_err != STM32_ERR_OK) {
740+
if (port->flags & PORT_STRETCH_W)
741+
stm32_warn_stretching("erase");
742+
return STM32_ERR_UNKNOWN;
743+
}
744+
return STM32_ERR_OK;
720745
} else {
721746
uint8_t cs = 0;
722747
uint8_t pg_num;
@@ -741,8 +766,11 @@ stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages)
741766
return STM32_ERR_UNKNOWN;
742767
}
743768
s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT);
744-
if (s_err != STM32_ERR_OK)
769+
if (s_err != STM32_ERR_OK) {
770+
if (port->flags & PORT_STRETCH_W)
771+
stm32_warn_stretching("erase");
745772
return STM32_ERR_UNKNOWN;
773+
}
746774
return STM32_ERR_OK;
747775
}
748776
}

0 commit comments

Comments
 (0)