Skip to content

Commit fa13e0d

Browse files
committed
stm32: Factor out flash and SPI block-device code to separate files.
Prior to this patch, storage.c was a combination of code that handled either internal flash or external SPI flash and exposed one of them as a block device for the local storage. It was also exposed to the USB MSC. This patch splits out the flash and SPI code to separate files, which each provide a general block-device interface (at the C level). Then storage.c just picks one of them to use as the local storage medium. The aim of this factoring is to allow to add new block devices in the future and allow for easier configurability.
1 parent 34911f1 commit fa13e0d

5 files changed

Lines changed: 376 additions & 296 deletions

File tree

ports/stm32/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ SRC_C = \
232232
rng.c \
233233
rtc.c \
234234
flash.c \
235+
flashbdev.c \
236+
spibdev.c \
235237
storage.c \
236238
sdcard.c \
237239
fatfs_port.c \

ports/stm32/flashbdev.c

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2013-2018 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <stdint.h>
28+
#include <string.h>
29+
30+
#include "py/obj.h"
31+
#include "systick.h"
32+
#include "led.h"
33+
#include "flash.h"
34+
#include "storage.h"
35+
36+
#if !defined(MICROPY_HW_SPIFLASH_SIZE_BITS)
37+
38+
// Here we try to automatically configure the location and size of the flash
39+
// pages to use for the internal storage. We also configure the location of the
40+
// cache used for writing.
41+
42+
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)
43+
44+
#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
45+
#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
46+
#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
47+
#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k
48+
49+
// enable this to get an extra 64k of storage (uses the last sector of the flash)
50+
#if 0
51+
#define FLASH_MEM_SEG2_START_ADDR (0x080e0000) // sector 11
52+
#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 11: 128k
53+
#endif
54+
55+
#elif defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx)
56+
57+
STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k
58+
#define CACHE_MEM_START_ADDR (&flash_cache_mem[0])
59+
#define FLASH_SECTOR_SIZE_MAX (0x4000) // 16k max due to size of cache buffer
60+
#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
61+
#define FLASH_MEM_SEG1_NUM_BLOCKS (128) // sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k
62+
63+
#elif defined(STM32F429xx)
64+
65+
#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
66+
#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
67+
#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1
68+
#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k
69+
70+
#elif defined(STM32F439xx)
71+
72+
#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
73+
#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM
74+
#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12
75+
#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k
76+
#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18
77+
#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k)
78+
79+
#elif defined(STM32F746xx) || defined(STM32F767xx) || defined(STM32F769xx)
80+
81+
// The STM32F746 doesn't really have CCRAM, so we use the 64K DTCM for this.
82+
83+
#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k
84+
#define FLASH_SECTOR_SIZE_MAX (0x08000) // 32k max
85+
#define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1
86+
#define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k
87+
88+
#elif defined(STM32L475xx) || defined(STM32L476xx)
89+
90+
extern uint8_t _flash_fs_start;
91+
extern uint8_t _flash_fs_end;
92+
93+
// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this.
94+
#define CACHE_MEM_START_ADDR (0x10000000) // SRAM2 data RAM, 32k
95+
#define FLASH_SECTOR_SIZE_MAX (0x00800) // 2k max
96+
#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start)
97+
#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512)
98+
99+
#else
100+
#error "no internal flash storage support for this MCU"
101+
#endif
102+
103+
#if !defined(FLASH_MEM_SEG2_START_ADDR)
104+
#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment
105+
#define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment
106+
#endif
107+
108+
#define FLASH_FLAG_DIRTY (1)
109+
#define FLASH_FLAG_FORCE_WRITE (2)
110+
#define FLASH_FLAG_ERASED (4)
111+
static __IO uint8_t flash_flags = 0;
112+
static uint32_t flash_cache_sector_id;
113+
static uint32_t flash_cache_sector_start;
114+
static uint32_t flash_cache_sector_size;
115+
static uint32_t flash_tick_counter_last_write;
116+
117+
void flash_bdev_init(void) {
118+
flash_flags = 0;
119+
flash_cache_sector_id = 0;
120+
flash_tick_counter_last_write = 0;
121+
}
122+
123+
uint32_t flash_bdev_num_blocks(void) {
124+
return FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS;
125+
}
126+
127+
void flash_bdev_flush(void) {
128+
if (flash_flags & FLASH_FLAG_DIRTY) {
129+
flash_flags |= FLASH_FLAG_FORCE_WRITE;
130+
while (flash_flags & FLASH_FLAG_DIRTY) {
131+
NVIC->STIR = FLASH_IRQn;
132+
}
133+
}
134+
}
135+
136+
static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) {
137+
uint32_t flash_sector_start;
138+
uint32_t flash_sector_size;
139+
uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
140+
if (flash_sector_size > FLASH_SECTOR_SIZE_MAX) {
141+
flash_sector_size = FLASH_SECTOR_SIZE_MAX;
142+
}
143+
if (flash_cache_sector_id != flash_sector_id) {
144+
flash_bdev_flush();
145+
memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size);
146+
flash_cache_sector_id = flash_sector_id;
147+
flash_cache_sector_start = flash_sector_start;
148+
flash_cache_sector_size = flash_sector_size;
149+
}
150+
flash_flags |= FLASH_FLAG_DIRTY;
151+
led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on
152+
flash_tick_counter_last_write = HAL_GetTick();
153+
return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
154+
}
155+
156+
static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) {
157+
uint32_t flash_sector_start;
158+
uint32_t flash_sector_size;
159+
uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
160+
if (flash_cache_sector_id == flash_sector_id) {
161+
// in cache, copy from there
162+
return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
163+
}
164+
// not in cache, copy straight from flash
165+
return (uint8_t*)flash_addr;
166+
}
167+
168+
static uint32_t convert_block_to_flash_addr(uint32_t block) {
169+
if (block < FLASH_MEM_SEG1_NUM_BLOCKS) {
170+
return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE;
171+
}
172+
if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) {
173+
return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE;
174+
}
175+
// can add more flash segments here if needed, following above pattern
176+
177+
// bad block
178+
return -1;
179+
}
180+
181+
void flash_bdev_irq_handler(void) {
182+
if (!(flash_flags & FLASH_FLAG_DIRTY)) {
183+
return;
184+
}
185+
186+
// This code uses interrupts to erase the flash
187+
/*
188+
if (flash_erase_state == 0) {
189+
flash_erase_it(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
190+
flash_erase_state = 1;
191+
return;
192+
}
193+
194+
if (flash_erase_state == 1) {
195+
// wait for erase
196+
// TODO add timeout
197+
#define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET)
198+
if (!flash_erase_done()) {
199+
return;
200+
}
201+
flash_erase_state = 2;
202+
}
203+
*/
204+
205+
// This code erases the flash directly, waiting for it to finish
206+
if (!(flash_flags & FLASH_FLAG_ERASED)) {
207+
flash_erase(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
208+
flash_flags |= FLASH_FLAG_ERASED;
209+
return;
210+
}
211+
212+
// If not a forced write, wait at least 5 seconds after last write to flush
213+
// On file close and flash unmount we get a forced write, so we can afford to wait a while
214+
if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || sys_tick_has_passed(flash_tick_counter_last_write, 5000)) {
215+
// sync the cache RAM buffer by writing it to the flash page
216+
flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
217+
// clear the flash flags now that we have a clean cache
218+
flash_flags = 0;
219+
// indicate a clean cache with LED off
220+
led_state(PYB_LED_RED, 0);
221+
}
222+
}
223+
224+
bool flash_bdev_readblock(uint8_t *dest, uint32_t block) {
225+
// non-MBR block, get data from flash memory, possibly via cache
226+
uint32_t flash_addr = convert_block_to_flash_addr(block);
227+
if (flash_addr == -1) {
228+
// bad block number
229+
return false;
230+
}
231+
uint8_t *src = flash_cache_get_addr_for_read(flash_addr);
232+
memcpy(dest, src, FLASH_BLOCK_SIZE);
233+
return true;
234+
}
235+
236+
bool flash_bdev_writeblock(const uint8_t *src, uint32_t block) {
237+
// non-MBR block, copy to cache
238+
uint32_t flash_addr = convert_block_to_flash_addr(block);
239+
if (flash_addr == -1) {
240+
// bad block number
241+
return false;
242+
}
243+
uint8_t *dest = flash_cache_get_addr_for_write(flash_addr);
244+
memcpy(dest, src, FLASH_BLOCK_SIZE);
245+
return true;
246+
}
247+
248+
#endif // !defined(MICROPY_HW_SPIFLASH_SIZE_BITS)

