Skip to content

Commit ec7982e

Browse files
committed
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.
1 parent 7f41f73 commit ec7982e

2 files changed

Lines changed: 130 additions & 24 deletions

File tree

ports/stm32/mboot/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,32 @@ How to use
3131
#define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_UP)
3232
#define MBOOT_BOOTPIN_ACTIVE (0)
3333

34+
Mboot supports programming external SPI flash via the DFU and I2C
35+
interfaces. SPI flash will be mapped to an address range. To
36+
configure it use the following options (edit as needed):
37+
38+
#define MBOOT_SPIFLASH_ADDR (0x80000000)
39+
#define MBOOT_SPIFLASH_BYTE_SIZE (2 * 1024 * 1024)
40+
#define MBOOT_SPIFLASH_LAYOUT "/0x80000000/64*32Kg"
41+
#define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE (32 / 4)
42+
#define MBOOT_SPIFLASH_SPIFLASH (&spi_bdev.spiflash)
43+
#define MBOOT_SPIFLASH_CONFIG (&spiflash_config)
44+
45+
This assumes that the board declares and defines the relevant SPI flash
46+
configuration structs, eg in the board-specific bdev.c file. The
47+
`MBOOT_SPIFLASH2_LAYOUT` string will be seen by the USB DFU utility and
48+
must describe the SPI flash layout. Note that the number of pages in
49+
this layout description (the `64` above) cannot be larger than 99 (it
50+
must fit in two digits) so the reported page size (the `32Kg` above)
51+
must be made large enough so the number of pages fits in two digits.
52+
Alternatively the layout can specify multiple sections like
53+
`32*16Kg,32*16Kg`, in which case `MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE`
54+
must be changed to `16 / 4` to match tho `16Kg` value.
55+
56+
Mboot supports up to two external SPI flash devices. To configure the
57+
second one use the same configuration names as above but with
58+
`SPIFLASH2`, ie `MBOOT_SPIFLASH2_ADDR` etc.
59+
3460
2. Build the board's main application firmware as usual.
3561

3662
3. Build mboot via:

ports/stm32/mboot/main.c

