# Wrong I²C signal for some bytes on Atmel microcontroller

In theory I want to start I2C communication as a master with a slave. Then I need to read 5 bytes of data.

In practice when I use the ASF provided by ATMEL what it does is start the communication as a master with the slave sents a byte and then reads 5 bytes.

The microcontroller I use is in ARM Cortex-M4: ATSAM4LC2A

This is how I initialize:

I instert these arguments into the initialization routine

/* Initialize I2C Master */
const i2c_master_settings my_i2c_master_settings =
{
.i2c_port   = TWIM2,
.speed      = TWI_FAST_MODE_SPEED,
.sda_pin    = IOPORT_CREATE_PIN( IOPORT_GPIOA , 21 ),
.sda_mux    = IOPORT_MODE_MUX_E,
.scl_pin    = IOPORT_CREATE_PIN( IOPORT_GPIOA , 22 ),
.scl_mux    = IOPORT_MODE_MUX_E
};


Routine

/**
* \brief Initialize I2C Master bus.
*
* \param[in]   settings    Bus settings.
*
* \retval      0           Success.
* \retval      1           Failed.
*/
uint32_t i2c_master_initialize( const i2c_master_settings settings )
{
/* Set TWIM options */
struct twim_config opts =
{
.twim_clk = sysclk_get_peripheral_bus_hz( settings.i2c_port ),
.speed = settings.speed,
.hsmode_speed = 0,
.data_setup_cycles = 0,
.hsmode_data_setup_cycles = 0,
.smbus = false,
.clock_slew_limit = 0,
.clock_drive_strength_low = 0,
.data_slew_limit = 0,
.data_drive_strength_low = 0,
.hs_clock_slew_limit = 0,
.hs_clock_drive_strength_high = 0,
.hs_clock_drive_strength_low = 0,
.hs_data_slew_limit = 0,
.hs_data_drive_strength_low = 0,
};
/* GPIO pins */
ioport_init();
ioport_set_pin_mode( settings.sda_pin, settings.sda_mux);
ioport_disable_pin( settings.sda_pin );
ioport_set_pin_mode( settings.scl_pin, settings.scl_mux );
ioport_disable_pin( settings.scl_pin );

/* Initialize the TWIM Module */
twim_set_callback( settings.i2c_port, 0, twim_default_callback, 1);
if ( twim_set_config( settings.i2c_port, &opts ) == STATUS_OK )
{
return 0;
}
else
{
return 1;
}
}


Here is my code:

/******************************************
* MY BUGGY FUNCTION
******************************************/
{
uint8_t data[5];//For debugging reasons I use 5. After debug 4 is sufficient. The 4th byte is configure register value.

{
/* Prepare packet */
twi_package_t packet_rx;
packet_rx.addr[0] = 0x00;                       /* TWI address/commands to issue to the other chip (node) */

/* Length of the TWI data address segment (1-3 bytes) */
packet_rx.buffer = (uint8_t*) data;             /* Where to find the data to be written */
packet_rx.length = 5;                           /* How many bytes do we want to write */
packet_rx.ten_bit = false;                      /* Indicate if it is 10-bit addressing */
packet_rx.high_speed = false;                   /* Indicate if it is a high-speed transfer */

/* Read data from TARGET */
if ( twi_master_read( p_port, &packet_rx) != STATUS_OK )
{
/* Exit with i2c error */
return 1;
}
}

/* Exit with success */
return 0;
}


And here is the logic analyser results

What am I doing wrong?

• Your code appears to be OK. Can you show us the TWIM initialization code? Also can you verify that 'twim.c' and 'twim.h' are included in the build? – Bruce Abbott Dec 31 '16 at 1:07
• It kind of looks like the addr_length field isn't being honored. I'd almost be tempted to set it to a non-zero value and see if the problem gets worse or the transfer longer. Or else perhaps the address is being treated as having a longer word length. It's probably worth diving into the details of what the ASF code is doing, in general it has some oddities. – Chris Stratton Dec 31 '16 at 3:55
• I tried with non zero values. It issues a write or lenght bytes before the bug read... I will insert the initialization code in the question by edit. The fact that ASF is made to support both AVR and ARM makes it very hard for me to understand and I kept avoiding it until now. – Tedi Dec 31 '16 at 11:53