第三十三天:Tiny4412驱动开发之LED驱动和u-boot移植

  从今天开始进入驱动开发的课程的学习,共完成三件事情。一:u-boot的简单移植,二:uboot中编写helloword程序 三:开发板中led灯的驱动编写,包括led点亮,闪烁,跑马,流水。

  一:u-boot的简单移植

  1.进入开发板提供的源码文件包,解压uboot源码包。

  cd /home/bunfly/source_code/    

  tar xf uboot_tiny4412-20130729.tgz

  2.进入uboot文件夹,更改uboot中tiny4412的配置文件。将225 中的Tiny4412更改为bunfly。

  cd uboot_tiny4412

  vim include/configs/tiny4412.h

  更改255行为#define CONFIG_SYS_PROMPT               "bunfly # "
  3. 回到u-boot文件夹,编译u-boot

  make tiny4412_config

  make

  4.进入sd_fuse文件夹 编译

  cd sd_fuse

  make

  5.编译结束后生成tiny4412文件夹,进入文件夹。插入sd卡到电脑。烧写u-boot到sd卡中

  cd tiny4412/

  sd卡会自动加载,所以先卸载sd卡 umount /media/aaa

  参看sd卡挂载点:fdisk -l 发现sd卡挂载在/dev/sdb中

  烧写: ./sd_fusing.sh /dev/sdb

  6.显示烧写成功后将sd插入开发板,开发板设置从sd卡启动。显示下图表示烧写成功。

  第三十三天:Tiny4412驱动开发之LED驱动和u-boot移植_第1张图片

 

     二:u-boot中编写hello world 程序

  U-Boot作为嵌入式Linux系统的引导,不具有标准C库中的内容。要使用printf函数,就需要u-boot中提供的。u-boot函数内容在u-boot源码文件中

的System.map文件中。System.map文件是被内核所使用的符号表。符号表是一个在符号名称与它们的存储器位置间的查询表格。符号名称可能是变量的名称或是函数名称。当要查询符号名称的位置或是特定位置的符号名称时,就会需要System.map。

   查找System.map中printf中的位置 在538行, c3e114d8 T printf,使用c3e114d8就表示使用printf函数,下面是helloword函数的汇编代码实现: 

 1 .global main
 2 main:
 3     mov ip,sp
 4     stmfd sp!,{fp,ip,lr}
 5     sub fp,ip,#4
 6 
 7     ldr r0, =string    
 8     ldr r2, haha
 9     blx r2
10 
11     sub sp,fp,#8
12     ldmfd sp,{fp,sp,pc}
13 
14 haha:
15     .word 0xc3e114d8
16 string:
17     .asciz "hello world\n"
18     .align 2

 

  注意:blx表示跳转到寄存器。

 编译时候有三个步骤:

  1.arm-none-linux-gnueabi-gcc -c hello.s -o hello.o
    2.arm-none-linux-gnueabi-ld -Ttext=0x40008000 hello.o -o hello

    3.arm-none-linux-gnueabi-objcopy -Ielf32-littlearm -Obinary hello hello.bin
    第一步:只编译,不链接标准C库的内容,因为不需要。 
  第二步:链接时指定程序分配地址从40008000开始分配

  第三步:去文件头,将linux文件头lelf32装换成ARM的文件头。

 完成三个步骤后,通过dnw将hello.bin文件传到开发板40008000地址中。通过 go 执行代码。

  开发板:dnw 40008000

  宿主机:dnw hello.bin

  开发板:go 40008000

  结果如下图:

  第三十三天:Tiny4412驱动开发之LED驱动和u-boot移植_第2张图片

 接下来是输出hellowrold字符用C代码实现:

1 int (*printf)(char *,...) = 0xc3e114d8;
2 int main()
3 {
4     printf("hello world\n");
5 
6 }

  C语言编写相当简洁有木有。第一行定义函数指针指向u-boot中的printf函数。编译,运行过程和上面相同。

      为了以后方便,编写Makefile文件,实现编译过程:

 1 name=hello
 2 bin=${name}.bin
 3 o=${name}.o
 4 tar=${name}.c
 5 ${bin}:${name}
 6     arm-none-linux-gnueabi-objcopy -Ielf32-littlearm -Obinary $^ $@
 7 ${name}:${o}
 8     arm-none-linux-gnueabi-ld -Ttext=0x50005000 $^ -o $@
 9 ${o}:${tar}
