步进调试和 运行 程序在 tiva c 上的不同结果

Different results between step debugging and running program on tiva c

我有一个 TIVA tm4c123G 我一直在尝试使用 I2C 协议在它和我的 ADXL345 传感器之间建立通信,我成功地从加速度计写入和读取了设备地址的读数和我刚才的寄存器值写到这意味着一切 运行ning 都很好。但是,我已经在 keil 中逐步调试了这个并且它工作正常但是如果我 运行 程序它会一直给零,我不知道为什么?我应该在寄存器的写入和读取之间添加延迟,还是我的代码出了什么问题?

附上我的代码
我正在为系统使用 80 MHZ 的时钟,我认为这可能是问题所在,但是因为代码对下一次发送的执行来说太快了,应该有一些延迟?我不确定我只是在猜测,请帮忙谢谢!

我的 adxl 连接也是

  1. Vcc -> 3.3 伏特
  2. GND -> 地面
  3. CS -> 3.3 伏
  4. SDO -> 地面
  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;
    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 
}

您的 WriteRegisterReadRegister 函数不遵循 TM4C123G 数据 sheet 中定义的流程图。除了不检查或处理 MCS 错误标志外,图 16-10 多数据字节的主传输 显示在写入 MCS 寄存器时,您应该断言特定位,同时写入所有位,你应该改为执行read-modify-write:

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

应该是:

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

同样地:

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

应该是

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

ReadRegister() 有类似的问题(尽管在这种情况下不太可能成为问题):

I2C0_MCS_R = 0x00000007; //stop start run

应该严格是:

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

数据sheet推荐位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.

上面的代码就是这样做的,但实际上对于这个特定的产品来说应该不是必需的,但在任何情况下都是很好的做法。

无论如何您都应该添加推荐的错误处理代码。可能没有设置错误标志,但我们不知道,除非您检查它,这样做至少有助于调试 - 而不是单步执行代码,您可以简单地设置一个 break-point错误处理,然后 运行 在 full-speed。这将缩小可能性的数量。

正如@Clifford 所解释的那样,我应该遵循流程图,虽然他的回答是完全正确的,但它没有给我任何结果(之前给出了值,以防进入函数后给出零)但是,我在流程图中注意到一些我之前没有注意到的东西,它与数据中的初始化和配置部分相矛盾 sheet

现在如第 11 步所述,您应该轮询 MCS 寄存器中的总线忙位,但这是错误的并且与流程图相矛盾,流程图更正确,因为您应该检查总线是否在发送任何内容之前忙,然后在从 MDR 寄存器读取或继续执行和进一步的步骤之前检查主忙位

基本上正确的初始化和配置步骤应该是: 在第 10 步之前轮询总线忙位,以防任何其他主机正在发送,如果是单个主机,则可以省略

在第 10 步之后轮询忙碌位,然后再读取或进行任何进一步的步骤以确定发送是否已完成以及主机是否空闲

对不起,我现在觉得自己像个彻头彻尾的白痴,因为我没有仔细阅读流程图,但我遵循了另一部分,即初始化和配置部分,接受了一个不存在的事实,即两者应该暗示同样的事情.

我还发现它在 tivaware API 中按照流程图正常工作,而不是数据中的其他部分sheet 但是我不想使用 Tivaware API 因为我很期待这样的问题,这样可以更好地理解事物的工作原理

再次感谢您的帮助@Clifford 干杯!