diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md index 3486ebfb33..2ff6101b44 100644 --- a/ports/stm32/mboot/README.md +++ b/ports/stm32/mboot/README.md @@ -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: diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 5e2e1819f6..11053971bc 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -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();