历史上的今天
返回首页

历史上的今天

今天是:2024年10月14日(星期一)

正在发生

2018年10月14日 | Exynos4412之C语言实现流水灯

2018-10-14 来源:eefocus

在前边我们使用汇编完成了一个流水灯实验: Tiny4412汇编流水灯代码,Tiny4412裸机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 > 0; time-- );

}

 

int main(void)

{

    unsigned long tmp = 0;

    int i = 0;

 

    // GPM4_0-GPM4_3 设置为输出功能

 

    tmp = GPM4CON;

    tmp &= ~0xffff;

    tmp |= 0x1111;

    GPM4CON = tmp;

 

    // 实现流水灯

 

    while(1)

    {

        GPM4DAT = i;

        if (++i == 16)

            i = 0;

        delay(9999999);

    }

    return 0;

}

来看看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开发板,上电即可看到流水灯效果(和汇编流水灯效果一样)。

Tiny4412 流水灯

Tiny4412 流水灯


推荐阅读

史海拾趣

德力西(DELIXI)公司的发展小趣事

进入90年代,德力西进入快速发展阶段。1992年,公司引进外资,成立了“中外合资温州德力西电器有限公司”。随后,通过兼并联合和行业整合,德力西不断扩大生产规模和市场影响力。1994年,经有关部门批准,组建了浙江德力西集团公司,成为浙江省首个省级股份合作制电器企业集团。

ELECTRONIC ASSEMBLY公司的发展小趣事

在环保日益受到重视的今天,一家名为“绿源电子组装”的公司积极响应国家号召,致力于推动绿色环保的产业发展。公司引进了一系列环保设备和材料,采用了低碳、节能的生产工艺和管理方式,实现了生产过程中的减排降耗。同时,绿源电子组装还积极参与社会公益活动,倡导绿色消费理念,为行业的可持续发展贡献了自己的力量。

Elektron公司的发展小趣事

Elektron公司一直注重技术研发和创新投入,致力于在行业中保持领先地位。公司不断推出具有创新性和领先性的产品,如高性能的电池充电器、先进的焊接和切割设备等。这些产品的推出不仅提高了公司的市场竞争力,也推动了整个行业的发展和进步。同时,Elektron还积极参与行业标准的制定和推广工作,为行业的健康发展做出了重要贡献。

Analogix Semiconductor公司的发展小趣事

Elektron公司的故事始于1942年,由威利·科伯以Elektron物理技术设备工厂Kerber的名称成立。当时,该公司主要生产基于汞蒸气整流器的固定电池电源和船用电池充电器。这些产品在市场上取得了良好的反响,为公司的发展奠定了坚实的基础。在随后的几年里,Elektron不断扩大产品范围,开始涉足汽车行业的电池充电器以及焊接和切割工艺的电源等领域。

Green Solution Technology Co Ltd公司的发展小趣事

在电子行业中,产品质量是企业生存和发展的关键。Armel Electronics Inc公司深知此道,始终坚持品质至上的原则。公司从原材料采购到生产流程,再到产品出厂,每一个环节都严格把控,确保产品质量的稳定性和可靠性。这种对品质的执着追求,使得Armel的产品在市场上赢得了良好的口碑,并逐渐树立了公司的品牌形象。

Advanced Monolythic Ceramics公司的发展小趣事

在电子行业中,产品质量是企业生存和发展的关键。Armel Electronics Inc公司深知此道,始终坚持品质至上的原则。公司从原材料采购到生产流程,再到产品出厂,每一个环节都严格把控,确保产品质量的稳定性和可靠性。这种对品质的执着追求,使得Armel的产品在市场上赢得了良好的口碑,并逐渐树立了公司的品牌形象。

问答坊 | AI 解惑

带字库12864资料

本帖最后由 paulhyde 于 2014-9-15 09:01 编辑 带字库12864资料  …

查看全部问答>

教你做端口映射

(Port Mapping): 如果你是ADSL、MODEM或光纤等宽带接入用户,想在公司或单位内部建一个服务器或WEB站点,并且想让互联网上的用户访问你的服务器,那么你就会遇到端口映射问题。 通常情况下,路由器都有防火墙功能,互联网用户只能访问到你的 ...…

查看全部问答>

请问哪家的NOR FLASH速度最快?

请问哪家的NOR FLASH速度最快? 请大家讨论…

查看全部问答>

atmega8单片机是否可以操作flash芯片

atmega8单片机是否可以操作flash芯片,16MHz的晶振,flash芯片(SLC闪存芯片)是从U盘上卸下来的,atmega8用于接收另一个单片机传送的数据,然后转存到flash芯片(就是专门用于处理flash的数据),所以1K的RAM用于缓冲应该不是问题,想问的是单片机 ...…

查看全部问答>

请教NandFlash物理地址如何计算

在硬件上SDRAM可以通过nGCSi片选信号的连接确定,NandFlash看不出来,内存映射表上也看不出 请教各位,先谢了!…

查看全部问答>

串口发送问题。100分,在另一个帖子。

evc写的,详见:(100分) http://topic.eeworld.net/u/20080313/13/25419c0c-4a83-44c1-b971-1c1e28fabc91.html…

查看全部问答>

LM3SLib_SSI

 LM3SLib_SSI   SSI兼容SPI…

查看全部问答>

TI杯09年D题 单相正弦波变频电源

那位有TI杯09年D题  单相正弦波变频电源   的相关资料吗??      还有这个能用L298达到要求吗 谢谢了。。。…

查看全部问答>

发现我团购的板子已发货了

小小的高兴一下,在eeworld团购的msp430开发板已经发货了。非常感谢活动组织者,也希望各位拿到板子的童鞋一起好好利用!呵呵…

查看全部问答>

单片机到共阴极LED七段数码管的显示

朋友要做毕业论文。因为我帮助他查资料,所以请大家帮帮我们,看我们需要在那些方面着手,查那些资料,给一些头绪。我们只负责做  “由单片机到共阴极LED七段数码管的显示”   ,其余那些是课题需求。谢谢了!以下两张图片是概 ...…

查看全部问答>