The flash driver provided in the SDK package can communicate with the flashes as listed in Flash.
If a different external flash is being used, the flash driver will need certain modifications and configuration changes to work properly. This guide will help in the process of developing/modifying the flash driver to suit the custom external flash being used.
The QSPI interface present in the SOC can support only the 1S-1S-1S mode or the 1S-1S-4S modes for reading from the flash.
qspi_flash_diag
example : QSPI Flash Diag. This example communicates with the flash in 1S-1S-1S mode and queries the flash for the SFDP table (if SFDP is supported by the flash) among other things. The logs from this example would be required later to configure the flash driver.qspi_flash_transfer
example : QSPI Flash TransferRefer the example page QSPI Flash Diag on building this application.
You will need have to initialize the SOC in no boot mode as mentioned in SOC Initialization Using CCS Gels and also load and run this example using CCS, as mentioned in CCS Launch, Load and Run.
Take logs printed by the example and save it in a txt file. We would need to refer these logs later while configuring the flash driver.
The flash driver in the SDK composes of two layers :
The application should only use the APIs from the generic flash layer, this makes sure that there is no dependency on a particular flash type. This layer mostly needs no modifications to support a new flash. The generic flash driver has 5 major functions which will internally just call registered callbacks specific to the device. They are :
Out of these, the Flash_open is the most important one. That is where the flash would be configured to work in a specific mode and also set the NOR SPI controller to talk to the flash. The callbacks to these will be implemented in the device specific layer.
There are 3 files needed per flash in the device specific layer as per the current driver structure :
flash_nor_qspi.c
flash_nor_qspi.h
flash_nor_qspi_device_<flash-part-number>.c
These files are located in the ${SDK_ROOT_DIRECTORY}/source/board/flash
folder. For example we have flash_nor_qspi.c
, flash_nor_qspi.h
and flash_nor_qspi_device_GD25B64C.c
files for the GD25B64C device. These can be edited to support the new flash device. The implementation of the 5 callbacks mentioned in the above section can be found in flash_nor_qspi.c
. A new device data file (similar to flash_nor_qspi_device_GD25B64C.c
) needs to created with the appropriate flash part number. Copy from the existing file and change just the flash part numbers for now. Other details can be updated based on specification.
To enable build support for this file, add it to the makefile ${SDK_ROOT_DIRECTORY}/source/board/makefile.{soc}.{core}.ti-arm-clang
under FILES_common.
The flash sysconfig also should be updated so that later in examples the flash can be selected appropriately. For this open the /source/board/.meta/flash/flash_{soc}.syscfg.js
file. The object flash_devices
will have a number of entries corresponding to the currently supported flashes. Add a new entry corresponding the new flash.
flash_nor_qspi_device_<flash_part_number>.c
filenamegFlashNorQspiFxns
Flash_NorQspiDevDefines
and Flash_Attrs
in flash_nor_qspi.h
. Please refer gFlashNorQspiDeviceDefines_GD25B64C
and gFlashNorQspiAttrs_GD25B64C
for GD25B64C.Confirm that the files build and the new flash device is selectable in sysconfig. We can now update the files according to the new flash device.
In order to program the flash device and NOR SPI controller these are the bare minimum data required from the flash :
Enabling a specific protocol or setting the dummy cycles is done by writing to various configuration registers in the flash. These data about the flash can be found out in 2 ways, from the flash datasheet or SFDP (Serial Flash Discoverable Parameters) standard. Strictly speaking the SFDP is not a complete replacement for the datasheet, but SFDP can provide data about all the details mentioned above. If the custom flash device supports SFDP, we can use that. If not, we'll have to rely on the flash datasheet to get these informations.
The Serial Flash Discoverable Parameters (SFDP) is a standard which provides a consistent method of describing the functional and feature capabilities of the flash device in a standard set of internal parameter tables. This table can be queried to identify the configurations and adjustments needed to set the flash in a desired state.
The parsing of the SFDP table is time consuming. Considering this, the SFDP parsing feature in this SDK is tied with a diagnostic example of the NOR SPI driver. In flashes where the SFDP is supported, this example can be used to parse the details into a config structure which can aid in writing the custom flash driver. As of now the SFDP parsing in the SDK supports JEDS216D standard.
The qspi_flash_diag
example reads the SFDP table (in 1S-1S-1S mode) and prints the parsed result in the form of a struct which can be used to fill in your own device defines struct. Here is a sample output:
Comparing this output and the definitions in the flash_nor_qspi_device_<flash_part_number>.c
file (This should currently have data corresponding to the GD25B64C flash device), we can update the different struct member values and macros like FLASH_PAGE_SIZE and FLASH_BLOCK_SIZE. Note, the sample output given here is from GD25B64C device.
Here are the changes to look out for in the driver depending on the SFDP parsed table print:
qeType Value | Implication |
---|---|
0 | Device does not have a QE bit. Device detects 1-1-4 and 1-4-4 reads based on instruction. |
1 | QE is bit 1 of status register 2. It is set via Write Status with two data bytes where bit 1 of the second byte is one. It is cleared via Write Status with two data bytes where bit 1 of the second byte is zero. Writing only one byte to the status register has the side-effect of clearing status register 2, including the QE bit. |
2 | QE is bit 6 of status register 1. It is set via Write Status with one data byte where bit 6 is one. It is cleared via Write Status with one data byte where bit 6 is zero |
3 | QE is bit 7 of status register 2. It is set via Write status register 2 instruction 3Eh with one data byte where bit 7 is one. It is cleared via Write status register 2 instruction 0x3E with one data byte where bit 7 is zero. The status register 2 is read using instruction 0x3F . |
4 | QE is bit 1 of status register 2. It is set via Write Status with two data bytes where bit 1 of the second byte is one. It is cleared via Write Status with two data bytes where bit 1 of the second byte is zero. Writing one byte to the status register does not modify status register 2. |
5 | QE is bit 1 of the status register 2. Status register 1 is read using Read Status instruction 0x05 . Status register 2 is read using instruction 0x35 . QE is set via Write Status instruction 01h with two data bytes where bit 1 of the second byte is one. It is cleared via Write Status with two data bytes where bit 1 of the second byte is zero. |
6 | QE is bit 1 of the status register 2. Status register 1 is read using Read Status instruction 0x05 . Status register 2 is read using instruction 0x35 , and status register 3 is read using instruction 0x15 . QE is set via Write Status Register instruction 0x31 with one data byte where bit 1 is one. It is cleared via Write Status Register instruction 0x31 with one data byte where bit 1 is zero. |
Flag set | Operation |
---|---|
seq444Enable[0] | Enable quad mode as per qeType description above, then issue instruction 0x38 |
seq444Enable[1] | Issue instruction 0x38 |
seq444Enable[2] | Issue instruction 0x35 |
seq444Enable[3] | Device uses a read-modify-write sequence of operations: read the XSPI_NOR_QUAD_MODE_CFG_ADDR (Make sure to add XSPI_NOR_VREG_OFFSET ) using XSPI_NOR_CMD_RDREG command and set bit XSPI_NOR_QUAD_MODE_CFG_BIT_LOCATION to 1. Now write the modified value using XSPI_NOR_CMD_WRREG . |
seq444Enable[4] | If this flag is set, don't care about the seq444Disable array. This is again a read-modify-write. Use the XSPI_NOR_CMD_RDREG cmd without any address, set bit 7 to 0. Now write back using 0x61 cmd. For disabling follow the same procedure, but set bit 7 to 1 instead. |
Flag set | Operation |
---|---|
seq444Disable[0] | Issue instruction 0xFF |
seq444Disable[1] | Issue instruction 0xF5 |
seq444Disable[2] | Device uses a read-modify-write sequence of operations: read the XSPI_NOR_QUAD_MODE_CFG_ADDR (Make sure to add XSPI_NOR_VREG_OFFSET ) using XSPI_NOR_CMD_RDREG command and set bit XSPI_NOR_QUAD_MODE_CFG_BIT_LOCATION to 0. Now write the modified value using XSPI_NOR_CMD_WRREG . |
seq444Disable[3] | Issue soft reset by sending XSPI_NOR_CMD_RSTEN cmd followed by XSPI_NOR_CMD_RSTMEM cmd. |
flash_nor_qspi_device_<flash_part_number>.c
.This section can be ignored if the flash supports SFDP.
All the details regarding the flash including fast read opcodes, supported erase sizes, dummy clocks needed for each instruction and flash configuration registers information will be available from the flash data sheet.
flash_nor_qspi_device_<flash_part_number>.c
file. Make necessary changes in the Flash_norQspiOpen
function to set the 4 byte addressing mode correctly. If it is a case of separate opcodes, you only need to set this for the NOR SPI controller. If it needs a register write to one of the flash config registers, then that needs to be done.flash_nor_qspi.c
file, Flash_norQspiQuadReadEnableEnable
function. For this flash QE is bit 1 of the status register 2. Status register 1 is read using Read Status instruction 0x05
. Status register 2 is read using instruction 0x35
. QE is set via Write Status instruction 01h with two data bytes where bit 1 of the second byte is one. Update the implementation of this function as specified in the datasheet.qspi_flash_transfer
example QSPI Flash Transfer using SysConfig GUI to select the new flash device you have added.qspi_flash_transfer
example, update the example.syscfg for QSPI bootloader (sbl_qspi
) SBL QSPI and flash writer (sbl_uart_uniflash
) SBL UART Uniflash