ports/stm32/spibdev.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2017-2018 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "py/obj.h"
28+
#include "storage.h"
29+
30+
#if defined(MICROPY_HW_SPIFLASH_SIZE_BITS)
31+
32+
#include "drivers/memory/spiflash.h"
33+
#include "genhdr/pins.h"
34+
35+
STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = {
36+
.base = {&mp_machine_soft_spi_type},
37+
.delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY,
38+
.polarity = 0,
39+
.phase = 0,
40+
.sck = &MICROPY_HW_SPIFLASH_SCK,
41+
.mosi = &MICROPY_HW_SPIFLASH_MOSI,
42+
.miso = &MICROPY_HW_SPIFLASH_MISO,
43+
};
44+
45+
STATIC const mp_spiflash_t spiflash = {
46+
.cs = &MICROPY_HW_SPIFLASH_CS,
47+
.spi = (mp_obj_base_t*)&spiflash_spi_bus.base,
48+
};
49+
50+
void spi_bdev_init(void) {
51+
mp_spiflash_init((mp_spiflash_t*)&spiflash);
52+
}
53+
54+
bool spi_bdev_readblock(uint8_t *dest, uint32_t block) {
55+
// we must disable USB irqs to prevent MSC contention with SPI flash
56+
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
57+
58+
mp_spiflash_read((mp_spiflash_t*)&spiflash,
59+
block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest);
60+
61+
restore_irq_pri(basepri);
62+
63+
return true;
64+
}
65+
66+
bool spi_bdev_writeblock(const uint8_t *src, uint32_t block) {
67+
// we must disable USB irqs to prevent MSC contention with SPI flash
68+
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
69+
70+
int ret = mp_spiflash_write((mp_spiflash_t*)&spiflash,
71+
block * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src);
72+
73+
restore_irq_pri(basepri);
74+
75+
return ret == 0;
76+
}
77+
78+
#endif // defined(MICROPY_HW_SPIFLASH_SIZE_BITS)

0 commit comments

Comments
 (0)