You are here
Home > embedded >

SAME54 I2C Driver Issue Solved

If you are reading this post that means you are using ATMEL or Microchip controller. We are using ATSAME54 micro from microchip, it is ARM based cortex-M4 series controller. In our application we have around eight I2C ( Inter-integrated Circuit) slave devices connected. I2C slave devices includes, RTC, onboard temperature sensor, FRAM, LED drivers etc. Well as you know all I2C slave devices can be addressed using their addresses.

Well as most of guys does we too have downloaded sample code from and tested. We have SAME54 explained pro and we brought PCA9685 LED driver. This is simple I2C based LED driver and is easily available, its schematic and design also available from adafruit. With sample code and its default address it works like charm, meaning, in first go it starts communicating with LED driver.

Now fun part starts, after verifying this we have incorporated same design in our hardware. After we receive hardware, LED driver is not at all responding, it was not coming out of sleep mode. We have tried all the options, but no luck. Now when we are running same code on explained pro it is working. So only difference was the address. With PCA9685 module connected with explained pro as I2C master, we were using default address ie 0x40. Now when we change this address by shorting address lines, it stops working. We are getting “RXNACK” bit set on (received not acknowledged). Strange thing is if we revert back its address to default address ie 0x40 it works.

When we connected oscilloscope to SDA line we were getting data, ie address then registers.

I2C without driver change



Well after lot of googling and spending almost two weeks, we found solution, that was issue with ATMEL I2C driver source code generated from The solution is very simple once you found out the root cause :-). Yes it is bug in microchip’s I2C driver and its very unique.

I2C is very simple and we suspected hardware. Started with pull up registers for SDA and SCL lines, After trying out with various combinations of pull up registers (4K, 10K, 2.2k) we diverted our attention to I2C drivers. Yes, The culprit is – ‘i2c_m_sync_cmd_read()’ and ‘i2c_m_sync_cmd_write()’ functions from ‘hal\src\hal_i2c_m_sync.c’. The present code it is sending two bytes, but it is expected is to send three bytes. We have modified these read/write commands and it is working. Please note this change is necessary if you are using I2C and code downloaded from atmel start.

Follow below steps to fix this issue,

Open – ‘hal\src\hal_i2c_m_sync.c’

In function ‘i2c_m_sync_cmd_read()’ and ‘i2c_m_sync_cmd_write()’ comment out following code, so after commenting out the functions should look as below,

	struct _i2c_m_msg msg;
int32_t           ret;
#if 0
msg.addr   = i2c->slave_addr;
msg.len    = 1;
msg.flags  = 0;
msg.buffer = ®
ret = _i2c_m_sync_transfer(&i2c->device, &msg);
if (ret != 0) {
/* error occurred */
return ret;
msg.addr   = i2c->slave_addr;
msg.flags  = I2C_M_STOP;
msg.buffer = buffer;
msg.len    = length;
ret = _i2c_m_sync_transfer(&i2c->device, &msg);
if (ret != 0) {
/* error occurred */
return ret;
return ERR_NONE;

Now connect oscilloscope and check SDA line, it gives results as expected.

I2C after change in driver

If your I2C slave devices are configured with default addresses ie 0x00, then this change is not required, but remember to make this change every time you download I2C driver code from Share your findings on I2C issues while using ATMEL SAME54P20A controller.

Leave a Reply