SAM C21 SERCOM SPI Slave Configuration
Overview
This page provides a more detailed description of how to configure the SAM C21 SERCOM peripheral into an SPI Slave. It will cover the key registers to be configured to implement a simple SPI Slave application where the SAM C21 accepts and responds to SPI commands sent by an SPI Host Application running on a PC.
The SPI Slave has several configuration possibilities that need to be considered when interfacing to external SPI Master devices.
Data Transfer Modes
The SPI Slave of the SAM C21 supports all four data transfer modes.
Module Block Diagram (SPI Slave)
Data Interface
There is only a single register interface for the SERCOM in SPI Slave mode, the DATA register. The block diagram above shows these as two separate paths but they share a common register address.
Data to be transmitted by the SPI Slave is written to the DATA register.
Data to be received by the SPI Slave is read from the DATA register.
Clock Interface
The external clock provided via the SCK pin function provides the necessary module clocks. There is no need to configure the BAUD register in SPI Slave mode.
Slave Select (SS) Operation
Per the previous diagrams, an SPI transaction is started with the SS line being asserted by the Master. This detection is automatically detected by the SERCOM module. However, there is an option to allow the device to be woken up when the SS line is asserted by enabling the CTRLB.SSDE bit.
Interrupts
In SPI Slave mode, there are five interrupt sources:
Data Register Empty (DRE) | Set when the DATA register is empty NOTE — flag is cleared by writing to the DATA register |
Transmission Complete (TXC) | Set when a rising edge is detected on SS |
Reception Complete (RXC) | Set when unread data is in the DATA register NOTE — flag is cleared by reading the DATA register |
Slave Select Low (SSL) | Set when a falling edge is detected on SS |
Error (ERR) | Set when an error is detected — the only error in SPI Slave mode is the buffer overflow, found at the STATUS.BUFOVF |
Addressing Modes
In SPI Slave mode, there are three optional slave addressing modes. These modes work by performing the desired address comparison on the first data byte received by the SERCOM module after SS is asserted.
Enabling Addressing is selected via the CTRLA.FORM register bits.
The desired addressing mode is selected by the CTRLB.AMODE register bits.
MODE | FUNCTION |
---|---|
Mask | ADDRMASK[n] removes bit n from the address mask comparison |
2 Addresses | ADDRMASK contains the first match address ADDR contains the second match address |
Address Range | ADDRMASK contains the lower limit of the address range ADDR contains the higher limit of the address range NOTE — Address ranges are inclusive of the ADDRMASK and ADDR register values |
Configuration Steps
Use the following instructions when configuring the SERCOM peripheral to work as an SPI Slave. This section explores a simple and basic configuration, where the SAM C21 is connected as an SPI Slave to an MCP2210 SPI Master device, which issues commands from a PC Terminal Application.
This application uses:
- SERCOM5 in SPI Slave mode, with Address Range slave addressing mode enabled
- PB01 (SCK), PB00 (MOSI), PB02 (MISO), PB03 (SS)
More advanced applications might use extra functionalities from the peripheral, but the basic principle remains the same.
Below is a high-level step list to configure the peripheral:
- Configure the SERCOM pins using the PMUX
- Provide a Bus Clock to the peripheral using MCLK
- Provide a Generic Clock to the peripheral using GCLK
- Configure the SERCOM SPI control registers for SPI Slave operation
- Configure Interrupts
- Enable Module
1. Configure the SERCOM Pins Using the PMUX
Use the “I/O Multiplexing and Considerations” section of the SAM C21 Family datasheetto determine what pins can be used and for which SERCOM. For the example application that follows this page, PB00, PB01, PB02 and PB03 are used, along with SERCOM5.
For the configuration selected above, PB00, PB01, PB02, and PB03 PMUX functionality must be configured to use setting D, from the datasheet PMUX table section, as shown:
The following is a code example which performs this assignment:
#define SPI_SCK_PIN 1
#define SPI_MOSI_PIN 0
#define SPI_MISO_PIN 2
#define SPI_nSS_PIN 3
// SPI-MOSI
// PB00 (SERCOM5-PAD2)
PORT->Group[PORTB].PINCFG[SPI_MOSI_PIN].bit.PMUXEN = 1;
PORT->Group[PORTB].PMUX[0].bit.PMUXE = GPIO_PIN_FUNCTION_D;
PORT->Group[PORTB].DIRCLR.reg = (0x00000001 << SPI_MOSI_PIN);
// SPI-CLK
// PB01 (SERCOM5-PAD3)
PORT->Group[PORTB].PINCFG[SPI_SCK_PIN].bit.PMUXEN = 1;
PORT->Group[PORTB].PMUX[0].bit.PMUXO = GPIO_PIN_FUNCTION_D;
PORT->Group[PORTB].DIRCLR.reg = (0x00000001 << SPI_SCK_PIN);
// SPI-MISO
// PB02 (SERCOM5-PAD0)
PORT->Group[PORTB].PINCFG[SPI_MISO_PIN].bit.PMUXEN = 1;
PORT->Group[PORTB].PMUX[1].bit.PMUXE = GPIO_PIN_FUNCTION_D;
PORT->Group[PORTB].DIRSET.reg = (0x00000001 << SPI_MISO_PIN);
// SPI-nSS
// PB03 (SERCOM5-PAD1)
PORT->Group[PORTB].PINCFG[SPI_nSS_PIN].bit.PMUXEN = 1;
PORT->Group[PORTB].PMUX[1].bit.PMUXO = GPIO_PIN_FUNCTION_D;
PORT->Group[PORTB].DIRCLR.reg = (0x00000001 << SPI_nSS_PIN);
Note: In addition to configuring the PORT registers, the SERCOM module must also correctly assign the PADS to the SPI input and output pin functions in the SERCOM control registers. For SPI Slave, CTRLA.DIPO is used to assign the MOSI pin location and CTRL.DOPO is used to assign the MISO, SCK and SS pin locations:
If these are not configured correctly, the module will not operate properly with the pins assigned. See Step 4 below for a code example that initializes these bit-fields.
2. Provide a Bus Clock to the Peripheral Using MCLK
The SERCOM peripheral is implemented on the Advanced Peripheral Bus C (APBC). To communicate with the register set, we enable the synchronous clock to the peripheral using the Main Clock Controller (MCLK) register set.
Here is a code example for enabling the bus clock for SERCOM5:
3. Provide a Generic Clock to the Peripheral Using GCLK
The Generic Clock for a peripheral must be configured by writing to the respective Peripheral Channel Control register PCHCTRLm. The Generator used as the source for the Peripheral Clock must be written to the GEN bit field in the Peripheral Channel Control register PCHCTRLm.GEN.
For SERCOM5, there are two clock input selections, a Main clock and a Slow clock. Table 16-9 in the SAM C21 datasheet outlines the PCHCTRLm register-to-peripheral-channel mapping as shown:
The following code snippet assigns the GCLK to these peripheral channels:
GCLK->PCHCTRL[25].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // Main clock
Each SERCOM module has two clock input selections, a Main clock and a Slow clock. Only the Main clock needs to be assigned for SPI Slave operation.
4. Configure the SERCOM SPI Control Registers for SPI Slave Operation
The following code example enables SPI Slave mode operation, with Address Range addressing mode enabled (addresses between 0x01 and 0x07 will be detected). 8-bit data size is selected, and the SERCOM PADS are assigned to the appropriate SPI pin functions via CTRLA.DIPO and CTRLA.DOPO bit-fields:
SERCOM5->SPI.ADDR.bit.ADDR = 0x07; // High address limit
SERCOM5->SPI.ADDR.bit.ADDRMASK = 0x01; // Low address limit
SERCOM5->SPI.BAUD.reg = 0x00;
SERCOM5->SPI.CTRLB.reg |= SERCOM_SPI_CTRLB_RXEN
| SERCOM_SPI_CTRLB_AMODE(2) // Address Range addressing mode
| SERCOM_SPI_CTRLB_SSDE
| SERCOM_SPI_CTRLB_CHSIZE(0); // 8-bit data
while (SERCOM5->SPI.SYNCBUSY.bit.CTRLB);
SERCOM5->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_RUNSTDBY
| SERCOM_SPI_CTRLA_DOPO(3) // SERCOM5 Data Out Pinout
| SERCOM_SPI_CTRLA_DIPO(2) // SERCOM5 Data In Pinout
| SERCOM_SPI_CTRLA_FORM(2) // Format: SPI frame with address
| SERCOM_SPI_CTRLA_MODE(2); // SPI Slave mode operation
// Do not enable module yet
while (SERCOM5->SPI.SYNCBUSY.bit.ENABLE);
Note that the module is not enabled until interrupts are configured.
5. Configure Interrupts
For this example application, the following SPI interrupts will be enabled:
- TXC (TRANSMIT COMPLETE)
- RXC (RECEIVE COMPLETE)
- SSL (SLAVE SELECT LOW)
- ERROR (BUFFER OVERFLOW ERROR HAS OCCURRED)
The following code example enables these interrupt sources, and set the interrupt priority level to "3" (lowest priority):
| SERCOM_SPI_INTFLAG_RXC
| SERCOM_SPI_INTFLAG_SSL
| SERCOM_SPI_INTFLAG_ERROR; // clear all flags
SERCOM5->SPI.INTENSET.reg = SERCOM_SPI_INTFLAG_TXC
| SERCOM_SPI_INTFLAG_RXC
| SERCOM_SPI_INTFLAG_SSL
| SERCOM_SPI_INTFLAG_ERROR; // enable interrupts
NVIC_SetPriority(SERCOM5_IRQn, 3); // set priority
NVIC_EnableIRQ(SERCOM5_IRQn); // enable SERCOM5 NVIC interrupt line
6. Enable Module
Finally, we enable the module:
while (SERCOM5->SPI.SYNCBUSY.bit.ENABLE);
After all the steps of this configuration are done, the system is ready to receive commands/data. Visit the "SAM C21 SERCOM SPI Slave Example Project" page to see the complete working demo.