stm32/mboot: Implement DFU mass erase.
The implementation internally uses sector erase to wipe everything except the sector(s) that mboot lives in (by erasing starting from APPLICATION_ADDR). The erase command can take some time (eg an STM32F765 with 2MB of flash takes 8 to 10 seconds). This time is normally enough to make pydfu.py fail with a timeout. The DFU standard includes a mechanism for the DFU device to request a longer timeout as part of the get-status response just before starting an operation. This timeout functionality has been implemented here.
This commit is contained in:
parent
4d6f60d428
commit
8bbaa20227
|
@ -67,6 +67,12 @@ typedef enum {
|
||||||
DFU_CMD_DNLOAD = 8,
|
DFU_CMD_DNLOAD = 8,
|
||||||
} dfu_cmd_t;
|
} dfu_cmd_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DFU_CMD_DNLOAD_SET_ADDRESS = 0x21,
|
||||||
|
DFU_CMD_DNLOAD_ERASE = 0x41,
|
||||||
|
DFU_CMD_DNLOAD_READ_UNPROTECT = 0x92,
|
||||||
|
};
|
||||||
|
|
||||||
// Error status flags
|
// Error status flags
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DFU_STATUS_OK = 0x00, // No error condition is present.
|
DFU_STATUS_OK = 0x00, // No error condition is present.
|
||||||
|
|
|
@ -441,6 +441,11 @@ static int usrbtn_state(void) {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// FLASH
|
// FLASH
|
||||||
|
|
||||||
|
#if defined(STM32WB)
|
||||||
|
#define FLASH_END FLASH_END_ADDR
|
||||||
|
#endif
|
||||||
|
#define APPLICATION_FLASH_LENGTH (FLASH_END + 1 - APPLICATION_ADDR)
|
||||||
|
|
||||||
#ifndef MBOOT_SPIFLASH_LAYOUT
|
#ifndef MBOOT_SPIFLASH_LAYOUT
|
||||||
#define MBOOT_SPIFLASH_LAYOUT ""
|
#define MBOOT_SPIFLASH_LAYOUT ""
|
||||||
#endif
|
#endif
|
||||||
|
@ -464,8 +469,9 @@ static int usrbtn_state(void) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int mboot_flash_mass_erase(void) {
|
static int mboot_flash_mass_erase(void) {
|
||||||
// TODO
|
// Erase all flash pages after mboot.
|
||||||
return -1;
|
int ret = flash_erase(APPLICATION_ADDR, APPLICATION_FLASH_LENGTH / sizeof(uint32_t));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mboot_flash_page_erase(uint32_t addr, uint32_t *next_addr) {
|
static int mboot_flash_page_erase(uint32_t addr, uint32_t *next_addr) {
|
||||||
|
@ -523,7 +529,7 @@ static int mboot_flash_write(uint32_t addr, const uint8_t *src8, size_t len) {
|
||||||
// Writable address space interface
|
// Writable address space interface
|
||||||
|
|
||||||
static int do_mass_erase(void) {
|
static int do_mass_erase(void) {
|
||||||
// TODO
|
// TODO spiflash erase ?
|
||||||
return mboot_flash_mass_erase();
|
return mboot_flash_mass_erase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,20 +797,45 @@ static void dfu_init(void) {
|
||||||
dfu_context.addr = 0x08000000;
|
dfu_context.addr = 0x08000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The DFU_GETSTATUS response before dfu_process_dnload is run should include the needed timeout adjustments
|
||||||
|
static size_t get_timeout_ms(void) {
|
||||||
|
if (dfu_context.wBlockNum == 0) {
|
||||||
|
// download control commands
|
||||||
|
if (dfu_context.wLength >= 1 && dfu_context.buf[0] == DFU_CMD_DNLOAD_ERASE) {
|
||||||
|
if (dfu_context.wLength == 1) {
|
||||||
|
// mass erase command
|
||||||
|
// It takes 10-12 seconds to erase a 2MB stm part. Extrapolate a suitable timeout from this.
|
||||||
|
return APPLICATION_FLASH_LENGTH / 170;
|
||||||
|
|
||||||
|
} else if (dfu_context.wLength == 5) {
|
||||||
|
// erase page command
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (dfu_context.wBlockNum > 1) {
|
||||||
|
// write data to memory command
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int dfu_process_dnload(void) {
|
static int dfu_process_dnload(void) {
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
if (dfu_context.wBlockNum == 0) {
|
if (dfu_context.wBlockNum == 0) {
|
||||||
// download control commands
|
// download control commands
|
||||||
if (dfu_context.wLength >= 1 && dfu_context.buf[0] == 0x41) {
|
if (dfu_context.wLength >= 1 && dfu_context.buf[0] == DFU_CMD_DNLOAD_ERASE) {
|
||||||
if (dfu_context.wLength == 1) {
|
if (dfu_context.wLength == 1) {
|
||||||
// mass erase
|
// mass erase
|
||||||
ret = do_mass_erase();
|
ret = do_mass_erase();
|
||||||
|
if (ret != 0) {
|
||||||
|
dfu_context.cmd = DFU_CMD_NONE;
|
||||||
|
}
|
||||||
} else if (dfu_context.wLength == 5) {
|
} else if (dfu_context.wLength == 5) {
|
||||||
// erase page
|
// erase page
|
||||||
uint32_t next_addr;
|
uint32_t next_addr;
|
||||||
ret = do_page_erase(get_le32(&dfu_context.buf[1]), &next_addr);
|
ret = do_page_erase(get_le32(&dfu_context.buf[1]), &next_addr);
|
||||||
}
|
}
|
||||||
} else if (dfu_context.wLength >= 1 && dfu_context.buf[0] == 0x21) {
|
} else if (dfu_context.wLength >= 1 && dfu_context.buf[0] == DFU_CMD_DNLOAD_SET_ADDRESS) {
|
||||||
if (dfu_context.wLength == 5) {
|
if (dfu_context.wLength == 5) {
|
||||||
// set address
|
// set address
|
||||||
dfu_context.addr = get_le32(&dfu_context.buf[1]);
|
dfu_context.addr = get_le32(&dfu_context.buf[1]);
|
||||||
|
@ -888,12 +919,16 @@ static int dfu_handle_tx(int cmd, int arg, int len, uint8_t *buf, int max_len) {
|
||||||
default:
|
default:
|
||||||
dfu_context.state = DFU_STATE_BUSY;
|
dfu_context.state = DFU_STATE_BUSY;
|
||||||
}
|
}
|
||||||
|
size_t timeout_ms = get_timeout_ms();
|
||||||
buf[0] = dfu_context.status; // bStatus
|
buf[0] = dfu_context.status; // bStatus
|
||||||
buf[1] = 0; // bwPollTimeout (ms)
|
buf[1] = (timeout_ms >> 16) & 0xFF; // bwPollTimeout (ms)
|
||||||
buf[2] = 0; // bwPollTimeout (ms)
|
buf[2] = (timeout_ms >> 8) & 0xFF; // bwPollTimeout (ms)
|
||||||
buf[3] = 0; // bwPollTimeout (ms)
|
buf[3] = timeout_ms & 0xFF; // bwPollTimeout (ms)
|
||||||
buf[4] = dfu_context.state; // bState
|
buf[4] = dfu_context.state; // bState
|
||||||
buf[5] = dfu_context.error; // iString
|
buf[5] = dfu_context.error; // iString
|
||||||
|
// Clear errors now they've been sent
|
||||||
|
dfu_context.status = DFU_STATUS_OK;
|
||||||
|
dfu_context.error = 0;
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
|
Loading…
Reference in New Issue