SMIF (Serial Memory Interface)

group group_smif

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.

Features

  • Standard SPI Master interface

  • Supports single/dual/quad/octal SPI memory devices

  • Supports dual quad SPI mode

  • Design-time configurable support for multiple (up to 4) external serial memory devices

  • eXecute-In-Place (XIP) operation mode for both read and write accesses with 4KB XIP read cache and on-the-fly encryption and decryption

  • Supports external serial memory initialization via Serial Flash Discoverable Parameters (SFDP) standard

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

  • cy_smif.h API

  • cy_smif_memslot.h API

  • SMIF configuration structures

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.

../../../_images/smif_3_0_p01_layers.png

note

Above image is applicable only for SMIF v3 IP.

../../../_images/smif_1_0_p01_layers.png

note

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

warning

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.

warning

Example is simplified, without checks of error conditions.

note

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.  */
    Cy_SMIF_TransmitCommand( SMIF,                            
                            0x06U, /* External memory write enable command */                 
                            CY_SMIF_WIDTH_SINGLE, 
                            CMD_WITHOUT_PARAM, /* Command does not have parameters */
                            CMD_WITHOUT_PARAM, 
                            CY_SMIF_WIDTH_SINGLE, 
                            CY_SMIF_SLAVE_SELECT_0, /* External memory connected to nSS0 */
                            1U, /* Disable nSS after command transfered */
                            &smifContext); 
    
    /* Wait while SMIF IP is transferring command to external memory */
    while(Cy_SMIF_BusyCheck(SMIF));

    uint8_t tst_txBuffer[TX_SIZE]; /* Buffer to put read date */
    
    /* Send page program command to external memory */
    Cy_SMIF_TransmitCommand( SMIF,                             
                            0x02U,   /* Page Program external memory command */  
                            CY_SMIF_WIDTH_SINGLE,
                            address, 
                            MEMORY_ADDRESS_SIZE, 
                            CY_SMIF_WIDTH_SINGLE, 
                            CY_SMIF_SLAVE_SELECT_0, 
                            0U, /* Not last byte, does not disable nSS line */
                            &smifContext);
    /* Send programming data to external memory */
    Cy_SMIF_TransmitData(SMIF, tst_txBuffer, TX_SIZE, CY_SMIF_WIDTH_SINGLE, 
                            NULL, /* Callback function is not used */
                            &smifContext);
    
    /* Wait while SMIF transfers data */
    while(Cy_SMIF_BusyCheck(SMIF));

    
    /* Wait until the memory is programed. Cy_SMIF_MemIsBusy() of memslot
     * API level could be used instead */
    bool memBusy;
    
    do
    {
        uint8_t readReg = 0U;
        
        /* Read the memory status register */
        Cy_SMIF_TransmitCommand( SMIF,
                                0x05U, /* Read status register of external memory */               
                                CY_SMIF_WIDTH_SINGLE,
                                CMD_WITHOUT_PARAM, 
                                CMD_WITHOUT_PARAM, 
                                CY_SMIF_WIDTH_SINGLE, 
                                CY_SMIF_SLAVE_SELECT_0, 
                                0U, /* Not last byte, does not disable nSS line */ 
                                &smifContext);
        Cy_SMIF_ReceiveData(SMIF, &readReg,                    
                            1U, /* Read 1-byte */ 
                            CY_SMIF_WIDTH_SINGLE, 
                            NULL, /* Callback function is not used */
                            &smifContext);

        /* Check if the SMIF IP is busy */
        while(Cy_SMIF_BusyCheck(SMIF));

        memBusy = ((readReg & MEM_WIP_MASK) != 0U);
    }
    while(memBusy);
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.

warning

Example is simplified, without checks of error conditions.

