The supported board list:
- SAMD21 Xplained Pro
- SAMR21 Xplained Pro
- SAML21 Xplained Pro
- SAML22 Xplained Pro
- SAMDA1 Xplained Pro
- SAMC21 Xplained Pro
- SAMHA1G16A Xplained Pro
In this use case, the I2C will used and set up as follows:
- Slave mode
- 100KHz operation speed
- Not operational in standby
- 65535 unknown bus state timeout value
Prerequisites
The device must be connected to an I2C slave.
Setup
Code
The following must be added to the user application:
- Address to respond to:
#define SLAVE_ADDRESS 0x12
- A sample buffer to send, number of entries to send and address of slave:
#define DATA_LENGTH 10
uint8_t read_buffer[DATA_LENGTH];
- Globally accessible module structure:
- Function for setting up the module:
void configure_i2c_slave(void)
{
config_i2c_slave.address = SLAVE_ADDRESS;
config_i2c_slave.buffer_timeout = 1000;
#if SAMR30
config_i2c_slave.pinmux_pad0 = CONF_SLAVE_SDA_PINMUX;
config_i2c_slave.pinmux_pad1 = CONF_SLAVE_SCK_PINMUX;
#endif
i2c_slave_init(&i2c_slave_instance, CONF_I2C_SLAVE_MODULE, &config_i2c_slave);
}
- Globally accessible DMA module structure:
- Globally accessible DMA transfer descriptor:
DmacDescriptor i2c_dma_descriptor SECTION_DMAC_DESCRIPTOR;
- Function for setting up the DMA resource:
{
config.peripheral_trigger = CONF_I2C_DMA_TRIGGER;
}
- Function for setting up the DMA transfer descriptor:
void setup_dma_descriptor(DmacDescriptor *descriptor)
{
descriptor_config.src_increment_enable = false;
descriptor_config.block_transfer_count = DATA_LENGTH;
descriptor_config.destination_address = (uint32_t)read_buffer + DATA_LENGTH;
descriptor_config.source_address =
(uint32_t)(&i2c_slave_instance.hw->I2CS.DATA.reg);
}
- Add to user application
main()
: configure_i2c_slave();
configure_dma_resource(&i2c_dma_resource);
setup_dma_descriptor(&i2c_dma_descriptor);
Workflow
- Configure and enable module:
void configure_i2c_slave(void)
{
config_i2c_slave.address = SLAVE_ADDRESS;
config_i2c_slave.buffer_timeout = 1000;
#if SAMR30
config_i2c_slave.pinmux_pad0 = CONF_SLAVE_SDA_PINMUX;
config_i2c_slave.pinmux_pad1 = CONF_SLAVE_SCK_PINMUX;
#endif
i2c_slave_init(&i2c_slave_instance, CONF_I2C_SLAVE_MODULE, &config_i2c_slave);
}
- Create and initialize configuration structure.
- Change settings in the configuration.
config_i2c_slave.address = SLAVE_ADDRESS;
config_i2c_slave.buffer_timeout = 1000;
#if SAMR30
config_i2c_slave.pinmux_pad0 = CONF_SLAVE_SDA_PINMUX;
config_i2c_slave.pinmux_pad1 = CONF_SLAVE_SCK_PINMUX;
#endif
- Initialize the module with the set configurations.
i2c_slave_init(&i2c_slave_instance, CONF_I2C_SLAVE_MODULE, &config_i2c_slave);
- Enable the module.
- Configure DMA
- Create a DMA resource configuration structure, which can be filled out to adjust the configuration of a single DMA transfer.
- Initialize the DMA resource configuration struct with the module's default values.
- Note
- This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
- Set extra configurations for the DMA resource. It is using peripheral trigger. SERCOM RX trigger causes a beat transfer in this example.
config.peripheral_trigger = CONF_I2C_DMA_TRIGGER;
- Allocate a DMA resource with the configurations.
- Create a DMA transfer descriptor configuration structure, which can be filled out to adjust the configuration of a single DMA transfer.
- Initialize the DMA transfer descriptor configuration struct with the module's default values.
- Note
- This should always be performed before using the configuration struct to ensure that all values are initialized to known default settings.
- Set the specific parameters for a DMA transfer with transfer size, source address, and destination address.
descriptor_config.src_increment_enable = false;
descriptor_config.block_transfer_count = DATA_LENGTH;
descriptor_config.destination_address = (uint32_t)read_buffer + DATA_LENGTH;
descriptor_config.source_address =
(uint32_t)(&i2c_slave_instance.hw->I2CS.DATA.reg);
- Create the DMA transfer descriptor.
Implementation
Code
Add to user application main()
:
while (true) {
if (i2c_slave_dma_read_interrupt_status(&i2c_slave_instance) &
SERCOM_I2CS_INTFLAG_AMATCH) {
i2c_slave_dma_write_interrupt_status(&i2c_slave_instance,
SERCOM_I2CS_INTFLAG_AMATCH);
}
}
Workflow
- Start to wait a packet from master.
- Once data ready, clear the address match status.
while (true) {
if (i2c_slave_dma_read_interrupt_status(&i2c_slave_instance) &
SERCOM_I2CS_INTFLAG_AMATCH) {
i2c_slave_dma_write_interrupt_status(&i2c_slave_instance,
SERCOM_I2CS_INTFLAG_AMATCH);
}
}