友坚4412开发板设置栈和C语言点亮LED

友坚4412开发板设置栈和C语言点亮LED

第一节 为什么调用C函数要设置栈

1. 栈的整体作用

1) 保存现场;

2) 传递参数:汇编代码调用C函数时,需传递参数;

3) 保存临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量;

 

2. 详细解释

1) 保存现场

现场,意思就相当于案发现场,总有一些现场的情况,要记录下来的,否则被别人破坏掉之后,你就无法恢复现场了。而此处说的现场,就是指CPU运行的时候,用到了一些寄存器,比如r0,r1等等,对于这些寄存器的值,如果你不保存而直接跳转到子函数中去执行,那么很可能就被其破坏了,因为其函数执行也要用到这些寄存器。因此,在函数调用之前,应该将这些寄存器等现场,暂时保持起来(入栈push),等调用函数执行完毕返回后(出栈pop),再恢复现场。这样CPU就可以正确的继续执行了。保存寄存器的值,一般用的是push指令,将对应的某些寄存器的值,一个个放到栈中,把对应的值压入到栈里面,即所谓的压栈。然后待被调用的子函数执行完毕的时候,再调用pop,把栈中的一个个的值,赋值给对应的那些你刚开始压栈时用到的寄存器,把对应的值从栈中弹出去,即所谓的出栈。其中保存的寄存器中,也包括lr的值(因为用bl指令进行跳转的话,那么之前的PC的值是存在lr中的),然后在子程序执行完毕的时候,再把栈中的lr的值pop出来,赋值给PC,这样就实现了子函数的正确的返回。

 

2) 传递参数

C语言进行函数调用的时候,常常会传递给被调用的函数一些参数,对于这些C语言级别的参数,被编译器翻译成汇编语言的时候,就要找个地方存放一下,并且让被调用的函数能够访问,否则就没发实现传递参数了。对于找个地方放一下,分两种情况。一种情况是,本身传递的参数不多于4个,就可以通过寄存器r0~r3传送参数。因为在前面的保存现场的动作中,已经保存好了对应的寄存器的值,那么此时,这些寄存器就是空闲的,可以供我们使用的了,那就可以放参数。另一种情况是,参数多于4个时,寄存器不够用,就得用栈了。

 

3) 临时变量保存在栈中

包括函数的非静态局部变量以及编译器自动生成的其他临时变量。

第二节 程序相关讲解

完整代码见目录2.leds_c_sp

 

1.start.S

本章我们将使用C函数来实现点灯和延时的功能,在代码2.leds_c_sp中,start.S的作用如下:

第一步:设置栈;

第二步:调用C函数leds_blink(),实现LED闪烁;

设置栈,其实就是设置sp寄存器,让其指向一块可用的内存,我们将其指向0x02050000,原因如下:

iRAM大小为256KB,地址范围为0x02020000-0x02060000,内存图如下:


 

Internal Memory Map

地址0x02023400大家是不是很熟悉,没错,它就是我们BL2代码的链接地址了。因为BL2代码的大小是14KBBL2代码的地址范围是0x02023400-0x02026c00,所以我们还有一大堆空间可以用,因此,为了方便就设置栈为0x02050000

 

2leds.c

代码自己看源码,都是比较简单的C语言。

第三节 编译代码和烧写运行

sd卡插入PCUbuntu终端执行如下命令:

#cd 2.leds_c_sp

#make

#sudo ./sd_fusing.sh /dev/sdb bl2.bin

第四节 实验现象

sd卡插入UT4412BV03中,选择sd卡启动,然后上电,可以看到以下现象: LED正常闪烁,设置栈以后,我们的程序就能调用C函数,这样将大大提升我们编写代码的速度。

本手册版权归属本人所有, 并保留一切权力。非经本人同意(书面形式),任何单位及个人不得擅自摘录本手册部分或全部,违者我们将追究其法律责任。 转载请注明来源及其原创作者。特此声明!


猜你喜欢

转载自blog.csdn.net/candy19912015/article/details/45029921