19.8.5.1.3 Workflow

  1. Create a module software instance structure for the SPI module to store the SPI driver state while it is in use.
    struct spi_module spi_master_instance;
    struct spi_module spi_slave_instance;
    
    Note: This should never go out of scope as long as the module is in use. In most cases, this should be global.
  2. Create a module software instance structure for DMA resource to store the DMA resource state while it is in use.
    struct dma_resource example_resource_tx;
    struct dma_resource example_resource_rx;
    
    Note: This should never go out of scope as long as the module is in use. In most cases, this should be global.
  3. Create transfer done flag to indication DMA transfer done.
    static volatile bool transfer_tx_is_done = false;
    static volatile bool transfer_rx_is_done = false;
    
  4. Define the buffer length for TX/RX.
    #define BUF_LENGTH 20
    
  5. Create buffer to store the data to be transferred.
    static const uint8_t buffer_tx[BUF_LENGTH] = {
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
            0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
    };
    static uint8_t buffer_rx[BUF_LENGTH];
    
  6. Create the SPI module configuration struct, which can be filled out to adjust the configuration of a physical SPI peripheral.
    struct spi_config config_spi_master;
    
    struct spi_config config_spi_slave;
    
  7. Initialize the SPI configuration struct with the module's default values.
    spi_get_config_defaults(&config_spi_master);
    
    spi_get_config_defaults(&config_spi_slave);
    
    Note: This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
  8. Alter the SPI settings to configure the physical pinout, baudrate, and other relevant parameters.
    config_spi_master.mux_setting = CONF_MASTER_MUX_SETTING;
    
    config_spi_slave.mux_setting = CONF_SLAVE_MUX_SETTING;
    
  9. Configure the SPI module with the desired settings, retrying while the driver is busy until the configuration is stressfully set.
    spi_init(&spi_master_instance, CONF_MASTER_SPI_MODULE, &config_spi_master);
    
    spi_init(&spi_slave_instance, CONF_SLAVE_SPI_MODULE, &config_spi_slave);
    
  10. Enable the SPI module.
    spi_enable(&spi_master_instance);
    
    spi_enable(&spi_slave_instance);
    
  11. Create the DMA resource configuration structure, which can be filled out to adjust the configuration of a single DMA transfer.
    struct dma_resource_config tx_config;
    
    struct dma_resource_config rx_config;
    
  12. Initialize the DMA resource configuration struct with the module's default values.
    dma_get_config_defaults(&tx_config);
    
    dma_get_config_defaults(&rx_config);
    
    Note: This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
  13. Set extra configurations for the DMA resource. It is using peripheral trigger. SERCOM TX empty and RX complete trigger causes a beat transfer in this example.
    tx_config.peripheral_trigger = CONF_PERIPHERAL_TRIGGER_TX;
    tx_config.trigger_action = DMA_TRIGGER_ACTON_BEAT;
    
    rx_config.peripheral_trigger = CONF_PERIPHERAL_TRIGGER_RX;
    rx_config.trigger_action = DMA_TRIGGER_ACTON_BEAT;
    
  14. Allocate a DMA resource with the configurations.
    dma_allocate(tx_resource, &tx_config);
    
    dma_allocate(rx_resource, &rx_config);
    
  15. Create a DMA transfer descriptor configuration structure, which can be filled out to adjust the configuration of a single DMA transfer.
    struct dma_descriptor_config tx_descriptor_config;
    
    struct dma_descriptor_config rx_descriptor_config;
    
  16. Initialize the DMA transfer descriptor configuration struct with the module's default values.
    dma_descriptor_get_config_defaults(&tx_descriptor_config);
    
    dma_descriptor_get_config_defaults(&rx_descriptor_config);
    
    Note: This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
  17. Set the specific parameters for a DMA transfer with transfer size, source address, and destination address.
    tx_descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE;
    tx_descriptor_config.dst_increment_enable = false;
    tx_descriptor_config.block_transfer_count = sizeof(buffer_tx)/sizeof(uint8_t);
    tx_descriptor_config.source_address = (uint32_t)buffer_tx + sizeof(buffer_tx);
    tx_descriptor_config.destination_address =
        (uint32_t)(&spi_master_instance.hw->SPI.DATA.reg);
    
    rx_descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE;
    rx_descriptor_config.src_increment_enable = false;
    rx_descriptor_config.block_transfer_count = sizeof(buffer_rx)/sizeof(uint8_t);
    rx_descriptor_config.source_address =
        (uint32_t)(&spi_slave_instance.hw->SPI.DATA.reg);
    rx_descriptor_config.destination_address =
        (uint32_t)buffer_rx + sizeof(buffer_rx);
    
  18. Create the DMA transfer descriptor.
    dma_descriptor_create(tx_descriptor, &tx_descriptor_config);
    
    dma_descriptor_create(rx_descriptor, &rx_descriptor_config);