stm32/mboot: Add support for erase/read/write of external SPI flash.
This patch adds support to mboot for programming external SPI flash. It allows SPI flash to be programmed via a USB DFU utility in the same way that internal MCU flash is programmed.
This commit is contained in:
parent
7f41f73f0f
commit
ec7982ec6d
|
@ -31,6 +31,32 @@ How to use
|
|||
#define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_UP)
|
||||
#define MBOOT_BOOTPIN_ACTIVE (0)
|
||||
|
||||
Mboot supports programming external SPI flash via the DFU and I2C
|
||||
interfaces. SPI flash will be mapped to an address range. To
|
||||
configure it use the following options (edit as needed):
|
||||
|
||||
#define MBOOT_SPIFLASH_ADDR (0x80000000)
|
||||
#define MBOOT_SPIFLASH_BYTE_SIZE (2 * 1024 * 1024)
|
||||
#define MBOOT_SPIFLASH_LAYOUT "/0x80000000/64*32Kg"
|
||||
#define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE (32 / 4)
|
||||
#define MBOOT_SPIFLASH_SPIFLASH (&spi_bdev.spiflash)
|
||||
#define MBOOT_SPIFLASH_CONFIG (&spiflash_config)
|
||||
|
||||
This assumes that the board declares and defines the relevant SPI flash
|
||||
configuration structs, eg in the board-specific bdev.c file. The
|
||||
`MBOOT_SPIFLASH2_LAYOUT` string will be seen by the USB DFU utility and
|
||||
must describe the SPI flash layout. Note that the number of pages in
|
||||
this layout description (the `64` above) cannot be larger than 99 (it
|
||||
must fit in two digits) so the reported page size (the `32Kg` above)
|
||||
must be made large enough so the number of pages fits in two digits.
|
||||
Alternatively the layout can specify multiple sections like
|
||||
`32*16Kg,32*16Kg`, in which case `MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE`
|
||||
must be changed to `16 / 4` to match tho `16Kg` value.
|
||||
|
||||
Mboot supports up to two external SPI flash devices. To configure the
|
||||
second one use the same configuration names as above but with
|
||||
`SPIFLASH2`, ie `MBOOT_SPIFLASH2_ADDR` etc.
|
||||
|
||||
2. Build the board's main application firmware as usual.
|
||||
|
||||
3. Build mboot via:
|
||||
|
|
|
@ -81,7 +81,7 @@ static uint32_t get_le32(const uint8_t *b) {
|
|||
void mp_hal_delay_us(mp_uint_t usec) {
|
||||
// use a busy loop for the delay
|
||||
// sys freq is always a multiple of 2MHz, so division here won't lose precision
|
||||
const uint32_t ucount = HAL_RCC_GetSysClockFreq() / 2000000 * usec / 2;
|
||||
const uint32_t ucount = CORE_PLL_FREQ / 2000000 * usec / 2;
|
||||
for (uint32_t count = 0; ++count <= ucount;) {
|
||||
}
|
||||
}
|
||||
|
@ -314,6 +314,14 @@ static int usrbtn_state(void) {
|
|||
/******************************************************************************/
|
||||
// FLASH
|
||||
|
||||
#ifndef MBOOT_SPIFLASH_LAYOUT
|
||||
#define MBOOT_SPIFLASH_LAYOUT ""
|
||||
#endif
|
||||
|
||||
#ifndef MBOOT_SPIFLASH2_LAYOUT
|
||||
#define MBOOT_SPIFLASH2_LAYOUT ""
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t base_address;
|
||||
uint32_t sector_size;
|
||||
|
@ -332,7 +340,7 @@ typedef struct {
|
|||
|| defined(STM32F732xx) \
|
||||
|| defined(STM32F733xx)
|
||||
|
||||
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg"
|
||||
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
|
||||
|
||||
static const flash_layout_t flash_layout[] = {
|
||||
{ 0x08000000, 0x04000, 4 },
|
||||
|
@ -350,7 +358,7 @@ static const flash_layout_t flash_layout[] = {
|
|||
|
||||
#elif defined(STM32F767xx)
|
||||
|
||||
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg"
|
||||
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
|
||||
|
||||
// This is for dual-bank mode disabled
|
||||
static const flash_layout_t flash_layout[] = {
|
||||
|
@ -378,20 +386,18 @@ static uint32_t flash_get_sector_index(uint32_t addr) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int do_mass_erase(void) {
|
||||
static int flash_mass_erase(void) {
|
||||
// TODO
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int do_page_erase(uint32_t addr) {
|
||||
static int flash_page_erase(uint32_t addr) {
|
||||
uint32_t sector = flash_get_sector_index(addr);
|
||||
if (sector == 0) {
|
||||
// Don't allow to erase the sector with this bootloader in it
|
||||
return -1;
|
||||
}
|
||||
|
||||
led_state(LED0, 1);
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
// Clear pending flags (if any)
|
||||
|
@ -411,8 +417,6 @@ static int do_page_erase(uint32_t addr) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
led_state(LED0, 0);
|
||||
|
||||
// Check the erase set bits to 1, at least for the first 256 bytes
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
if (((volatile uint32_t*)addr)[i] != 0xffffffff) {
|
||||
|
@ -423,15 +427,12 @@ static int do_page_erase(uint32_t addr) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
|
||||
static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) {
|
||||
if (addr >= flash_layout[0].base_address && addr < flash_layout[0].base_address + flash_layout[0].sector_size) {
|
||||
// Don't allow to write the sector with this bootloader in it
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint32_t led_tog = 0;
|
||||
led_state(LED0, (led_tog++) & 16);
|
||||
|
||||
const uint32_t *src = (const uint32_t*)src8;
|
||||
size_t num_word32 = (len + 3) / 4;
|
||||
HAL_FLASH_Unlock();
|
||||
|
@ -449,6 +450,84 @@ static int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Writable address space interface
|
||||
|
||||
static int do_mass_erase(void) {
|
||||
// TODO
|
||||
return flash_mass_erase();
|
||||
}
|
||||
|
||||
#if defined(MBOOT_SPIFLASH_ADDR) || defined(MBOOT_SPIFLASH2_ADDR)
|
||||
static int spiflash_page_erase(mp_spiflash_t *spif, uint32_t addr, uint32_t n_blocks) {
|
||||
for (int i = 0; i < n_blocks; ++i) {
|
||||
int ret = mp_spiflash_erase_block(spif, addr);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
addr += MP_SPIFLASH_ERASE_BLOCK_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int do_page_erase(uint32_t addr) {
|
||||
led_state(LED0, 1);
|
||||
|
||||
#if defined(MBOOT_SPIFLASH_ADDR)
|
||||
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
|
||||
return spiflash_page_erase(MBOOT_SPIFLASH_SPIFLASH,
|
||||
addr - MBOOT_SPIFLASH_ADDR, MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MBOOT_SPIFLASH2_ADDR)
|
||||
if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
|
||||
return spiflash_page_erase(MBOOT_SPIFLASH2_SPIFLASH,
|
||||
addr - MBOOT_SPIFLASH2_ADDR, MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE);
|
||||
}
|
||||
#endif
|
||||
|
||||
return flash_page_erase(addr);
|
||||
}
|
||||
|
||||
static void do_read(uint32_t addr, int len, uint8_t *buf) {
|
||||
#if defined(MBOOT_SPIFLASH_ADDR)
|
||||
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
|
||||
mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, buf);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if defined(MBOOT_SPIFLASH2_ADDR)
|
||||
if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
|
||||
mp_spiflash_read(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, buf);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Other addresses, just read directly from memory
|
||||
memcpy(buf, (void*)addr, len);
|
||||
}
|
||||
|
||||
static int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
|
||||
static uint32_t led_tog = 0;
|
||||
led_state(LED0, (led_tog++) & 4);
|
||||
|
||||
#if defined(MBOOT_SPIFLASH_ADDR)
|
||||
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
|
||||
return mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, src8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MBOOT_SPIFLASH2_ADDR)
|
||||
if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
|
||||
return mp_spiflash_write(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, src8);
|
||||
}
|
||||
#endif
|
||||
|
||||
return flash_write(addr, src8, len);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// I2C slave interface
|
||||
|
||||
|
@ -554,7 +633,7 @@ void i2c_slave_process_rx_end(void) {
|
|||
if (len > I2C_CMD_BUF_LEN) {
|
||||
len = I2C_CMD_BUF_LEN;
|
||||
}
|
||||
memcpy(buf, (void*)i2c_obj.cmd_rdaddr, len);
|
||||
do_read(i2c_obj.cmd_rdaddr, len, buf);
|
||||
i2c_obj.cmd_rdaddr += len;
|
||||
} else if (buf[0] == I2C_CMD_WRITE) {
|
||||
if (i2c_obj.cmd_wraddr == APPLICATION_ADDR) {
|
||||
|
@ -732,7 +811,8 @@ static int dfu_handle_tx(int cmd, int arg, int len, uint8_t *buf, int max_len) {
|
|||
if (cmd == DFU_UPLOAD) {
|
||||
if (arg >= 2) {
|
||||
dfu_state.cmd = DFU_CMD_UPLOAD;
|
||||
memcpy(buf, (void*)((arg - 2) * max_len + dfu_state.addr), len);
|
||||
uint32_t addr = (arg - 2) * max_len + dfu_state.addr;
|
||||
do_read(addr, len, buf);
|
||||
return len;
|
||||
}
|
||||
} else if (cmd == DFU_GETSTATUS && len == 6) {
|
||||
|
@ -773,14 +853,14 @@ enum {
|
|||
|
||||
typedef struct _pyb_usbdd_obj_t {
|
||||
bool started;
|
||||
bool tx_pending;
|
||||
USBD_HandleTypeDef hUSBDDevice;
|
||||
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wLength;
|
||||
uint8_t rx_buf[USB_XFER_SIZE];
|
||||
uint8_t tx_buf[USB_XFER_SIZE];
|
||||
bool tx_pending;
|
||||
__ALIGN_BEGIN uint8_t rx_buf[USB_XFER_SIZE] __ALIGN_END;
|
||||
__ALIGN_BEGIN uint8_t tx_buf[USB_XFER_SIZE] __ALIGN_END;
|
||||
|
||||
// RAM to hold the current descriptors, which we configure on the fly
|
||||
__ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END;
|
||||
|
@ -1135,14 +1215,14 @@ enter_bootloader:
|
|||
__ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory");
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#if defined(MICROPY_HW_BDEV_IOCTL)
|
||||
MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0);
|
||||
#if defined(MBOOT_SPIFLASH_ADDR)
|
||||
MBOOT_SPIFLASH_SPIFLASH->config = MBOOT_SPIFLASH_CONFIG;
|
||||
mp_spiflash_init(MBOOT_SPIFLASH_SPIFLASH);
|
||||
#endif
|
||||
|
||||
#if defined(MICROPY_HW_BDEV2_IOCTL)
|
||||
MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0);
|
||||
#endif
|
||||
#if defined(MBOOT_SPIFLASH2_ADDR)
|
||||
MBOOT_SPIFLASH2_SPIFLASH->config = MBOOT_SPIFLASH2_CONFIG;
|
||||
mp_spiflash_init(MBOOT_SPIFLASH2_SPIFLASH);
|
||||
#endif
|
||||
|
||||
dfu_init();
|
||||
|
|
Loading…
Reference in New Issue