正点原子Mini Linux—C语言驱动LED灯

现在终于可以使用习惯的C语言进行代码的编写了,但是在编写主要C语言代码之前,还是需要使用汇编进行一系列的准备操作,这和stm32每个项目的汇编启动文件相似。下面介绍详细的方法:

C语言驱动LED

  • 一、C语言运行环境的搭建
    • 1、设置处理器模式
    • 2、设置sp指针
    • 3、跳转到C语言
  • 二、C语言编写
  • 三、程序的编译链接
    • 1、不使用链接脚本
    • 2、使用链接脚本
  • 四、其他知识链接

一、C语言运行环境的搭建

1、设置处理器模式

在正点原子之前的视频中有讲述过Cortex-A处理器具有9中运行模式,如下表所示:
正点原子Mini Linux—C语言驱动LED灯_第1张图片
这里需要先设置处理器为SVC模式,即超级管理员模式,而设置处理器模式就需要调节程序状态寄存器CPSR的M[4:0]这五位的数据了,不同数据对应的不同模式如下:
正点原子Mini Linux—C语言驱动LED灯_第2张图片
从该图可知要使处理器进入SVC模式,必须先通过汇编语言将CPSR的M[4:0]设置为10011,即0x13。因为这里是对CPSR这个特殊寄存器进行配置,要使用MRS(读)和MSR(写)这两个指令来进行操作。但我们知道我们只需要操作CPSR中的五位数据,所以我们要用到汇编语言的逻辑运算指令,详细说明可以参考开发指南ARM汇编基础,具体如下:

.global _start

_start:
	/* 设置处理器进入SVC模式 */
	mrs r0, cpsr		@ 读取cpsr到r0
	bic r0, r0, #0x1f	@ 清除cpsr的bit4~0
	orr r0, r0, #0x13	@ 设置为SVC模式
	msr cpsr, r0		@ 将设置好的r0写入到cpsr

2、设置sp指针

设置好了处理器模式之后,需要对sp指针进行设置(sp指针可以指向内如RAM,也可以指向DDR,这里将其指向了DDR)。设置栈大小为2MB = 0x200000,因为对于Cortex-A7栈是向下增长的,为了使其不越界DDR起始地址0x80000000,这里设置sp指针指向0x80200000。

	/* 设置sp指针 */
	ldr sp, = 0x80200000

3、跳转到C语言

这里是C语言环境构建的最后一步,在设置好处理器模式并初始化了sp指针之后,就可以使用C语言了,这里只需要进行一下跳转,具体的话可是使用b指令转跳到main函数。

	b main			@ 跳转到C语言main函数

这三段代码都在一.s文件下

二、C语言编写

在上述操作下,C语言的运行环境已经搭建完毕了,现在就可以编写LED的C代码了,这个实验很简单,只包括一个main.c和一个main.h文件,main.h里面主要对寄存器地址进行宏定义,在main.c中编写具体main函数实验LED的点亮和闪烁。

这里main.h的内容就不全部书写出来,用到的就是汇编驱动LED时的那些寄存器。这里主要还是volatile这个关键字,在我学习32时没有深入学习,因此在网上查阅了相关资料,大家可以参考用C语言宏定义寄存器地址解释 和 关键字 volatile

另外关于main.c的程序发开指南有详解,这里就不再赘述。

三、程序的编译链接

1、不使用链接脚本

接下来就是文件的编译和链接了,在之前写到的文章中没有具体说明其中命令里的细节,这对刚刚接触到Linux的我们来说还是有点不习惯的,文章结尾有具体介绍的链接供大家学习参考。除此之外,还可以自己在网上找一些makefile的文章看看(这里有自动化变量的知识)对具体代码的理解会有进一部的加深。
这里就直接上makefile代码:

objs = start.o main.o		# 定义变量(:= 和 = 有一些细微的差别,可自行查阅,在这里都可以使用)

ledc.bin : $(objs)
	arm-linux-gnueabihf-ld -Ttext 0x87800000 -o ledc.elf &^		
	arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
	arm-linux-gnueabihf-objdump -D -m arm ledc.elf > led.dis
%.o : %.s
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o &@ $<		# -Wall -nostdlib 优化

%.o : %.S
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o &@ $<

%.o : %.c
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o &@ $<
	
clean:
	rm -rf *.o ledc.bin ledc.elf ledc.dis

2、使用链接脚本

使用链接脚本可以自定义段/区域,能自由指定这些段的起始地址,这里使用到的段分别是.text,.data,.bss,.rodata。

意义
.text 代码段,存放程序执行代码的区域
.data 初始化的数据段,存放程序中已初始化的全局变量
.bss 未初始化的数据段,存放程序中未初始化的全局变量
.rodata 只读数据段,存放C语言中的字符串和宏定义常量

代码中的COMMON,经过网上的查找好像是普通符号,如果有知道的小伙伴可以评论补充。
连接脚本需要在.lds中书写,代码见开发指南。
在使用链接脚本的情况下,需要改变Makefile文件中的链接代码:

	arm-linux-gnueabihf -T<链接文件名> ledc.elf &^

例如 :arm-linux-gnueabihf -Timx6ul.lds ledc.elf &^

四、其他知识链接

这里是一些指令的介绍:
arm-linux-gnueabihf-ld介绍
arm-linux-gnueabihf-objcopy介绍
arm-linux-gnueabihf-objdump介绍

你可能感兴趣的:(正点原子Mini Linux—C语言驱动LED灯)