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.

TM4C1290NCPDT: Having problem reading I2C data.

Part Number: TM4C1290NCPDT

I'm trying to read a byte of data as Master.  So the I2C bus should send 1) the device I2C address, 2) send the register number being accessed, 3) read the value being returned.  Code as follows:

u8 RtcRead(u8 Register) {                                          //
                                                                   //
    while(I2CMasterBusy(I2C0_BASE)) {}                             // Wait if still running.
    I2CMasterSlaveAddrSet(I2C0_BASE, RtcAddr, I2CRead);            // This shifts the addr left 1.
    I2CMasterDataPut(I2C0_BASE, Register);                         //
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);       // Send Register.
    while( ! I2CMasterBusy(I2C0_BASE)) {}                          // Wait for master to go busy,
    while(I2CMasterBusy(I2C0_BASE)) {}                             // then wait till done.
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);    // Get Data.
    while( ! I2CMasterBusy(I2C0_BASE)) {}                          // Wait for master to go busy,
    while(I2CMasterBusy(I2C0_BASE)) {}                             // then wait till done.
    return(I2CMasterDataGet(I2C0_BASE));                           //
}                                                                  //

Here's what happens on the I2C bus, not the NAK on the second byte as 0x40 is an invalid register number:

Thanks, Doug

P.S. I wish there was a much better writeup on using the I2C than in the TivaWare manual - and the examples haven't been of that much help.  Aren't there a lot of folks using the TM4C parts and I2C?

  • I tried using Burst mode with the following results:

         while(I2CMasterBusy(I2C0_BASE)) {}                             // Wait if still running.
        I2CMasterSlaveAddrSet(I2C0_BASE, RtcAddr, I2CRead);            // This shifts the addr left 1.
        I2CMasterDataPut(I2C0_BASE, Register);                         //
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);       // Send Register.
        while( ! I2CMasterBusy(I2C0_BASE)) {}                          // Wait for master to go busy,
        while(I2CMasterBusy(I2C0_BASE)) {}                             // then wait till done.
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);       // Send Register.
        while( ! I2CMasterBusy(I2C0_BASE)) {}                          // Wait for master to go busy,
        while(I2CMasterBusy(I2C0_BASE)) {}                             // then wait till done.
        return(I2CMasterDataGet(I2C0_BASE));                           //

    Here's the waveform:

    I don't know where the 0x40 is coming from, the Register is #1.

  • Hi Doug,

      What is your slave device?

      I don't think you are doing it right to start with I2CMasterSlaveAddrSet(I2C0_BASE, RtcAddr, I2CRead) as to read the slave yet. You need to first write to the slave to specify the register (0x1) which you want to read from. Therefore, you should start with something like (I2C0_BASE, RtcAddr, I2CWrite) instead. After you write the register value 0x1 using I2C_MASTER_CMD_BURST_SEND_START, the I2C bus is being held and  you can read the register using I2C_MASTER_CMD_BURST_RECEIVE_FINISH.

    This app note is useful to explain how to use the I2C. Start with section 4.5.1. 

    https://www.ti.com/lit/pdf/spma073

  • Hi Charles,

    The slave is a MAX31329 real time clock, and it seems to be reading things correctly as it will NAK an invalid register number and ACK valid ones.

    I tried the ..BURST_SEND_START and then ...BURST_RECEIVE_FINISH but it didn't work.  I don't think Burst mode will work for this as whether the transaction is a Read or a Write is determined within the Address frame, so to do a write followed by a read won't I have to do a single write followed by a single read?

    When I do a Single Send followed by a Single Receive (first code above) it does a Read followed by a a Read !! 

    If I do a Burst Send Start followed by a Burst Receive Finish it does 2 Writes in a row of the same data.


    If I do a Burst Send Start followed by a Single Receive it does a Receive followed by a Receive. (whew!)

    Something funny is going on here.  Thanks, Doug

  • Reading section 3.2 of SLVA704 "Understanding the I2C Bus", it show that to be able to read a register the following has to happen:

    How do I do this?

    Thanks

  • Doug,

      Can you try like below code sequence. Does it make a difference? Note I did not include the I2CMasterBusy() and !I2CMasterBusy() as mentioned in the first reply. You still need them. 

        I2CMasterSlaveAddrSet(I2C0_BASE, RtcAddr, I2CWrite);      
        I2CMasterDataPut(I2C0_BASE, Register);                         
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);  
        I2CMasterSlaveAddrSet(I2C0_BASE, RtcAddr, I2CRead);  
        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);   
        return(I2CMasterDataGet(I2C0_BASE));

  • Ah, need to set the Read bit.  This code didn't work but when I do a ..BURST_SEND_START followed by a ..SINGLE_RECEIVE works correctly!  The Burst Start generates the Repeated Start frame needed and the Single Receive sends the Address frame again while the BURST_RECEIVE_FINISH doesn't.

    Thanks Charles!

  • I think the Burst mode is to work with I2C slaves that have an "auto-register-increment" facility.

  • Hi Doug,

      Glad your issue is resolved. Can you post your snippet of code so people in the community can benefit when using MAX31329 device. 

  • Very good.  I haven't implemented other than basics for the RTC.  I've also included the code I have so far for a backlight P/S chip LM3530UME-40.

    //-- RTC I2C Register Address' and Bits --//

    const u8 RtcStatusReg          = 0x00;

      const u8 RtcStatPsDectBit    = 0x80;

      const u8 RtcStatOsfBit       = 0x40;

      const u8 RtcStatPFailBit     = 0x20;

      const u8 RtcStatLosBit       = 0x10;

      const u8 RtcStatDifBit       = 0x08;

      const u8 RtcStatTifBit       = 0x04;

      const u8 RtcStatA2fBit       = 0x02;

      const u8 RtcStatA1fBit       = 0x01;

     

    const u8 RtcIntEnReg           = 0x01;

      const u8 RtcIntEnDosfBit     = 0x40;

      const u8 RtcIntEnPFailBit    = 0x20;

      const u8 RtcIntEnDieBit      = 0x80;

      const u8 RtcIntEnTieBit      = 0x40;

      const u8 RtcIntEnA2ieBit     = 0x20;

      const u8 RtcIntEnA1ieBit     = 0x10;

     

    const u8 RtcResetReg           = 0x02;

      const u8 RtcRstBit           = 0x01;

     

    const u8 RtcCfg1Reg            = 0x03;

      const u8 RtcCfg1EnIoBit      = 0x08;

      const u8 RtcCfg1DataRetBit   = 0x04;

      const u8 RtcCfg1TimeoutBit   = 0x02;

      const u8 RtcCfg1EnOscBit     = 0x01;

     

    const u8 RtcCfg2Reg            = 0x04;

      const u8 RtcCfg2ClkOutBit    = 0x80;

      const u8 RtcCfg2ClkOutHzBits = 0x60;    // 2 bits.

      const u8 RtcCfg2DipBit       = 0x08;

      const u8 RtcCfg2ClkInBit     = 0x04;

      const u8 RtcCfg2ClkInHzBits  = 0x03;    // 2 bits.

    void RtcReset(void) {

        RtcWrite(RtcResetReg, RtcRstBit);

        RtcWrite(RtcResetReg, 0);

    }

    u8 RtcRead(u8 Register) {                                          //

        while(I2CMasterBusy(I2C0_BASE)) {}                             // Wait if still running.

        I2CMasterSlaveAddrSet(I2C0_BASE, RtcAddr, I2CWrite);           // Shifts addr left. Write Reg#.

        I2CMasterDataPut(I2C0_BASE, Register);                         //

        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);  // Send Register.

        while( ! I2CMasterBusy(I2C0_BASE)) {}                          // Wait for master to go busy,

        while(I2CMasterBusy(I2C0_BASE)) {}                             // then wait till done.

        I2CMasterSlaveAddrSet(I2C0_BASE, RtcAddr, I2CRead);            // Shifts addr left. Read Data.

        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);    // Get Data.

        while( ! I2CMasterBusy(I2C0_BASE)) {}                          // Wait for master to go busy,

        while(I2CMasterBusy(I2C0_BASE)) {}                             // then wait till done.

        return((u8)I2CMasterDataGet(I2C0_BASE));                       //

    }                                                                  //

     

    void RtcWrite(u8 Register, u8 Data) {                              //

        while(I2CMasterBusy(I2C0_BASE)) {}                             // Wait if still running.

        I2CMasterSlaveAddrSet(I2C0_BASE, RtcAddr, I2CWrite);           // This shifts the addr left 1.

        I2CMasterDataPut(I2C0_BASE, Register);                         //

        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);  // Send Register.

        while( ! I2CMasterBusy(I2C0_BASE)) {}                          // Wait for master to go busy,

        while(I2CMasterBusy(I2C0_BASE)) {}                             // then wait till done.

        I2CMasterDataPut(I2C0_BASE, Data);                             //

        I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH); // Send Data.

        while( ! I2CMasterBusy(I2C0_BASE)) {}                          // Wait for master to go busy,

    }                                                                  // for back to back calls here.

    Code for the LM3530UME-40 follows:

    const   u8 BacklightAddr = 0x38;        // For LM3530UME-40

     

    const u8 BL_GenRegAddr   = 0x10;

    const u8 BL_GenI2CBit    = 0b00000001;

    const u8 BL_GenMapBit    = 0b00000010;

    const u8 BL_GenBriteBits = 0b00011100;

     

    const u8 BL_Max5ma       = 0b00000000;

    const u8 BL_Max8_5ma     = 0b00000100;

    const u8 BL_Max12ma      = 0b00001000;

    const u8 BL_Max15_5ma    = 0b00001100;

     

    const u8 BL_BriteAddr    = 0xA0;

    const u8 BL_BriteOff     = 0x00;

    const u8 BL_Brite25Pct   = 0x20;

    const u8 BL_Brite50Pct   = 0x40;

    const u8 BL_Brite100Pct  = 0x7F;

     

    void BacklightInit(void) {

        BacklightWrite(BL_GenRegAddr, BL_GenI2CBit |   // Simple I2C control.

                                      BL_GenMapBit |   // Linear Map.

                                      BL_Max12ma  );   // Max backlight current.

        BacklightWrite(BL_BriteAddr,  BL_BriteOff);    // Turn backlight off.

     

     

    void BacklightLevel(u8 BriteVal) {

        if(BriteVal > BL_Brite100Pct) {

            Error(INVAL_BACKLIGHT_LEVEL);

        }

        BacklightWrite(BL_BriteAddr,  BriteVal);       // Set backlight level.

    }

     

    void BacklightWrite(u8 Register, u8 Data) {                        //

        while(I2CMasterBusBusy(I2C2_BASE)) {}                          // Wait if busy.

        I2CMasterSlaveAddrSet(I2C2_BASE, BacklightAddr, I2CWrite);     // This shifts the addr left 1.

        I2CMasterDataPut(I2C2_BASE, Register);                         //

        I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_START);  // Register.

        while( ! I2CMasterBusy(I2C2_BASE)) {}                          // Wait till busy.

        while(I2CMasterBusy(I2C2_BASE)) {}                             // Wait till done.

        I2CMasterDataPut(I2C2_BASE, Data);                             //

        I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH); // Data.

        while( ! I2CMasterBusy(I2C2_BASE)) {}                          // Wait till busy, for back to

    }                                                                  // back calls here.

    Note that needing the  while( ! I2CMasterBusy(I2C2_BASE)) {}  is probably because I'm only running the core clock at 20MHz.

  • Note also that I need to go back and implement calls to I2CMasterErr().

  • HI Doug,

     Thanks for sharing. I will bookmark this post for future reference.