700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > I.MX6ULL裸机驱动开发四种方式总结

I.MX6ULL裸机驱动开发四种方式总结

时间:2021-10-09 21:21:38

相关推荐

I.MX6ULL裸机驱动开发四种方式总结

学习裸机驱动开发也有一阵子,终于是把几种裸机驱动方法学完了,总体来说难度并不大。因为毕竟有基础在,能大概看懂数据手册和知道如何是控制寄存器。

驱动方法目前所学共有四种:

1.纯汇编驱动

2.汇编驱动头文件,剩下的使用C语言来驱动

3.模仿STM32的方式来进行驱动

4.移植NXP的官方SDK来进行驱动

四种方法有共同点和不同点,下面我来 一 一总结:

共同点:

1.无论怎么样,都必须使用汇编语言来启动头文件。选择了启动方式之后如果不使用汇编语言来启动头文件,任你后面的代码再怎么写你也驱动不了开发板。驱动代码对于接下来的所有方法都是相同的!

2.编译程序的步骤都是大同小异的。第一步先把软件代码写好,第二步将.C(源文件).S(汇编文件)文件转换为.O(已编译不可执行)文件。第三步将所有的.O文件链接为elf格式的可执行文件。最后将.elf文件转换成.bin文件。这个.bin文件会和头文件一起被写入你所选择的启动方式里面去。我建议还可以在这里再加上一步,反汇编elf文件。为什么呢?因为反汇编最重要的就是可以看到你文件的开头文件,一定要是.S文件开头,只有汇编文件开头启动一些外设,其他文件才有写入的可能!

下面附上:个C语言代码源文件需要经过如图四个步骤,才能变成可以被计算机执行的文件。

3.Makefile。这个肯定是毋庸置疑很好用的make工具。使用它可以省去很多的操作步骤和少些很多的代码。而且如果需要修改一部分链接文件的代码,可以直接修改,然后编译。如果不使用,修改.C .S文件之后,又要重新走一遍编译程序的步骤,很繁琐不建议!而且最重要的一天,以后要学习的大头:系统移植和uboot都是要经常使用Makefile的!

CROSS_COMPILE ?= arm-linux-gnueabihf-NAME?= ledc//如果以后其他模块需要使用,只需要改名字就好了CC := $(CROSS_COMPILE)gccLD := $(CROSS_COMPILE)ldOBJCOPY := $(CROSS_COMPILE)objcopyOBJDUMP := $(CROSS_COMPILE)objdumpOBJS:= start.o main.o$(NAME).bin:$(OBJS)$(LD) -Timx6u.lds -o $(NAME).elf $^$(OBJCOPY) -O binary -S $(NAME).elf $@$(OBJDUMP) -D -m arm $(NAME).elf > $(NAME).dis%.o : %.c$(CC) -Wall -nostdlib -c -O2 -o $@ $<%.o : %.S$(CC) -Wall -nostdlib -c -O2 -o $@ $<clean:rm -rf *.o $(NAME).bin $(NAME).elf $(NAME).disdownload:./imxdownload $(NAME).bin /dev/sdb

4.链接脚本也是可以通用的。有了链接脚本我们就可以调控很多文件到我们指定的区域!我们是通过“-Ttext”来指定链接地址是 0X87800000 的,这样的话所有的文件都会链接到以0X87800000 为起始地址的区域。但是有时候我们很多文件需要链接到指定的区域,或者叫做段里面,比如在 Linux 里面初始化函数就会放到 init 段里面。因此我们需要能够自定义一些段,这些段的起始地址我们可以自由指定,同样的我们也可以指定一个文件或者函数应该存放到哪个段里面去。要完成这个功能我们就需要使用到链接脚本。

