How to create a driver to handle External flash memory using SPI?
Welcome back!
In this last part we'll continue creating driver functions for STM32 microcontroller to interact with external memory device through the SPI peripheral
WriteData(void:( This WriteData function writes the SPI Flash memory with the data from the audio files by taking into consideration the audio file size and calculating the required memory size. Starting from the very first sector, the erase sector command is performed corresponding to the required size; once completed, the audio files are programmed into the external Flash memory by using the sendPageProgram instruction and waiting until write in progress bit of the status register gets cleared before writing the next page.
#define SPI_FLASH_PAGESIZE 256
void WriteData(void)
{
uint32_t sizeOfBitmaps = (uint32_t)(&__MY_AUDIOFILES_END)- (uint32_t) (&__MY_AUDIOFILES_START);
//erase sections required
uint32_t address = 0x000000;
do
{
sendWriteEnable();
sendSectorErase(address);
//wait until WIP is cleared
uint32_t status;
do
{
status = readStatusRegister();
} while (status & STATUS_WIP);
address += 0x001000;
} while (address < sizeOfBitmaps);
constuint8_t* bitmapStart = &__MY_AUDIOFILES_START;
//page program required pages
address = 0x00000000;
do
{
sendWriteEnable();
sendPageProgram(address, bitmapStart + address, SPI_FLASH_PAGESIZE);
//wait until WIP is cleared
uint32_t status;
do
{
status = readStatusRegister();
} while (status & STATUS_WIP);
address += 256;
} while (address < sizeOfBitmaps);
}
readData(uint32_t address24, uint8_t* buffer, uint32_t length) This function reads the content from the serial flash memory. The data is read from the memory location specified by the instruction code CMD_READ 03h followed by a 24-bit address. After the address is received, the data byte of the addressed memory location will be shifted out and then address is automatically incremented to the next higher address after each byte of data is shifted out allowing for a continuous stream of data.
#define CMD_READ 0x03
void readData(uint32_t address24, uint8_t* buffer, uint32_t length)
{
FLASH_CS_LOW();
uint8_t bufferOut[4];
bufferOut[0] = CMD_READ;
bufferOut[1] = (address24 >> 16) & 0xFF;
bufferOut[2] = (address24 >> 8) & 0xFF;
bufferOut[3] = address24 & 0xFF;
if (HAL_SPI_Transmit(&flashSPIh, bufferOut, sizeof(bufferOut), 1000) !=HAL_OK)
{
/* Transfer error in transmission process */
Error_Handler();
}
if (HAL_SPI_Receive(&flashSPIh, bufferIn, sizeof(bufferIn), 1000) != HAL_OK)
{
/* Transfer error in transmission process */
Error_Handler();
}
FLASH_CS_HIGH();
}
SPIFlash_RunTest(void) This function is just a test, which evaluates and verifies that the memory device is ready for the flash write operation. It checks if the Flash memory is protected by reading the status register; if it is protected, unprotects it and then checks if there is any write in progress and waits till it gets cleared, and then issues the write enable command.
uint32_t SPIFlash_RunTest(void)
{
//RDSR test
statusReg = readStatusRegister();
/*Unprotect if protected*/
sendWriteEnable();
while(statusReg & 0x38)
{
statusReg &= ~0x38;
writeStatusRegister(0x01, statusReg);
statusReg = readStatusRegister();
}
sendWriteEnable();
statusReg = readStatusRegister();
//wait until WIP is cleared
uint32_t status;
do
{
status = readStatusRegister();
} while (status & STATUS_WIP);
//WREN
sendWriteEnable();
return 0;
}
Macro Settings: • #define FLASH_CS_PIN: This macro defines a GPIO pin for use as the SPI chip select line (NSS) for the external flash memory device• #define FLASH_CS_GPIO_PORT: This macro defines the GPIO port for the software NSS pin• #define FLASH_CS_LOW(): This macro drives the CS pin low• #define FLASH_CS_HIGH(): This macro drives the CS pin high• #define FLASH_CS_GPIO_CLK_ENABLE(): This macro enables the GPIO pin RCC clock• #define FLASH_CS_GPIO_CLK_DISABLE(): This macro disables the GPIO pin RCC clock• #define SPI_FLASH_PAGESIZE 256: This macro defines the External Flash memory size When we execute this example code via STM32CubeIDE, the audio files are programmed into the external SPI flash memory using the driver we created. We can also use the driver to read back the data and playback audio using the setup from the previous article. Conclusion: In this article, we demonstrated how to create a driver using the SPI interface, which is available in all STM32 microcontrollers, to access an external serial flash memory. We went through a sample firmware implementation that can be easily tailored to any other STM32. We also went through the usage of SPI flash driver APIs created to implement the memory write/read operations and store the audio files. In the next article we will cover how to create an external loader file, which will allow us to program the external memory using the STM32CubeProgrammer.