嵌入式Linux驱动开发------汇编点灯
本文章开始记录学习嵌入式Linux的过程,使用的开发板是正点原子的阿尔法,以及左老师的书籍和视频。然后这个系列不会介绍基础知识(书上都有),主要是记录思考过程以及需要注意的点。
代码编写
使能时钟
🚀🚀这个地方的代码还是很简单的,主要就是去哪找CCM的地址,不过也不算难找,比如CCGR0,就是0x020c4068。
🚀🚀然后找到GPIO1的时钟由CCM_CCGR1 的 bit27 和 bit26 这两个位控制,将这两个位都设置位 11 即可

            
            
              assembly
              
              
            
          
          .global _start  /* 全局标号 */
/*
 * 描述:	_start函数,程序从此函数开始执行此函数完成时钟使能、
 *		  GPIO初始化、最终控制GPIO输出低电平来点亮LED灯。
 */
_start:
	/* 1、使能GPIO1时钟 */
	ldr r1, =0xFFFFFFFF 	
	ldr r0, =0X020C406C  	/* CCGR1 */
	str r1, [r0]- .global _start: 这是一个全局标签,标记了程序的起始位置。
- _start: 这是程序的入口点,程序将从这里开始执行。
- ldr r1, =0xFFFFFFFF: 这一行使能CCGR1。
- ldr r0, =0X020C406C: 这一行将立即数- 0X020C406C加载到寄存器- r0中,这个值是GPIO1的时钟寄存器的地址。
- str r1, [r0]: 这一行将寄存器- r1中的值写入到地址为- r0的内存位置,即将生成的掩码写入到GPIO1的时钟寄存器,从而启用GPIO1时钟。
设置复用
- ldr r0, =0X020E0068: 这一行将立即数- 0X020E0068加载到寄存器- r0中,这个值是SW_MUX_GPIO1_IO03_BASE寄存器的地址,也是像上面那样找。这个寄存器用于控制GPIO1_IO03引脚的复用功能。
- ldr r1, =0X5: 这一行将立即数- 0X5加载到寄存器- r1中。在i.MX系列处理器中,设置为5的MUX_MODE表示该引脚被设置为GPIO模式,即将该引脚设置为普通GPIO引脚功能。
- str r1, [r0]: 这一行将寄存器- r1中的值写入到地址为- r0的内存位置,即将MUX_MODE设置为5,从而将GPIO1_IO03引脚的复用功能设置为GPIO1_IO03。
            
            
              assembly
              
              
            
          
          	/* 2、设置GPIO1_IO03复用为GPIO1_IO03 */
	ldr r0, =0X020E0068	/* 将寄存器SW_MUX_GPIO1_IO03_BASE加载到r0中 */
	ldr r1, =0X5		/* 设置寄存器SW_MUX_GPIO1_IO03_BASE的MUX_MODE为5 */
	str r1,[r0]
设置IO

            
            
              assembly
              
              
            
          
          /* 3、配置GPIO1_IO03的IO属性	
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 00 默认下拉
     *bit [13]: 0 kepper功能
     *bit [12]: 1 pull/keeper使能,开启上下拉
     *bit [11]: 0 关闭开路输出
     *bit [7:6]: 10 速度100Mhz
     *bit [5:3]: 110 R0/6驱动能力
     *bit [0]: 0 低转换率
     */
    ldr r0, =0X020E02F4	/*寄存器SW_PAD_GPIO1_IO03_BASE */
    ldr r1, =0X10B0
    str r1,[r0]设置GPIO
🚀🚀这个的地址有一点点不一样,在GPIO Memory Map/Register Definition里面。

            
            
              assembly
              
              
            
          
          /* 4、设置GPIO1_IO03为输出 */
    ldr r0, =0X0209C004	/*寄存器GPIO1_GDIR */
    ldr r1, =0X0000008		
    str r1,[r0]
    
/* 5、打开LED0
* 设置GPIO1_IO03输出低电平
*/
   ldr r0, =0X0209C000	/*寄存器GPIO1_DR */
   ldr r1, =0		
   str r1,[r0]
/*
 * 描述:	loop死循环
 */
loop:
	b loop 			编译
