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.

TM4C123: ROM boot loader unexpected response using I2C

I'm having trouble using the I2C interface with the ROM boot loader active. I don't get the reponses I expect.

Code from my I2C master:

#define TIVA_DEVICEADDRESS (0x42<<1)

uint8 status_cmd = COMMAND_GET_STATUS;
uint8 ping_cmd = COMMAND_PING;

void EeSetStart(void)
{
  volatile uint16 x;

  // Start condition
  ACCESS2_CTRL_REG &= ~(EN_ACCESS_BUS);
  x++; // 624 ns
  ACCESS2_CTRL_REG |= (SCL_VAL | SDA_VAL);
  BusyWait1();

  ACCESS2_CTRL_REG &= ~(SDA_VAL);
  BusyWait1();

  ACCESS2_CTRL_REG &= ~(SCL_VAL);
  BusyWait1();
}

void EeSetStop(void)
{
  // stop condition
  ACCESS2_CTRL_REG &= ~(EN_ACCESS_BUS);
  ACCESS2_CTRL_REG &= ~(SCL_VAL | SDA_VAL);
  BusyWait1();

  ACCESS2_CTRL_REG |= SCL_VAL;
  BusyWait1();

  ACCESS2_CTRL_REG |= SDA_VAL;
  BusyWait1();
}

void EeSendByte(BYTE a)
{
  volatile WORD n;
  ACCESS2_CTRL_REG |= EN_ACCESS_BUS;  // automatic control SDA/SCL-VAL
  n++; // this is neccesssary to delay following events

  ACCESS2_CLEAR_INT_REG = 0;

  ACCESS2_IN_OUT_REG=a;
  // Wait until transmission is done
  while (!(ACCESS2_CTRL_REG & ACCESSx_INT)) ;
  ACCESS2_CLEAR_INT_REG = 0;
}

BYTE ReadByte_Ack(UByte nextNoAck)
{
  volatile uint16 Read = 0;

  ACCESS2_CTRL_REG &= ~ACKn;
  while (!(ACCESS2_CTRL_REG & ACCESSx_INT));
  Read=ACCESS2_IN_OUT_REG;   // Read received byte
  ACCESS2_CLEAR_INT_REG = 0;
  if (nextNoAck)
  {
    ACCESS2_CTRL_REG |= ACKn; // don't transmit Acknowledge
  }
  return(Read);
}

BYTE ReadByte_NoAck(void)
{
  volatile uint16 Read = 0;

  ACCESS2_CTRL_REG |= ACKn;  // don't transmit Acknowledge
  while (!(ACCESS2_CTRL_REG & ACCESSx_INT));
  Read=ACCESS2_IN_OUT_REG;   // Read received byte
  ACCESS2_CLEAR_INT_REG = 0;

  return(Read);
}

uint8 send_packet(uint8* data, uint8 size)
{
  uint8 i, ack, checksum = 0;
  for (i = 0; i < size; i++) {
    checksum += data[i];
  }

  do
  {
    EeSetStop();
    EeSetStart();
    EeSendByte(TIVA_DEVICEADDRESS);
  } while (ACCESS2_CTRL_REG & ACKn);

  EeSetStop();
  EeSetStart();

  EeSendByte(size +2);
  EeSendByte(checksum);

  for (i = 0; i < size; i++) {
    EeSendByte(data[i]);
  }

  EeSetStart();
  // Set Device address for read
  EeSendByte(TIVA_DEVICEADDRESS|0x01);

  ack = ReadByte_NoAck();
  debugf("-%02X-\n", ack);
  EeSetStop();

  return ack;
}

uint8 get_packet(uint8* data, uint8* size)
{
  uint8 i, psize, pchecksum, checksum = 0;

  do
  {
    EeSetStop();
    EeSetStart();
    EeSendByte(TIVA_DEVICEADDRESS);
  } while (ACCESS2_CTRL_REG & ACKn);

  EeSetStart();
  EeSendByte(TIVA_DEVICEADDRESS|0x01);
  psize = ReadByte_Ack(0);
  debugf("psize = %02X\n", psize);
  if (psize < *size) *size = psize;
  pchecksum = ReadByte_Ack(0);
  debugf("pchecksum = %02X\n", pchecksum);

  for (i = 0; i < *size; i++) {
    if (i == (*size-1)) {
      data[i] = ReadByte_NoAck();
    } else if (i == (*size-2)) {
      ReadByte_Ack(1);
    } else {
      data[i] = ReadByte_Ack(0);
    }
  }
  for (i = 0; i < *size; i++) {
    checksum = data[i];
  }

  EeSetStart();
  // Set Device address for write
  EeSendByte(TIVA_DEVICEADDRESS);
  if (checksum == pchecksum) {
    EeSendByte(COMMAND_ACK);
    EeSetStop();
    return COMMAND_ACK;
  } else {
    EeSendByte(COMMAND_NAK);
    EeSetStop();
    return COMMAND_NAK;
  }
}

