Tiny4412之C语言实现流水灯,Tiny4412裸机程序[3]
在前边我们使用汇编完成了一个流水灯实验: Tiny4412汇编流水灯代码,Tiny4412裸机LED操作
----
-
--
--
--
-
--
--
修改:
# ${MKBL2} ${SOURCE_FILE} bl2.bin 14336
./${MKBL2} ${SOURCE_FILE} bl2.bin 14336
或者:
MKBL2=my_mkbl2改成MKBL2=./my_mkbl2
必须有:chmod +x my_mkbl2
chmod 777 my_mkbl2
然后 查看下权限
ls -l my_mkbl2
变黄即可
后编译成功
root@phone-desktop:/opt/FriendlyARM/tiny4412/bare/led# sudo ./sd_fusing.sh /dev/sdc ../led/led.bin
/dev/sdc reader is identified.
./sd_fusing.sh: 59: ./sd_fusing.sh: my_mkbl2: not found
---------------------------------------
BL1 fusing
记录了16+0 的读入
记录了16+0 的写出
8192字节(8.2 kB)已复制,0.0270466 秒,303 kB/秒
---------------------------------------
BL2 fusing
dd: 正在打开"./bl2.bin": 没有那个文件或目录
Write BL2 Error!
./sd_fusing.sh: 91: exit: Illegal number: -1
root@phone-desktop:/opt/FriendlyARM/tiny4412/bare/led# sudo ./sd_fusing.sh /dev/sdc ../led/led.bin
/dev/sdc reader is identified.
---------------------------------------
BL1 fusing
记录了16+0 的读入
记录了16+0 的写出
8192字节(8.2 kB)已复制,0.0233195 秒,351 kB/秒
---------------------------------------
BL2 fusing
记录了28+0 的读入
记录了28+0 的写出
14336字节(14 kB)已复制,0.0504196 秒,284 kB/秒
---------------------------------------
source file image is fused successfully.
Eject SD card and insert it to Exynos 4412 board again.
root@phone-desktop:/opt/FriendlyARM/tiny4412/bare/led#
设置权限后,解决上面问题。
但是,汇编语言可读性太差,在这一节我们用 C语言来实现了同样的功能,而以后的试验也尽量用 C语言实现。
我们在编写上位机程序时,C语言程序执行的第一条指令,并不在main函数中。生成一个 C程序的可执行文件时,编译器通常会在我们的代码中加上几个被称为启动文件的代码—— crtl.o 、crti.o、crtend.o 、crtn.o 等,它们是标准库文件。这些代码设置C程序的堆栈等,然后调用 main 函数。它们依赖于操作系统,在裸板上这些代码无法执行,所以需要自己写一个。
这段代码很简单, 关键指令只有2条。自己编写的 start .S启动文件内容如下:
.text
.globl _start
_start:
ldr sp, =0x02027800 // 调用C函数之前必须设置栈,栈用于保存运行环境,给局部变量分配空间
// 参考ROM手册P14, 我们把栈指向BL2上方1K处(1K已经够用),
// 即:0x02020000 (iRAM基地址) + 5K(iROM代码用) + 8K(BL1用) + 16K(BL2用) + 1K(用作栈)) bl main // 调用main函数(main这个名称不是固定的,可以随意改) halt_loop:
b halt_loop
它在第 4行设置好栈指针后,就可以通过第8行调用C函数 main了--------------- C函数执行前,必须设置栈。
问:CPU不是有看门狗嘛?为什么没有看到关看门狗的代码?这样程序能正常运行吗?
答:在上一篇文章《Exynos 4412的启动过程分析》中,我们已经介绍过了,在执行我们的程序前,CPU会首先执行iROM中的代码和BL1的代码,在这两部分程序中会关闭看门狗。
其实我们自己关闭看门狗也很简单,只需往寄存器WTCON写入0即可;
问:为什么调用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)临时变量保存在栈中
包括函数的非静态局部变量以及编译器自动生成的其他临时变量。
现在,我们可以很容易写出控制 LED 的程序了。毕竟是用C语言嘛,相当的灵活。 main 函数在 led.c 文件中,代码如下:
#define GPM4CON (*(volatile unsigned int *)0x110002E0)
#define GPM4DAT (*(volatile unsigned int *)0x110002E4) void delay(volatile int time)
{
for(; time > ; time-- )
;
} int main(void)
{
unsigned long tmp = ;
int i = ; /*
* GPM4_0-GPM4_3 设置为输出功能
*/ tmp = GPM4CON;
tmp &= ~0xffff;
tmp |= 0x1111;
GPM4CON = tmp; /*
* 实现流水灯
*/ while()
{
GPM4DAT = i;
if (++i == )
i = ;
delay();
} return ;
}
来看看Makefile:
objs := start.o led.o
led.bin : $(objs)
arm-linux-ld -Tled.lds -N -o led.elf $^
arm-linux-objcopy -O binary -S led.elf $@
arm-linux-objdump -D -m arm led.elf > led.dis %.o:%.c
arm-linux-gcc -Wall -marm -c -O2 -o $@ $< %.o:%.S
arm-linux-gcc -Wall -marm -c -O2 -o $@ $< clean:
rm -f *.dis *.bin *.elf *.o
执行 make 命令时,它的目是去生成第1个目标,即 led.bin ;
led.bin 依赖于start.o 和 led.o,所以要先生成这 2个.o 文件;
start.o 依赖于start.S ,符合第 11 行的规则,会使用第 12 行的命令生成start.o ;
类似的, led.o 依赖于led.c ,符合第 8行的规则,会使用第 9行的命令生成 led.o ;
当这 2个.o 文件都生成之后,就会执行第 4~6行的命令生成 led.bin文件: 第 4行将编译得到的 .o 文 件连接为led.elf
可执行程序,第 5行是生成二进制格式的可执行程序,第 6行是得到反汇编程序以供查看。
链接脚本还和汇编流水灯一样。
好了,下面开始验证我们的程序了。
1.将程序源码上传到服务器,并执行make,生成led.bin文件。
2.借鉴上一个实验的步骤,将程序烧写到SD卡。
3.将SD卡插到Tiny4412开发板,上电即可看到流水灯效果(和汇编流水灯效果一样)。
完整的程序下载地址(解压密码:WWW.techbulo.Com):
原文:http://www.techbulo.com/1347.html
---
Tiny4412之C语言实现流水灯,Tiny4412裸机程序[3]的更多相关文章
- 【接口时序】2、Verilog实现流水灯及与C语言的对比
一. 软件平台与硬件平台 软件平台: 1.操作系统:Windows-8.1 2.开发套件:ISE14.7 3.仿真工具:ModelSim-10.4-SE 硬件平台: 1.FPGA型号:XC6SLX45 ...
- C语言基于NIOSII的软件开发及流水灯设计
一.Quartus II 12.1 (32-Bit)进行硬件设计 1.所需要的系统元器件组成 2.系统电路图 二.Nios II 12.1 Software Build Tools for Eclip ...
- NIOS ii 流水灯
为了做项目的前期验证工作,实验室购买了某开发板,下面是基于该板子的实现过程.作为笔记记录,供入门者参考. 1:创建一个Quartus II的工程 next选择器件,然后finish.我的器件是cycl ...
- Tiny4412汇编流水灯代码,Tiny4412裸机LED操作[1]
从今天开始就正式进入到tiny4412的开发学习中了,今天主要看了一下Tiny4412的启动流程及存储器映射及Exynos4412数据手册,用汇编写了一个跑马灯程序(后续会有C语言版本的出来),先说一 ...
- Tiny4412汇编流水灯代码,Tiny4412裸机LED操作【转】
本转载自:http://www.techbulo.com/1313.html Tiny4412汇编流水灯代码,Tiny4412裸机LED操作 2014年10月20日 ⁄ 裸机程序 ⁄ 共 4171字 ...
- Tiny4412之蜂鸣器驱动与led灯驱动
一:LED驱动编写 要编写LED驱动,首先的知道开发板的构造:开发板分为核心板与底板:编写驱动的第一步就是要看开发板,找到LED灯在开发板上的位置及所对应的名字:第一步就要查看核心板电路图,以及底板电 ...
- 单片机教程4.C语言基础以及流水灯的实现
单片机教程4.C语言基础以及流水灯的实现 C语言,没接触过计算机编程语言的人会把它看的很神秘,感觉非常的难,而在我看来,C语言的逻辑和运算,就是小学水平,所以大家不要怕它,我尽可能的从小学数学逻辑方式 ...
- STM32学习笔记(二) 基于STM32-GPIO的流水灯实现
学会了如何新建一个工程模板,下面就要开始动手实践了.像c/c++中经典的入门代码"hello world"一样,流水灯作为最简单的硬件设备在单片机领域也是入门首推.如果你已经有了一 ...
- 毕业回馈-89C51之GPIO使用(流水灯)
今天分享一个89c51制作的8位流水灯案例.使用Proteus仿真. 同上一遍文章不同.上一篇文章中对于GPIO操作主要是位操作,即sbit led1=P0^0;其中P0^0代表p0.0这个引脚,然后 ...
随机推荐
- CMakeLists实战解读--YouCompleteMe
原文转载自:Ricky.K http://www.cnblogs.com/rickyk/p/3877238.html 个人一直有一个想法,就是想出一系列关于CMakeLists.txt国外经典例子的实 ...
- Qt5中使用lambda表达式
c11新特性中加入了lambda表达式,所以Qt 也支持 需在.pro文件中加入 CONFIG += c++11 例子: QString program = "C:/Windows/Syst ...
- 无法建立到http://localhost:6080/arcgis/manager/的连接
安装ArcGIS server10.1后,打开管理页面提示“无法建立到http://localhost:6080/arcgis/manager/的连接” 原因是:在ArcGIS for Server ...
- STM32F10XXX 启动设置
在STMF103XXX 里,可以通过Boot[1:0]引脚选择3种不同的启动模式: 启动模式选择引脚 启动模式 说明 BOOT1 BOOT ...
- IOS离线教程下载与Dash的使用
都知道,苹果官网的IOS Developer Library是开发者最喜欢用的知识仓库,但由于有时打开它实在太慢了! 但是,我们可以手动下载离线版的!离线的文档,在这里,叫做DocSet,意指文档集合 ...
- const和#define的区别
在刷题的时候经常遇到定义全局常量我一般都是用#define(可能是因为很少接触const的原因) 在昨天做到51nod1082时照常暴力用#define定义最大.可是提交超时..... 后来看他人写的 ...
- php三维数组去重(示例代码)
php三维数组去重的示例代码. 假设叫数组 $my_array; <?php // 新建一个空的数组. $tmp_array = array(); $new_array = array(); ...
- java环境搭建的问题
本人用eclipse开发,首先在java官网中下载最新版本的jdk,jdk的版本一定要与eclipse版本位数相同,否则会提示错误“Java was started but returned exit ...
- C语言socket编程--每日签到
前几天写了个python的每日签到,你运行还得借助crontab,很是不爽.....正好前几天看了个关于c编写daemon进程,加上自己那点可怜的socket知识,于是我们重操旧页,C语言版的每日签到 ...
- wpf 制作播放视频的屏保程序、而且能分屏显示
这个程序用到了WPF里 “visual_Brush”(主要是为了实现分屏显示) , “UserControl” ,这两个知识点: 在屏保状态下播放指定文件夹下的视频,而且能分屏显示: 把编译好的屏保 ...