Lines changed: 104 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static uint32_t get_le32(const uint8_t *b) {
8181
void mp_hal_delay_us(mp_uint_t usec) {
8282
// use a busy loop for the delay
8383
// sys freq is always a multiple of 2MHz, so division here won't lose precision
84-
const uint32_t ucount = HAL_RCC_GetSysClockFreq() / 2000000 * usec / 2;
84+
const uint32_t ucount = CORE_PLL_FREQ / 2000000 * usec / 2;
8585
for (uint32_t count = 0; ++count <= ucount;) {
8686
}
8787
}
@@ -314,6 +314,14 @@ static int usrbtn_state(void) {
314314
/******************************************************************************/
315315
// FLASH
316316

317+
#ifndef MBOOT_SPIFLASH_LAYOUT
318+
#define MBOOT_SPIFLASH_LAYOUT ""
319+
#endif
320+
321+
#ifndef MBOOT_SPIFLASH2_LAYOUT
322+
#define MBOOT_SPIFLASH2_LAYOUT ""
323+
#endif
324+
317325
typedef struct {
318326
uint32_t base_address;
319327
uint32_t sector_size;
@@ -332,7 +340,7 @@ typedef struct {
332340
|| defined(STM32F732xx) \
333341
|| defined(STM32F733xx)
334342

335-
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg"
343+
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
336344

337345
static const flash_layout_t flash_layout[] = {
338346
{ 0x08000000, 0x04000, 4 },
@@ -350,7 +358,7 @@ static const flash_layout_t flash_layout[] = {
350358

351359
#elif defined(STM32F767xx)
352360

353-
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg"
361+
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
354362

355363
// This is for dual-bank mode disabled
356364
static const flash_layout_t flash_layout[] = {
@@ -378,20 +386,18 @@ static uint32_t flash_get_sector_index(uint32_t addr) {
378386
return 0;
379387
}
380388

381-
static int do_mass_erase(void) {
389+
static int flash_mass_erase(void) {
382390
// TODO
383391
return -1;
384392
}
385393

386-
static int do_page_erase(uint32_t addr) {
394+
static int flash_page_erase(uint32_t addr) {
387395
uint32_t sector = flash_get_sector_index(addr);
388396
if (sector == 0) {
389397
// Don't allow to erase the sector with this bootloader in it
390398
return -1;
391399
}
392400

393-
led_state(LED0, 1);
394-
395401
HAL_FLASH_Unlock();
396402

397403
// Clear pending flags (if any)
@@ -411,8 +417,6 @@ static int do_page_erase(uint32_t addr) {
411417
return -1;
412418
}
413419

414-
led_state(LED0, 0);
415-
416420
// Check the erase set bits to 1, at least for the first 256 bytes
417421
for (int i = 0; i < 64; ++i) {
418422
if (((volatile uint32_t*)addr)[i] != 0xffffffff) {
@@ -423,15 +427,12 @@ static int do_page_erase(uint32_t addr) {
423427
return 0;
424428
}
425429

426-
static int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
430+
static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) {
427431
if (addr >= flash_layout[0].base_address && addr < flash_layout[0].base_address + flash_layout[0].sector_size) {
428432
// Don't allow to write the sector with this bootloader in it
429433
return -1;
430434
}
431435

432-
static uint32_t led_tog = 0;
433-
led_state(LED0, (led_tog++) & 16);
434-
435436
const uint32_t *src = (const uint32_t*)src8;
436437
size_t num_word32 = (len + 3) / 4;
437438
HAL_FLASH_Unlock();
@@ -449,6 +450,84 @@ static int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
449450
return 0;
450451
}
451452

453+
/******************************************************************************/
454+
// Writable address space interface
455+
456+
static int do_mass_erase(void) {
457+
// TODO
458+
return flash_mass_erase();
459+
}
460+
461+
#if defined(MBOOT_SPIFLASH_ADDR) || defined(MBOOT_SPIFLASH2_ADDR)
462+
static int spiflash_page_erase(mp_spiflash_t *spif, uint32_t addr, uint32_t n_blocks) {
463+
for (int i = 0; i < n_blocks; ++i) {
464+
int ret = mp_spiflash_erase_block(spif, addr);
465+
if (ret != 0) {
466+
return ret;
467+
}
468+
addr += MP_SPIFLASH_ERASE_BLOCK_SIZE;
469+
}
470+
return 0;
471+
}
472+
#endif
473+
474+
static int do_page_erase(uint32_t addr) {
475+
led_state(LED0, 1);
476+
477+
#if defined(MBOOT_SPIFLASH_ADDR)
478+
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
479+
return spiflash_page_erase(MBOOT_SPIFLASH_SPIFLASH,
480+
addr - MBOOT_SPIFLASH_ADDR, MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE);
481+
}
482+
#endif
483+
484+
#if defined(MBOOT_SPIFLASH2_ADDR)
485+
if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
486+
return spiflash_page_erase(MBOOT_SPIFLASH2_SPIFLASH,
487+
addr - MBOOT_SPIFLASH2_ADDR, MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE);
488+
}
489+
#endif
490+
491+
return flash_page_erase(addr);
492+
}
493+
494+
static void do_read(uint32_t addr, int len, uint8_t *buf) {
495+
#if defined(MBOOT_SPIFLASH_ADDR)
496+
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
497+
mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, buf);
498+
return;
499+
}
500+
#endif
501+
#if defined(MBOOT_SPIFLASH2_ADDR)
502+
if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
503+
mp_spiflash_read(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, buf);
504+
return;
505+
}
506+
#endif
507+
508+
// Other addresses, just read directly from memory
509+
memcpy(buf, (void*)addr, len);
510+
}
511+
512+
static int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
513+
static uint32_t led_tog = 0;
514+
led_state(LED0, (led_tog++) & 4);
515+
516+
#if defined(MBOOT_SPIFLASH_ADDR)
517+
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
518+
return mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, src8);
519+
}
520+
#endif
521+
522+
#if defined(MBOOT_SPIFLASH2_ADDR)
523+
if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
524+
return mp_spiflash_write(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, src8);
525+
}
526+
#endif
527+
528+
return flash_write(addr, src8, len);
529+
}
530+
452531
/******************************************************************************/
453532
// I2C slave interface
454533

@@ -554,7 +633,7 @@ void i2c_slave_process_rx_end(void) {
554633
if (len > I2C_CMD_BUF_LEN) {
555634
len = I2C_CMD_BUF_LEN;
556635
}
557-
memcpy(buf, (void*)i2c_obj.cmd_rdaddr, len);
636+
do_read(i2c_obj.cmd_rdaddr, len, buf);
558637
i2c_obj.cmd_rdaddr += len;
559638
} else if (buf[0] == I2C_CMD_WRITE) {
560639
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) {
732811
if (cmd == DFU_UPLOAD) {
733812
if (arg >= 2) {
734813
dfu_state.cmd = DFU_CMD_UPLOAD;
735-
memcpy(buf, (void*)((arg - 2) * max_len + dfu_state.addr), len);
814+
uint32_t addr = (arg - 2) * max_len + dfu_state.addr;
815+
do_read(addr, len, buf);
736816
return len;
737817
}
738818
} else if (cmd == DFU_GETSTATUS && len == 6) {
@@ -773,14 +853,14 @@ enum {
773853

774854
typedef struct _pyb_usbdd_obj_t {
775855
bool started;
856+
bool tx_pending;
776857
USBD_HandleTypeDef hUSBDDevice;
777858

778859
uint8_t bRequest;
779860
uint16_t wValue;
780861
uint16_t wLength;
781-
uint8_t rx_buf[USB_XFER_SIZE];
782-
uint8_t tx_buf[USB_XFER_SIZE];
783-
bool tx_pending;
862+
__ALIGN_BEGIN uint8_t rx_buf[USB_XFER_SIZE] __ALIGN_END;
863+
__ALIGN_BEGIN uint8_t tx_buf[USB_XFER_SIZE] __ALIGN_END;
784864

785865
// RAM to hold the current descriptors, which we configure on the fly
786866
__ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END;
@@ -1135,14 +1215,14 @@ void stm32_main(int initial_r0) {
11351215
__ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory");
11361216
#endif
11371217

1138-
#if 0
1139-
#if defined(MICROPY_HW_BDEV_IOCTL)
1140-
MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0);
1218+
#if defined(MBOOT_SPIFLASH_ADDR)
1219+
MBOOT_SPIFLASH_SPIFLASH->config = MBOOT_SPIFLASH_CONFIG;
1220+
mp_spiflash_init(MBOOT_SPIFLASH_SPIFLASH);
11411221
#endif
11421222

1143-
#if defined(MICROPY_HW_BDEV2_IOCTL)
1144-
MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0);
1145-
#endif
1223+
#if defined(MBOOT_SPIFLASH2_ADDR)
1224+
MBOOT_SPIFLASH2_SPIFLASH->config = MBOOT_SPIFLASH2_CONFIG;
1225+
mp_spiflash_init(MBOOT_SPIFLASH2_SPIFLASH);
11461226
#endif
11471227

11481228
dfu_init();

0 commit comments

Comments
 (0)