🚀🚀这四条命令用于将汇编代码编译、链接、转换为二进制文件,并生成反汇编文件,具体作用如下:
- arm-linux-gnueabihf-gcc -g -c led.s -o led.o:- arm-linux-gnueabihf-gcc:使用arm-linux-gnueabihf工具链中的gcc编译器。
- -g:生成带有调试信息的目标文件。
- -c:表示只编译,不链接。
- led.s:源文件名,这里是汇编代码文件。
- -o led.o:指定输出的目标文件名为led.o,这里是编译后的目标文件。
 
- arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf:- arm-linux-gnueabihf-ld:使用arm-linux-gnueabihf工具链中的ld链接器。
- -Ttext 0X87800000:指定链接地址,这里设置程序的起始地址为0X87800000。
- led.o:输入的目标文件名,即刚刚生成的目标文件。
- -o led.elf:指定输出的可执行文件名为led.elf,这里是链接后的可执行文件。
 
- arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin:- arm-linux-gnueabihf-objcopy:使用arm-linux-gnueabihf工具链中的objcopy工具。
- -O binary:指定目标文件的格式为二进制。
- -S:去除调试符号和调试信息。
- -g:保留全局符号信息。
- led.elf:输入的可执行文件名,即刚刚生成的可执行文件。
- led.bin:指定输出的二进制文件名为led.bin,这里是转换后的二进制文件。
 
- arm-linux-gnueabihf-objdump -D led.elf > led.dis:- arm-linux-gnueabihf-objdump:使用arm-linux-gnueabihf工具链中的objdump工具。
- -D:显示反汇编代码。
- led.elf:输入的可执行文件名,即刚刚生成的可执行文件。
- > led.dis:将反汇编的结果输出到led.dis文件中,这里是生成的反汇编文件。
 
            
            
              bash
              
              
            
          
          kali@ubuntu:~/linux/driver/01_leds$ arm-linux-gnueabihf-gcc -g -c led.s -o led.o
kali@ubuntu:~/linux/driver/01_leds$ arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
kali@ubuntu:~/linux/driver/01_leds$ arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
kali@ubuntu:~/linux/driver/01_leds$ arm-linux-gnueabihf-objdump -D led.elf > led.dis
makefile
            
            
              makefile
              
              
            
          
          led.bin:led.s
	arm-linux-gnueabihf-gcc -g -c led.s -o led.o
	arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
	arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
	arm-linux-gnueabihf-objdump -D led.elf > led.dis
clean:
	rm -rf *.o led.bin led.elf led.dis🚀🚀这个Makefile文件用于管理编译、链接、转换和清理操作,具体作用如下:
- 
led.bin: led.s:定义了一个目标文件led.bin,它依赖于led.s文件。也就是说,当led.s文件被修改时,会触发后续的编译、链接、转换操作。
- 
arm-linux-gnueabihf-gcc -g -c led.s -o led.o:编译led.s文件为目标文件led.o,这里使用了arm-linux-gnueabihf工具链中的gcc编译器,并且指定生成带有调试信息的目标文件。
- 
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf:链接led.o文件为可执行文件led.elf,这里使用了arm-linux-gnueabihf工具链中的ld链接器,并且指定了链接地址为0X87800000。
- 
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin:将led.elf文件转换为二进制文件led.bin,这里使用了arm-linux-gnueabihf工具链中的objcopy工具,并且指定了输出的文件格式为二进制。
- 
arm-linux-gnueabihf-objdump -D led.elf > led.dis:生成反汇编文件led.dis,这里使用了arm-linux-gnueabihf工具链中的objdump工具,并且指定了显示反汇编代码。
- 
clean::定义了一个伪目标clean,用于清理生成的目标文件和中间文件。
- 
rm -rf *.o led.bin led.elf led.dis:删除所有的目标文件和生成的二进制文件,以及反汇编文件。
代码烧录
🚀🚀这个就是使用imxdownload,比较简单
            
            
              bash
              
              
            
          
          kali@ubuntu:~/linux/driver/01_leds$ ./imxdownload led.bin /dev/sdb
I.MX6ULL bin download software
Edit by:zuozhongkai
Date:2019/6/10
Version:V1.1
log:V1.0 initial version,just support 512MB DDR3
    V1.1 and support 256MB DDR3
file led.bin size = 88Bytes
Board DDR SIZE: 512MB
Delete Old load.imx
Create New load.imx
Download load.imx to /dev/sdb  ......
6+1 records in
6+1 records out
3160 bytes (3.2 kB, 3.1 KiB) copied, 0.0569602 s, 55.5 kB/s结果