note

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 */
    Cy_SMIF_TransmitCommand(SMIF,                            
                            0x03U,    /* External memory Read command code */            
                            CY_SMIF_WIDTH_SINGLE, /* Normal SPI mode */
                            address, 
                            MEMORY_ADDRESS_SIZE, 
                            CY_SMIF_WIDTH_SINGLE,
                            CY_SMIF_SLAVE_SELECT_0, /* External memory connected to nSS0 */
                            0U, /* Not last byte, does not disable nSS line */
                            &smifContext);
    Cy_SMIF_ReceiveData(SMIF, tst_rxBuffer, RX_SIZE, CY_SMIF_WIDTH_SINGLE, 
                            NULL, /* Callback function is not used */
                            &smifContext);
    
    /* 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

cy_stc_smif_context_t smifContext;

void SMIF_Interrupt_User(void)
{
    Cy_SMIF_Interrupt(SMIF, &smifContext);
}
SMIF driver initialization for low level API usage (cysmif.h)
    
    /* Main configuration paramters*/
    #define NUMBER_OF_EXTERNAL_MEM      (2U)
    #define SMIF_PRIORITY               (1U)
    #define TIMEOUT_1_S                 (1000U)
    #define DESELECT_DELAY              (7U)

    /* Pin initialization */
    
    
    /* SMIF interrupt initialization */ 
    cy_stc_sysint_t smifIntConfig =
    {
        #if (CY_CPU_CORTEX_M0P)
            /* .intrSrc */ NvicMux7_IRQn,
            /* .cm0pSrc */ smif_interrupt_IRQn,
        #else
            /* .intrSrc */ smif_interrupt_IRQn, /* SMIF interrupt number (non M0 core)*/
        #endif   
        /* .intrPriority */ SMIF_PRIORITY
    };
    (void) Cy_SysInt_Init(&smifIntConfig, SMIF_Interrupt_User);
    
    __enable_irq(); /* Enable global interrupts. */
    
    /* Enable SMIF interrupt */
    #if (__CORTEX_M == 0)
        NVIC_EnableIRQ(NvicMux7_IRQn);
    #else
        NVIC_EnableIRQ(smif_interrupt_IRQn);
    #endif
    
    /* 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*/
    cy_stc_smif_mem_device_cfg_t S25FL512S;
    /* Configuration parameters for memory configuration autodetection*/
    cy_stc_smif_mem_device_cfg_t autodetectedMemory;
    
    cy_stc_smif_mem_config_t memSs0 =    
    { 
        /* .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 */    
    };
    
    cy_stc_smif_mem_config_t memSs1 =    
    { 
        /* .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 */    
    };
    
    cy_stc_smif_mem_config_t* smifMemConfigs[NUMBER_OF_EXTERNAL_MEM] = {
        &memSs0,
        &memSs1,
    };
    
    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);

note

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).


    /* SMIF IP initialization */
    Cy_SMIF_Init(SMIF, &tst_smifConfig, TIMEOUT_1_S, &smifContext);
    Cy_SMIF_SetDataSelect(SMIF, CY_SMIF_SLAVE_SELECT_0, CY_SMIF_DATA_SEL0);
    Cy_SMIF_MemInit(SMIF, &smifBlockConfig, &smifContext);
    
    /* Set XIP mode */
    Cy_SMIF_SetMode(SMIF, CY_SMIF_MEMORY);
    
    Cy_SMIF_Enable(SMIF, (cy_stc_smif_context_t *)&smifContext);

note

Example of input parameters initialization is in SMIF Initialization section.

warning

Functions that called from external memory should be declared with long call attribute.

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

Changelog

Version

Changes

Reason for Change

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_SMIF_SEND_CMPLT into CY_SMIF_SEND_COMPLETE;
CY_SMIF_REC_CMPLT into CY_SMIF_RX_COMPLETE;
CY_SMIF_REC_BUSY into CY_SMIF_RX_BUSY;
CY_SMIF_SEL_INV_INTERNAL_CLK into CY_SMIF_SEL_INVERTED_INTERNAL_CLK;
CY_SMIF_SEL_INV_FEEDBACK_CLK into CY_SMIF_SEL_INVERTED_FEEDBACK_CLK;
cy_en_smif_cache_en_t into cy_en_smif_cache_t.
The following MACROs are renamed:
CY_SMIF_FLAG_WR_EN into CY_SMIF_FLAG_WRITE_ENABLE;
CY_SMIF_FLAG_CRYPTO_EN into CY_SMIF_FLAG_CRYPTO_ENABLE;
CY_SMIF_SFDP_SING_BYTE_00 into CY_SMIF_SFDP_SIGNATURE_BYTE_00;
CY_SMIF_SFDP_SING_BYTE_01 into CY_SMIF_SFDP_SIGNATURE_BYTE_01;
CY_SMIF_SFDP_SING_BYTE_02 into CY_SMIF_SFDP_SIGNATURE_BYTE_02;
CY_SMIF_SFDP_SING_BYTE_03 into CY_SMIF_SFDP_SIGNATURE_BYTE_03;
CY_SMIF_WR_STS_REG1_CMD into CY_SMIF_WRITE_STATUS_REG1_CMD;
CY_SMIF_WR_DISABLE_CMD into CY_SMIF_WRITE_DISABLE_CMD;
CY_SMIF_RD_STS_REG1_CMD into CY_SMIF_READ_STATUS_REG1_CMD;
CY_SMIF_WR_ENABLE_CMD into CY_SMIF_WRITE_ENABLE_CMD;
CY_SMIF_RD_STS_REG2_T1_CMD into CY_SMIF_READ_STATUS_REG2_T1_CMD;
CY_SMIF_WR_STS_REG2_CMD into CY_SMIF_WRITE_STATUS_REG2_CMD;
CY_SMIF_RD_STS_REG2_T2_CMD into CY_SMIF_READ_STATUS_REG2_T2_CMD;
CY_SMIF_QE_BIT_STS_REG2_T1 into CY_SMIF_QE_BIT_STATUS_REG2_T1;
CY_SMIF_STS_REG_BUSY_MASK into CY_SMIF_STATUS_REG_BUSY_MASK.

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