一.如何阅读芯片手册(datasheet)
作为嵌入式学习者,如何去阅读芯片手册是重中之重。不管是什么芯片手册,在写的怎么天花乱坠,它的本质也就是使用说明书。
可是问题来了,它Y的是本英语的说明书,但是英语不好的友友们不要过于焦虑,我们现在有了很好的翻译软件,而且只要我们多读多看,在未来的一个时间点厚积薄发,阅读芯片手册对你来说再也不是问题。
下面我将以生动形象用一个三星的芯片手册结合如何进行简单驱动开发去带领大家一起读芯片手册,了解到它的功能强大之处。
二.裸机驱动开发步骤
1.当我们拿到一块板子,如果想要实现具体的功能,首先我们要想到的肯定是明白自己想要实现一个什么样的功能。(这里我就拿各位学生看到都烦的点灯来举例)
2.既然明白了我们的目标是点灯,那么我们接下来要做的就是找到板子上的小灯泡(发光二极管)
如图:
然后我们看到了led【2-5】一共四个小灯泡
找到小灯泡以及名字后也就正式开启了我们的点灯之路。
裸机驱动开发
(1)看电路图
--1.找到我要控制的设备(这里就拿小灯泡led2来举例)
打开我们的外设硬件说明书在搜索栏搜索led2
如图
从这张图我们了解到,这是一个npn三极管,基极连接着cpu的侧控制管脚CHG_COK,由cpu来进行模数转换控制高低电位,决定三极管的导通以及关断。这里我们忽略已经标好的GPX2_7。
(2)看芯片手册
搜索,电路图里对应的控制模块,然后如果有coreboard的话去那里找到对应的GPX2-7。
看模块的overview了解该模块的大概功能。
(3)看控制寄存器
如果寄存器比较多我们该怎么办?
看技术支持提供的例子程序,找到需要修改的寄存器(常常都只有几个)。
部分厂商会提供配置软件,通过界面去配置功能,我们只需要使用配置好的寄存器的值就可以了。
来到芯片手册,如图所示:
(4)编程
1.定义要控制的寄存器的宏(与手册里的寄存器地址对应起来)
2.设备初始化(如设置GPIO的输出状态) tips:GPIO就是与cpu相连的引脚
3.把功能分成最基本的小块,逐个实现,如:点亮灯——灭灯——加延时——闪烁——跑马灯
以下代码是在这个cpu以及开发板上实现的:
cpu:samsung Exynos
开发板: FS4412
三.纯汇编实现点灯
@ GPX2CON 寄存器地址: 0x11000000 + 0x0c40 .text ldr r0, =0x11000c40 @ 将GPX2CON寄存器地址搬移到 r0,那么r0 就代表 GPX2CON ldr r1, [r0] bic r1, #0xf0000000 @ 将 28~31号比特位清零 orr r1, #0x10000000 @ 28号比特位置位1,其他比特位不动,设置GPX2_7输出功能 str r1, [r0] ldr r0, =0x114001e0 @ 将GPF3CON寄存器地址搬移到 r0 GPF3_4 ldr r1, [r0] @ 将地址上的内容取 4字节,相当于取出GPF3CON寄存器的内容 bic r1, #0xf0000 orr r1, #0x10000 str r1, [r0] while: ldr r2, =0x11000c44 @ 将GPX2DAT寄存器的地址搬移到 r2 ldr r3, [r2] orr r3, #0x80 @ 将GPX2DAT的7号位置 1,亮灯 str r3, [r2] ldr r2, =0x114001e4 @ 将GPF3DAT ldr r3, [r2] orr r3, #0x10 @ 将GPF3DAT的4号位置 1,亮灯 str r3, [r2] bl delay_1s ldr r2, =0x11000c44 @ 将GPX2DAT寄存器的地址搬移到 r2 ldr r3, [r2] bic r3, #0x80 str r3, [r2] ldr r2, =0x114001e4 @ 将GPF3DAT ldr r3, [r2] bic r3, #0x10 @ 将GPF3DAT的4号位置 0,灭灯 str r3, [r2] bl delay_1s b while delay_1s: ldr r10, =0x4ffffff loop: cmp r10, #0 subgt r10, #1 bgt loop mov pc, lr .end
makefile
CROSS=arm-linux- CC=gcc LD=ld OC=objcopy all: $(CROSS)$(CC) -c start.s $(CROSS)$(LD) start.o -Ttext 40008000 -o start.elf $(CROSS)$(OC) -O binary -S start.elf start.bin clean: rm *.o *.elf *.bin
四. 汇编结合c点灯
mian.c 实现延时
> Created Time: 2022年08月10日 星期三 15时43分06秒 ***********************************************************************/ void delay() { int i, j; for(i = 0; i < 10000; i++) for(j = 0; j < 256; j++); } /*******************************end of file*****************************/
@ GPX2CON 寄存器地址: 0x11000000 + 0x0c40 .text ldr r0, =0x11000c40 @ 将GPX2CON寄存器地址搬移到 r0,那么r0 就代表 GPX2CON ldr r1, [r0] bic r1, #0xf0000000 @ 将 28~31号比特位清零 orr r1, #0x10000000 @ 28号比特位置位1,其他比特位不动,设置GPX2_7输出功能 str r1, [r0] ldr r0, =0x114001e0 @ 将GPF3CON寄存器地址搬移到 r0 GPF3_4 ldr r1, [r0] @ 将地址上的内容取 4字节,相当于取出GPF3CON寄存器的内容 bic r1, #0xf0000 orr r1, #0x10000 str r1, [r0] while: ldr r2, =0x11000c44 @ 将GPX2DAT寄存器的地址搬移到 r2 ldr r3, [r2] orr r3, #0x80 @ 将GPX2DAT的7号位置 1,亮灯 str r3, [r2] ldr r2, =0x114001e4 @ 将GPF3DAT ldr r3, [r2] orr r3, #0x10 @ 将GPF3DAT的4号位置 1,亮灯 str r3, [r2] bl delay @ 调用main.c中的delay函数,进行延时 ldr r2, =0x11000c44 @ 将GPX2DAT寄存器的地址搬移到 r2 ldr r3, [r2] bic r3, #0x80 str r3, [r2] ldr r2, =0x114001e4 @ 将GPF3DAT ldr r3, [r2] bic r3, #0x10 @ 将GPF3DAT的4号位置 0,灭灯 str r3, [r2] bl delay @ 调用main.c中的delay函数,进行延时 b while .end
makefile
CROSS=arm-linux- CC=gcc LD=ld OC=objcopy all: $(CROSS)$(CC) -c start.s $(CROSS)$(CC) -c main.c $(CROSS)$(LD) start.o main.o -Ttext 40008000 -o start.elf $(CROSS)$(OC) -O binary -S start.elf start.bin clean: rm *.o *.elf *.bin
五.c实现点灯,这种方法是我们用的最多的,也是最简便的
main.c
***********************************************************************/ void delay() { int i, j; for(i = 0; i < 10000; i++) for(j = 0; j < 256; j++); } #define GPX2CON *(volatile unsigned int *)0x11000c40 #define GPX2DAT *(volatile unsigned int *)0x11000c44 void led2_init() { // GPX2CON = GPX2CON & 0x0fffffff | (1 << 28) GPX2CON = GPX2CON & (~(0xf << 28)) | ( 0x1 << 28 ); } void led2_on() { GPX2DAT = GPX2DAT | (1 << 7); } void led2_off() { GPX2DAT = GPX2DAT & (~(1 << 7)); } int main() { led2_init(); while(1){ led2_on(); delay(); led2_off(); delay(); } } /*******************************end of file*****************************/
.text b main .end
makefile
CROSS=arm-linux- CC=gcc LD=ld OC=objcopy all: $(CROSS)$(CC) -c start.s $(CROSS)$(CC) -c main.c $(CROSS)$(LD) start.o main.o -Ttext 40008000 -o start.elf $(CROSS)$(OC) -O binary -S start.elf start.bin clean: rm *.o *.elf *.bin
六.纯汇编实现跑马灯
@ GPX2CON 寄存器地址: 0x11000000 + 0x0c40 .text ldr r0, =0x11000c40 @ 将GPX2CON寄存器地址搬移到 r0,那么r0 就代表 GPX2CON ldr r1, [r0] bic r1, #0xf0000000 @ 将 28~31号比特位清零 orr r1, #0x10000000 @ 28号比特位置位1,其他比特位不动,设置GPX2_7输出功能 str r1, [r0] ldr r0,=0x11000c20 ldr r1,[r0] bic r1,#0xf orr r1,#0x1 str r1,[r0] ldr r0, =0x114001e0 @ 将GPF3CON寄存器地址搬移到 r0 GPF3_4 ldr r1, [r0] @ 将地址上的内容取 4字节,相当于取出GPF3CON寄存器的内容 bic r1, #0xf0000 orr r1, #0x10000 str r1, [r0] ldr r0,=0x114001E0 ldr r1,[r0] bic r1,#0xf00000 orr r1,#0x100000 str r1,[r0] while: @开灯led2 ldr r2, =0x11000c44 @ 将GPX2DAT寄存器的地址搬移到 r2 ldr r3, [r2] orr r3, #0x80 @ 将GPX2DAT的7号位置 1,亮灯 str r3, [r2] bl delay_1s @开灯led3 ldr r2,=0x11000c24 ldr r3,[r2] orr r3,#0x1 str r3,[r2] bl delay_1s @开灯led4 ldr r2, =0x114001e4 @ 将GPF3DAT ldr r3, [r2] orr r3, #0x10 @ 将GPF3DAT的4号位置 1,亮灯 str r3, [r2] bl delay_1s @开灯led5 ldr r2,=0x114001E4 ldr r3,[r2] orr r3,#0x20 str r3,[r2] bl delay_1s @关灯led2 ldr r2, =0x11000c44 @ 将GPX2DAT寄存器的地址搬移到 r2 ldr r3, [r2] bic r3, #0x80 str r3, [r2] bl delay_1s @关灯led3 ldr r2,=0x11000c24 ldr r3,[r2] bic r3,#0x1 str r3,[r2] bl delay_1s @关灯led4 ldr r2, =0x114001e4 @ 将GPF3DAT ldr r3, [r2] bic r3, #0x10 @ 将GPF3DAT的4号位置 0,灭灯 str r3, [r2] bl delay_1s @关灯led5 ldr r2,=0x114001E4 ldr r3,[r2] bic r3,#0x20 str r3,[r2] bl delay_1s b while delay_1s: ldr r10, =0x4ffffff loop: cmp r10, #0 subgt r10, #1 bgt loop mov pc, lr .end
makefile
CROSS=arm-linux- CC=gcc LD=ld OC=objcopy all: $(CROSS)$(CC) -c start.s $(CROSS)$(LD) start.o -Ttext 40008000 -o start.elf $(CROSS)$(OC) -O binary -S start.elf start.bin clean: rm *.o *.elf *.bin