Atmel website | ARM Community | AVR freaks | Technical Support
Banner
 FAQ •  Search •  Register •  Login 

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 1 post ] 
Author Message
 Post subject: problem on TWI on SAM7X
PostPosted: Thu Feb 18, 2010 11:54 am 
Offline

Joined: Tue Oct 11, 2005 5:43 pm
Posts: 12
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:
Image

and here is a detail of the nack contition:
Image

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


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: