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.

TM4C123GH6PM: different results on I2C between step debugging and running the program

Part Number: TM4C123GH6PM

hello , i have a tiva C microcontroller and i was working on a project of interfacing an adxl 345 accelerometer sensor with it using I2C i have managed to get it working using a clock of 80 MHZ and using the PLL to set the clock of the I2C module to 100 and it is working perfectly fine if i use step by step debugging , however , if i run the program i get zeroes on the MDR register and the variables that i read the data from MDR register into 

step by step debugging gives clear and CORRECT results my problem is when letting the program to run it gives all zeroes

if i try to step debug after that it will keep the zeroes and i have to disconnect the sensor's power and reconnect it for it to work again , i dont know why this is happening any help ? is the clock too much at 80 MHZ or what ? 

things i have tried:

i have tried adding some software delay to act as a step by step debugging between each read and write operation and still it didnt work and gave me zeroes again. 

here is my code in case it is needed

#include "tm4c123gh6pm.h"
#include "stdint.h"

void EnableI2CModule0(void);
uint8_t ReadRegister(uint8_t RegisterAddress);
void PLL_Init(void);
void WriteRegister(uint8_t RegisterAddress,uint8_t Data);
volatile uint8_t X_Axis1,X_Axis2,Y_Axis1,Y_Axis2,Z_Axis1,Z_Axis2=0;

int main()	
{
	volatile long temp;
	PLL_Init();
	EnableI2CModule0();
	temp=ReadRegister(0x00);
	WriteRegister(0x2D,0x08);
	temp=ReadRegister(0x2D);
	WriteRegister(0x31,0x0B);
	temp=ReadRegister(0x31);	
	while(1)
	{
		X_Axis1=ReadRegister(0x32);
		X_Axis2=ReadRegister(0x33);
		Y_Axis1=ReadRegister(0x34);
		Y_Axis2=ReadRegister(0x35);
		Z_Axis1=ReadRegister(0x36);
		Z_Axis2=ReadRegister(0x37);
	}
}
void PLL_Init(void){
  // 0) Use RCC2
  SYSCTL_RCC2_R |=  0x80000000;  // USERCC2
  // 1) bypass PLL while initializing
  SYSCTL_RCC2_R |=  0x00000800;  // BYPASS2, PLL bypass
  // 2) select the crystal value and oscillator source
  SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0)   // clear XTAL field, bits 10-6
                 + 0x00000540;   // 10101, configure for 16 MHz crystal
  SYSCTL_RCC2_R &= ~0x00000070;  // configure for main oscillator source
  // 3) activate PLL by clearing PWRDN
  SYSCTL_RCC2_R &= ~0x00002000;
  // 4) set the desired system divider
  SYSCTL_RCC2_R |= 0x40000000;   // use 400 MHz PLL
  SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000)  // clear system clock divider
                  + (4<<22);      // configure for 80 MHz clock
  // 5) wait for the PLL to lock by polling PLLLRIS
  while((SYSCTL_RIS_R&0x00000040)==0){};  // wait for PLLRIS bit
  // 6) enable use of PLL by clearing BYPASS
  SYSCTL_RCC2_R &= ~0x00000800;
}

void EnableI2CModule0(void)
{
	volatile int Delay=0;
	SYSCTL_RCGCI2C_R|=0x00000001; //set i2c module 0 clock active
	Delay=SYSCTL_RCGCI2C_R; //delay allow clock to stabilize 
	SYSCTL_RCGCGPIO_R |=0x00000002; //i2c module 0 is portB so activate clock for port B
	Delay = SYSCTL_RCGCGPIO_R; //delay allow clock to stabilize 
	GPIO_PORTB_AFSEL_R|= 0x0000000C; //enable alternate functions for PB2 and PB3
	GPIO_PORTB_ODR_R |= 0x00000008; //set PB3 (I2C SDA)  for open drain
	GPIO_PORTB_DEN_R |= 0xFF; //Enable digital on Port B
	GPIO_PORTB_PCTL_R |=0x03;
	I2C0_PP_R |= 0x01;
	I2C0_MTPR_R |= 0x00000027; //set SCL clock
	I2C0_MCR_R |= 0x00000010; //intialize mcr rigester with that value given in datasheet
}
uint8_t ReadRegister(uint8_t RegisterAddress)
{
	volatile uint8_t result=0;
	I2C0_MSA_R = 0x000000A6; //write operation
	I2C0_MDR_R = RegisterAddress; //place data to send mdr register
	I2C0_MCS_R = 0x00000007; //stop start run
	while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit 
	I2C0_MSA_R = 0x000000A7; // read operation
	I2C0_MCS_R = 0x00000007; // stop start run
	while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit 
	result = I2C0_MDR_R;
	return result;
}

void WriteRegister(uint8_t RegisterAddress,uint8_t Data)
{
	I2C0_MSA_R = 0x000000A6; //write operation
	I2C0_MDR_R = RegisterAddress; //place register address to set in mdr register
	I2C0_MCS_R = 0x00000003; //burst send ( multiple bytes send ) 
	while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit 
	I2C0_MDR_R = Data; //place data to be sent in  mdr register
	I2C0_MCS_R = 0x00000005; // transmit followed by stop state 
	while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit 
}

  • update , i tried changing the divisor value at the same clock and it gave the same error ! so i am guessing this is a problem with the divisor however the way i see it the values are correct arent they ?
  • Essam Eid said:
    step by step debugging gives clear and CORRECT results my problem is when letting the program to run it gives all zeroes

    My guess is that there is a timing problem such that the code doesn't wait for the I2C bus transactions to complete.

    I haven't attempted to fully understand the code since it is written in Direct Register Mode (DRM) with magic numbers for the register fields, rather than the easier to understand TivaWare APIs.

    If you want to use DRM for "learning" purposes suggest you at least use the macros from the Tivaware hw_i2c.h include file for the register fields. E.g. use I2C_MCS_BUSBSY rather than 0x00000040.

    One thing from the code which is wrong is the structure of the polling of the busy bits with the following statement:

    	while((I2C0_MCS_R &= 0x00000040)==1); //poll busy bit

    The use of &= means the code tries to modify the read only I2C Master Control/Status register, and then checks for the register having the value one which is not what you want and means the loop doesn't wait until the I2C bus is idle.

    Try replacing the polls on the bus being busy with:

    	while((I2C0_MCS_R & I2C_MCS_BUSBSY) !=0); //poll busy bit 

  • Hello Essam

    If you put a delay loop of 100 before the while((I2C0_MCS_R &= 0x00000040)==1); then does it work as expected?