SPI Flash

In my bare metal experiments with the STM32 MicroMod processor card I tried different ways to send image data to the e-ink display. My first plan was to store images in the internal flash memory along with the code to display them, reading them in the same way as data in RAM. This sounded like a nice idea until I realised that I had confused the amounts of internal and external flash on the card. With only 1MB internal flash there was only room for about 8 images. With 16MB external flash there would be room for many more. Unfortunately, that meant storing and retrieving the data from external flash, which is not accessed in the same way as RAM.

SPI Revisited

External flash is accessed via a Serial Peripheral Interface (SPI) bus on the processor card. It's a nice touch that SparkFun added this storage on the card and, while some developers might not like that it ties up the SPI3 bus, it's very convenient if you need a bit of fixed storage beyond the processor's internal flash memory.

I was hoping that the dfu-util tool I use to program the processor, with help from the bootloader installed on it, could be used to program the external flash from my development machine. It didn't seem to be possible to do that, so I wrote a bare metal program to receive data sent via the UART and write it into the external flash. A new version of the slideshow program I had written for the internal flash was created, reading from the external flash instead, and it was possible to look at the images stored there.

With all the groundwork done, getting Inferno to use the external flash is “simply” a matter of bringing over the code to interact with the flash memory controller (a Winbond W25Q128), adapting the SPI code to be able to work with either of the SPI buses in use (one for the display, the other for the flash), and writing a simple device driver to expose the device to Inferno.

A simple flash device

There are existing flash device drivers and file systems for Inferno, so I thought about trying to reuse as much of those as possible, but I didn't want to have to reformat the image data already in the external flash memory. For convenience I simply passed read calls on to the low-level API I had already written to access the flash, exposing the data via a data file. The init script binds the device to the /dev/flash directory which also contains a info file that shows basic information about the device:

stm32f405$ ls /dev/flash
data
info
stm32f405$ cat /dev/flash/info ; echo
manufacturer=ef device=17

It's easiest to read image data from the flash memory with the dd utility. Since I had left the first 4K of flash free for my slideshow program's configuration information, the images start 8 blocks (512 bytes per block) from the start of the memory. (The flash actually uses 256 byte blocks but that's hidden from Inferno.) Reading the first image (250 blocks in size) is therefore just a matter of specifying the -iseek option to dd:

stm32f405$ dd -if /dev/flash/data -iseek 8 -count 250 | xd
1+0 records in
1+0 records out
0000000 00000004 04040400 00000000 00000000
0000010 00000000 00000000 00000000 00000000
0000020 00000000 00000000 00000000 00000000
...

A more useful application of this is to send it to the e-ink device, which is simply a matter of using the -of option:

stm32f405$ dd -if /dev/flash/data -iseek 8 -count 250 -of /dev/ink/data

Redirection can also be used, but there's no need to involve stdout here.


David Boddie
14 March 2023