Synchronous Serial Interface (SSI) Usage Scenarios#
The Synchronous Serial Interface (SSI) on SiWx917 supports both Primary and Secondary roles, blocking and non-blocking transfers, and advanced SPI modes (Dual and Quad).
SSI integrates with Direct Memory Access (DMA) through the Universal DMA (UDMA) controller in the WiSeConnect SDK for high throughput and minimal CPU load.
This section provides practical examples, detailed workflows, and guidance to help select the appropriate transfer mode.
Usage Scenarios#
Common SSI workflows include:
Primary transfers (non-DMA): Short, simple transfers where the CPU can wait.
Secondary transfers (non-DMA): Device responds to primary-initiated communication.
DMA-based transfers: Efficient high-speed data movement with minimal CPU intervention.
Dual/Quad SPI: Enhanced throughput using two or four data lines for flash or high-bandwidth peripherals.
Use Case 1: SSI Primary (Non-DMA)#
Use primary mode without DMA for short or low-frequency transfers where the CPU can wait.
This configuration is ideal for sending sensor data, reading from flash, or communicating with simple peripherals.
Implementation Steps#
Initialize the SSI driver and configure the instance.
Set the secondary device number (chip select).
Register a callback to handle completion and error events.
Use transmit and receive APIs for data exchange.
Deinitialize the driver when the transfer is complete.
1. Include Headers and Define Buffers#
#include "sl_si91x_ssi.h"
uint8_t tx_buffer[256] = {0x01, 0x02, 0x03, /* ... */};
uint8_t rx_buffer[256] = {0};2. Define Callback and State Variables#
static volatile bool data_received = false;
static volatile bool transfer_error = false;
static void ssi_callback(uint32_t event)
{
    if (event & SSI_EVENT_TRANSFER_COMPLETE) {
        data_received = true;
    }
    if ((event & SSI_EVENT_DATA_LOST) || (event & SSI_EVENT_MODE_FAULT)) {
        transfer_error = true;
    }
}3. Initialize the SSI Primary#
sl_ssi_handle_t ssi_handle;
sl_ssi_control_config_t ssi_primary_config = {0};
ssi_primary_config.bit_width = 8;
ssi_primary_config.device_mode = SL_SSI_MASTER_ACTIVE;
ssi_primary_config.clock_mode = SL_SSI_PERIPHERAL_CPOL0_CPHA0;
ssi_primary_config.baud_rate = 10000000;
ssi_primary_config.receive_sample_delay = 0;
sl_status_t status = sl_si91x_ssi_init(SL_SSI_MASTER_ACTIVE, &ssi_handle);
if (status != SL_STATUS_OK) {
    // Handle initialization error
}4. Configure the Secondary and SSI#
sl_si91x_ssi_set_slave_number(SSI_SLAVE_0);
status = sl_si91x_ssi_set_configuration(ssi_handle, &ssi_primary_config, SSI_SLAVE_0);
if (status != SL_STATUS_OK) {
    // Handle configuration error
}5. Register the Callback#
status = sl_si91x_ssi_register_event_callback(ssi_handle, ssi_callback);
if (status != SL_STATUS_OK) {
    // Handle callback registration error
}6. Send Data#
status = sl_si91x_ssi_send_data(ssi_handle, tx_buffer, sizeof(tx_buffer));
if (status != SL_STATUS_OK) {
    // Handle send error
}7. Receive Data#
status = sl_si91x_ssi_receive_data(ssi_handle, rx_buffer, sizeof(rx_buffer));
if (status != SL_STATUS_OK) {
    // Handle receive error
}8. Deinitialize SSI#
sl_si91x_ssi_deinit(ssi_handle);Note
In non-DMA mode, for larger transfers you must manually control chip select (CS) using General-Purpose Input/Output (GPIO) APIs.
Use
sl_gpio_set_pin_output()to assert CS before sending or receiving andsl_gpio_clear_pin_output()to deassert CS after transfer completion. This ensures correct SPI timing.
Use Case 2: SSI Secondary (Non-DMA)#
In secondary mode, the device responds to a primary’s communication. This flow mirrors the primary configuration but waits for the primary device to initiate data transfer.
1. Initialize the SSI Secondary#
sl_ssi_handle_t ssi_handle;
sl_status_t status = sl_si91x_ssi_init(SL_SSI_SLAVE_ACTIVE, &ssi_handle);
if (status != SL_STATUS_OK) {
    // Handle initialization error
}2. Configure the Secondary and SSI#
sl_si91x_ssi_set_slave_number(SSI_SLAVE_0);
sl_ssi_control_config_t ssi_secondary_config = {0};
ssi_secondary_config.bit_width = 8;
ssi_secondary_config.device_mode = SL_SSI_SLAVE_ACTIVE;
ssi_secondary_config.clock_mode = SL_SSI_PERIPHERAL_CPOL0_CPHA0;
ssi_secondary_config.baud_rate = 10000000;
status = sl_si91x_ssi_set_configuration(ssi_handle, &ssi_secondary_config, SSI_SLAVE_0);
if (status != SL_STATUS_OK) {
    // Handle configuration error
}3. Start Receive Operation#
data_received = false;
transfer_error = false;
status = sl_si91x_ssi_receive_data(ssi_handle, rx_buffer, sizeof(rx_buffer));
if (status != SL_STATUS_OK) {
    // Handle receive error
}Use Case 3: DMA-Based Transfers#
Direct Memory Access (DMA) reduces CPU overhead during data transfers.
In the WiSeConnect SDK, DMA operations are managed by the Universal DMA (UDMA) controller, which automatically handles channel allocation and transfer completion.
SDK Layer Interaction#
The SSI driver interfaces with UDMA for transmit and receive operations.
Applications use the following high-level SSI APIs to initiate DMA transfers:
sl_si91x_ssi_transfer_data()sl_si91x_ssi_send_data()sl_si91x_ssi_receive_data()
DMA Event Handling#
Completion and error events are reported through the registered callback function.
Handle the following events for reliable DMA operation:
SSI_EVENT_TRANSFER_COMPLETESSI_EVENT_DATA_LOST
Use Case 4: Dual/Quad SPI Advanced Transfers#
Dual and Quad SPI modes enhance throughput by transmitting multiple bits per clock cycle.
These modes support blocking and DMA transfers only; interrupt-based transfers are not supported.
Configuration:
In Simplicity Studio’s Project Configurator (UC), enable Dual or Quad transfer mode under the SSI component settings to activate these features.
Dual/Quad SPI Flash Memory Example (Blocking Mode):
// Configure Quad SPI: 8-bit instruction, 24-bit address, Quad frame format
sl_si91x_ssi_command_config(ssi, SSI_INST_LEN_8_BITS, 
                            SSI_ADDR_LEN_24_BITS, 
                            SSI_FRF_QUAD, 
                            SSI_XFER_TYPE_INST_ADDR_STD);
