MTB CAT1 Peripheral driver library
SMIF (Serial Memory Interface)

General Description

The SPI-based communication interface to the external quad SPI (QSPI) high-speed memory devices.

The functions and other declarations used in this driver are in cy_smif.h and cy_smif_memslot.h (if used). If you are using the ModusToolbox QSPI Configurator, also include cycfg_qspi_memslot.h.

SMIF: Serial Memory Interface: This IP block implements an SPI-based communication interface for interfacing external memory devices to PSoC. The SMIF supports SPI, dual SPI (DSPI), quad SPI (QSPI), dual QSPI and octal SPI.


The primary usage model for the SMIF is that of an external memory interface. The SMIF is capable of interfacing with different types of memory, up to four types.

SMIF driver is divided into three layers

The SMIF API is divided into the low-level functions and memory-slot functions. Use the low level API for the SMIF block initialization and for implementing a generic SPI communication interface using the SMIF block.

The memory slot API has functions to implement the basic memory operations such as program, read, erase etc. These functions are implemented using the memory parameters in the memory device configuration data structure. The Cy_SMIF_MemInit() API initializes all the memory slots based on the settings in the array.

Above image is applicable only for SMIF v3 IP.
Above image is applicable only for SMIF v1 IP.

SMIF Configuration Tool is a stand-alone application, which is a part of PDL (Creator) and could be found in <PDL_DIR>/tools/<OS_DIR>/SMIFConfigurationTool (e.g. for PDL 3.0.0 and Windows OS PDL/3.0.0/tools/win/SMIFConfigurationTool).

In ModusToolbox this tool is called QSPI Configurator. QSPI Configurator is a part of PSoC 6 Software Library and can be found in <ModusToolbox>/tools/qspi-configurator-1.1

Tool generates *.c and *.h file with configuration structures. These configuration structures are input parameters for cy_smif_memslot API level

The driver is not responsible for external memory persistence. You cannot edit a buffer during the Read/Write operations. If there is a memory error, the SMIF ip block can require a reset. To determine if this has happened, check the SMIF busy status using Cy_SMIF_BusyCheck() and implement a timeout. Reset the SMIF block by toggling CTL.ENABLED. Then reconfigure the SMIF block.

For the Write operation, check that the SMIF driver has completed transferring by calling Cy_SMIF_BusyCheck(). Also, check that the memory is available with Cy_SMIF_MemIsBusy() before proceeding.

Simple example of external flash memory programming using low level SMIF API. All steps mentioned in example below are incorporated in Cy_SMIF_MemCmdWriteEnable(), Cy_SMIF_MemCmdProgram(), and Cy_SMIF_MemIsBusy() of the memory slot level API.

