SAM9G45死机问题
最近有个项目,用的SAM9G45平台,遇到一个问题,就是运行一段时间‘’死机‘’问题,现象就是下发协议没有反应。这个问题解决耗费了好长时间,现记录如下,希望能够帮助需要的人吧。
首先分析是程序真的死掉了,还是逻辑进入了死循环跳不出来。在心跳PIT中断里面加入灯闪烁,测试发现灯不闪了,说明是程序死掉了。接着分析看看程序死到哪里了?首先看ARM9手册,查看异常,如下:
我猜想,是否进入某个异常了,没有退出,导致PIT中断不能进入。看下启动文件:
Vectors LDR pc,=resetHandler
undefVector b undefVector ; Undefined instruction
swiVectorb swiVector ; Software interrupt
prefetchAbortVectorb prefetchAbortVector ; Prefetch abort
dataAbortVectorb dataAbortVector ; Data abort
reservedVectorb reservedVector ; Reserved for future use
irqVectorb irqHandler ; Interrupt
fiqVector; Fast interrupt;------------------------------------------------------------------------------
; Handles a fast interrupt request by branching to the address defined in the
; AIC.
;------------------------------------------------------------------------------
fiqHandlerb fiqHandler
看到没有除了IRQ,其它都是死循环,再看下系统外设中断怎么设置的:
/* Initialize AIC****************/AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;AT91C_BASE_AIC->AIC_SVR[0] = (unsigned int) defaultFiqHandler;for (i = 1; i < 31; i++) {AT91C_BASE_AIC->AIC_SVR[i] = (unsigned int) defaultIrqHandler;}AT91C_BASE_AIC->AIC_SPU = (unsigned int) defaultSpuriousHandler;// Unstack nested interruptsfor (i = 0; i < 8 ; i++) {AT91C_BASE_AIC->AIC_EOICR = 0;}
再看:
void defaultSpuriousHandler( void )
{while (1);
}//------------------------------------------------------------------------------
/// Default handler for fast interrupt requests. Infinite loop.
//------------------------------------------------------------------------------
void defaultFiqHandler( void )
{while (1);
}//------------------------------------------------------------------------------
/// Default handler for standard interrupt requests. Infinite loop.
//------------------------------------------------------------------------------
void defaultIrqHandler( void )
{while (1);
}
看到没有,默认所有的中断和外设都是死循环,修改如下:
Vectors LDR pc,=resetHandler
undefVector b undefHandler ; Undefined instruction
swiVectorb swiHandler ; Software interrupt
prefetchAbortVectorb prefetchAbortHandler ; Prefetch abort
dataAbortVectorb dataAbortHandler ; Data abort
reservedVectorb reservedVector ; Reserved for future use
irqVectorb irqHandler ; Interrupt
fiqVectorb fiqHandler ; Fast interrupt
处理函数添加打印标志,例如:
void defaultFiqHandler( void )
{led_on();while (1){printf("defaultFiqHandler\r\n");delayms(20);led_on();delayms(20);led_off();}
}
上电测试,发现进入了swiVector,查阅文档发现这个是软中断,通过SWI命令进入。难道代码里面有这部分操作,查看整个C代码,并没有发现有这个操作,然后通过反汇编查看asm文件,全部查找,也没有发现SWI指令,这可奇了怪了,为什么会进入这个中断呢?
另外一个同事通过不停的打LOG,最后定位到某个固定函数不能return,也就是说return没有执行,就触发SWI中断了。至此我们算是找到了死机的地方。可是为什么呢?我怀疑是栈溢出了,于是加大了栈,效果一样。于是我在SWI里面加了一点打印栈的东西,
MOV r0, spMRS r1, SPSRMSR CPSR_c, #ARM_MODE_IRQ :OR: I_BIT :OR: F_BITMOV r2, spMOV r3, lr MSR CPSR_c, #ARM_MODE_SVC :OR: I_BIT :OR: F_BIT ;´ò¿ªIRQ,¹Ø±ÕFIQBL defaultSwiHandler
汇编里面用R0~R3传递参数;
void defaultSwiHandler(uint32_t *pwPC,uint32_t hwSPSR,uint32_t *pwSPIRQ,uint32_t hwIRQLR)
{//uint32_t* cur_sp = 0, *cur_lr = 0, *cur_pc = 0;uint16_t i=0;uint32_t *p=0;led_on();while (1){printf("START\r\n");extern unsigned char MainUsbOperFlag;printf("defaultSwiHandler SP=%X\r\n",(uint32_t)pwPC);printf("defaultSwiHandler SPSR=%X\r\n",(uint32_t)hwSPSR);printf("defaultSwiHandler IrqSP=%X\r\n",(uint32_t)pwSPIRQ);printf("defaultSwiHandler IrqLr=%X\r\n",(uint32_t)hwIRQLR);printf("defaultSwiHandler MainUsbOperFlag=%u\r\n",MainUsbOperFlag);p=(uint32_t*)0x00310000;for(i=0;i<2048;i++){printf("defaultSwiHandler =%X\r\n",*p);p--;}printf("END\r\n");//printf("RSTC_RSR =%u\r\n",AT91C_BASE_RSTC->RSTC_RSR);delayms(60);led_on();delayms(60);led_off();}
}
打印发现栈里面有一段全是0xFFFFFFFF,难道PC指针因为这个?试了如下语句:
(*((void(*)())(0xFFFFFFFF)))();
果然触发了SWI中断。这样还是不确定是不是这个问题,于是我把正常栈打印出来:
添加如下语句:
{static uint16_t i=0;i++;if(i>100){__asm {SWI 0}}}
发现打印出来的栈并没有一段0xFFFFFFFF。
首先还是考虑栈溢出,于是我给栈加了标签:
; 给栈打印标签LDR R0, = |Image$$ARM_LIB_STACK$$ZI$$Limit| ;ÔÚmapÎļþÀïÃ棬±íʾһ¸öµØÖ·MOV R1,#2048
STATIC1SUB R0,#4MOV R2,#165STR R2,[R0]SUB R1,#1CMP R1,#0BNE STATIC1; Enter the C codeIMPORT __mainLDR R0, =__mainBX R0
loop4B loop4 END
发现栈并没有越界,那只能考虑是某个指针飞了。于是添加下面的宏:
#define my_pi(_Name,__X) do{ \if((__X)>=0x30E000){ \while(1){ \delayms(1000); \printf("NAME=%d %X\n\r",_Name,(uint32_t)(__X)); \} \} \}while(0)
注:
1、地址需要根据栈里面的0xFFFFFFFF处地址调整。
然后在不能反回的函数里面把用到的指针地址全部打出来,果然发现有问题。函数嵌套调用,上层函数把局部变量的地址传给子函数,子函数获得的地址有时候是错的。在局部变量前加static,在测试,问题解决。至此我想吐血。。。。。
再说下官方给的启动文件一个bug,就是原来的栈设置是这样:
; Setup Stack for each modeLDR R0, = |Image$$ARM_LIB_STACK$$ZI$$Limit|; Enter IRQ Mode and set its Stack PointerMSR CPSR_c, #ARM_MODE_IRQ:OR:I_BIT:OR:F_BITMOV SP, R0SUB R4, SP, #IRQ_Stack_Size; Supervisor mode (interrupts enabled) MSR CPSR_c, #ARM_MODE_SVC :OR: F_BITMOV SP, R4 ; Enter the C codeIMPORT __mainLDR R0, =__mainBX R0
loop4B loop4 END
但是,我追了下,发现ARM_MODE_SVC栈在经过__main,进入main时候,被修改了,在SRAM最高处,也就是说ARM_MODE_SVC只能设置在最高地址处,不明白为什么这样。
原因找到,如下:
If you use a scatter file to tailor stack and heap placement, the linker includes a version of the library
heap and stack setup code using the linker defined symbols, ARM_LIB_*, for these region names.
Alternatively you can create your own implementation.
Load_region 0x300000 0x10000 { Fixed_region 0x300000 {*.o (VECTOR, +First).ANY (+RO)}Relocate_region +0 {*(cstartup +First).ANY (+RW +ZI)}ScatterAssert((ImageLength(Fixed_region) + ImageLength(Relocate_region)) < 0xE000); ARM_LIB_HEAP 0x30F000 EMPTY 0x800 {
; }; ARM_LIB_STACK 0x310000 EMPTY -0x800 {
; }ARM_LIB_HEAP 0x30E000 EMPTY 0x800 {}ARM_LIB_STACK 0x310000 EMPTY -0x1800 {}
}
__main_main_stk0x003000b4: e59fd00c .... LDR sp,__lit__00000000 ; [0x3000c8] = 0x310000
(这个是汇编文件,__main首先就是修改SP操作,不知道__lit__00000000可不可以修改)
于是我修改了栈设置,把ARM_MODE_SVC设置在最高处:
; Setup Stack for each modeLDR R0, = |Image$$ARM_LIB_STACK$$ZI$$Limit| ;ÔÚmapÎļþÀïÃ棬±íʾһ¸öµØÖ·;SUB R0,R0, #SVC_Stack_SizeMSR CPSR_c, #ARM_MODE_SVC:OR:I_BIT:OR:F_BIT ;±£´æµ½×´Ì¬¼Ä´æÆ÷,CPSR_c±íʾCPSRµÄµÍ°ËλMOV SP, R0; Enter ABT Mode and set its Stack PointerMSR CPSR_c, #ARM_MODE_ABT:OR:I_BIT:OR:F_BIT ;±£´æµ½×´Ì¬¼Ä´æÆ÷,CPSR_c±íʾCPSRµÄµÍ°ËλSUB R4, R0, #SVC_Stack_SizeMOV SP, R4; Enter UND Mode and set its Stack PointerMSR CPSR_c, #ARM_MODE_UND:OR:I_BIT:OR:F_BIT ;±£´æµ½×´Ì¬¼Ä´æÆ÷,CPSR_c±íʾCPSRµÄµÍ°ËλSUB R4, R4, #ABT_Stack_SizeMOV SP, R4; Enter FIQ Mode and set its Stack PointerMSR CPSR_c, #ARM_MODE_FIQ:OR:I_BIT:OR:F_BIT ;±£´æµ½×´Ì¬¼Ä´æÆ÷,CPSR_c±íʾCPSRµÄµÍ°ËλSUB R4, R4, #UND_Stack_SizeMOV SP, R4; Enter IRQ Mode and set its Stack PointerMSR CPSR_c, #ARM_MODE_IRQ:OR:I_BIT:OR:F_BIT ;±£´æµ½×´Ì¬¼Ä´æÆ÷,CPSR_c±íʾCPSRµÄµÍ°ËλSUB R4, R4, #FIQ_Stack_SizeMOV SP, R4; Supervisor mode (interrupts enabled) ;MSR CPSR_c, #ARM_MODE_SYS :OR:I_BIT:OR: F_BIT;±£´æµ½×´Ì¬¼Ä´æÆ÷,CPSR_c±íʾCPSRµÄµÍ°Ëλ;SUB R4, R4, #IRQ_Stack_Size;MOV SP, R4 MSR CPSR_c, #ARM_MODE_SVC :OR: F_BIT ;´ò¿ªIRQ,¹Ø±ÕFIQ
好了至此完毕。
说句题外话,为什么官网启动代码错误的,也能跑呢,首先看下iqr汇编:
irqHandler; Save interrupt context on the stack to allow nesting */SUB lr, lr, #4STMFD sp!, {lr}MRS lr, SPSRSTMFD sp!, {r0,r1,lr}; Write in the IVR to support Protect Mode */LDR lr, =AT91C_BASE_AICLDR r0, [r14, #AIC_IVR]STR lr, [r14, #AIC_IVR]; Branch to interrupt handler in Supervisor mode */MSR CPSR_c, #ARM_MODE_SVCSTMFD sp!, {r1-r4, r12, lr}MOV lr, pcBX r0LDMIA sp!, {r1-r4, r12, lr}MSR CPSR_c, #ARM_MODE_IRQ :OR: I_BIT; Acknowledge interrupt */LDR lr, =AT91C_BASE_AICSTR lr, [r14, #AIC_EOICR]; Restore interrupt context and branch back to calling codeLDMIA sp!, {r0,r1,lr}MSR SPSR_cxsf, lrLDMIA sp!, {pc}^
在IRQ模式下只用了4个字,我追了下栈,发现main里面,在进如while(1)时候,有入栈操作,但是不会反回,因此占用前四个字,没有影响,我入栈15个寄存器,直接跑飞。
i.mainmain0x00306564: e92d400e .@-. PUSH {r1-r3,lr}0x00306568: e3a000c0 .... MOV r0,#0xc0
(查看这段汇编,main刚进入,就有刚好4个字节的入栈操作,哎,就是这个恰好隐藏了一个很深的Bug)
再补充一个调试过程当中遇到的奇怪问题,就是刚开始用官方的启动代码调试,中断优先级只能设置为一样,如果不一样,就会死机。原因如下:
首先看栈设置:
; Setup Stack for each modeLDR R0, = |Image$$ARM_LIB_STACK$$ZI$$Limit|; Enter IRQ Mode and set its Stack PointerMSR CPSR_c, #ARM_MODE_IRQ:OR:I_BIT:OR:F_BITMOV SP, R0SUB R4, SP, #IRQ_Stack_Size; Supervisor mode (interrupts enabled) MSR CPSR_c, #ARM_MODE_SVC | F_BITMOV SP, R4 ; Enter the C codeIMPORT __mainLDR R0, =__mainBX R0
loop4B loop4 END
首先设置的IRQ中断栈,在
|Image$$ARM_LIB_STACK$$ZI$$Limit|
处,查看MAP文件,在SRAM最高地址处。然后是一个
IRQ_Stack_Size的偏移,设置SVC栈。通过上面的分析可知,这里SVC栈被__main修改为SRAM最高地址处。也就是和
IRQ栈重合。那么再看IRQ中断怎么处理:
MSR CPSR_c, #ARM_MODE_SVC
看到没有在进入具体中断处理函数之前,把模式改为SVC,同时打开了IRQ和FIQ,也就是说在中断处理函数里面是可以进行中断嵌套的。那么这个时候,如果有中断就会有问题了,前面讲的很清楚了。
哎,至此完毕,睡觉,心好累。。。。。。
2019.01.14
看了很多资料,说ARM9不支持非对齐访问,于是我写了如下程序:
while(1){volatile static uint8_t *pi=(uint8_t *)&spid;volatile static uint32_t j=0;printf("pi= %X",(uint32_t)pi);j=*((uint32_t*)pi);printf("j= %X",(uint32_t)j);pi++;delayms(1000);}
发现程序能够正常打印,并没有进入异常,因此说明ARM9支持地址非对齐访问。
SAM9G45死机问题相关推荐
- Linux拷贝数据死机了,Linux系统“死机”时怎么办?
如果问题能够再现,那么问题已经解决 80% 了.对于操作系统核心而言,如果有问题的再现方法,那么可以说是已经解决 99% 了.经常遇到的问题是系统可以正常运行一段时间,然后死机.如果不好再现问题,那么 ...
- android上传图片崩溃,导致安卓手机死机的照片拍摄者表示这张照片是无意之举...
原标题:导致安卓手机死机的照片拍摄者表示这张照片是无意之举 上周,我们报道了在一些安卓手机上将某张图片设置为壁纸会导致手机崩溃,并卡在一个开启和关闭显示屏的循环中,让用户无法进行锁屏.它影响了大多数A ...
- svg图片怎么存手机上_一张普通的图片,是怎么让安卓手机死机的?
关于我们日常使用的智能手机,大家可能都在网络上看过,一条简单的微信或者一个简单的表情包等就可以让我们的智能手机死机,情节较轻的重启手机解决,较为严重的直接就是数据丢失.而这背后的根本原因,很多都是相关 ...
- 插入u盘计算机未响应,win7系统插入u盘死机怎么办|win7插入u盘无响应的解决方法...
最近有些win7旗舰版用户遇到u盘插入计算机后会出现未响应导致系统死机,虽然等一会儿就能恢复正常,但是每次插入u盘都要卡一下决对是有问题的.遇到在win7系统插入u盘死机怎么办呢?会出现插入u盘 ...
- thinkphp 个别字段无法更新_香港华为手机大面积死机?只是个别手机更新出问题...
点击箭头处"蓝色字",关注我们哦!! 导读 近日,有个别香港媒体报道称,大批香港华为手机用户在自动更新时出现手机无法关机,甚至死机的情况:出现问题的华为手机用户纷纷前往位于旺角的华 ...
- 升级BIOS解决DELL R730XD虚拟机死机问题
1台新配置的DELL R730XD(配置有2个Intel E5-2640 V4的CPU.128GB内存.H730的RAID卡.12块4TB的SATA硬盘.2个495W电源),在安装VMware ESX ...
- 金山电子表格金山电子表格为何会死机?
在写这篇文章之前,xxx已经写过了几篇关于改金山电子表格主题的文章,想要了解的朋友可以去翻一下之前的文章 金山电子表格为何会死机? 有的读者在留言中说,金山电子表格在大批盘算时会涌现死机现象.这是什么 ...
- 死机一个月后,31岁的哈勃望远镜又复活了
点击上方"AI遇见机器学习",选择"星标"公众号 重磅干货,第一时间送达 来自:机器之心 这或许是人类创造的最伟大的太空设备,它即将在自己生命的第四个十年继续工 ...
- 死机、蓝屏、系统运行过慢
[系统环境:] windows xp +瑞星杀毒 [基本配置:]tcl 品牌机p4 1.7256内存; [故障描述:] 打游戏时死机. [解决方法:] 怀疑是系统用的比较久了!从装系统无效;打开 ...
最新文章
- [转载]Surging 分布式微服务框架使用入门
- 借一个同事的经历,谈一谈程序员的成长
- 做程序猿的老婆应该注意的一些事情
- nginx php-fpm display_errors,php5-fpm的display_errors不能使用nginx
- 从零开始学习PYTHON3讲义(一)认识Python
- xcode6不显示键盘------解决方案
- linux内核杂记(16)-系统调用(3)
- 反应堆Reactor
- 清华王兴再抛神论:为什么教育决定着中国餐饮业质量?
- 二刻拍案惊奇之——国人为什么那么轻视技术
- [建议]添加模板功能
- oracle rac redo log,RAC共享online redo log和archived log的官方说明
- Django--ORM基本操作
- 胎压监测 (15 分)
- 从EXCEL中读出数据到数据库中
- SpringBoot2 Spring Cloud consul 分布式配置中心使用教程
- WinCE6.0 BootloaderMain源码分析之DownloadImage
- iOS OC和Swift相互引用,测试在swift项目
- VMware解决黑屏
- U盘图标显示成文件夹图标
热门文章
- 印度尼西亚通过加密货币期货交易规则
- [小说]魔王冢(2)意乱情迷
- 三十二楼层选几层最好_一般买房买几楼比较好 1一32高楼层选最佳楼层
- 基于STM32F103C8T6(HAL库)的HC-SR501红外人体传感及HC-SR04超声波测距
- 45-Jenkins-Sidebar Link插件实现添加侧边栏
- 深度解读BN、LN、WN、CN
- m1卡读写c语言,Android NFC(一) M1卡读写
- 神经网络之过拟合与欠拟合
- 洛谷 P5266 【深基17.例6】学籍管理
- MVG(second)读书笔记-3D摄影几何和变换