Overview
This page provides a more detailed description of how to configure the SAM D21 MCU SERCOM peripheral into an I²C slave. We cover the key registers to be configured to implement a simple I²C slave application where an I²C master can read and write to the slave register map on the MCU.
The very first thing to consider when configuring an I²C slave driver is to decide which of the two interrupt strategies will be picked for the application (they can be changed in run mode if necessary). The strategies are controlled by the SCL Stretch Mode bit (CTRLA.SCLSM)
The default strategy is CTRLA.SCLSM = 0, where the SCL line is stretched before or after the acknowledge bit. In this mode, the I²C slave operates according to the following behavioral diagram:
The circles labeled Sn (S1, S2..) indicate the nodes the bus logic can jump to, based on software or hardware interaction.
The second strategy is CTRLA.SCLSM = 1, where interrupts will only occur after the ACK bit is sent. This strategy can be used when it is not necessary to check DATA before acknowledging. For master reads, an address and data interrupt will be issued simultaneously after the address acknowledge. However, for master writes, the first data interrupt will be seen after the first data byte has been received by the slave and the acknowledge bit has been sent to the master.
We will focus on the default operation of the SCLSM bit (CTRLA.SCLSM = 0) so that the application firmware can have control over clock stretching and acknowledgment.
Configuration Steps
The following instructions should be used when configuring the SERCOM peripheral to work as an I²C slave. This section explores a simple and basic configuration. More advanced applications might use extra functionalities from the peripheral, but the basic principle remains the same.
Here is a high-level step list to configure the peripheral:
- Configure the pins to work as SERCOM I/Os using the PMUX
- Provide a bus clock to the SERCOM peripheral using the Power Manager
- Provide a generic clock to the SERCOM peripheral using GCLK
- Configure the SERCOM I²CS control registers
- Configure the SERCOM interrupts.
Step 1. Configure the SERCOM I²C Pins Using the PMUX
Use the “I/O Multiplexing and Considerations” section of the "SAM D21 Family Datasheet" to determine what pins can be used and for which SERCOM. For the example application that will follow this page, PA08 and PA09 are used, along with SERCOM2.
For the configuration selected above, PA08 and PA09 PMUX functionality must be configured to setting D, from datasheet PMUX table section, as shown:
The following is a code example which performs this assignment:
PORT->Group[0].WRCONFIG.reg =
PORT_WRCONFIG_WRPINCFG | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_PMUXEN |
PORT_WRCONFIG_PMUX(PORT_PMUX_PMUXE_D_Val) | //Config for PMUX
PORT_WRCONFIG_PINMASK(PORT_PA08|PORT_PA09); //Config PA08 and PA09
Step 2. Provide a Bus Clock to the SERCOM Peripheral Using the Power Manager
The SERCOM peripheral is implemented on the Advanced Peripheral Bus (APB) C. To communicate with the register set, we enable the synchronous clock to the peripheral using the Power Manager (PM) register set. Here is example code for enabling SERCOM2:
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM2; //Enable the SERCOM2 under the PM
Step 3. Provide a Generic Clock to the SERCOM Peripheral Using GCLK
The following is an example for SERCOM2 being configured to use generic clock source 0 (GCLK 0 - same clock source as used for the CPU):
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM2_GCLK_ID_CORE) |
GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0);
This is only valid for the SAMD Cortex®-M0+ devices. On the SAML, the configuration for the clocks will be different!
Step 4. Configure the SERCOM I²CS Control Registers
To configure the actual SERCOM operation, the following control registers will be configured:
- CTRLA: Set the MODE bits to configure the I²C Slave mode.
- CTRLB: Set the SMART mode bit, which will help to automate the ACK/NACK issuing on the I²C operation.
- ADDR: Add here what will be the 7-bit Slave address which the peripheral will reply to.
The following is a code example that performs these actions:
SERCOM2->I2CS.CTRLA.reg = SERCOM_I2CS_CTRLA_MODE_I2C_SLAVE; //I2C Slave Mode
SERCOM2->I2CS.CTRLB.reg = SERCOM_I2CS_CTRLB_SMEN; //Configure I2C in SMART mode
SERCOM2->I2CS.ADDR.reg = SERCOM_I2CS_ADDR_ADDR(I2C_SLAVE_ADDR); //I2C Slave address (7-bit address)
Step 5. Configure the SERCOM Interrupts
Finally, in most I²C applications in Slave mode, you will enable interrupts so that each frame can be processed using such functionality, instead of polling from a loop. The following an example for enabling interrupts under Slave Address Match, Data Ready Match, and STOP Condition for the SERCOM2:
SERCOM2->I2CS.INTENSET.reg =
SERCOM_I2CS_INTENSET_PREC | //Enable interrupt on STOP condition
SERCOM_I2CS_INTENSET_AMATCH | //Enable interrupt on ADD MATCH condition
SERCOM_I2CS_INTENSET_DRDY; //Enable interrupt on DAT READY condition
NVIC_EnableIRQ(SERCOM2_IRQn); //Enable the global interrupt for the peripheral
After all the steps of this configuration are done, the system is ready to receive I²C commands, which causes the interrupt into the SERCOM vector when one of the conditions set for interrupt happens. Note that this configuration sequence is basic and can be expanded for higher complexity applications.
Learn More
Table of Contents
|