Hi all,
I'm still having problems on TWI (i2c), that are present on all sam7x (128, 256 or 512).
When I try to perform a write to a device that respond with nack (for example an i2c memory not mounted on PCB) the TWI device seems to enter in aloop of retry.
Here is a screenshot of logic analizer:

and here is a detail of the nack contition:

the piece of code is that:
Code:
void twi_Init(void)
{
PMC_PCER = BV(TWI_ID);
/* Disable PIO on TWI pins */
PIOA_ASR = BV(TWD) | BV(TWCK);
PIOA_PDR = BV(TWD) | BV(TWCK);
/* Enable open drain on TWI pins */
PIOA_MDER = BV(TWD) | BV(TWCK);
PIOA_PUER = BV(TWD) | BV(TWCK);
/* Disable all irqs */
TWI_IDR = 0xFFFFFFFF;
/* reset TWI */
TWI_CR = BV(TWI_SWRST);
/* Enable master mode */
TWI_CR = BV(TWI_MSEN);
/*
* Compute twi clock.
* CLDIV = ((Tlow * 2^CKDIV) -3) * Tmck
* CHDIV = ((THigh * 2^CKDIV) -3) * Tmck
* Only CLDIV is computed since CLDIV = CHDIV (50% duty cycle)
*/
uint16_t cldiv, ckdiv = 0;
while ((cldiv = ((CPU_FREQ / (2 * CONFIG_TWI_FREQ)) - 3) / (1 << ckdiv)) > 255)
ckdiv++;
/* Atmel errata states that ckdiv *must* be less than 5 for unknown reason */
ASSERT(ckdiv < 5);
TWI_CWGR = ((uint32_t)ckdiv << TWI_CKDIV_SHIFT) | (cldiv << TWI_CLDIV_SHIFT) | (cldiv << TWI_CHDIV_SHIFT);
TRACEMSG("TWI_CWGR [%08lx]", TWI_CWGR);
aperta = true;
}
int twi_Read(int deviceAddr,int addrSize,uint32_t addr,int bufSize, void *_buf)
{
int counter;
char *buffer = (char *)_buf;
char dummy;
bool nack;
if(bufSize <= 0)
return 0;
TWI_CR = BV(TWI_MSEN);
TWI_MMR = (deviceAddr<<16) | (addrSize<<8);
TWI_MMR |= BV(TWI_MREAD);
TWI_IADR = addr;
reg32_t status;
counter = 0;
nack = false;
if(bufSize == 1)
{
TWI_CR = BV(TWI_START)|BV(TWI_STOP);
}
else
{
TWI_CR = BV(TWI_START);
do
{
/* NACK errata handling */
/* Do not poll the TWI_SR */
/* Wait 3 x 9 TWCK pulse (max) 2 if IADRR not used, before reading TWI_SR */
/* From 400Khz down to 1Khz, the time to wait will be in us range.*/
timer_busyWait(us_to_hptime(2+(3*9*1000000L)/CONFIG_TWI_FREQ));
while(((status=TWI_SR) & (BV(TWI_RXRDY) | BV(TWI_NACK)))==0);
if((status&BV(TWI_NACK)) != 0)
{
nack = true;
dummy = TWI_RHR; // dummy read
break;
}
buffer[counter]=TWI_RHR;
counter++;
bufSize--;
}while(bufSize>1);
TWI_CR = BV(TWI_STOP);
}
/* NACK errata handling */
/* Do not poll the TWI_SR */
/* Wait 3 x 9 TWCK pulse (max) 2 if IADRR not used, before reading TWI_SR */
/* From 400Khz down to 1Khz, the time to wait will be in us range.*/
timer_busyWait(us_to_hptime(2+(3*9*1000000L)/CONFIG_TWI_FREQ));
while(((status=TWI_SR) & (BV(TWI_RXRDY) | BV(TWI_NACK)))==0);
if((status&BV(TWI_NACK)) != 0)
{
nack = true;
}
if(!nack)
{
buffer[counter]=TWI_RHR; // dummy read
counter++;
}
else
{
dummy = TWI_RHR;
}
while(((status=TWI_SR) & BV(TWI_TXCOMP))==0);
TWI_CR = BV(TWI_MSDIS);
return counter;
}
int twi_Write(int deviceAddr,int addrSize,uint32_t addr,int bufSize, const void *_buf)
{
reg32_t status;
const char *buffer = (const char *)_buf;
if(bufSize <= 0)
return 0;
TWI_MMR = (deviceAddr<<16) | (addrSize<<8);
TWI_IADR = addr;
TWI_CR = BV(TWI_MSEN);
int counter=0;
do
{
TWI_THR = buffer[counter++];
/* NACK errata handling */
/* Do not poll the TWI_SR */
/* Wait 3 x 9 TWCK pulse (max) 2 if IADRR not used, before reading TWI_SR */
/* From 400Khz down to 1Khz, the time to wait will be in us range.*/
timer_busyWait(us_to_hptime(2+(3*9*1000000L)/CONFIG_TWI_FREQ));
while(((status=TWI_SR) & (BV(TWI_TXRDY) | BV(TWI_NACK))) == 0); //<===== it hangs here
//while(((status=TWI_SR) & BV(TWI_TXRDY)) == 0); // I tried also in this way, but still hangs
if((status & BV(TWI_NACK))!=0) break; // NACK
}while(counter<bufSize);
while((TWI_SR & BV(TWI_TXCOMP))==0);
TWI_CR = BV(TWI_MSDIS);
return counter;
}
It hangs on status register read. here is the slice of code for clarity:
Code:
do
{
TWI_THR = buffer[counter++];
/* NACK errata handling */
/* Do not poll the TWI_SR */
/* Wait 3 x 9 TWCK pulse (max) 2 if IADRR not used, before reading TWI_SR */
/* From 400Khz down to 1Khz, the time to wait will be in us range.*/
timer_busyWait(us_to_hptime(2+(3*9*1000000L)/CONFIG_TWI_FREQ));
while(((status=TWI_SR) & (BV(TWI_TXRDY) | BV(TWI_NACK))) == 0); //<===== it hangs here
//while(((status=TWI_SR) & BV(TWI_TXRDY)) == 0); // I tried also in this way, but still hangs
if((status & BV(TWI_NACK))!=0) break; // NACK
}while(counter<bufSize);
It seems that TWI device retry to contact the i2c device despite of nack condition, and neither TXRDY nor NACK bit in status register are never asserted.
Is that a silicon bug? Or maybe I have wrongly initialized the device?
In that case how can I correctly initialize the TWI device.
note that CPU_FREQ is defined as 48023000UL and CONFIG_TWI_FREQ in 100000UL (100KHz)
Also note that if I try a read operation instead a write, all works.
thanks in advance for your feedbak