uint8 send_command(uint8* cmd, uint8 size)
{
  uint8 ret;

  uint8 status, ssize;
  ret = send_packet(cmd, size);
  ret = send_packet(&status_cmd, 1);
  ssize = sizeof(status);
  ret = get_packet(&status, &ssize);
  debugf("status: %02X\n", status);
  return ret;
}

void tiva_main()
{
send_commnad(&ping_cmd, 1);
}

Output from my debug interface:

-c2-			<-- expected 0xCC = COMMAND_ACK
-c2-			<-- expected 0xCC = COMMAND_ACK
psize = c2		<-- expected 1
pchecksum = f0		<-- expected 0x40
status: fc		<-- expected 0x40 = COMMAND_RET_SUCCESS

Any ideas?

  • Hello Thomas

    The first command response 0xC2 is not defined in the bl_cmmands.h. Do you have the I2C Transaction captured on the scope for the PING Command?

    Regards

    Amit

  • I simplified my code to just send a ping, but I get different responses. On 1st run I get 0x00, 2nd run I get 0xCC and for the following runs I get 0xC2.

    void EeSetStart(void)
    {
      volatile uint16 x;
    
      // Start condition
      ACCESS2_CTRL_REG &= ~(EN_ACCESS_BUS);  // manual control SDA/SCL-VAL
      x++; // 624 ns
      ACCESS2_CTRL_REG |= (SCL_VAL | SDA_VAL);
      BusyWait1();
      BusyWait1();
    
      ACCESS2_CTRL_REG &= ~(SDA_VAL);
      BusyWait1();
      BusyWait1();
      ACCESS2_CTRL_REG &= ~(SCL_VAL);       // 1200 ns (clock pulse width low)
      BusyWait1();
      BusyWait1();
    }
    
    void EeSetStop(void)
    {
      // stop condition
      ACCESS2_CTRL_REG &= ~(EN_ACCESS_BUS);   // manual control SDA/SCL-VAL
      ACCESS2_CTRL_REG &= ~(SCL_VAL | SDA_VAL);
      BusyWait1();
      BusyWait1();
    
      ACCESS2_CTRL_REG |= SCL_VAL;
      BusyWait1();
      BusyWait1();
    
      ACCESS2_CTRL_REG |= SDA_VAL;
      BusyWait1();
      BusyWait1();
    }
    
    void EeSendByte(BYTE a)
    {
      volatile WORD n;
      ACCESS2_CTRL_REG |= EN_ACCESS_BUS;  // automatic control SDA/SCL-VAL
      BusyWait1();
    
      ACCESS2_CLEAR_INT_REG = 0;
    
      ACCESS2_IN_OUT_REG=a;
      BusyWait1();
      // Wait until transmission is done
      while (!(ACCESS2_CTRL_REG & ACCESSx_INT)) ;
      ACCESS2_CLEAR_INT_REG = 0;
    }
    
    BYTE ReadByteTiva(void)
    {
      volatile uint16 Read = 0;
    
      while (!(ACCESS2_CTRL_REG & ACCESSx_INT));
      Read=ACCESS2_IN_OUT_REG;   // Read received byte
      ACCESS2_CLEAR_INT_REG = 0;
    
      return(Read);
    }
    
    uint8 send_packet(uint8* data, uint8 size)
    {
      uint8 i, ack, ack2, checksum = 0;
      for (i = 0; i < size; i++) {
        checksum += data[i];
      }
      debugf("checksum: %02X\n", checksum);
    
      do
      {
        EeSetStart();
        EeSendByte(TIVA_DEVICEADDRESS);
      } while (ACCESS2_CTRL_REG & ACKn);
    
      EeSendByte(size +2);
      EeSendByte(checksum);
    
      for (i = 0; i < size; i++) {
        EeSendByte(data[i]);
      }
    
      EeSetStart();
      // Set Device address for read
      EeSendByte(TIVA_DEVICEADDRESS|0x01);
      while (ACCESS2_CTRL_REG & ACKn);
      ACCESS2_CTRL_REG |= ACKn;  // don't transmit Acknowledge
    
      ack = ReceiveByte_NoAck();
      EeSetStop();
      ACCESS2_CTRL_REG &= ~ACKn;  // transmit Acknowledge
      debugf("ack: %02X\n", ack);
    
      return ack;
    }
    
    uint8 send_command(uint8* cmd, uint8 size)
    {
      uint8 ret;
      ret = send_packet(cmd, size);
      return ret;
    }
    

    I've attached captures from the scope on 3 runs.

    Thanks!

  • Hello Thomas,

    The PING command should be the next byte after the Address for the slave. However what I see is that it is the second byte after the address.

    Secondly I do not see a Repeated Start so that the program receives an ACK

    Regards

    Amit

  • Hi Amit,

    According to the ROM user's guide (spmu367.pdf), every packet starts with the length, then the check sum and finally the data. This is also what I understood from the boot loader sources in TivaWare_C_Series-2.1.0.12573\boot_loader.

    So a ping packet would be:

    0x03    0x20      0x20
    length  checksum  command

    Is this wrong?

    It's receiving the ACK that's the problem. For the 1st run I get 0x00, the 2nd run (without resetting the Tiva) I get 0xCC, and the following runs I get 0xC2.

    There's a repeated start:

    Thanks!

  • Hello Thomas

    It also mentions that the Master has to wait for the single byte ACK from the device. So as long as you get 0x00 from the device the Master should wait.

    Regards

    Amit

  • If I wait for the ACK byte to be non zero, I get 0xFF for the 1st run, 0xCC for the 2nd run and 0xC2 for the following runs.

    If I wait for the ACK byte to be either COMMAND_ACK (0xCC) or COMMAND_NAK (0x33) the 1st run never returns...

  • Hello Thomas,

    In the earlier waveform snapshot you had the 1st run showed 0x00 and then it showed 0xCC in the 2nd RUN. What I am mentioning here is that the 1st RUN should not be terminated till the non-zero byte is received.

    Regards

    Amit

  • Yes, and if I wait for the ACK byte to be non zero, I get 0xFF (read 0x00 then try and read again and get 0xFF) for the 1st run, 0xCC for the 2nd run and 0xC2 for the following runs.

    uint8 send_packet(uint8* data, uint8 size)
    {
      uint8 i, ack = 0, checksum = 0;
      for (i = 0; i < size; i++) {
        checksum += data[i];
      }
      debugf("checksum: %02X\n", checksum);
    
      do
      {
        EeSetStart();
        EeSendByte(TIVA_DEVICEADDRESS);
      } while (ACCESS2_CTRL_REG & ACKn);
    
      EeSendByte(size +2);
      EeSendByte(checksum);
    
      for (i = 0; i < size; i++) {
        EeSendByte(data[i]);
      }
    
      EeSetStart();
      // Set Device address for read
      EeSendByte(TIVA_DEVICEADDRESS|0x01);
      while (ACCESS2_CTRL_REG & ACKn);
      ACCESS2_CTRL_REG |= ACKn;  // don't transmit Acknowledge
    
      while ((ack = ReceiveByte_NoAck()) == 0x00)
        __asm("nop");
      EeSetStop();
      ACCESS2_CTRL_REG &= ~ACKn;  // transmit Acknowledge
      debugf("ack: %02X\n", ack);
    
      return ack;
    }
    

    EDIT: I tried to mark the changed line in red, but got "<span style="color:#ff0000;">" instead.

  • Hello Thomas,

    Give me a day or two to get the setup working to see what is happening.

    Regards

    Amit

  • Hello Thomas,

    I have attached a scope plot of what I am doing. Every time I send PING Command I get the response as 0xCC. If I change the checksum not to match the command then I get 0x33

    Regards

    Amit

  • Thanks!

    I read an extra byte with the acknowledge bit before reading the actual ACK/NAK byte and now it works.