summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-06-22 15:30:34 +1000
committerDamien George <damien.p.george@gmail.com>2018-06-22 15:30:34 +1000
commitec7982ec6dc195a6b1381af2a18590414ef9e621 (patch)
tree09ca40f5cdb70e6eca209c09b68848312bdb39d5
parent7f41f73f0f81e0ecbdb37d32ea7ad8cbc7468b06 (diff)
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.
-rw-r--r--ports/stm32/mboot/README.md26
-rw-r--r--ports/stm32/mboot/main.c128
2 files changed, 130 insertions, 24 deletions
diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md
index 3486ebfb3..2ff6101b4 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 5e2e1819f..11053971b 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();
@@ -450,6 +451,84 @@ static int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
}
/******************************************************************************/
+// 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
#if defined(MBOOT_I2C_SCL)
@@ -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();