Example is simplified, without checks of error conditions.
Flash memories need erase operation before programming. Refer to external memory datasheet for specific memory commands.
/* Enable write operation in external memory. Send Write Enable command to
* external memory. */
0x06U, /* External memory write enable command */
CMD_WITHOUT_PARAM, /* Command does not have parameters */
CY_SMIF_SLAVE_SELECT_0, /* External memory connected to nSS0 */
1U, /* Disable nSS after command transfered */
/* Wait while SMIF IP is transferring command to external memory */
uint8_t tst_txBuffer[TX_SIZE]; /* Buffer to put read date */
/* Send page program command to external memory */
0x02U, /* Page Program external memory command */
0U, /* Not last byte, does not disable nSS line */
/* Send programming data to external memory */
Cy_SMIF_TransmitData(SMIF, tst_txBuffer, TX_SIZE, CY_SMIF_WIDTH_SINGLE,
NULL, /* Callback function is not used */
/* Wait while SMIF transfers data */
/* Wait until the memory is programed. Cy_SMIF_MemIsBusy() of memslot
* API level could be used instead */
bool memBusy;
uint8_t readReg = 0U;
/* Read the memory status register */
0x05U, /* Read status register of external memory */
0U, /* Not last byte, does not disable nSS line */
Cy_SMIF_ReceiveData(SMIF, &readReg,
1U, /* Read 1-byte */
NULL, /* Callback function is not used */
/* Check if the SMIF IP is busy */
memBusy = ((readReg & MEM_WIP_MASK) != 0U);

For the Read operation, before accessing the read buffer, check that it is ready by calling Cy_SMIF_GetTxFifoStatus().

Simple example of external flash memory read using low level SMIF API. All steps mentioned in example below are incorporated in Cy_SMIF_MemCmdRead() of the memory slot level API.

Example is simplified, without checks of error conditions.
Refer to external memory datasheet for specific memory commands.
/* Read memory data */
uint8_t address[MEMORY_ADDRESS_SIZE] = {0U,0U,0U}; /* Read from 3-byte 0 address */
uint8_t tst_rxBuffer[RX_SIZE]; /* Buffer to put read date */
0x03U, /* External memory Read command code */
CY_SMIF_WIDTH_SINGLE, /* Normal SPI mode */
CY_SMIF_SLAVE_SELECT_0, /* External memory connected to nSS0 */
0U, /* Not last byte, does not disable nSS line */
Cy_SMIF_ReceiveData(SMIF, tst_rxBuffer, RX_SIZE, CY_SMIF_WIDTH_SINGLE,
NULL, /* Callback function is not used */
/* Check SMIF fishes reading operation */
while(Cy_SMIF_GetTransferStatus(SMIF, &smifContext) == CY_SMIF_RX_BUSY);

The user should invalidate the cache by calling Cy_SMIF_CacheInvalidate() when switching from the MMIO mode to XIP mode.

Configuration Considerations

PDL API has common parameters: base, context, config described in PDL Design section.

See the documentation for Cy_SMIF_Init() and Cy_SMIF_MemInit() for details on the required configuration structures and other initialization topics.

The normal (MMIO) mode is used for implementing a generic SPI/DSPI/QSPI/dual QSPI/octal SPI communication interface using the SMIF block. This interface can be used to implement special commands like Program/Erase of flash, memory device configuration, sleep mode entry for memory devices or other special commands specific to the memory device. The transfer width (SPI/DSPI/QSPI/octal SPI) of a transmission is a parameter set for each transmit/receive operation. So these can be changed at run time.

In a typical memory interface with flash memory, the SMIF is used in the memory mode when reading from the memory and it switches to the normal mode when writing to flash memory. A typical memory device has multiple types of commands.

The SMIF interface can be used to transmit different types of commands. Each command has different phases: command, dummy cycles, and transmit and receive data which require separate APIs.

SMIF Initialization

Create interrupt function and allocate memory for SMIF context structure

void SMIF_Interrupt_User(void)
Cy_SMIF_Interrupt(SMIF, &smifContext);

SMIF driver initialization for low level API usage (cysmif.h)

/* Main configuration paramters*/
#define SMIF_PRIORITY (1U)
#define TIMEOUT_1_S (1000U)
/* Pin initialization */
#if defined (CY_IP_M4CPUSS)
#define SMIF_INTERRUPT smif_interrupt_IRQn
#elif defined (CY_IP_M33SYSCPUSS)
#define SMIF_INTERRUPT smif_interrupt_normal_IRQn
#else /* M7 CPUSS */
#define SMIF_INTERRUPT smif_0_interrupt_IRQn
/* SMIF interrupt initialization */
cy_stc_sysint_t smifIntConfig =
/* .intrSrc */ NvicMux7_IRQn,
/* .cm0pSrc */ SMIF_INTERRUPT,
/* .intrSrc */ SMIF_INTERRUPT, /* SMIF interrupt number (non M0 core)*/
/* .intrPriority */ SMIF_PRIORITY
(void) Cy_SysInt_Init(&smifIntConfig, SMIF_Interrupt_User);
__enable_irq(); /* Enable global interrupts. */
/* Enable SMIF interrupt */
#if (__CORTEX_M == 0)
/* SMIF configuration parameters */
cy_stc_smif_config_t tst_smifConfig =
/* .mode */ CY_SMIF_NORMAL, /* Mode of operation */
/* .deselectDelay */ DESELECT_DELAY, /* Minimum duration of SPI deselection */
/* .rxClockSel */ CY_SMIF_SEL_INVERTED_INTERNAL_CLK, /* Clock source for the receiver clock */
/* .blockEvent */ CY_SMIF_BUS_ERROR /* What happens when there is a read
* to an empty RX FIFO or write to a full TX FIFO
/* SMIF initialization */
Cy_SMIF_Init(SMIF, &tst_smifConfig, TIMEOUT_1_S, &smifContext);
Cy_SMIF_Enable(SMIF, &smifContext);

Additional steps to initialize SMIF driver for memory slot level API usage (cy_smif_memslot.h).

/* Configuration parameters for memory S25FL512S*/
/* Configuration parameters for memory configuration autodetection*/
cy_stc_smif_mem_device_cfg_t autodetectedMemory;
/* .slaveSelect */ CY_SMIF_SLAVE_SELECT_0, /* Determines the slot number where the memory device is placed */
/* .flags */ CY_SMIF_FLAG_MEMORY_MAPPED | CY_SMIF_FLAG_WRITE_ENABLE, /* Determines if the device is memory mapped. If enabled this memory slot will be initialised in System init */
/* .dataSelect */ CY_SMIF_DATA_SEL0, /* Data line selection options for a slave device */
/* .baseAddress */ 0x18000000UL, /* The base address the memory slave is mapped to in the PSoC memory map. Valid when memory mapped mode is enabled */
/* .memMappedSize */ 0xFFE00000UL, /* The size allocated in the PSoC memory map, for the memory slave device. The size is allocated from the base address
* Valid when memory mapped mode is enabled */
/* .dualQuadSlots */ 0x0UL,
/* .deviceCfg */ &S25FL512S, /* Configuration of the device */
/* .mergeTimeout */ CY_SMIF_MERGE_TIMEOUT_256_CYCLES
/* .slaveSelect */ CY_SMIF_SLAVE_SELECT_1, /* Determines the slot number where the memory device is placed */
/* .flags */ CY_SMIF_FLAG_DETECT_SFDP, /* Determines if the device is memory mapped. If enabled this memory slot will be initialised in System init */
/* .dataSelect */ CY_SMIF_DATA_SEL2, /* Data line selection options for a slave device */
/* .baseAddress */ 0x0UL,
/* .memMappedSize */ 0x0UL,
/* .dualQuadSlots */ 0x0UL,
/* .deviceCfg */ &autodetectedMemory, /* Configuration of the device */
/* .mergeTimeout */ CY_SMIF_MERGE_TIMEOUT_256_CYCLES
cy_stc_smif_mem_config_t* smifMemConfigs[NUMBER_OF_EXTERNAL_MEM] = {
cy_stc_smif_block_config_t smifBlockConfig =
/* .memCount */ NUMBER_OF_EXTERNAL_MEM, /* Number of SMIF memories defined */
/* .memConfig */ smifMemConfigs, /* Pointer to the array of memory configuration structures of size memCount */
/* .majorVersion */ 1U, /* Version of the SMIF driver */
/* .minorVersion */ 0U /* Version of the SMIF Driver */
/* Memslot level initialization */
Cy_SMIF_MemInit(SMIF, &smifBlockConfig, &smifContext);
Example does not include initialization of all needed configuration structures (cy_stc_smif_mem_device_cfg_t, cy_stc_smif_mem_cmd_t). SMIF/QSPI Configuration tool generates all configuration structures needed for memslot level API usage.

SMIF XIP Initialization

The eXecute In Place (XIP) is a mode of operation where read or write commands to the memory device are directed through the SMIF without any use of API function calls. In this mode the SMIF block maps the AHB bus-accesses to external memory device addresses to make it behave similar to internal memory. This allows the CPU to execute code directly from external memory. This mode is not limited to code and is suitable also for data read and write accesses. The memory regions available for XIP addresses allocation are defined in a linker script file (.ld).

With SMIF V3 IP, MMIO mode transacations are also allowed when the device is set to XIP mode. However, only blocking SMIF API's are expected to be used for erase or program operations as external flash will be busy for such operation and may not be available for XIP at that moment. Blocking API's will ensure the transaction is complete and then switch back to XIP.

/* SMIF IP initialization */
Cy_SMIF_Init(SMIF, &tst_smifConfig, TIMEOUT_1_S, &smifContext);
Cy_SMIF_MemInit(SMIF, &smifBlockConfig, &smifContext);
/* Set XIP mode */
Cy_SMIF_Enable(SMIF, (cy_stc_smif_context_t *)&smifContext);
Example of input parameters initialization is in SMIF Initialization section.
Functions that called from external memory should be declared with long call attribute.

SMIF XIP On-the-fly encryption

In XIP mode, a cryptography component supports on-the-fly encryption for write data and on-the-fly decryption for read data. On-the-fly encryption/decryption in XIP mode can be enabled by setting the flags CY_SMIF_FLAG_CRYPTO_ENABLE. Encryption and decryption are based on the AES-128 forward block cipher: advanced encryption standard blockcipher with a 128-bit key. KEY[127:0] is a secret (private) key programmed into the CRYPTO_KEY3,...,CRYPTO_KEY0 registers using Cy_SMIF_SetCryptoKey. These registers are software write-only. A software read returns 0. In the SMIF hardware, by applying AES-128 with KEY[127:0] on a plaintext PT[127:0], we get a ciphertext CT[127:0]. In XIP mode, the XIP address is used as the plaintext PT[]. The resulting ciphertext CT[] is used on-the-fly and not software accessible. The XIP address is extended with the CRYPTO_INPUT3, ..., CRYPTO_INPUT0 registers. Cy_SMIF_SetCryptoIV can be used to set initialization vector (96-bits). In XIP mode, the resulting ciphertext CT[] (of the encrypted address) is XORed with the memory transfers read data or write data. Note that the AES-128 block cipher is on the address of the data and not on the data itself.


Rules for PSoC6 QSPI/SMIF Block Usage

  1. All operations must use one or more dummy cycles between the PSoC 6 Command and Address phase (when the PSoC 6 MCU drives the data pins) and the device's Response phase (when the device drives the same data pins). Bus contention may occur if no (zero) dummy cycles are used.
  2. Any transfer that does not allow dummy cycles (such as Register Status Reads) must use the single-bit transfer mode. In single-bit mode, the PSoC 6 drives the Command on the Data0 line and the device responds on the Data1 line, so bus contention cannot occur.

More Information

More information regarding the Serial Memory Interface can be found in the component datasheet and the Technical Reference Manual (TRM). More information regarding the SMIF Configuration Tool are in SMIF Configuration Tool User Guide located in <PDL_DIR>/tools/<OS_DIR>/SMIFConfigurationTool/ folder


VersionChangesReason for Change
2.30 Octal SDR and DDR support using SFDP mode. Octal device support.
Move SFDP related functionality to cy_smif_sfdp.c. Code Enhancements.
Added support for new product families Support for CAT1B and CAT1C devices.
Added new API's:
Following macros renamed:
Support for SFDP 1.0 devices.
Added new API's for CAT1D devices
Support for CAT1D devices.
2.20 Bug fixes in Cy_SMIF_MemEraseSector for Hybrid memory configuration. Updated Cy_SMIF_MemIsReady to use Cy_SysLib_Rtos_Delay and Cy_SysLib_Rtos_DelayUs. Code enhancement.
2.10 New silicon family support. Added extended API for DDR support.
2.0 Reworked the Cy_SMIF_MemRead and Cy_SMIF_MemWrite functions to use polling instead of interrupts. Extend the usability of these functions.
Reworked the length-parameter check in the Cy_SMIF_MemEraseSector function. The Erase operation is not performed and CY_SMIF_SUCCESS is no longer returned when the sectors are not aligned. Fix the user error-handling of the length parameter.
Fixed the address-parameter check in the Cy_SMIF_MemLocateHybridRegion function. CY_SMIF_SUCCESS or CY_SMIF_NOT_HYBRID_MEM is no longer returned when the address exceeds the memory size. Address a defect.
Fixed MISRA 2012 violations. MISRA 2012 compliance.
1.50.1 Minor documentation updates. Documentation improvement.
1.50 Added a new function: Cy_SMIF_MemLocateHybridRegion.
Added a new structure cy_stc_smif_hybrid_region_info_t.
Updated the Cy_SMIF_MemEraseSector and Cy_SMIF_MemCmdSectorErase functions.
Updated the Cy_SMIF_MemSfdpDetect function.
Updated the cy_stc_smif_mem_device_cfg_t structure.
Support for memories with hybrid regions.
1.40.1 The Cy_SMIF_MemInit is changed. Corrected a false assertion during initialization in SFDP mode.
Minor documentation updates.
1.40 The following functions are renamed:
Cy_SMIF_GetTxfrStatus into Cy_SMIF_GetTransferStatus;
Cy_SMIF_Memslot_Init into Cy_SMIF_MemInit;
Cy_SMIF_Memslot_DeInit into Cy_SMIF_MemDeInit;
Cy_SMIF_Memslot_CmdWriteEnable into Cy_SMIF_MemCmdWriteEnable;
Cy_SMIF_Memslot_CmdWriteDisable into Cy_SMIF_MemCmdWriteDisable;
Cy_SMIF_Memslot_IsBusy into Cy_SMIF_MemIsBusy;
Cy_SMIF_Memslot_QuadEnable into Cy_SMIF_MemQuadEnable;
Cy_SMIF_Memslot_CmdReadSts into Cy_SMIF_MemCmdReadStatus;
Cy_SMIF_Memslot_CmdWriteSts into Cy_SMIF_MemCmdWriteStatus;
Cy_SMIF_Memslot_CmdChipErase into Cy_SMIF_MemCmdChipErase;
Cy_SMIF_Memslot_CmdSectorErase into Cy_SMIF_MemCmdSectorErase;
Cy_SMIF_Memslot_SfdpDetect into Cy_SMIF_MemSfdpDetect;
Cy_SMIF_Memslot_CmdProgram into Cy_SMIF_MemCmdProgram;
Cy_SMIF_Memslot_CmdRead into Cy_SMIF_MemCmdRead.
The following ENUMa are renamed:
cy_en_smif_cache_en_t into cy_en_smif_cache_t.
The following MACROs are renamed:
Documentation improvement.
Updated the description of the Cy_SMIF_MemInit() function. Updated the Cy_SMIF_Encrypt() function usage example.
The type of arguments that are not modified by the functions are set to const. Usability improvement.
The Cy_SMIF_MemSfdpDetect() function is updated to support new commands for 4 bytes addressing. Memory devices with new 4 byte addressing commands support.
Added the blocking functions which take care of the busy-status check of the memory: Added new high-level blocking functions.
1.30 The CY_SMIF_CMD_FIFO_WR_RX_COUNT_Msk value is changed to 0x0000FFFFUL. Driver maintenance.
Added the check of the size parameter in the Cy_SMIF_TransmitData() function.
Added conditional check for presence of the SMIF hardware IP.
Fixed the wrong erase command in the SFDP protocol for devices with Erase Type 3.
Updated the General Description section with minor changes. Updated the ordering of the parameters descriptions for some functions. Added the text saying that the Cy_SMIF_MemInit() function is applicable to use the external memory as memory-mapped to PSoC (XIP mode). Added the snippet for the Cy_SMIF_Encrypt() function to show how to use this function. Added below the picture in the Low-Level Functions section the sequence of PDL functions required in a Read or Write transaction. Added the text below the picture about the address. Updated DUMMY COUNT in this picture. Added checking of the size parameter in the Cy_SMIF_TransmitData() function. Documentation improvement.
1.20.1 Added upper limit to size parameter in several functions. Documentation improvement.
1.20 Flattened the organization of the driver source code into the single source directory and the single include directory. Driver library directory-structure simplification.
Added a new return status and transfer width option for the case when the memory command is not supported. Improved the memory command structure usability.
Added register access layer. Use register access macros instead of direct register access using dereferenced pointers. Makes register access device-independent, so that the PDL does not need to be recompiled for each supported part number.
1.11 Fixed internal function that writes to the SMIF FIFO The write function stuck in the loop when write speed in external memory is significantly lower than PSoC CPU core speed and write transfer is not finished during the single function call.
Added optional mode part to the program command flow Extend usability of program command
1.10.1 Added Low Power Callback section Documentation update and clarification
1.10 Fix write to external memory from CM0+ core. Add checks of API input parameters. Minor documentation updates
1.0 Initial version

API Reference

 Data Structures
 Enumerated Types