第三章:ARM驱动交叉编译指令

裸机编程的思路

  • 1.    分析原理图:gec6818_base_V1.1-底板.pdfgec6818cv1_20170407-核心板.pdf
  • 2.    理解硬件的工作原理
  • 3.    找到对应的库函数寄存器
  • 4.    理解寄存器的控制流程
  • 5.    根据地址访问寄存器
  • 6.    实现硬件的控制

一、通过寄存器实现LED灯工作
         如果控制D7亮,GPIOE13输出低电平;如果控制D7灭,GPIOE13要输出高电平。

二、寄存器的配置
找到对应的寄存器必须阅读芯片手册,本篇用到的是S5P6818芯片的数据手册

1.    找到GPIO输出模式的配置方法
     1)配置某个端口某个引脚为输出模式
           GPIOE多功能寄存器,设置对应的bits为b“00”

     2)使能当前引脚的输出
           GPIOE输出使能寄存器对应的位设置为1

     3)输出高低电平
           GPIOE输出寄存器的对应的位设置为1或0.

2.    对应的寄存器
    1)GPIOxOUT寄存器

    2)GPIOxOUTENB寄存器

    3)GPIOxALTFN0寄存器,有些引脚需要阅读GPIOxALTFN1寄存器,这点要注意。  

             //0~15Pin(要配置的是GPIOxALTFN0寄存器)

             //16~31Pin(要配置的是GPIOxALTFN1寄存器)

             //由于官方文档这里没有详细描述ALT Function0 ~ ATLFunction3,因此需要各位还得阅读第二章节。

     最后知道GPIOE13要配置为ALT Function0.

三、编写代码

1.    源码如下

/***定义寄存器***/
/*定义GPIOE的输出寄存器地址*/
#define GPIOEOUT          (*(volatile unsigned int *)0xC001E000) 
/*定义GPIOE输出使能寄存器地址*/  
#define GPIOEOUTENB       (*(volatile unsigned int *)0xC001E004)
/*定义GPIOE功能配置寄存器地址*/  
#define GPIOEALTFN0       (*(volatile unsigned int *)0xC001E020)

static void delay(void);      //声明一个延时函数

/**
 * C程序的入口,同时不需要使用标准C的库,因此入口函数为_start.
**/
void _start(void)
{
    /*GPIOE13配置为输出模式*/
    GPIOEALTFN0&=~(3<<26);    //将GPIOEALTFN0寄存器[27:26]清零
    
    /*GPIOE13输出使能*/
    GPIOEOUTENB|=1<<13;    
    
    while(1)
    {
        
        //点亮D7
        GPIOEOUT&=~(1<<13);    //将GPIOEOUT寄存器中[13]清零
        
        //延时一会
        delay();
        
        //熄灭D7
        GPIOEOUT|= (1<<13);    //将GPIOEOUT寄存器中[13]置1    

        //延时一会
        delay();
    }
    
}

/**
 * 延时函数
**/
void delay(void)
{
    //思考为什么要加volatile,如果不加,会出现什么结果?
    volatile unsigned int i=0x20000000;
    
    while(i--);
}

四、使用交叉编译器来进行编译

1.    检查Ubuntu是否存在交叉编译器

root@ubuntu:/home/gec# which arm-linux-gcc
/usr/local/arm/5.4.0/usr/bin/arm-linux-gcc

2.    [可选操作]进入共享目录去编译

1)将demo.c编译为目标文件led.o,且不使用标准C的库(因为使用标准C的库需要使用汇编配置堆和栈)

      arm-linux-gcc -o led.o -c demo.c -nostdlib

2)将led.o文件链接到0x40000000这个地址,输出新的执行程序为led.elf
      arm-linux-ld -Ttext 0x40000000 -o  led.elf led.o

3)由于uboot不是linux操作系统,它不具有运行应用程序的能力,需要转换为bin文件。
      arm-linux-objcopy -O binary led.elf led.bin

五、下载led.bin文件到开发板执行
1.    使用uboot的tftp进行下载

      tftp 0x40000000 led.bin

2.    执行led.bin
      go 0x40000000
3.    演示效果

1)点亮

2)熄灭

 

注:
1、delay函数的源码为什么要加volatile关键字,如果不加,会出现什么结果?

    1) 加上volatile关键字,可以防止被编译器优化删除掉这个时候,led灯的闪烁是正常的。

    40000088 :                        //函数或标签        
    运行地址    机器码        指令
   40000088:    e52db004     push    {fp}        ; (str fp, [sp, #-4]!)
   4000008c:    e28db000     add    fp, sp, #0
   40000090:    e24dd00c     sub    sp, sp, #12
   40000094:    e3a03202     mov    r3, #536870912    ; 0x20000000
   40000098:    e50b3008     str    r3, [fp, #-8]
   4000009c:    e1a00000     nop            ; (mov r0, r0)
   400000a0:    e51b3008     ldr    r3, [fp, #-8]
   400000a4:    e2432001     sub    r2, r3, #1
   400000a8:    e50b2008     str    r2, [fp, #-8]
   400000ac:    e3530000     cmp    r3, #0
   400000b0:    1afffffa     bne    400000a0
   400000b4:    e1a00000     nop            ; (mov r0, r0)
   400000b8:    e24bd000     sub    sp, fp, #0
   400000bc:    e49db004     pop    {fp}        ; (ldr fp, [sp], #4)
   400000c0:    e12fff1e     bx    lr            //函数返回

   以上就是delay函数的反汇编代码,起到延时的作用。

   对led.elf输出反汇编代码
   arm-linux-objdump -D led.elf > led.dis1.  
2) 不加上volatile关键字,这个时候,led灯的闪烁是有的,但是人眼是观察不到,因为delay函数被编译器优化删除掉,导致闪烁速度太快!
 

你可能感兴趣的:(基于A53的内核驱动学习分享)