// Write data (Quad Input Fast Program)
sl_si91x_ssi_send_command_data(ssi, tx_buf, data_length, CMD, Address);
// Read data (Dual Output Fast Read, 8 dummy cycles)
sl_si91x_ssi_receive_command_data(ssi, rx_buf, data_length, CMD, Address, waitcycle);Dual/Quad SPI Flash Memory Example (DMA Mode):
To enable DMA for SSI in Simplicity Studio, set DMA Enable to On in the SSI component configuration.
#include "sl_si91x_ssi.h"
static volatile bool transfer_complete = false;
// Callback for DMA completion in Dual/Quad mode
static void quad_spi_dma_callback(uint32_t event)
{
    if (event & SSI_EVENT_TRANSFER_COMPLETE) {
        transfer_complete = true;
    }
    if ((event & SSI_EVENT_DATA_LOST) || (event & SSI_EVENT_MODE_FAULT)) {
        // Error: Data lost during Dual/Quad SPI DMA transfer
    }
}
sl_status_t SSI_Transfer(void)
{
    // Step 1: Configure Quad SPI for DMA-based flash memory operation
    sl_status_t status;
    sl_ssi_handle_t ssi_handle;
    sl_ssi_control_config_t ssi_dma_config = {0};
    ssi_dma_config.bit_width            = 8;
    ssi_dma_config.device_mode          = SL_SSI_MASTER_ACTIVE;
    ssi_dma_config.clock_mode           = SL_SSI_PERIPHERAL_CPOL0_CPHA0;
    ssi_dma_config.baud_rate            = 10000000;
    ssi_dma_config.transfer_mode        = SPI_TRANSFER_MODE_QUAD;
    ssi_dma_config.receive_sample_delay = 0;
    status = sl_si91x_ssi_init(SL_SSI_MASTER_ACTIVE, &ssi_handle);
    if (status != SL_STATUS_OK) return status;
    sl_si91x_ssi_set_slave_number(SSI_SLAVE_0);
    status = sl_si91x_ssi_set_configuration(ssi_handle, &ssi_dma_config, SSI_SLAVE_0);
    if (status != SL_STATUS_OK) return status;
    status = sl_si91x_ssi_command_config(ssi_handle, 
                                         SSI_INST_LEN_8_BITS, 
                                         SSI_ADDR_LEN_24_BITS, 
                                         SSI_FRF_QUAD, 
                                         SSI_XFER_TYPE_INST_ADDR_STD);
    if (status != SL_STATUS_OK) return status;
    // Step 2: Register DMA completion callback
    status = sl_si91x_ssi_register_event_callback(ssi_handle, quad_spi_dma_callback);
    if (status != SL_STATUS_OK) return status;
    // Step 3: Prepare data buffers
    uint8_t tx_buf[256] = {/* ... */};
    uint8_t rx_buf[256] = {0};
    uint32_t data_length = sizeof(tx_buf);
    uint8_t CMD = 0x32;      // Example command
    uint32_t Address = 0x000000; // Example address
    uint8_t waitcycle = 8;   // 8 dummy cycles
    // Step 4: Start DMA-based write (Quad Input Fast Program)
    transfer_complete = false;
    status = sl_si91x_ssi_send_command_data(ssi_handle, 
                                            tx_buf, 
                                            data_length, 
                                            CMD, 
                                            Address);
    if (status != SL_STATUS_OK) return status;
    // Wait for DMA completion
    while (!transfer_complete) {
        sl_si91x_power_manager_sleep();
    }
    // Configure to dual transfer mode to read data in dual mode
    status = sl_si91x_ssi_command_config(ssi_handle,
                                         SSI_INST_LEN_8_BITS,
                                         SSI_ADDR_LEN_24_BITS,
                                         SSI_FRF_DUAL,
                                         SSI_XFER_TYPE_INST_ADDR_STD);
    if (status != SL_STATUS_OK) return status;
    // Step 5: Start DMA-based read (Dual Output Fast Read)
    transfer_complete = false;
    CMD = 0x6B;
    status = sl_si91x_ssi_receive_command_data(ssi_handle, rx_buf, data_length, 
                                               CMD, Address, waitcycle);
    if (status != SL_STATUS_OK) return status;
    while (!transfer_complete) {
        sl_si91x_power_manager_sleep();
    }
    // Step 6: Process received data
    printf("Quad/Dual SPI DMA transfer completed: %d bytes\n", data_length);
    // Optional: Deinitialize SSI if no longer needed
    sl_si91x_ssi_deinit(ssi_handle);
    return SL_STATUS_OK;
}Example: Read Flash Status Register in Standard SPI Mode#
Use sl_si91x_ssi_receive_command_data() to read a flash status register and check the Write In Progress (WIP) bit to verify completion of write/erase operations.
#define READ_STATUS_REG_CMD 0x05 // Flash status register instruction
// Assume ssi_driver_handle is initialized and configured for standard SPI
uint8_t status_reg = 0;
sl_status_t status;
// Step 1: Configure SSI for standard SPI command phase (8-bit instruction, no address)
status = sl_si91x_ssi_command_config(ssi_driver_handle,
                                     SSI_INST_LEN_8_BITS,
                                     SSI_ADDR_LEN_0_BITS,
                                     SSI_FRF_STANDARD,
                                     SSI_XFER_TYPE_INST_ADDR_STD);
