Different results between step debugging and running program on tiva c


I have a TIVA tm4c123G I have been trying to create a communication between it and my ADXL345 sensor using I2C protocol which I succeeded in writing and reading from the accelerometer the readings of the device address and the register values that I just wrote to which means everything is running fine. However I have tried this in step by step debugging in keil and it works fine but if I run the program it will give zeroes all the way and I have no idea why? Should I add delays between the write and read from registers or whats going wrong in my code?

Here is my code attached
I am using a clock of 80 MHZ for the system and I think this might be the problem however as the code goes too fast to the execution of a next send and there should be some delay? I am not sure I'm only guessing please help thanks !

also my connection for the adxl is

  1. Vcc -> 3.3 volts
  2. GND -> ground
  3. CS -> 3.3 volts
  4. SDO -> ground
  5. SDA -> PB3
  6. SCL -> PB2

#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;

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 
asked on Stack Overflow Feb 12, 2017 by Essam Eid • edited Apr 25, 2017 by Mahendra Gunawardena

2 Answers


Your WriteRegister and ReadRegister functions do not follow the flowcharts defined in the TM4C123G data sheet. Apart from not checking or handling the MCS ERROR flag, Figure 16-10 Master TRANSMIT of Multiple Data Bytes shows that when writing the MCS register, you should assert specific bits, while you are writing to all bits, You should instead perform a read-modify-write:

I2C0_MCS_R = 0x00000003; //burst send ( multiple bytes send ) 

should be:

// I2CMCS = ---0-011
uint32_t mcs = I2C0_MCS_R ;
msc &= ~0x00000014; // ---0-0-- 
mcs |= 0x00000003;  // ------11
I2C0_MCS_R = mcs ;

And similarly:

I2C0_MCS_R = 0x00000005; // transmit followed by stop state 

should be

// I2CMCS = ---0-101
mcs = I2C0_MCS_R ;
mcs &= ~0x00000012; // ---0--0- 
mcs |= 0x00000005;  // -----1-1
I2C0_MCS_R = mcs ;

enter image description here

ReadRegister() has a similar issue (although it is unlikely to be an issue in this case):

I2C0_MCS_R = 0x00000007; //stop start run

should strictly be:

// I2CMCS = ---00111
uint32_t mcs = I2C0_MCS_R ;
mcs &= ~0x00000018; // ---00--- 
mcs |= 0x00000007;  // -----111
I2C0_MCS_R = mcs ;

The datasheet recommends for bits 31:5:

Software should not rely on the value of a reserved bit. To provide compatibility with future products, the value of a reserved bit should be preserved across a read-modify-write operation.

The above code does that, but in practice should not be necessary on this specific product, but is good practice in any case.

enter image description here

In any event you should add the recommended error handling code. It may be that no error flag is being set, but we don't know that unless you check for it, and doing so will at least assist debugging - rather then stepping the code, you can simply set a break-point on the error handling and then run at full-speed. This will narrow down the number of possibilities.

answered on Stack Overflow Feb 12, 2017 by Clifford • edited Feb 12, 2017 by Clifford

as @Clifford had explained that i should follow the flow charts and although his answer is completely correct it didn't give me any results (previously gave values in case of stepping into the function gave zeroes afterwards) but , i noticed something in the flow charts that i hadn't noticed before which contradicts with the initialization and configuration section in the data sheet

initialization and configuration from the datasheet

now as it says in step 11 that you should be polling the bus busy bit in the MCS register but this is wrong and contradicts with the flow charts , the flow charts are more correct as u should check if the bus is busy before sending anything and then check for the master busy bit before reading from the MDR register or moving on to execute and further steps

basically the correct steps in the initialization and configuration should be : before step 10 poll the bus busy bit in case any other master is sending which can be omitted in case of a single master

after step 10 poll the busy bit before reading or going to any further step to conclude whether the sending has been completed and the master is idle or not

i'm sorry i feel like a complete idiot now for not reading the flow charts carefully but i followed another part which is the initialization and configuration part accepting a fact which wasn't there that both should imply the same thing .

i also found that it works correctly in the tivaware API following the flow charts and not that other section in the datasheet however i didn't want to use the Tivaware API as i am looking forward for problems like this which lead to a better understanding of how things work

thanks again for your help @Clifford cheers!

answered on Stack Overflow Feb 12, 2017 by Essam Eid

User contributions licensed under CC BY-SA 3.0