From d6a2d0016793ad962a8f2b6da48f2a64de84b023 Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Tue, 24 Jan 2017 16:58:50 +1100
Subject: [PATCH] stmhal: Add ability to have filesystem stored on external SPI
 flash.

To use this feature a port should define MICROPY_HW_SPIFLASH_SIZE_BITS
along with x_CS, x_SCK, x_MOSI, x_MISO (x=MICROPY_HW_SPIFLASH).  This will
then use external SPI flash on those pins instead of the internal flash.

The SPI is done using the software implementation.  There is currently only
support for standard SPI (ie not dual or quad mode).
---
 stmhal/Makefile  |  5 +++
 stmhal/storage.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+)

diff --git a/stmhal/Makefile b/stmhal/Makefile
index 9a9c50f06..87236068b 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -117,6 +117,10 @@ SRC_LIB = $(addprefix lib/,\
 	utils/pyexec.c \
 	)
 
+DRIVERS_SRC_C = $(addprefix drivers/,\
+	memory/spiflash.c \
+	)
+
 SRC_C = \
 	main.c \
 	system_stm32.c \
@@ -256,6 +260,7 @@ endif
 OBJ =
 OBJ += $(PY_O)
 OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
 OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
 OBJ += $(addprefix $(BUILD)/, $(SRC_O))
 OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o))
diff --git a/stmhal/storage.c b/stmhal/storage.c
index 14b504d71..60a7e9f48 100644
--- a/stmhal/storage.c
+++ b/stmhal/storage.c
@@ -38,6 +38,14 @@
 #include "storage.h"
 #include "irq.h"
 
+#if defined(MICROPY_HW_SPIFLASH_SIZE_BITS)
+#define USE_INTERNAL (0)
+#else
+#define USE_INTERNAL (1)
+#endif
+
+#if USE_INTERNAL
+
 #if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)
 
 #define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
@@ -158,19 +166,50 @@ static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) {
     return (uint8_t*)flash_addr;
 }
 
+#else
+
+#include "drivers/memory/spiflash.h"
+#include "genhdr/pins.h"
+
+#define FLASH_PART1_START_BLOCK (0x100)
+#define FLASH_PART1_NUM_BLOCKS (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE)
+
+static bool flash_is_initialised = false;
+
+STATIC const mp_spiflash_t spiflash = {
+    .cs = &MICROPY_HW_SPIFLASH_CS,
+    .spi = {
+        .base = {&mp_machine_soft_spi_type},
+        .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY,
+        .polarity = 0,
+        .phase = 0,
+        .sck = &MICROPY_HW_SPIFLASH_SCK,
+        .mosi = &MICROPY_HW_SPIFLASH_MOSI,
+        .miso = &MICROPY_HW_SPIFLASH_MISO,
+    },
+};
+
+#endif
+
 void storage_init(void) {
     if (!flash_is_initialised) {
+        #if USE_INTERNAL
         flash_flags = 0;
         flash_cache_sector_id = 0;
         flash_tick_counter_last_write = 0;
+        #else
+        mp_spiflash_init((mp_spiflash_t*)&spiflash);
+        #endif
         flash_is_initialised = true;
     }
 
+    #if USE_INTERNAL
     // Enable the flash IRQ, which is used to also call our storage IRQ handler
     // It needs to go at a higher priority than all those components that rely on
     // the flash storage (eg higher than USB MSC).
     HAL_NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH, IRQ_SUBPRI_FLASH);
     HAL_NVIC_EnableIRQ(FLASH_IRQn);
+    #endif
 }
 
 uint32_t storage_get_block_size(void) {
@@ -182,6 +221,8 @@ uint32_t storage_get_block_count(void) {
 }
 
 void storage_irq_handler(void) {
+    #if USE_INTERNAL
+
     if (!(flash_flags & FLASH_FLAG_DIRTY)) {
         return;
     }
@@ -222,10 +263,14 @@ void storage_irq_handler(void) {
         // indicate a clean cache with LED off
         led_state(PYB_LED_R1, 0);
     }
+
+    #endif
 }
 
 void storage_flush(void) {
+    #if USE_INTERNAL
     flash_cache_flush();
+    #endif
 }
 
 static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) {
@@ -264,6 +309,8 @@ static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_blo
     buf[15] = num_blocks >> 24;
 }
 
+#if USE_INTERNAL
+
 static uint32_t convert_block_to_flash_addr(uint32_t block) {
     if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
         // a block in partition 1
@@ -279,6 +326,8 @@ static uint32_t convert_block_to_flash_addr(uint32_t block) {
     return -1;
 }
 
+#endif
+
 bool storage_read_block(uint8_t *dest, uint32_t block) {
     //printf("RD %u\n", block);
     if (block == 0) {
@@ -299,6 +348,8 @@ bool storage_read_block(uint8_t *dest, uint32_t block) {
         return true;
 
     } else {
+        #if USE_INTERNAL
+
         // non-MBR block, get data from flash memory, possibly via cache
         uint32_t flash_addr = convert_block_to_flash_addr(block);
         if (flash_addr == -1) {
@@ -308,6 +359,27 @@ bool storage_read_block(uint8_t *dest, uint32_t block) {
         uint8_t *src = flash_cache_get_addr_for_read(flash_addr);
         memcpy(dest, src, FLASH_BLOCK_SIZE);
         return true;
+
+        #else
+
+        // non-MBR block, get data from SPI flash
+
+        if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
+            // bad block number
+            return false;
+        }
+
+        // we must disable USB irqs to prevent MSC contention with SPI flash
+        uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
+
+        mp_spiflash_read((mp_spiflash_t*)&spiflash,
+            (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest);
+
+        restore_irq_pri(basepri);
+
+        return true;
+
+        #endif
     }
 }
 
@@ -318,6 +390,8 @@ bool storage_write_block(const uint8_t *src, uint32_t block) {
         return true;
 
     } else {
+        #if USE_INTERNAL
+
         // non-MBR block, copy to cache
         uint32_t flash_addr = convert_block_to_flash_addr(block);
         if (flash_addr == -1) {
@@ -327,6 +401,27 @@ bool storage_write_block(const uint8_t *src, uint32_t block) {
         uint8_t *dest = flash_cache_get_addr_for_write(flash_addr);
         memcpy(dest, src, FLASH_BLOCK_SIZE);
         return true;
+
+        #else
+
+        // non-MBR block, write to SPI flash
+
+        if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
+            // bad block number
+            return false;
+        }
+
+        // we must disable USB irqs to prevent MSC contention with SPI flash
+        uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
+
+        int ret = mp_spiflash_write((mp_spiflash_t*)&spiflash,
+            (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src);
+
+        restore_irq_pri(basepri);
+
+        return ret == 0;
+
+        #endif
     }
 }
 
-- 
GitLab