10     arm-none-linux-gnueabi-gcc -c $^ -o $@
11 clean:
12     rm -f ${bin} ${o} ${name}

   三:LED驱动编写

  首先要明白开发板的构造。开发板分为核心板和底板。核心板的电路图文件路径:schematics/Tiny4412/Tiny4412_1306_sch.pdf

    底板电路图路径在:schematics/Tiny4412SDK 1306Tiny4412SDK_1306_sch.pdf

  开发板数据手册在:datasheet/Exynos_4_Quad_User_Manaul_Public_REV100-0.pdf

  整个编写过程都是围绕着这三个文件进行。

  因为LED灯在核心板上,所以先查看核心板电路图,打开电路图,看开发板中led灯的标号分别为LED1,LED2,LED3,LED4,LED5,LED6 

  通过查找功能,找到LED的电路图:

  第三十三天:Tiny4412驱动开发之LED驱动和u-boot移植_第3张图片 

  可以观察到的是,LED灯的一端已经接高电平,只要给另一端加低电平LED就会被点亮。

   继续查找LED1在核心板中的引脚定义。

  第三十三天:Tiny4412驱动开发之LED驱动和u-boot移植_第4张图片

  由上图可知LED1对应的灯就是GPM4_0,   最后一步就是使用GPM4_0为关键字在芯片数据手册中查看引脚的具体使用说明了。

第三十三天:Tiny4412驱动开发之LED驱动和u-boot移植_第5张图片

第三十三天:Tiny4412驱动开发之LED驱动和u-boot移植_第6张图片

  GPM4CON 置一输出,表示控制,置零输入,表示检测,GPM4DAT表示它的值和引脚的电压状态对于,值为一时表示高电平,值为零时表示底电平。下面是控制LED1的汇编代码:

 1 .global main
 2 main:
 3     mov ip,sp
 4     stmfd sp!,{fp,ip,lr}
 5     sub fp,ip,#4
 6 
 7     ldr r0,gpmcon
 8     mov r1,#1
 9     str r1,[r0]
10     
11     ldr r0,gpmdat
12     mov r1,#0
13     str r1,[r0]    
14 
15     sub sp,fp,#8
16     ldmfd sp,{fp,sp,pc}
17 
18 gpmcon:
19     .word 0x110002e0
20 gpmdat:
21     .word 0x110002e4

    将GOM4CON对于位置1,GOM4DAT对应位置0。LED灯就亮了。

然后是C语言代码实现四个LED灯闪烁:

 1 void (*udelay)(int) = 0xc3e25f90;
 2 void  abc(void)
 3 {
 4     volatile unsigned long  *GPM4CON  = 0x110002e0;
 5     volatile unsigned long  *GPM4DAT  = 0x110002e4;
 6     
 7     *GPM4CON =  0x1111;
 8     while(1){
 9         *GPM4DAT = 0xf;//led off
10         udelay(250000);
11         *GPM4DAT = 0x0;
12         udelay(250000);//led on
13     }
14     16 }

  这里用到udelay延迟函数。同样也是在System.map中查询到的,单位是微秒。

还有实现跑马灯和流水灯:

 1 void (*udelay)(int) = 0xc3e25f90;
 2   3 void  abc(void)
 3   4 {
 4   5         volatile unsigned long  *GPM4CON  = 0x110002e0;
 5   6         volatile unsigned long  *GPM4DAT  = 0x110002e4;
 6   7 
 7   8         *GPM4CON =  0x1111;
 8   9         unsigned long tmp = 0x0f;
 9  10         while(1){
10  11                 if((tmp & 0x0f) == 0x00)
11  12                         tmp =0x0f;
12  13                 *GPM4DAT = tmp << 1 ; //跑马
13  14                 tmp = *GPM4DAT;
14  15                 udelay(250000);
15  16         }
16  17 
17  18         return;
18  19 }
跑马灯
 1 void (*udelay)(int) = 0xc3e25f90;
 2 void  abc(void)
 3 {
 4     volatile unsigned long  *GPM4CON  = 0x110002e0;
 5     volatile unsigned long  *GPM4DAT  = 0x110002e4;
 6     
 7     *GPM4CON =  0x1111;
 8     unsigned long i = 0;
 9     while(1){
10         *GPM4DAT =  0xf;
11         *GPM4DAT &= ~(1 << i);
12         udelay(500000);
13         i++;
14         if(i ==4)
15             i=0;
16     }
17     
18     return;
19 }
流水灯

 

你可能感兴趣的:(Linux)