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.

Feeling demented by I2C!

hello, 

I am trying to get the I2c going on a tm4c1237hpz using my own board. If I run the board without debugging then the I2c functions as expected. If I debug it just hangs waiting on a busy flag that never sets. 

I have been checking the latency on the busy flag being set (logger[] array). I seen this in another post. Am i doing anything wrong or non-standard?

SYSCTL->RCGCI2C = SYSCTL_RCGCI2C_R1; // Enable I2C run mode clock
I2C1->MCR = I2C_MCR_MFE; // Enable I2C master mode
I2C1->MTPR = ((uiCoreClockSpeed / (20 * uiFrequency)) - 1); // 100KHz transfer rate

I2C1->MSA = I2C_WRITE_ADDRESS; // IO expander I2C address
I2C1->MDR = I2C_CONFIG_PORT0; // TX register to write
I2C1->MCS = (I2C_MCS_START | I2C_MCS_RUN); // TX start, address + register
logger[0] = I2C1->MCS;
logger[1] = I2C1->MCS;
logger[2] = I2C1->MCS;
while(!(I2C1->MCS & I2C_MCS_BUSY));
while(I2C1->MCS & I2C_MCS_BUSY); // Wait for TX complete

I2C1->MDR = 0x07; // TX Port 0 setting -> All P0.0 to P0.2 as inputs
I2C1->MCS = I2C_MCS_RUN; // TX data only
logger[3] = I2C1->MCS;
logger[4] = I2C1->MCS;
logger[5] = I2C1->MCS;
while(!(I2C1->MCS & I2C_MCS_BUSY));   <-----------------------------------------------------  hangs here
while(I2C1->MCS & I2C_MCS_BUSY); // Wait for TX complete

I2C1->MDR = 0x00; // TX Port 1 setting -> All outputs
I2C1->MCS = (I2C_MCS_RUN | I2C_MCS_STOP); // TX data + stop
logger[6] = I2C1->MCS;
logger[7] = I2C1->MCS;
logger[8] = I2C1->MCS;
while(!(I2C1->MCS & I2C_MCS_BUSBSY));
while(I2C1->MCS & I2C_MCS_BUSBSY); // Wait for TX complete

I2C1->MSA = I2C_WRITE_ADDRESS;
I2C1->MDR = I2C_OUTPUT_PORT1;
I2C1->MCS = (I2C_MCS_START | I2C_MCS_RUN); // TX start, address + register
logger[9] = I2C1->MCS;
logger[10] = I2C1->MCS;
logger[11] = I2C1->MCS;
while(!(I2C1->MCS & I2C_MCS_BUSY));
while(I2C1->MCS & I2C_MCS_BUSY); // Wait for TX complete

I2C1->MDR = 0x00; // Port 1 outputs = 0
I2C1->MCS = (I2C_MCS_RUN | I2C_MCS_STOP); // TX data + stop
logger[12] = I2C1->MCS;
logger[13] = I2C1->MCS;
logger[14] = I2C1->MCS;
while(!(I2C1->MCS & I2C_MCS_BUSY));
while(I2C1->MCS & I2C_MCS_BUSY);
while(I2C1->MCS & I2C_MCS_BUSBSY);

I appreciate any help. I am really stuck on this one. Even just a nudge in the right direction would be great.

Thanks

sarah 

  • Hello Sarah,

    When in debug mode the transaction time for the step is way longer than the time it takes for I2C to transmit/receive and update the flag. Rathen than using

    while(!(I2C1->MCS & I2C_MCS_BUSY));
    while(I2C1->MCS & I2C_MCS_BUSY); // Wait for TX complete

    you may want to

    Delay(10)
    while(I2C1->MCS & I2C_MCS_BUSY); // Wait for TX complete

    and it would work well in debug mode as well.

    Regards
    Amit
  • Ms. Sarah,

    May I commend you for a simply GREAT, "Headline!"

    Now - sometimes (perhaps often) the IDE proves intrusive - and spoils your (pardon) "prying eye."   (IDE's "access" of critical variable/register "disturbs.")

    Vendor's Amit will shortly arrive - yet I believe if you run correctly "free from debug" you may direct your "worries" to more pressing issues!

    BTW - feeling you report is not unique - although your memorialization (demented) surely is!

  • Thanks for the replies and the kudos on my title. 

    The problem is now resolved. 

    When I first powered up the unit it would initialize ok then try to do a read. The read function was incorrect and was started with a I2C_MCS_START | I2C_MCS_RUN | I2C_MCS_ACK. The waiting for an ack caused the i2c to crash and hold sda low. The debugger would then reset the unit and try to use the i2c and the busbusyflag would get set instantly. So my code now removes the ack and all works perfectly. 

    //initialize i2c

    I2C1->MSA = I2C_WRITE_ADDRESS; // IO expander I2C address
    I2C1->MDR = I2C_CONFIG_PORT0; // TX register to write
    I2C1->MCS = (I2C_MCS_START | I2C_MCS_RUN); // TX start, address + register
    vDelayX(10);
    while(I2C1->MCS & I2C_MCS_BUSY); // Wait for TX complete
    I2C1->MDR = 0x07; //port 0 as inputs // TX Port 0 setting -> All P0.0 to P0.2 as inputs
    I2C1->MCS = I2C_MCS_RUN; // TX data only
    vDelayX(10);
    while(I2C1->MCS & I2C_MCS_BUSY); // Wait for TX complete
    I2C1->MDR = 0x00; //port 1 as outputs // TX Port 1 setting -> All outputs
    I2C1->MCS = (I2C_MCS_RUN | I2C_MCS_STOP); // TX data + stop
    vDelayX(10);
    while(I2C1->MCS & I2C_MCS_BUSBSY); // Wait for TX complete
    I2C1->MSA = I2C_WRITE_ADDRESS;
    I2C1->MDR = I2C_OUTPUT_PORT1;
    I2C1->MCS = (I2C_MCS_START | I2C_MCS_RUN); // TX start, address + register
    vDelayX(10);
    while(I2C1->MCS & I2C_MCS_BUSY);
    I2C1->MDR = 0x00; //port1 as low // Port 1 outputs = 0
    I2C1->MCS = (I2C_MCS_RUN | I2C_MCS_STOP); // TX data + stop
    vDelayX(10);
    while(I2C1->MCS & I2C_MCS_BUSBSY); // Wait for TX complete

    //read port function

    I2C1->MSA = I2C_WRITE_ADDRESS; // IO expander I2C address
    I2C1->MDR = I2C_INPUT_PORT0; // TX register to read
    I2C1->MCS = (I2C_MCS_START | I2C_MCS_RUN); // TX start, address + register
    while(I2C1->MCS & I2C_MCS_BUSY); // Wait for TX complete
    I2C1->MSA = I2C_READ_ADDRESS; // IO expander I2C address
    I2C1->MCS = (I2C_MCS_START | I2C_MCS_RUN|I2C_MCS_ACK); // TX restart + read + stop
    while(I2C1->MCS & I2C_MCS_BUSY); // Wait for RX complete
    I2C1->MCS = I2C_MCS_STOP; // Stop
    while(I2C1->MCS & I2C_MCS_BUSBSY); // Wait for stop complete
    ucReadData = I2C1->MDR; // Read data from RX register
    return(ucReadData);

    I am now un-demented and very relieved. 

    Sarah 

  • Hello Sarah,

    The code in its current form does not cater to any error handling such as NAK or ARB LOST. If it is a single master system then ARB LOST is not a worry but NAK can still be a case (based on slave device behavior) and it would be good to have a check of the same.

    Regards
    Amit