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.

i2c Comms Issue between TM4C123GH6PM and MS5803-14BA

Hi all,


I'm having two (seemingly) related issues getting these devices to communicate. As the data sheet here specifies, I need to retrieve the device coefficients from the PROM before I start polling for readings, and I have written code to begin this first part. My two issues are this: if I step through my code line by line, the first byte I read from I2CMDR is 0 (it should be some 8-bit number) and I get a BUSBSY if I attempt to read the second byte. If I let my code run at full speed instead, I always end up with an I2CMCS of 0x2A (Error, No Ack, Idle) before I even attempt to read the first byte (this is why you see all those delays in my code, I've been trying to find out where that delay needs to be). Below is my full code:

#include <tm4c123gh6pm.h>
#include <stdint.h>

float calSENS;
float calOFF;

void delay(unsigned int number){
  int counter = 0;
  while(counter<number){
      counter++;
  }
}

float getPress(){
  float P = 0.0;
  
  //send cmd to convert ADC for D1 (0x40)
  
  //wait a max of 15 cycles
  
  //send ADC read cmd (0x00)
  
  //read raw Dig value (do I need 3 bytes or 4?)
  
  //calculate OFF
  
  //calculate SENS
  
  //calculate P (assume room temp, 20degC)
  
  //convert to PSI
  
  return P;
}

int readByte(){
  int dataByte;
  
  // to receive, set bit |= (1<<0)
  I2C1_MSA_R |= (1<<0);
  
  //initiate read
  I2C1_MCS_R = 0x7u;
  
  //wait for completion
  while((I2C1_MCS_R & (1<<0)) != 0);
  
  //assuming no error, read data
  if((I2C1_MCS_R & (1<<1)) == 0){ //pg 1020
    dataByte = I2C1_MDR_R;
  }
  
  return dataByte;
}

void writeByte(unsigned int dataByte, unsigned int conditions){
  //set i2c to "Write" mode
  I2C1_MSA_R &= ~(1<<0); //clear to transmit
  delay(15);
  
  //place data to be sent
  I2C1_MDR_R = dataByte;
  
  //initiate transmit
  I2C1_MCS_R = conditions;
  
  //wait for completion
  while((I2C1_MCS_R & (1<<0)) != 0);
  
  //check ERROR bit for ACK
  if((I2C1_MCS_R & (1<<1)) != 0){ //pg 1020
    if((I2C1_MCS_R & (1<<4)) == 1){
      //arbitration
    }else{
      I2C1_MCS_R = (1<<2); //send stop
      while((I2C1_MCS_R & (1<<0)) != 0);
    }
  }
  
  //wait before closing
  delay(10);
  
  //close line
  I2C1_MCS_R = (1<<2);
}

void i2cCFG(){
  //enable i2c clock for module 1, pg 348
  SYSCTL_RCGCI2C_R = 0x2u;
  
  //enable clock on port A, pg 1351
  SYSCTL_RCGCGPIO_R = 0x1u;
  
  //turn on GPIO alt functions, pg 671 and pg 1344
  GPIO_PORTA_AFSEL_R = (1<<6)|(1<<7);
  GPIO_PORTA_DEN_R = (1<<6)|(1<<7);
  
  //enable SDA pin for open-drain, pg 676
  GPIO_PORTA_ODR_R = (1<<7);
  
  //set port MUX for i2c, pg 688 and 1351
  GPIO_PORTA_PCTL_R = (3<<28)|(3<<24); //3s in PMC6 and 7
  
  //intialize i2c master
  I2C1_MCR_R = (1<<4);
  
  //set clock speed to 400Kbps
  I2C1_MTPR_R = (1<<0); //make into function
  
  //set slave address to sensor
  I2C1_MSA_R = (0x76u<<1); //make into function later
  
  //set i2c to "Write" mode
  I2C1_MSA_R &= ~(1<<0); //clear to transmit 
  
  //reset sensor
  writeByte(0x1Eu,(1<<0)|(1<<1)); //1E is reset command
  
  //give it cycles
  delay(100);
}

void getCals(){
  int byte1;
  int byte2;
  int C1;
  int C2;
  
  //send PROM read cmd (0xA0) and offset for C1 (+0) (pressure sensitivity)
  writeByte(0xA0u,(1<<0)|(1<<1));
  delay(20);
  
  //read and concat two bytes of C1
  byte1 = readByte();
  byte2 = readByte();
  C1 = (byte1<<8)|byte2;
  
  //send PROM read cmd (0xA0) and offset for C2 (+2) (pressure offset)
  writeByte(0xA2u,(1<<0)|(1<<1));
  
  //read and concat two bytes of C2
  
  //write both to global vars
}

int main()
{
  i2cCFG();
  delay(100);
  getCals();
  
  float curPress = 0.0;
  int val = 0;
  while(1){
    delay(16000000);
    if(val==0){
      curPress = getPress();
      val = 1;
    }else{
      
      val = 0;
    }
  }
  
  return 0;
}

So inside i2cCFG(), my Reset command works fine and is acknowledged. When stepping, the PROM Read command inside getCals() is also acknowledged. However, I'll usually get the MCS errors after initiating the read inside readByte().

Below is a scope capture of the Reset command when stepping:

Below is a scope capture of the PROM read command when stepping:

Finally, below is a scope capture of both commands when run at full speed together. You'll notice that I've forced large delays between commands and even between the first command and the stop condition.

I don't really know why I'm not getting an ACK on the second command, nor why I get a zero in I2CMDR and then an MCS error even if I step through my code.

Any thoughts?