5.DA14531 SPI Flash¶
The following section details how to use the DA14531 Serial Peripheral Interface (SPI) to read/write a serial flash memory. Both the PRO and USB development kits contain a serial flash memory and we will use this to demonstate how to use the SPI flash functionality provided with SDK6.
Note
You must have created a modified version of theempty_peripheral_templateexample project, as described in theInitial Projectchapter, before proceeding!
5.1.SPI Flash Memory Layout¶
Before using the SPI flash it is important to remember that, depending upon the operating mode, the SDK will use some of the flash. These areas should not be written to or erased by the user application. The SPI flash used on the PRO and USB development kits is the Macronix MX25R2035. This is a 2Mb (256KByte) device and the areas used by the SDK are detailed in the following table.
Flash Address |
Size |
Description |
---|---|---|
0x0000 0000 |
Up to 48kB |
If the application code is stored in flash then it is located here. |
0x0000 BD80 |
Up to 74kB |
Available for user data storage. |
0x0001 E000 |
Up to 8kB |
If the bonding table is located in flash then it is stored here. The size of the table is defined in app_bond_db.h. |
0x0003 FFFF |
Up to 128kB |
Available for user data storage. |
5.2.Using the SPI Flash Driver¶
The following section provides step-by-step instructions showing how to update the modifiedempty_peripheral_templateexample project you created in theInitial Projectchapter to interface with a SPI Flash using the driver provided with SDK6.
5.2.1.Adding the SPI Flash Driver¶
The SPI flash driver is implemented in two files (spi_531.candspi_flash.c) and these have already been added to theempty_peripheral_templateexample project.
5.2.2.Initializing the SPI Flash Driver¶
The SPI flash used on the PRO and USB development kits is the Macronix MX25R2035. We need to tell the flash driver that this is the flash we are using and also define the SPI configuration that should be used when communicating with it. This configuration is contained within two data structures that need to be added to theuser_periph_setup.cfile (just after the UART configuration -uart_cfg
):
/* Default SPI configuration */staticconstspi_cfg_tspi_cfg={.spi_ms=SPI_MS_MODE_MASTER,.spi_cp=SPI_CP_MODE_0,.spi_speed=SPI_SPEED_MODE_4MHz,.spi_wsz=SPI_MODE_8BIT,.spi_cs=SPI_CS_0,.cs_pad.port=SPI_EN_PORT,.cs_pad.pin=SPI_EN_PIN,#if defined (__DA14531__).spi_capture=SPI_MASTER_EDGE_CAPTURE,#endif};/* SPI flash configuration - assumes use of a Macronix MXR2035F as this ispresent on the DA145xx PRO development kit */staticconstspi_flash_cfg_tspi_flash_cfg={.dev_index=MX25R2035F_DEV_INDEX,.jedec_id=MX25V2035F_JEDEC_ID,.chip_size=MX25V2035F_CHIP_SIZE,};
To use the above data structures the following header files must be included inuser_periph_setup.c:
#include"spi.h"#include"spi_flash.h"
Finally we can initialize the flash driver using the above configuration by adding the following to theperiph_setup
function (just beforeset_pad_functions
):
// Initialize interface to SPI flash so we can use it from within the applicationspi_flash_configure_env(&spi_flash_cfg);spi_initialize(&spi_cfg);
5.2.3.Disabling HW Reset¶
On the DA14531 development kits boards P0_0 is used as the SPI MOSI (data out) signal. This pin is also the hardware reset input to the DA14531 and so before it can be used as SPI MOSI the reset functionality must be disabled. This can be accomplished by adding the following code to the start ofuser_on_init
contained withinempty_peripheral_template.c
/ /禁用HW RST P0_0所以它可以作为SPIMOSI.GPIO_Disable_HW_Reset();
5.2.4.Erasing SPI flash¶
Now that the driver and GPIO pins have been initialized we can perform various actions such as erasing, writing and reading the flash memory. We will perform these actions from within theuser_on_init
function contained withinuser_empty_peripheral_template.cand so need to add the SPI flash driver header to this file as follows:
#include"spi_flash.h"
Now, within theuser_on_init
function, add the following code to erase the flash sector that starts at address 0x20000:
int8_tret;ret=spi_flash_block_erase(0x20000,SPI_FLASH_OP_SE);arch_printf("\n\rErase Status: %d",ret);
Note
If you want to erase more that one sector then it is strongly recommend that the watchdog is reloaded between each erase to ensure that it does not expire! This can be acheived by adding a call towdg_reload(WATCHDOG_DEFAULT_PERIOD);
after each sector erase operation.
When you build the project and run on your target you should see the following message being output via the serial debug port:
5.2.5.Writing to SPI Flash¶
Now that the flash sector has been erased we can write some data to it. To do this add the following code to theuser_on_init
function just after the code you added to erase the flash:
uint16_tbytes_written;uint8_tdata[8]={0,1,2,3,4,5,6,7};ret=spi_flash_write_data(&data[0],0x20000,sizeof(data),&bytes_written);arch_printf("\n\rWrite Status: %d",ret);arch_printf("\n\rBytes Written: %d",bytes_written);
When you rebuild the project and run it on your target you should see the following message being output via the serial debug port:
5.2.6.Reading from SPI Flash¶
Finally we can read back the data written in the following step by adding the following code to theuser_on_init
function just after the code you added to write to the flash:
uint16_tbytes_read;uint8_tdata_read[8]={0};ret=spi_flash_read_data(&data_read[0],0x20000,sizeof(data_read),&bytes_read);arch_printf("\n\rRead Status: %d",ret);arch_printf("\n\rBytes Read:");while(bytes_read){arch_printf(" %d",data_read[sizeof(data_read)-bytes_read]);bytes_read--;}
When you rebuild the project and run it on your target you should see the following message being output via the serial debug port:
5.3.Sleep Mode¶
After booting from flash the memory is left in its active state, allowing us to perform the read, write and erase operation described above. In order to reduce current consumption to a minimum the flash memory can be put into sleep mode by calling thespi_flash_power_down
function. Once the flash has entered sleep mode thespi_flash_release_from_powerdown
must be called to wake it before performing further read, write or erase operations.
5.4.Re-enabling HW Reset¶
一旦所有flash操作完整模型te the reset functionality of pin P0_0 can be restored, allowing switch SW1 on the development kit board to reset the DA14531. To do this add the following to the end of theuser_on_init
function:
// Re-enable HW reset input (must be disabled if/when further operations on// external flash are performed) - must set as input first!GPIO_ConfigurePin(SPI_DO_PORT,SPI_DO_PIN,INPUT_PULLDOWN,PID_GPIO,false);GPIO_Enable_HW_Reset();
5.5.Putting it all Together¶
Once all of the above modifications have been made youruser_on_init
function should look like the one shown below:
voiduser_on_init(void){arch_printf("\n\r%s",__FUNCTION__);default_app_on_init();/ /禁用HW RST P0_0所以它可以作为SPIMOSI.GPIO_Disable_HW_Reset();int8_tret;ret=spi_flash_block_erase(0x20000,SPI_FLASH_OP_SE);arch_printf("\n\rErase Status: %d",ret);uint16_tbytes_written;uint8_tdata[8]={0,1,2,3,4,5,6,7};ret=spi_flash_write_data(&data[0],0x20000,sizeof(data),&bytes_written);arch_printf("\n\rWrite Status: %d",ret);arch_printf("\n\rBytes Written: %d",bytes_written);uint16_tbytes_read;uint8_tdata_read[8]={0};ret=spi_flash_read_data(&data_read[0],0x20000,sizeof(data_read),&bytes_read);arch_printf("\n\rRead Status: %d",ret);arch_printf("\n\rBytes Read:");while(bytes_read){arch_printf(" %d",data_read[sizeof(data_read)-bytes_read]);bytes_read--;}// Reduce power consumption by putting flash into sleep mode */spi_flash_power_down();// Re-enable HW reset input (must be disabled if/when further operation on// external flash are performed) - must set as input first!GPIO_ConfigurePin(SPI_DO_PORT,SPI_DO_PIN,INPUT_PULLDOWN,PID_GPIO,false);GPIO_Enable_HW_Reset();}