Microchip® Advanced Software Framework

Quick Start Guide for SERCOM SPI Slave - Callback

In this use case, the SPI on extension header 1 of the Xplained Pro board will configured with the following settings:

  • Slave mode enabled
  • Preloading of shift register enabled
  • MSB of the data is transmitted first
  • Transfer mode 0
  • SPI MUX Setting E (see Slave Mode Settings)
  • 8-bit character size
  • Not enabled in sleep mode
  • GLCK generator 0

Setup

Prerequisites

The device must be connected to a SPI master, which must read from the device.

Code

The following must be added to the user application source file, outside any functions.

A sample buffer to send via SPI.

static uint8_t buffer_rx[BUF_LENGTH] = {0x00,};
static uint8_t buffer_expect[BUF_LENGTH] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13
};

Number of entries in the sample buffer.

#define BUF_LENGTH 20

A globally available software device instance struct to store the SPI driver state while it is in use.

struct spi_module spi_slave_instance;

A function for configuring the SPI.

void configure_spi_slave(void)
{
struct spi_config config_spi_slave;
/* Configure, initialize and enable SERCOM SPI module */
spi_get_config_defaults(&config_spi_slave);
config_spi_slave.mode = SPI_MODE_SLAVE;
config_spi_slave.mode_specific.slave.preload_enable = true;
config_spi_slave.mode_specific.slave.frame_format = SPI_FRAME_FORMAT_SPI_FRAME;
config_spi_slave.mux_setting = CONF_SLAVE_MUX_SETTING;
config_spi_slave.pinmux_pad0 = CONF_SLAVE_PINMUX_PAD0;
config_spi_slave.pinmux_pad1 = CONF_SLAVE_PINMUX_PAD1;
config_spi_slave.pinmux_pad2 = CONF_SLAVE_PINMUX_PAD2;
config_spi_slave.pinmux_pad3 = CONF_SLAVE_PINMUX_PAD3;
spi_init(&spi_slave_instance, CONF_SLAVE_SPI_MODULE, &config_spi_slave);
spi_enable(&spi_slave_instance);
}

A function for configuring the callback functionality of the SPI.

void configure_spi_slave_callbacks(void)
{
spi_register_callback(&spi_slave_instance, spi_slave_callback,
}

A global variable that can flag to the application that the buffer has been transferred.

volatile bool transfer_complete_spi_slave = false;

Callback function.

static void spi_slave_callback(struct spi_module *const module)
{
transfer_complete_spi_slave = true;
}

Add to user application main().

uint8_t result = 0;
/* Initialize system */
configure_spi_slave();
configure_spi_slave_callbacks();

Workflow

  1. Initialize system.
  2. Set-up the SPI.
    configure_spi_slave();
    1. Create configuration struct.
      struct spi_config config_spi_slave;
    2. Get default configuration to edit.
      spi_get_config_defaults(&config_spi_slave);
    3. Set the SPI in slave mode.
      config_spi_slave.mode = SPI_MODE_SLAVE;
    4. Enable preloading of shift register.
      config_spi_slave.mode_specific.slave.preload_enable = true;
    5. Set frame format to SPI frame.
      config_spi_slave.mode_specific.slave.frame_format = SPI_FRAME_FORMAT_SPI_FRAME;
    6. Set MUX setting E.
      config_spi_slave.mux_setting = CONF_SLAVE_MUX_SETTING;
    7. Set pinmux for pad 0 (data in MOSI).
    8. Set pinmux for pad 1 (slave select).
    9. Set pinmux for pad 2 (data out MISO).
    10. Set pinmux for pad 3 (SCK).
    11. Initialize SPI module with configuration.
      spi_init(&spi_slave_instance, CONF_SLAVE_SPI_MODULE, &config_spi_slave);
    12. Enable SPI module.
      spi_enable(&spi_slave_instance);
  3. Setup of the callback functionality.
    configure_spi_slave_callbacks();
    1. Register callback function for buffer transmitted.
      spi_register_callback(&spi_slave_instance, spi_slave_callback,
    2. Enable callback for buffer transmitted.

Use Case

Code

Add the following to your user application main().

spi_read_buffer_job(&spi_slave_instance, buffer_rx, BUF_LENGTH, 0x00);
while(!transfer_complete_spi_slave) {
/* Wait for transfer from master */
}
for (uint8_t i = 0; i < BUF_LENGTH; i++) {
if(buffer_rx[i] != buffer_expect[i]) {
result++;
}
}
while (true) {
/* Infinite loop */
if (result) {
/* Add a short delay to see LED toggle */
volatile uint32_t delay = 30000;
while(delay--) {
}
} else {
/* Add a short delay to see LED toggle */
volatile uint32_t delay = 600000;
while(delay--) {
}
}
}

Workflow

  1. Initiate a read buffer job.
    spi_read_buffer_job(&spi_slave_instance, buffer_rx, BUF_LENGTH, 0x00);
  2. Wait for the transfer to be complete.
    while(!transfer_complete_spi_slave) {
    /* Wait for transfer from master */
    }
  3. Compare the received data with the transmitted data from SPI master.
    for (uint8_t i = 0; i < BUF_LENGTH; i++) {
    if(buffer_rx[i] != buffer_expect[i]) {
    result++;
    }
    }
  4. Infinite loop. If the data is matched, LED0 will flash slowly. Otherwise, LED will flash quickly.
    while (true) {
    /* Infinite loop */
    if (result) {
    /* Add a short delay to see LED toggle */
    volatile uint32_t delay = 30000;
    while(delay--) {
    }
    } else {
    /* Add a short delay to see LED toggle */
    volatile uint32_t delay = 600000;
    while(delay--) {
    }
    }
    }

Callback

When the buffer is successfully transmitted from the master, the callback function will be called.

Workflow

  1. Let the application know that the buffer is transmitted by setting the global variable to true.
    transfer_complete_spi_slave = true;