ASFv4 I2C async slave bugs

Go To Last Post
2 posts / 0 new
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Hello all,


I am posting this to document this issue for anyone else googling for it.


I currently have a platform setup as follows:

  • A non-atmel I2C Master setup with a message structure of write 4 bytes then read 4 bytes.
  • A SAMD21J18A setup as the I2C Slave to interface with the master.


During previous version of my platform, I was implementing the I2C Slave Callback system in ASF v3. During this time I am able to send and receive bytes with no issue.


However, once I migrated to ASFv4 I have found that the Slave transmits bytes out of order. For Example, If the I2C slave is setup to have a tx buffer of 0x01020304, The first time there is a master read, it will read 0x01020304 correctly. However, After successive reads , the bytes will be shifted by one. Example, 2nd read -> 0x02030401, 3rd read -> 0x03040102, 4th read -> 0x04010203, 5th read -> 0x01020304.


After looking under the hood, I have found that in  _sercom_i2c_s_irq_handler(hpl_sercom.c), the tx callback (device->cb.tx()) was being called 6 times. Within the associated internal callback to the bus "i2c_s_async_tx", the tx_por was operating correctly and once it got to 5 when the buffer_length was 4; it correctly cleared the por and buffer length and called the tx_complete callback. However, once it is called a 6th time, it re-indexes the por and so by the time the Master actually comes around again we are already incremented on the buffer by one so everything gets shifted off by one. Breaking on the interrupt flags in "_sercom_i2c_s_irq_handler" I have found that:

1) The wrong flags are being read. The following line is referencing the master instead of the slave flags.

  • uint32_t flags = hri_sercomi2cm_read_INTFLAG_reg(hw);
  • instead of uint32_t flags = hri_sercomi2cs_read_INTFLAG_reg(hw);

2) The DRDY interrupt seemed to not be getting cleared after a stop condition has been detected causing another interrupt.


After posting to Microchip I have received the following response:

Hi Paul,


These are indeed bugs in the ASFv4 i2c driver. I have already reported this to the concerned team, as the issue was identified while debugging a similar case.

The patch you have applied is correct.

Following is the fixed implementation.

static void _sercom_i2c_s_irq_handler(struct _i2c_s_async_device *device)
	void *  hw  = device->hw;
	uint32_t flags = hri_sercomi2cs_read_INTFLAG_reg(hw);

	if (flags & SERCOM_I2CS_INTFLAG_DRDY) {
		if (!hri_sercomi2cs_get_STATUS_DIR_bit(hw)) {
			device->cb.rx_done(device, hri_sercomi2cs_read_DATA_reg(hw));
		} else {
	// clear AMATCH interrupt flag
	else if (flags & SERCOM_I2CS_INTFLAG_AMATCH) {

	// clear OREC interrupt flag
	else if (flags & SERCOM_I2CS_INTFLAG_PREC) {

Also, the AMATCH interrupt is not enabled by the driver. This has to be done manually after the i2c enable.

// Enable AMATCH interrupt
((Sercom *)I2C_0.device.hw)->I2CS.INTENSET.reg |= SERCOM_I2CS_INTENSET_AMATCH;


This seems to have cleared up the issue for me but if still having issues please also see the following:




  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, Similar issue i have in ASFv4.. can you suggest a solution??


I am trying to program SAMV71 with ASFV4 (Atmel start) as I2C ASYNC Slave (0x70) which includes a call back function for I2C_0_rx_complete_new(). Everytime master sends a request the call back function is called and bytes are read one by one as per ringbuffer logic and i am writing back the required bytes followed by every read.


My question is , I have also written a piece of program which reads the bytes from USART0 inside while(1) under main() function but these statements are not getting executed since the control is not returning from callback. It stays there forever...!


Following is my program please give your suggestions.


struct io_descriptor *io;
struct io_descriptor *uart;

uint8_t data_in[4];

uint8_t dataArray_C_SEL_ARRAY[35]  = {0x02,0x00,0x43,0x4f,0x4e,0x54,0x49,0x4e,0x45,0x4e,0x54,0x41,0x4c,0x20,0x32,0x30,0x32,0x34,0x30,0x30,0x20,0x32,0x30,0x32,0x34,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x63};

static void   I2C_0_rx_complete_new(const struct i2c_s_async_descriptor *const descr)
    uint32_t j = io_read(io, &data_in, 1);

    if (data_in[0]) { 

        io_write(io, &dataArray_C_SEL_ARRAY,35);




int main(void)



    usart_sync_get_io_descriptor(&USART_0, &uart);



    i2c_s_async_get_io_descriptor(&I2C_0, &io); 
    i2c_s_async_register_callback(&I2C_0, I2C_S_RX_COMPLETE, I2C_0_rx_complete_new);
    i2c_s_async_set_addr(&I2C_0, 0x70);

    while (1) {
    io_read(uart,&SER_ARRAY , 8);






I have checked the i2c log using logic analyzer where after every master request, 35 bytes of response is written properly and acknowledgement is also obtained. But still the control not return backs to main(). Please help..!