最近在工作中的一个项目中,大概是将两块板卡相连(一块STM32跑裸机程序,另一块AM335x跑Linux系统),但是发现在u-boot有时无法启动成功,需要通过一个GPIO的状态来判断,具体来说就是本来上电后端口默认高阻抗,先利用程序先拉低大概100ms,然后在使用程序拉高100ms,然后STM32程序检测这段电平跳变,从而确定系统正确启动,否则会进行软件复位使AM335X的单板能够正常启动,程序本身并不难,但是调试时遇到了一个奇怪的bug,简单记录下。
平台:
am335x,u-boot v2010.07,linux v3.1,arm-none-linux-gcc 2009.01
代码:
核心部分如下
//gpmc_a5(GPIO1_21=1*32+21=53):first low for 100ms,then high for 100ms
void set_gpmc_a5_level(void){
int i = 0;
configure_module_pin_mux(gpmc_a5_pin_mux);
if(gpio_request(53, "gpmc_a5") != 0) {
printf("gpmc_a5 request failed
);
return;
}
gpio_direction_output(53, 0);
while(1){
gpio_set_value(53, 0);
for (i = 0; i < 500; i++);
gpio_set_value(53, 1);
for (i = 0; i < 100; i++);
}
}
问题:
编译烧写到单板,使用示波器测量,发现这个GPIO口的占空比始终为50%,高低电平一直都是2ms左右,然后又修改了几个数字,发现依旧这样
调试:
由于程序看不出问题,示波器测得波形有问题,就考虑使用objdump对u-boot进行反汇编看看最后编译成的实际代码,然后发现无论如何修改for (i = 0; i < 500; i++);这句话里面的时间,反汇编里面的set_gpmc_a5_level延时都是0x53,示波器测得是2ms,后来考虑到u-boot可能会对代码进行优化,尝试修改了变量为volatile int i = 0;,重新测量波形,一切正常
结果:
volatile int i = 0;
由于此版本u-boot会对代码进行优化,因此需要加volatile关键字,这个关键词作用如下:这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了,因此编译器不会对这个变量进行优化,而是每次重新读取这个值