1)实验平台:正点原子Linux开发板
2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》
关注官方微信号公众号,获取更多资料:正点原子
![51ca0c64deff49a4ee1851a268135f0e.png](https://i-blog.csdnimg.cn/blog_migrate/a9fe35ab1db1ec9e081eb100d443ea39.jpeg)
第十一章模仿STM32驱动开发格式实验
在上一章使用C语言编写LED灯驱动的时候,每个寄存器的地址我们都需要写宏定义,使用起来非常的不方便。我们在学习STM32的时候,可以使用“GPIOB->ODR”这种方式来给GPIOB的寄存器ODR赋值,因为在STM32中同属于一个外设的所有寄存器地址基本是相邻的(有些会有保留寄存器)。因此我们可以借助C语言里面的结构体成员地址递增的特点来将某个外设的所有寄存器写入到一个结构体里面,然后定义一个结构体指针指向这个外设的寄存器基地址,这样我们就可以通过这个结构体指针来访问这个外设的所有寄存器。同理,I.MX6U也可以使用这种方法来定义外设寄存器,本章我们就模仿STM32里面的寄存器定义方式来编写I.MX6U的驱动,通过本章的学习也可以对STM32的寄存器定义方式有一个深入的认识。
11.1模仿STM32寄存器定义
11.1.1 STM32寄存器定义简介
为了开发方便,ST官方为STM32F103编写了一个叫做stm32f10x.h的文件,在这个文件里面定义了STM32F103所有外设寄存器,我们可以使用其定义的寄存器来进行开发,比如我们可以用如下代码来初始化一个GPIO:
GPIOE->CRL&=0XFF0FFFFF;
GPIOE->CRL|=0X00300000; //PE5推挽输出
GPIOE->ODR|=1<<5; //PE5输出高
上述代码是初始化STM32的PE5这个GPIO为推挽输出,需要配置的就是GPIOE的寄存器CRL和ODR,“GPIOE”的定义:
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
可以看出“GPIOE”是个宏定义,是一个指向地址GPIOE_BASE的结构体指针,结构体为GPIO_TypeDef,GPIO_TypeDef和GPIOE_BASE的定义如下:
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define PERIPH_BASE ((uint32_t)0x40000000)
上述定义中GPIO_TypeDef是个结构体,结构体里面的成员变量有CRL、CRH、IDR、ODR、BSRR、BRR和LCKR,这些都是GPIO的寄存器,每个成员变量都是32位(4字节),这些寄存器在结构体中的位置都是按照其地址值从小到大排序的。GPIOE_BASE就是GPIOE的基地址,其为:
GPIOE_BASE=APB2PERIPH_BASE+0x1800
= PERIPH_BASE + 0x10000 + 0x1800
=0x40000000 + 0x10000 + 0x1800
=0x40011800
GPIOE_BASE的基地址为0x40011800,宏GPIOE指向这个地址,因此GPIOE的寄存器CRL的地址就是0X40011800,寄存器CRH的地址就是0X40011800+4=0X40011804,其他寄存器地址以此类推。我们要操作GPIOE的ODR寄存器的话就可以通过“GPIOE->ODR”来实现,这个方法是借助了结构体成员地址连续递增的原理。
了解了STM32的寄存器定义以后,我们就可以参考其原理来编写I.MX6U的外设寄存器定义了。NXP官方并没有为I.MX6UL编写类似stm32f10x.h这样的文件,NXP只为I.MX6ULL提供了类似stm32f10x.h这样的文件,名为MCIMX6Y2.h,但是I.MX6UL和I.MX6ULL几乎一模一样,所以文件MCIMX6Y2.h可以用在I.MX6UL上。关于文件MCIMX6Y2.h的移植我们在下一章讲解,本章我们参考stm32f10x.h来编写一个简单的MCIMX6Y2.h文件。
11.1.2 I.MX6U寄存器定义
参考STM32的官方文件来编写I.MX6U的寄存器定义,比如IO复用寄存器组“IOMUX_SW_MUX_CTL_PAD_XX”,步骤如下:
1、编写外设结构体
先将同属于一个外设的所有寄存器编写到一个结构体里面,如IO复用寄存器组的结构体如下:
示例代码11.1.2.1 寄存器IOMUX_SW_MUX_Type
/*
* IOMUX寄存器组
*/
1typedefstruct
2{
3 volatileunsignedint BOOT_MODE0;
4 volatileunsignedint BOOT_MODE1;
5 volatileunsignedint SNVS_TAMPER0;
6 volatileunsignedint SNVS_TAMPER1;