This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

I2CCNT Doesn't Decrement

Hello,

I posted about my issues with the C6713 DSK's I2C module a while back (http://e2e.ti.com/support/dsp/tms320c6000_high_performance_dsps/f/115/p/73053/268178.aspx#268178), and while I've come a long way since then, I'm still having some serious issues.  The program below does the following:

1) Generate START condition.
2) Write a byte of data to a PIC slave.
3) Overwrite I2CMDR for master receiver mode while again generating START condition.
4) Read a byte of data from the PIC slave.

while(1)
{
     // Open I2C device 0 and reset I2C module:       
     hI2c=I2C_open(I2C_DEV0,I2C_OPEN_RESET);

     // Configure I2C device:
     I2C_RSETH(hI2c,I2CCLKH,35);
     I2C_RSETH(hI2c,I2CCLKL,35);
     I2C_RSETH(hI2c,I2CMDR,0x0600);
     I2C_RSETH(hI2c,I2CCNT,1);
     I2C_RSETH(hI2c,I2CSAR,0x24);
     I2C_RSETH(hI2c,I2COAR,0);
     I2C_RSETH(hI2c,I2CIER,0);
     I2C_RSETH(hI2c,I2CPSC,13);

     I2C_RSETH(hI2c,I2CMDR,0x0620);                      // Exit reset mode.

     while(I2C_FGETH(hI2c,I2CSTR,BB));                   // Wait for bus to be free.
     I2C_RSETH(hI2c,I2CMDR,0x2620);                      // Set START bit.

     while(!I2C_FGETH(hI2c,I2CSTR,ICXRDY));         // Wait until ready to transmit.
     I2C_writeByte(hI2c,0x01);                                        // Request "gain" value from PIC.

     //while(!I2C_FGETH(hI2c,I2CSTR,ARDY));          // Wait until stop bit is generated.
     I2C_RSETH(hI2c,I2CCNT,1);                                 // Set counter to 1 byte.
     I2C_RSETH(hI2c,I2CMDR,0x2C20);                     // Switch to receive mode, and set STT and STP.

     while(!I2C_FGETH(hI2c,I2CSTR,ICRRDY));       // Wait until ready to receive.
     distortion=I2C_readByte(hI2c);                              // Read byte.

     //while(I2C_FGETH(hI2c,I2CMDR,MST));            // Wait to exit master mode.

     I2C_close(hI2c);
 
printf("end\n");

If you'll notice, two of my "while" lines are commented out.  I'm quite sure that, after writing, I need to wait for ARDY to go high due to I2CCNT decrementing to 0.  My first issue is that I2CCNT never seems to decrement, but instead stays at 1.  The other commented line (waiting to exit master mode) is also an issue because again, I2CCNT never decrements, and thus the I2C module never generates the STOP and never exits master mode to signify the end of the transmission.  The code does work as shown above, but it only writes and reads once rather than looping as it's supposed to.  I can only assume that this issue has something to do with those two lines and/or with I2CCNT.

So, to summarize, my questions are as follows: Why isn't I2CCNT decrementing?  Is this keeping the I2C process from looping, or is there some other reason?  If the latter, does anyone have suggestions as to what might be wrong?

Any help would be very much appreciated.  I've been working on this for over a month now, and I'm completely frustrated.  Thanks!

Danielle

  • Hi Danielle,

    One suggestion you might try is to implement code to detect and handle a NACK. Further information to handle a NACK can be found in the following article: http://processors.wiki.ti.com/index.php/I2cTips.

    Hope this helps!

    -Kevin

  • Kevin,

    Thank you for the suggestion.  I actually printed the linked article a while back for help with configuring the clock, but I put it aside shortly after and thus didn't think to implement NACK detection!  After changing my code to check for a NACK before writing, I don't seem to be getting one, so that's not the problem (although that's still a good check to have).  When adding the lines for the user response to a NACK, I again came across the same issue with I2CCNT.  If I'm supposed to generate a STOP in response to a NACK, then the STOP condition will never occur (at least to my knowledge) if I2CCNT doesn't decrement to 0.  Then of course, I2CMDR.MST will never self-clear either.

    Danielle

     

    EDIT: Actually, after re-reading the "I2CCNT" page of the help menu a bit more carefully, I now see that this register remains unchanged but that it's value is copied to an internal data counter which will decrement.  For whatever reason, I thought these two things were the same.  So that explains why I never see a change in I2CCNT, but I'm still not getting a STOP condition...

  • Danielle,

    Do you mind sharing your updated code?

    Would you also mind trying the following sequence? These can be used to send/receive multiple data bytes. In your case, you could send a stop bit after the first successful transfer.

    *Write Sequence*

    BEGIN:  Configure I2C as Master Transmitter
                    Send start signal
    SEND:    Send data
                    Wait until either XRDY = 1 (Data sent) OR ARDY = 1 (NACK signal / ICNT = 0)
                    Check for NACK
                         1.) Case 1 - NACK occurred
                              Send stop signal
                              Clear NACK
                              Wait for Mode to switch to slave
                              Retry write sequence from beginning (BEGIN)
                         2.) Case 2 - No NACK
                              Send more data (SEND) OR terminate transfer (FINISH)
    FINISH: Wait until ARDY = 1 (ICNT = 0)
                    Send stop signal
                    Wait for Mode to switch to slave
     
    *Read Sequence*
     
    BEGIN:  Configure I2C as Master Receiver
                    Send start signal
    REC:       Wait until either RRDY = 1 (Data received) OR ARDY = 1 (NACK signal / ICNT = 0)
                    Check for NACK
                         1.) Case 1 - NACK occurred
                              Send stop signal
                              Clear NACK
                              Wait for Mode to switch to slave
                              Retry read sequence from beginning (BEGIN)
                         2.) Case 2 - No NACK
                              Store received data (from buffer to array or variable)
                              Receive more data (REC) OR terminate transfer (FINISH)
    FINISH: Wait until ARDY = 1 (ICNT = 0)
                    Send stop signal
                    Wait for Mode to switch to slave

    - Kevin

  • Kevin,

    Here is my updated code after implementing NACK detection:
     
    while(1)
    {      
                            // Open I2C device 0 and reset I2C module:      

                            hI2c=I2C_open(I2C_DEV0,I2C_OPEN_RESET);
     
                            // Configure I2C device:
                            I2C_RSETH(hI2c,I2CCLKH,35);
                            I2C_RSETH(hI2c,I2CCLKL,35);
                            I2C_RSETH(hI2c,I2CMDR,0x0600);
                            I2C_RSETH(hI2c,I2CCNT,1);
                            I2C_RSETH(hI2c,I2CSAR,0x24);
                            I2C_RSETH(hI2c,I2COAR,0);
                            I2C_RSETH(hI2c,I2CIER,0);
                            I2C_RSETH(hI2c,I2CPSC,13);
               
                            I2C_RSETH(hI2c,I2CMDR,0x0620);                      // Exit reset mode.
                           
                            while(I2C_FGETH(hI2c,I2CSTR,BB));                   // Wait for bus to be free.
                            I2C_RSETH(hI2c,I2CMDR,0x2620);                      // Set START bit.
     
    // Wait until ready to transmit:
                            while(!(I2C_FGETH(hI2c,I2CSTR,ICXRDY)||I2C_FGETH(hI2c,I2CSTR,ARDY)));      
                            if(I2C_FGETH(hI2c,I2CSTR,NACK))
                            {
                                        I2C_FSETH(hI2c,I2CMDR,STP,1);
                                        I2C_FSETH(hI2c,I2CSTR,NACK,1);
                                        printf("NACK\n");
                            }
                            else
                            {
                                        I2C_writeByte(hI2c,0x01);                                     // Request "gain" value from PIC.
                           
                                        //while(!I2C_FGETH(hI2c,I2CSTR,ARDY));       // Wait until stop bit is generated.
                                        I2C_RSETH(hI2c,I2CCNT,1);                              // Set counter to 1 byte.
                                        I2C_RSETH(hI2c,I2CMDR,0x2C20);      // Switch to receive mode, and set STT and STP.
     
                                        while(!I2C_FGETH(hI2c,I2CSTR,ICRRDY));     // Wait until ready to receive.
                                        distortion=I2C_readByte(hI2c);                            // Read byte.
                            }
                                        while(I2C_FGETH(hI2c,I2CMDR,MST));            // Wait to exit slave mode.
     
                            I2C_close(hI2c);
     
                printf("end\n");
                           
                

    After reviewing the sequences you posted, I've realized that I've been checking for XRDY before writing rather than before, so this may have been one problem.  I did implement both the write and read sequence, and I'm happy to say that they work perfectly when used independently.  For example, I can write multiple times in a row, and I can also read multiple times in a row.  Unfortunately, when I try to combine the two sequences (so I can write, read, write, read, write, etc), everything falls apart.  In this case, one write will occur, the I2C module gets configured as a master receiver after the whole process is complete, and then the program gets stuck while waiting for RRDY or ARDY.  My code is as follows:


    hI2c=I2C_open(I2C_DEV0,I2C_OPEN_RESET);
     
    // Configure I2C device:

    I2C_RSETH(hI2c,I2CCLKH,35);
    I2C_RSETH(hI2c,I2CCLKL,35);
    I2C_RSETH(hI2c,I2CMDR,0x0600);
    I2C_RSETH(hI2c,I2CCNT,1);
    I2C_RSETH(hI2c,I2CSAR,0x24);
    I2C_RSETH(hI2c,I2COAR,0);
    I2C_RSETH(hI2c,I2CIER,0);
    I2C_RSETH(hI2c,I2CPSC,13);

    I2C_RSETH(hI2c,I2CMDR,0x0620);                       // Exit reset mode.
     
    BEGINSEND:
    I2C_RSETH(hI2c,I2CMDR,0x0620);                      // Configure I2C as Master Transmitter
    I2C_start(hI2c);   // Send start signal
     
    SEND:
    I2C_writeByte(hI2c,0x01);                                          // Send data
     
    //Wait until either XRDY=1 or ARDY=1:
    while(!(I2C_FGETH(hI2c,I2CSTR,ICXRDY)||I2C_FGETH(hI2c,I2CSTR,ARDY)));
     
    if(I2C_FGETH(hI2c,I2CSTR,NACK))                       // Check for NACK
    {   // Case 1: NACK occurred
          I2C_sendStop(hI2c); // Send stop signal
          I2C_FSETH(hI2c,I2CSTR,NACK,1);   // Clear NACK
          while(I2C_FGETH(hI2c,I2CMDR,MST));   // Wait for mode to switch to slave
          goto BEGINSEND;
    }
     
    else  // Case 2: No NACK
    goto FINISH;
     
    FINISH:
    while(!(I2C_FGETH(hI2c,I2CSTR,ARDY)));
    I2C_sendStop(hI2c);   // Send stop signal
    while(I2C_FGETH(hI2c,I2CMDR,MST));   // Wait for mode to switch to slave
     
    BEGINREAD:
    I2C_RSETH(hI2c,I2CMDR,0x0420);     // Configure I2C as Master Receiver
    I2C_start(hI2c);   // Send start signal
     
    REC:
    // Wait until either RRDY=1 or ARDY=1
    while(!(I2C_FGETH(hI2c,I2CSTR,ICRRDY)||I2C_FGETH(hI2c,I2CSTR,ARDY)));
     
    if(I2C_FGETH(hI2c,I2CSTR,NACK))   // Check for NACK
              // Case 1: NACK occurred
          I2C_sendStop(hI2c);  // Send stop signal
          I2C_FSETH(hI2c,I2CSTR,NACK,1);   // Clear NACK
          while(I2C_FGETH(hI2c,I2CMDR,MST));   // Wait for mode to switch to slave
          goto BEGINREAD;
    }
     
    else
    {
          distortion=I2C_readByte(hI2c);   // Read byte
          goto FINISHSEND;
    }
     
    FINISHSEND:
    while(!I2C_FGETH(hI2c,I2CSTR,ARDY));
    I2C_sendStop(hI2c);
    while(I2C_FGETH(hI2c,I2CMDR,MST));
    goto BEGINSEND;

  • Quick Update: After playing around with the code for both devices in an attempt to figure out exactly what's going wrong, I don't think the C6713 is even generating the START after the BEGINREAD label.  If it was, then my PIC would enter its writing loop, and that isn't happening.  When the I2C module exits master mode, do any of the I2C registers get modified (with the exception of I2CMDR, of course)?  Is there anything I need to reconfigure?  Also, should I be sending the STOP after writing (as I have been doing), or should I just be jumping to BEGINREAD directly after?  I feel like I've tried everything with no results.

  • Danielle,

    Unfortunately, I am unfamiliar with a PIC and its I2C interface; however, the read/write sequences that were provided were intended to be generic enough that they should still function regardless of the type of slave. Do you need to send a command byte before sending/receiving your data? Can you confirm that the PIC is receiving your first data transfer byte, and the STOP bit? Has the PIC released the clock?

    -Kevin

  • Kevin,

    I have confirmed that the PIC is receiving the first data transfer byte, and I do tell it to release the clock, but unfortunately I have no way of checking for the STOP bit.  To be honest, after looking over the PIC specifications, I'm not even sure that it does anything with the STOP or even sees it when working correctly.  That got me thinking that, strange as it seems, maybe I shouldn't be sending a STOP at all.  Therefore, I tried skipping everything under the FINISH label (within the sequences that you posted) for both read and write, and now it works just fine.  This is the code as it is right now, with the write/read sequence occurring in an infinite loop:

    SEND:
    I2C_RSETH(hI2c,I2CMDR,0x0620);     // Configure I2C as Master Transmitter
    I2C_start(hI2c);                                         // Send start signal
    I2C_writeByte(hI2c,0x01);                       // Send data

    // Wait until either XRDY=1 or ARDY=1:
    while(!(I2C_FGETH(hI2c,I2CSTR,ICXRDY)||I2C_FGETH(hI2c,I2CSTR,ARDY)));

    if(I2C_FGETH(hI2c,I2CSTR,NACK))                  // Check for NACK
    {                                                                                 // Case 1: NACK occurred
            I2C_sendStop(hI2c);                                     // Send stop signal
            I2C_FSETH(hI2c,I2CSTR,NACK,1);           // Clear NACK
            while(I2C_FGETH(hI2c,I2CMDR,MST));    // Wait for mode to switch to slave
            goto SEND;
    }

    else                                                                          // Case 2: No NACK
            goto READ;

    READ:
    I2C_RSETH(hI2c,I2CMDR,0x0420);                 // Configure I2C as Master Receiver
    I2C_start(hI2c);                                                     // Send start signal
     
    // Wait until either RRDY=1 or ARDY=1
    while(!(I2C_FGETH(hI2c,I2CSTR,ICRRDY)||I2C_FGETH(hI2c,I2CSTR,ARDY)));
     
    if(I2C_FGETH(hI2c,I2CSTR,NACK))                 // Check for NACK
    {                                                                                // Case 1: NACK occurred
            I2C_sendStop(hI2c);                                    // Send stop signal
            I2C_FSETH(hI2c,I2CSTR,NACK,1);          // Clear NACK
            while(I2C_FGETH(hI2c,I2CMDR,MST));   // Wait for mode to switch to slave
            goto READ;
    }
     
    else
    {
            distortion=I2C_readByte(hI2c);                  // Read byte
            printf("%i\n",distortion);
            goto SEND;


    While I wouldn't be surprised if I ran into issues with this at some later point due to removing those few lines, I'm perfectly happy claiming success for now.  Thank you so much for your help!  It's nice to have finally made some progress.

    Danielle 

  • Danielle,

    I am glad to see you were able to make progress. Thanks for sharing your solution!

    -Kevin