在学习嵌入式程序时,编写一个倒计数自启动命令的过程中,使用了wdt定时器中断isr_wdt,由于原来编写的程序bin大于16KB,故分成了BL1和BL2两部分代码,IRQ_handle:部分的代码放在了BL2的start.S的尾部。代码如下:
#define WTCON 0xE2700000
#define SVC_STACK 0xd0037d80 //ARM的栈是满减栈,所以从高位地址开始
#define IRQ_STACK 0XD0037f80 //ARM的栈是满减栈,所以从高位地址开始
.global _start // 把_start链接属性改为外部,这样其他文件就可以看见_start了
.global IRQ_handle
_start:
// 第1步:关看门狗(向WTCON的bit5写入0即可)
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0]
// 第2步:初始化时钟
bl clock_init
// 第3步:设置SVC栈
ldr sp, =SVC_STACK
// 第4步:开/关icache
mrc p15,0,r0,c1,c0,0; // 读出cp15的c1到r0中
//bic r0, r0, #(1<<12) // bit12 置0 关icache
orr r0, r0, #(1<<12) // bit12 置1 开icache
mcr p15,0,r0,c1,c0,0;
bl main
// 从这里之后就可以开始调用C程序了
//bl led_blink // led_blink是C语言实现的一个函数
// 汇编最后的这个死循环不能丢
b .
//在这个汇编函数中,用来做中断irq模式下的现场保护和恢复,并且调用真正的中断处理程序
IRQ_handle:
//设置IRQ下的栈
ldr sp, =IRQ_STACK
//保存LR(暂存返回地址的)
//因为有流水线,在中断来临时(此时地址为a),返回地址应该是在当前指令的下一条指令地址为a+4,
//但是PC此时指向的是返回地址(地址为a+4)的下一条指令(此时地址为a+8),
//所以PC的值会比真正的执行的代码地址(地址为a)多8个字节,这就是流水线的效果。
sub lr, lr, #4
//保存r0~r12和lr到irq模式下的栈里面去
stmfd sp!, {r0-r12, lr}
//接着调用真正的中断处理程序isr的函数(此函数在int.c中的void irq_handler(void))来处理中断,
bl irq_handler
//上面的中断处理完成后,接着来恢复处理现场,其实就是做中断返回,关键是将r0-r12, pc, cpsr一起恢复
ldmfd sp!, {r0-r12, pc}^
在main函数中使用了printf 函数,但是不能输出变量的结果:
int g_bootdelay = 3;
int main(void)
{
shell_init();//所有初始化(包括绑定中断、使能中断等)
// 自动倒数执行默认命令
// 在这里等待用户按按键,如果没按就倒计时,如果按了就结束倒计时和自动执行直接
// 进入shell死循环。如果一直没按按键时间到了也进入shell死循环
puts("aston#");
printf("%d", g_bootdelay); //此句不能输出3,输出只是一个%.
/*
while ((!g_isgo) && (!is_key_press()));
//while (!((g_isgo) || (is_key_press())));
intc_disable(NUM_WDT);
// 也可以在这里通过判断g_isgo的值来判断是不是倒数结束,执行自动命令
if (g_isgo)
{
lcd_test();
}
// 执行shell死循环
shell_loop();
*/
//while(1)
return 0;
}
// wdt的中断处理程序
void isr_wdt(void)
{
static int i = 0;
// 看门狗定时器时间到了时候应该做的有意义的事情
printf("wdt interrupt, i = %d...\n", i++); //此句也不能输出,输出结果是:%
// 计时,然后时间没到的时候在屏幕上打印倒数计数,时间到了自动执行命令
// 执行完命令进入shell的死循环
//puts("aston#");
//g_bootdelay--;
//putchar('\b');
printf("%d", g_bootdelay); //此句也不能输出,输出结果是:%
/*
if (g_bootdelay == 0)
{
g_isgo = 1;
// 把要自动执行的命令添加到这里,但是这里是中断处理程序,不适合执行长代码
// 所以放在外面要好一些
//printf("g_isgo = 1.\n");
// 关闭wdt
//intc_disable(NUM_WDT);
}
*/
// 清中断
intc_clearvectaddr();
rWTCLRINT = 1;
}
为什么在没有分成BL1和BL2的情况下,也在使用此中断函数 isr_wdt()的里面和main函数里使用printf函数时输出结果正常,而当在有BL1和BL2的情况下,也使用此中断isr_wdt的里面和main函数里使用printf函数时输出结果就不正常呢?出现不正常的结果是不是BL1和BL2的内容没有调整对(IRQ_handle:是不是放在BL1的start.S中的尾部?),网上好多帖子说中断里不能使用printf函数,但是我的分成BL1和BL2的时候程序中,中断里使用printf函数都正常着呢?
哪位朋友给予指点!不胜感激!