if (status != SL_STATUS_OK) {
  // Handle error
  return;
}
// Step 2: Read status register (1 byte)
status = sl_si91x_ssi_receive_command_data(ssi_driver_handle,
                                           &status_reg,
                                           1,
                                           READ_STATUS_REG_CMD,
                                           0x000000,
                                           0);
if (status != SL_STATUS_OK) {
  // Handle error
  return;
}
// Step 3: Check WIP (Write In Progress) bit
if ((status_reg & 0x01) == 0) {
  // Operation complete
} else {
  // Operation still in progress, poll again if needed
}Example: Send Only Command and Address (No Data Phase)#
Some flash commands (for example, subsector erase or write enable) require only a command and address phase with no data phase. Use sl_si91x_ssi_send_command_data() as shown below.
#define SUBSECTOR_ERASE_CMD 0x20 // Example: Subsector Erase command
// Assume ssi_driver_handle is initialized and configured
sl_status_t status;
// Step 1: Configure SSI for command + address phase (8-bit instruction, 24-bit address)
status = sl_si91x_ssi_command_config(ssi_driver_handle,
                                     SSI_INST_LEN_8_BITS,
                                     SSI_ADDR_LEN_24_BITS,
                                     SSI_FRF_STANDARD,
                                     SSI_XFER_TYPE_INST_ADDR_STD);
if (status != SL_STATUS_OK) {
  // Handle error
  return;
}
// Step 2: Send command and address only (no data phase)
status = sl_si91x_ssi_send_command_data(ssi_driver_handle,
                                        NULL,        // No data buffer
                                        0,           // Data length = 0
                                        SUBSECTOR_ERASE_CMD,
                                        0x000000);   // Example address
if (status != SL_STATUS_OK) {
  // Handle error
  return;
}
// The erase operation is now triggered on the flash device.Advanced Features#
Dual SPI: Achieves 2× throughput using two data lines (DATA0/DATA1).
Quad SPI: Achieves 4× throughput using four data lines (DATA0–DATA3).
Configurable instruction and address phases: Supports both standard and enhanced transmission modes.
Programmable wait cycles: Optimize timing to meet device-specific requirements.
Transfer modes: Supports blocking and DMA modes for Dual/Quad SPI (interrupt mode not supported).
Flash protocol support: Compatible with most standard SPI flash devices.
Example References#
SSI Primary Example:
sl_si91x_ssi_masterULP SSI Primary Example:
sl_si91x_ulp_ssi_masterSSI Secondary Example:
sl_si91x_ssi_slave