From 30501d3f54fa642770faefa117b4c39d95aff549 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 28 Jan 2020 14:59:05 +1100 Subject: [PATCH] drivers, stm32: Support SPI/QSPI flash chips over 16MB. With a SPI flash that has more than 16MB, 32-bit addressing is required rather than the standard 24-bit. This commit adds support for 32-bit addressing so that the SPI flash commands (read/write/erase) are selected automatically depending on the size of the address being used at each operation. --- drivers/bus/qspi.h | 17 +++++++++++++++ drivers/bus/softqspi.c | 10 +++++---- drivers/memory/spiflash.c | 44 ++++++++++++++++++++++++--------------- ports/stm32/qspi.c | 24 ++++++++++++++++----- 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/drivers/bus/qspi.h b/drivers/bus/qspi.h index 31c9d14fca..c82796fac5 100644 --- a/drivers/bus/qspi.h +++ b/drivers/bus/qspi.h @@ -28,6 +28,8 @@ #include "py/mphal.h" +#define MP_SPI_ADDR_IS_32B(addr) (addr & 0xff000000) + enum { MP_QSPI_IOCTL_INIT, MP_QSPI_IOCTL_DEINIT, @@ -54,4 +56,19 @@ typedef struct _mp_soft_qspi_obj_t { extern const mp_qspi_proto_t mp_soft_qspi_proto; +static inline uint8_t mp_spi_set_addr_buff(uint8_t *buf, uint32_t addr) { + if (MP_SPI_ADDR_IS_32B(addr)) { + buf[0] = addr >> 24; + buf[1] = addr >> 16; + buf[2] = addr >> 8; + buf[3] = addr; + return 4; + } else { + buf[0] = addr >> 16; + buf[1] = addr >> 8; + buf[2] = addr; + return 3; + } +} + #endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H diff --git a/drivers/bus/softqspi.c b/drivers/bus/softqspi.c index 10c5992466..71ab559768 100644 --- a/drivers/bus/softqspi.c +++ b/drivers/bus/softqspi.c @@ -168,9 +168,10 @@ STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; - uint8_t cmd_buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + uint8_t cmd_buf[5] = {cmd}; + uint8_t addr_len = mp_spi_set_addr_buff(&cmd_buf[1], addr); CS_LOW(self); - mp_soft_qspi_transfer(self, 4, cmd_buf, NULL); + mp_soft_qspi_transfer(self, addr_len + 1, cmd_buf, NULL); mp_soft_qspi_transfer(self, len, src, NULL); CS_HIGH(self); } @@ -186,10 +187,11 @@ STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; - uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr}; + uint8_t cmd_buf[7] = {cmd}; + uint8_t addr_len = mp_spi_set_addr_buff(&cmd_buf[1], addr); CS_LOW(self); mp_soft_qspi_transfer(self, 1, cmd_buf, NULL); - mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles) + mp_soft_qspi_qwrite(self, addr_len + 3, &cmd_buf[1]); // 3/4 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles) mp_soft_qspi_qread(self, len, dest); CS_HIGH(self); } diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index 0eacc710e3..e870d39f5f 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -45,6 +45,12 @@ #define CMD_CHIP_ERASE (0xc7) #define CMD_C4READ (0xeb) +// 32 bit addressing commands +#define CMD_WRITE_32 (0x12) +#define CMD_READ_32 (0x13) +#define CMD_SEC_ERASE_32 (0x21) +#define CMD_C4READ_32 (0xec) + #define WAIT_SR_TIMEOUT (1000000) #define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer @@ -76,18 +82,26 @@ STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t } } -STATIC void mp_spiflash_write_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { +STATIC void mp_spiflash_transfer_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src, uint8_t *dest) { const mp_spiflash_config_t *c = self->config; if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { - uint8_t buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + uint8_t buf[5] = {cmd, 0}; + uint8_t buff_len = 1 + mp_spi_set_addr_buff(&buf[1], addr); mp_hal_pin_write(c->bus.u_spi.cs, 0); - c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); - if (len) { + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, buff_len, buf, NULL); + if (len && (src != NULL)) { c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, src, NULL); + } else if (len && (dest != NULL)) { + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, dest, dest); } + mp_hal_pin_write(c->bus.u_spi.cs, 1); } else { - c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src); + if (dest != NULL) { + c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, cmd, addr, len, dest); + } else { + c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src); + } } } @@ -107,25 +121,19 @@ STATIC uint32_t mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t le STATIC void mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { const mp_spiflash_config_t *c = self->config; + uint8_t cmd; if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { - uint8_t buf[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; - mp_hal_pin_write(c->bus.u_spi.cs, 0); - c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); - c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, dest, dest); - mp_hal_pin_write(c->bus.u_spi.cs, 1); + cmd = MP_SPI_ADDR_IS_32B(addr) ? CMD_READ_32 : CMD_READ; } else { - c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, CMD_C4READ, addr, len, dest); + cmd = MP_SPI_ADDR_IS_32B(addr) ? CMD_C4READ_32 : CMD_C4READ; } + mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, len, NULL, dest); } STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) { mp_spiflash_write_cmd_data(self, cmd, 0, 0); } -STATIC void mp_spiflash_write_cmd_addr(mp_spiflash_t *self, uint8_t cmd, uint32_t addr) { - mp_spiflash_write_cmd_addr_data(self, cmd, addr, 0, NULL); -} - STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) { uint8_t sr; do { @@ -210,7 +218,8 @@ STATIC int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr) } // erase the sector - mp_spiflash_write_cmd_addr(self, CMD_SEC_ERASE, addr); + uint8_t cmd = MP_SPI_ADDR_IS_32B(addr) ? CMD_SEC_ERASE_32 : CMD_SEC_ERASE; + mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, 0, NULL, NULL); // wait WIP=0 return mp_spiflash_wait_wip0(self); @@ -227,7 +236,8 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, size_t len } // write the page - mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, len, src); + uint8_t cmd = MP_SPI_ADDR_IS_32B(addr) ? CMD_WRITE_32 : CMD_WRITE; + mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, len, src, NULL); // wait WIP=0 return mp_spiflash_wait_wip0(self); diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index 30ee2c9ea7..20cdafb00d 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -52,6 +52,14 @@ #define MICROPY_HW_QSPI_CS_HIGH_CYCLES 2 // nCS stays high for 2 cycles #endif +#if (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1) >= 24 +#define QSPI_CMD 0xec +#define QSPI_ADSIZE 3 +#else +#define QSPI_CMD 0xeb +#define QSPI_ADSIZE 2 +#endif + static inline void qspi_mpu_disable_all(void) { // Configure MPU to disable access to entire QSPI region, to prevent CPU // speculative execution from accessing this region and modifying QSPI registers. @@ -116,6 +124,7 @@ void qspi_memory_map(void) { // Enable memory-mapped mode QUADSPI->ABR = 0; // disable continuous read mode + QUADSPI->CCR = 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction @@ -124,10 +133,10 @@ void qspi_memory_map(void) { | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines - | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | QSPI_ADSIZE << QUADSPI_CCR_ADSIZE_Pos | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line - | 0xeb << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode + | QSPI_CMD << QUADSPI_CCR_INSTRUCTION_Pos ; qspi_mpu_enable_mapped(); @@ -203,6 +212,8 @@ STATIC void qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { (void)self_in; + uint8_t adsize = MP_SPI_ADDR_IS_32B(addr) ? 3 : 2; + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag if (len == 0) { @@ -213,7 +224,7 @@ STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, | 0 << QUADSPI_CCR_DMODE_Pos // no data | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte - | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | adsize << QUADSPI_CCR_ADSIZE_Pos // 32/24-bit address size | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode @@ -230,7 +241,7 @@ STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte - | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | adsize << QUADSPI_CCR_ADSIZE_Pos // 32/24-bit address size | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode @@ -285,6 +296,9 @@ STATIC uint32_t qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { (void)self_in; + + uint8_t adsize = MP_SPI_ADDR_IS_32B(addr) ? 3 : 2; + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag QUADSPI->DLR = len - 1; // number of bytes to read @@ -297,7 +311,7 @@ STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines - | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | adsize << QUADSPI_CCR_ADSIZE_Pos // 32 or 24-bit address size | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line | cmd << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode