I've connected two E70 boards via TWI0 to test my TWI master application using a second E70 board running a simple TWI slave test application.
After debugging my application 3 days I finally could reproduce my problem in a few lines of two slightly modified ASF TWI master and slave demos.
What I do:
The master tries to read 8 bytes from the slave in a loop.
The slave responds with data until NACK condition has been detected. Slave data is an array with pre-initialized data bytes e.g. 0,1,2,3,....
What I expect: Master reads 8 bytes of data
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7
.....
What I get: Master reads 8 bytes of data
0 1 2 3 4 5 6 7
8 0 1 2 3 4 5 6
7 0 1 2 3 4 5 6
7 0 1 2 3 4 5 6
....
I can see exactly these bytes in the scope. Here are the last 2 bytes of the first 8 byte master read (0 1 2 3 4 5 6 7):
and here are last 2 bytes of the second 8 byte master read (8 0 1 2 3 4 5 6):
So the problem must somewhere arise on the slave side. The slave write code (snippet) goes like this:
for (i = 0; i < MEMORY_SIZE; i++) { uc_memory[i] = i & 0xff; } /* Configure TWIHS as slave */ puts("-I- Configuring the TWIHS in slave mode\n\r"); twihs_slave_init(BOARD_BASE_TWIHS_SLAVE, SLAVE_ADDRESS); /* Clear receipt buffer */ twihs_read_byte(BOARD_BASE_TWIHS_SLAVE); while(1) { uint32_t cnt = twihs_slave_write(BOARD_BASE_TWIHS_SLAVE, uc_memory); printf("Slave sent %ld bytes\n", cnt); }
and the master side:
twihs_master_options_t opt = { .speed = 40000, .chip = TCA6424A_BUS_ADDR }; twihs_package_t sTwiCmd = { .addr = 0, // TWIHS slave address data .addr_length = 0, // TWIHS slave address data size .chip = TCA6424A_BUS_ADDR, // TWIHS slave bus address .buffer = (void *)data_buffer, // transfer data source buffer }; twihs_master_setup( TWIM0, &opt); while(1) { sTwiCmd.length = 8; status = twihs_master_read(TWIM0, &sTwiCmd); if( status == TWIHS_SUCCESS ) printf("Master read %ld bytes\n", sTwiCmd.length); for(uint8_t i=0; i<sTwiCmd.length; i++) { if(data_buffer[i] != i) printf("Master read %d, expected %d\n", data_buffer[i], i); } }
Slave terminal output:
-I- Configuring the TWIHS in slave mode Slave sent 9 bytes Slave sent 8 bytes Slave sent 8 bytes Slave sent 8 bytes
Master terminal output:
-- SAME70-XPLD -- -- Compiled: Sep 4 2017 16:06:07 -- Master read 8 bytes Master 8 bytes test OK Master read 8 bytes Master read 8, expected 0 Master read 0, expected 1 Master read 1, expected 2 Master read 2, expected 3 Master read 3, expected 4 Master read 4, expected 5 Master read 5, expected 6 Master read 6, expected 7 Master read 8 bytes Master read 7, expected 0 Master read 0, expected 1 Master read 1, expected 2 Master read 2, expected 3 Master read 3, expected 4 Master read 4, expected 5 Master read 5, expected 6 Master read 6, expected 7
I assume that in the first transfer cycle the slave writes 9 bytes into the TWI transmit register but because the master only clocks in only 8 bytes "0...7" and the 9th byte ("8") remains in transmit register.
In the second 8 byte master read the remaining byte ("8") is sent in front of the test data before the requested data "0...7" is sent. Now the "7" remains unsent in the transmit register and is sent first at the next master read a.s.o.
Looking into the ASF slave read function code
uint32_t twihs_slave_write(Twihs *p_twihs, uint8_t *p_data) { uint32_t status, cnt = 0; do { status = p_twihs->TWIHS_SR; if (status & TWIHS_SR_SVACC) { if (!(status & (TWIHS_SR_GACC | TWIHS_SR_NACK)) && ((status & (TWIHS_SR_SVREAD | TWIHS_SR_TXRDY)) == (TWIHS_SR_SVREAD | TWIHS_SR_TXRDY))) { p_twihs->TWIHS_THR = *p_data++; cnt++; } } else if ((status & (TWIHS_SR_EOSACC | TWIHS_SR_TXCOMP)) == (TWIHS_SR_EOSACC | TWIHS_SR_TXCOMP)) { break; } } while (1); return cnt; }
Now my assumption is that after the transfer of the 8th byte the TX bit is set before the NACK bit and a 9th byte is written into the transmit register. This is probably a timing problem due to a race condition.
The E70 manual master read timing suggests that the NACK is always set before or at the same time as TX bit is set and the ASF code seems to rely on this:
Regarding the results above my only explanation is that NACK is (sometimes?) set after TX bit. Surprisingly this flowchart does not care about NACK bit:
although the I2C specification states that the slave shall stop sending bytes if NACK condition is detected:
A master-receiver is done reading data and indicates this to the slave through a NACK.
Am I wrong ? Who is right ? Has anyone seen such a problem before ?