SECTIONS{. = 0x87800000; //先将指定链接区域选中为0x87800000 .:定位计数器.text : //设置.text段{start.o//start.o 里面包含着第一个要执行的指令,所以一定要链接到最开始的地方。*(.text) //剩余的所有.text文件 通配符*}.rodate ALIGN(4) : {*(.rodata*)} //设置.rodata.data ALIGN(4) : {*(.data)} //设置.data段,对“.data”这个段的起--//--始地址做字节对齐的, ALIGN(4)表示 4 字节对齐__bss_start=.; .bss ALIGN(4) : {*(.bss) *(COMMON)}__bss_end=.; } //.bss 段的起始地址和结束地址保存在“__bss_start”和“__bss_end”,.bss 段是定义了但是没有被初始化的变量

不同点:

1.纯汇编语言驱动代码是简洁一些,但是如果用它来来做一些复杂的控制,我认为局限性比较大,例如使用汇编语言来实现呼吸灯、流水灯,这些会很麻烦。

2.模仿STM32来驱动是很大不同的,我们需要将结构体抽象为外设,获得外设寄存器的基地址。添加寄存器结构体(在结构体中添加寄存器的时候一定要注意地址的连续性,如果不连续的话要添加占位。)由于编写寄存器结构体代码实在过于枯燥和繁琐,我只展示了一部分,剩下的按照方法来就行。

/***************************************************************Copyright © godfatherlzq文件名: imx6ul.h作者 : godfatherlzq版本 : V1.0描述 : IMX6UL相关寄存器定义,参考STM32寄存器定义方法其他 : 无日志 : 初版V1.0 .4.22 李柱奇创建**************************************************************//* * 外设寄存器组的基地址 */#define CCM_BASE(0X020C4000)#define CCM_ANALOG_BASE(0X020C8000)#define IOMUX_SW_MUX_BASE(0X020E0044)#define IOMUX_SW_PAD_BASE(0X020E0204)#define GPIO1_BASE (0x0209C000)#define GPIO2_BASE (0x020A0000)#define GPIO3_BASE (0x020A4000)#define GPIO4_BASE (0x020A8000)#define GPIO5_BASE (0x020AC000)/* * CCM寄存器结构体定义,分为CCM和CCM_ANALOG */typedef struct {volatile unsigned int CCR;volatile unsigned int CCDR;volatile unsigned int CSR;volatile unsigned int CCSR;volatile unsigned int CACRR;volatile unsigned int CBCDR;volatile unsigned int CBCMR;volatile unsigned int CSCMR1;volatile unsigned int CSCMR2;volatile unsigned int CSCDR1;volatile unsigned int CS1CDR;volatile unsigned int CS2CDR;volatile unsigned int CDCDR;volatile unsigned int CHSCCDR;volatile unsigned int CSCDR2;volatile unsigned int CSCDR3;volatile unsigned int RESERVED_1[2];volatile unsigned int CDHIPR; volatile unsigned int RESERVED_2[2];volatile unsigned int CLPCR;volatile unsigned int CISR;volatile unsigned int CIMR;volatile unsigned int CCOSR;volatile unsigned int CGPR;volatile unsigned int CCGR0;volatile unsigned int CCGR1;volatile unsigned int CCGR2;volatile unsigned int CCGR3;volatile unsigned int CCGR4;volatile unsigned int CCGR5;volatile unsigned int CCGR6;volatile unsigned int RESERVED_3[1];volatile unsigned int CMEOR;} CCM_Type;

只要将这个配置的头文件配置好之后,剩下的我们就可以模仿STM32调用底层寄存器的方法来编写驱动代码啦。熟悉的感觉又回来了哈哈哈!

#include "imx6u.h"/** @description: 使能I.MX6U所有外设时钟* @param : 无* @return : 无*/void clk_enable(void){CCM->CCGR0 = 0XFFFFFFFF;CCM->CCGR1 = 0XFFFFFFFF;CCM->CCGR2 = 0XFFFFFFFF;CCM->CCGR3 = 0XFFFFFFFF;CCM->CCGR4 = 0XFFFFFFFF;CCM->CCGR5 = 0XFFFFFFFF;CCM->CCGR6 = 0XFFFFFFFF;}/** @description: 初始化LED对应的GPIO* @param : 无* @return : 无*/void led_init(void){/* 1、初始化IO复用 */IOMUX_SW_MUX->GPIO1_IO03 = 0X5;/* 复用为GPIO1_IO03 *//* 2、配置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 低转换率*/IOMUX_SW_PAD->GPIO1_IO03 = 0X10B0;/* 3、初始化GPIO */GPIO1->GDIR = 0X0000008;/* GPIO1_IO03设置为输出 *//* 4、设置GPIO1_IO03输出低电平,打开LED0 */GPIO1->DR &= ~(1 << 3);}/** @description: 打开LED灯* @param : 无* @return : 无*/void led_on(void){/* 将GPIO1_DR的bit3清零 */GPIO1->DR &= ~(1<<3); }/** @description: 关闭LED灯* @param : 无* @return : 无*/void led_off(void){/* 将GPIO1_DR的bit3置1 */GPIO1->DR |= (1<<3); }

3.通过移植NXP的官方SDK包来写驱动代码。上面自己来编写寄存器结构体确实过于枯燥,在STM32中TI公司编写了这部分代码,那在我们的I.MX6U系列芯片里面有吗?当然是有的,就是官方的SDK包。只需要在官网下载完毕后通过FZ软件传给Ubuntu,装进去就可以使用了!但是因为我们在SDK包里会用到很多数据类型,我们就需要自己来设置一个头文件来定义一些常用的数据类型。

#ifndef __CC_H#define __CC_H#define __Ivolatile#define __Ovolatile#define __IO volatiletypedef signed char int8_t;typedef signed short int16_t; typedef signed int int32_t;typedef unsigned char uint8_t;typedef unsigned shortuint16_t; typedef unsigned int uint32_t;typedef unsigned long longuint64_t; typedef signed char s8;typedef signed short s16; typedef signed int s32;typedef signed long long s64;typedef unsigned char u8;typedef unsigned shortu16; typedef unsigned int u32;typedef unsigned long longu64;#endif

这部分和STM32中我们熟知的u8也差不多。有了配置好的SDK包编写代码会比以前的更简单

IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10b0);

通过两个函数就可以解决所有配置的问题,很方便!

全文总结:

四种驱动方式,各有各的好处,我觉得应该都会一点。了解他们的优缺点,已便将来逻辑开发时能够快速的选择最好的驱动方法!总结一遍下来,感觉我对基础驱动的理解又深刻了一分,加油!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。