Linux之ARM(MX6U)裸机模仿 STM32 驱动开发格式实验 --驱动编写、编译

Linux之ARM(MX6U)裸机模仿 STM32 驱动开发格式实验 --驱动编写、编译

一、模仿 STM32 寄存器定义

①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”的定义:

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 上。

二、I.MX6U 寄存器定义

参考 STM32 的官方文件来编写 I.MX6U 的寄存器定义,比如 IO 复用寄存器组 “IOMUX_SW_MUX_CTL_PAD_XX”,步骤如下:

①、编写外设结构体

先将同属于一个外设的所有寄存器编写到一个结构体里面,如 IO 复用寄存器组的结构体 如下:

/*    * IOMUX 寄存器组   */ 
  typedef struct  2   { 
      volatile unsigned int BOOT_MODE0; 
      volatile unsigned int BOOT_MODE1; 
      volatile unsigned int SNVS_TAMPER0; 
      volatile unsigned int SNVS_TAMPER1; 
   ……….......
      volatile unsigned int CSI_DATA00; 
      volatile unsigned int CSI_DATA01; 
      volatile unsigned int CSI_DATA02; 
      volatile unsigned int CSI_DATA03;
      volatile unsigned int CSI_DATA04; 
      volatile unsigned int CSI_DATA05; 
      volatile unsigned int CSI_DATA06; 
      volatile unsigned int CSI_DATA07; 
      /* 为了缩短代码,其余 IO 复用寄存器省略 */ 
      }IOMUX_SW_MUX_Tpye;

上述结构体 IOMUX_SW_MUX_Type 就是 IO 复用寄存器组,成员变量是每个 IO 对应的复 用寄存器,每个寄存器的地址是 32 位,每个成员都使用“volatile”进行了修饰,目的是防止编译器优化。

②、定义 IO 复用寄存器组的基地址

根据结构体 IOMUX_SW_MUX_Type 的定义,其第一个成员变量为 BOOT_MODE0,也就 是 BOOT_MODE0 这个 IO 的 IO 复用寄存器,查找 I.MX6U 的参考手册可以得知其地址为 0X020E0014,所以 IO 复用寄存器组的基地址就是 0X020E0014,定义如下:

 #define IOMUX_SW_MUX_BASE   (0X020E0014) 

③、定义访问指针

访问指针定义如下:

#define IOMUX_SW_MUX  ((IOMUX_SW_MUX_Type *)IOMUX_SW_MUX_BASE) 

通过上面三步我们就可以通过“IOMUX_SW_MUX->GPIO1_IO03”来访问 GPIO1_IO03 的 IO 复用寄存器了。同样的,其他的外设寄存器都可以通过这三步来定义。

三、硬件原理分析

Linux之ARM(MX6U)裸机模仿 STM32 驱动开发格式实验 --驱动编写、编译_第1张图片

四、实验程序编写

创建 VSCode 工程,工作区名字为“ledc_stm32”,新建三个文件:start.S、main.c 和 imx6ul.h。 其中 start.S 是汇编文件,s,直接复制过来就可以。main.c 和 imx6ul.h 是 C 文件。
文件 imx6ul.h 用来存放外设寄存器定义

①、imx6ul.h文件

#define CCM_BASE      (0x020c4000)   /*CCM外设基地址*/ 
#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  外设*/
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;


typedef struct 
{
	volatile unsigned int PLL_ARM;
	volatile unsigned int PLL_ARM_SET;
	volatile unsigned int PLL_ARM_CLR;
	volatile unsigned int PLL_ARM_TOG;
	volatile unsigned int PLL_USB1;
	volatile unsigned int PLL_USB1_SET;
	volatile unsigned int PLL_USB1_CLR;
	volatile unsigned int PLL_USB1_TOG;
	volatile unsigned int PLL_USB2;
	volatile unsigned int PLL_USB2_SET;
	volatile unsigned int PLL_USB2_CLR;
	volatile unsigned int PLL_USB2_TOG;
	volatile unsigned int PLL_SYS;
	volatile unsigned int PLL_SYS_SET;
	volatile unsigned int PLL_SYS_CLR;
	volatile unsigned int PLL_SYS_TOG;
	volatile unsigned int PLL_SYS_SS;
	volatile unsigned int RESERVED_1[3];
	volatile unsigned int PLL_SYS_NUM;
	volatile unsigned int RESERVED_2[3];
	volatile unsigned int PLL_SYS_DENOM; 
	volatile unsigned int RESERVED_3[3];
	volatile unsigned int PLL_AUDIO;
	volatile unsigned int PLL_AUDIO_SET;
	volatile unsigned int PLL_AUDIO_CLR;
	volatile unsigned int PLL_AUDIO_TOG;
	volatile unsigned int PLL_AUDIO_DENOM;
	volatile unsigned int RESERVED_4[3];
	volatile unsigned int PLL_VIDEO;
	volatile unsigned int PLL_VIDEO_SET;
	volatile unsigned int PLL_VIDEO_CLR;
	volatile unsigned int PLL_VIDEO_TOG;
	volatile unsigned int PLL_VIDEO_NUM;
	volatile unsigned int RESERVED_5[3];
	volatile unsigned int PLL_VIDEO_DENOM;
	volatile unsigned int RESERVED_6[7];
	volatile unsigned int PLL_ENET;
	volatile unsigned int PLL_ENET_SET;
	volatile unsigned int PLL_ENET_CLR;
	volatile unsigned int PLL_ENET_TOG;
	volatile unsigned int PFD_480;
	volatile unsigned int PFD_480_SET;
	volatile unsigned int PFD_480_CLR;
	volatile unsigned int PFD_480_TOG;
	volatile unsigned int PFD_528;
	volatile unsigned int PFD_528_SET;
	volatile unsigned int PFD_528_CLR;
	volatile unsigned int PFD_528_TOG;
	volatile unsigned int RESERVED_7[16];
	volatile unsigned int MISC0;
	volatile unsigned int MISC0_SET;
	volatile unsigned int MISC0_CLR;
	volatile unsigned int MISC0_TOG;
	volatile unsigned int MISC1;
	volatile unsigned int MISC1_SET;
	volatile unsigned int MISC1_CLR;
	volatile unsigned int MISC1_TOG;
	volatile unsigned int MISC2;
	volatile unsigned int MISC2_SET;
	volatile unsigned int MISC2_CLR;
	volatile unsigned int MISC2_TOG;
} CCM_ANALOG_Type; 

/* 
 * IOMUX结构体 
 */
typedef struct 
{
	volatile unsigned int JTAG_MOD;
	volatile unsigned int JTAG_TMS;
	volatile unsigned int JTAG_TDO;
	volatile unsigned int JTAG_TDI;
	volatile unsigned int JTAG_TCK;
	volatile unsigned int JTAG_TRST_B;
	volatile unsigned int GPIO1_IO00;
	volatile unsigned int GPIO1_IO01;
	volatile unsigned int GPIO1_IO02;
	volatile unsigned int GPIO1_IO03;
	volatile unsigned int GPIO1_IO04;
	volatile unsigned int GPIO1_IO05;
	volatile unsigned int GPIO1_IO06;
	volatile unsigned int GPIO1_IO07;
	volatile unsigned int GPIO1_IO08;
	volatile unsigned int GPIO1_IO09;
	volatile unsigned int UART1_TX_DATA;
	volatile unsigned int UART1_RX_DATA;
	volatile unsigned int UART1_CTS_B;
	volatile unsigned int UART1_RTS_B;
	volatile unsigned int UART2_TX_DATA;
	volatile unsigned int UART2_RX_DATA;
	volatile unsigned int UART2_CTS_B;
	volatile unsigned int UART2_RTS_B;
	volatile unsigned int UART3_TX_DATA;
	volatile unsigned int UART3_RX_DATA;
	volatile unsigned int UART3_CTS_B;
	volatile unsigned int UART3_RTS_B;
	volatile unsigned int UART4_TX_DATA;
	volatile unsigned int UART4_RX_DATA;
	volatile unsigned int UART5_TX_DATA;
	volatile unsigned int UART5_RX_DATA;
	volatile unsigned int ENET1_RX_DATA0;
	volatile unsigned int ENET1_RX_DATA1;
	volatile unsigned int ENET1_RX_EN;
	volatile unsigned int ENET1_TX_DATA0;
	volatile unsigned int ENET1_TX_DATA1;
	volatile unsigned int ENET1_TX_EN;
	volatile unsigned int ENET1_TX_CLK;
	volatile unsigned int ENET1_RX_ER;
	volatile unsigned int ENET2_RX_DATA0;
	volatile unsigned int ENET2_RX_DATA1;
	volatile unsigned int ENET2_RX_EN;
	volatile unsigned int ENET2_TX_DATA0;
	volatile unsigned int ENET2_TX_DATA1;
	volatile unsigned int ENET2_TX_EN;
	volatile unsigned int ENET2_TX_CLK;
	volatile unsigned int ENET2_RX_ER;
	volatile unsigned int LCD_CLK;
	volatile unsigned int LCD_ENABLE;
	volatile unsigned int LCD_HSYNC;
	volatile unsigned int LCD_VSYNC;
	volatile unsigned int LCD_RESET;
	volatile unsigned int LCD_DATA00;
	volatile unsigned int LCD_DATA01;
	volatile unsigned int LCD_DATA02;
	volatile unsigned int LCD_DATA03;
	volatile unsigned int LCD_DATA04;
	volatile unsigned int LCD_DATA05;
	volatile unsigned int LCD_DATA06;
	volatile unsigned int LCD_DATA07;
	volatile unsigned int LCD_DATA08;
	volatile unsigned int LCD_DATA09;
	volatile unsigned int LCD_DATA10;
	volatile unsigned int LCD_DATA11;
	volatile unsigned int LCD_DATA12;
	volatile unsigned int LCD_DATA13;
	volatile unsigned int LCD_DATA14;
	volatile unsigned int LCD_DATA15;
	volatile unsigned int LCD_DATA16;
	volatile unsigned int LCD_DATA17;
	volatile unsigned int LCD_DATA18;
	volatile unsigned int LCD_DATA19;
	volatile unsigned int LCD_DATA20;
	volatile unsigned int LCD_DATA21;
	volatile unsigned int LCD_DATA22;
	volatile unsigned int LCD_DATA23;
	volatile unsigned int NAND_RE_B;
	volatile unsigned int NAND_WE_B;
	volatile unsigned int NAND_DATA00;
	volatile unsigned int NAND_DATA01;
	volatile unsigned int NAND_DATA02;
	volatile unsigned int NAND_DATA03;
	volatile unsigned int NAND_DATA04;
	volatile unsigned int NAND_DATA05;
	volatile unsigned int NAND_DATA06;
	volatile unsigned int NAND_DATA07;
	volatile unsigned int NAND_ALE;
	volatile unsigned int NAND_WP_B;
	volatile unsigned int NAND_READY_B;
	volatile unsigned int NAND_CE0_B;
	volatile unsigned int NAND_CE1_B;
	volatile unsigned int NAND_CLE;
	volatile unsigned int NAND_DQS;
	volatile unsigned int SD1_CMD;
	volatile unsigned int SD1_CLK;
	volatile unsigned int SD1_DATA0;
	volatile unsigned int SD1_DATA1;
	volatile unsigned int SD1_DATA2;
	volatile unsigned int SD1_DATA3;
	volatile unsigned int CSI_MCLK;
	volatile unsigned int CSI_PIXCLK;
	volatile unsigned int CSI_VSYNC;
	volatile unsigned int CSI_HSYNC;
	volatile unsigned int CSI_DATA00;
	volatile unsigned int CSI_DATA01;
	volatile unsigned int CSI_DATA02;
	volatile unsigned int CSI_DATA03;
	volatile unsigned int CSI_DATA04;
	volatile unsigned int CSI_DATA05;
	volatile unsigned int CSI_DATA06;
	volatile unsigned int CSI_DATA07;
}IOMUX_SW_MUX_Type;

typedef struct 
{
	volatile unsigned int DRAM_ADDR00;
	volatile unsigned int DRAM_ADDR01;
	volatile unsigned int DRAM_ADDR02;
	volatile unsigned int DRAM_ADDR03;
	volatile unsigned int DRAM_ADDR04;
	volatile unsigned int DRAM_ADDR05;
	volatile unsigned int DRAM_ADDR06;
	volatile unsigned int DRAM_ADDR07;
	volatile unsigned int DRAM_ADDR08;
	volatile unsigned int DRAM_ADDR09;
	volatile unsigned int DRAM_ADDR10;
	volatile unsigned int DRAM_ADDR11;
	volatile unsigned int DRAM_ADDR12;
	volatile unsigned int DRAM_ADDR13;
	volatile unsigned int DRAM_ADDR14;
	volatile unsigned int DRAM_ADDR15;
	volatile unsigned int DRAM_DQM0;
	volatile unsigned int DRAM_DQM1;
	volatile unsigned int DRAM_RAS_B;
	volatile unsigned int DRAM_CAS_B;
	volatile unsigned int DRAM_CS0_B;
	volatile unsigned int DRAM_CS1_B;
	volatile unsigned int DRAM_SDWE_B;
	volatile unsigned int DRAM_ODT0;
	volatile unsigned int DRAM_ODT1;
	volatile unsigned int DRAM_SDBA0;
	volatile unsigned int DRAM_SDBA1;
	volatile unsigned int DRAM_SDBA2;
	volatile unsigned int DRAM_SDCKE0;
	volatile unsigned int DRAM_SDCKE1;
	volatile unsigned int DRAM_SDCLK0_P;
	volatile unsigned int DRAM_SDQS0_P;
	volatile unsigned int DRAM_SDQS1_P;
	volatile unsigned int DRAM_RESET;
	volatile unsigned int TEST_MODE;
	volatile unsigned int POR_B;
	volatile unsigned int ONOFF;
	volatile unsigned int SNVS_PMIC_ON_REQ;
	volatile unsigned int CCM_PMIC_STBY_REQ;
	volatile unsigned int BOOT_MODE0;
	volatile unsigned int BOOT_MODE1;
	volatile unsigned int SNVS_TAMPER0;
	volatile unsigned int SNVS_TAMPER1;
	volatile unsigned int SNVS_TAMPER2;
	volatile unsigned int SNVS_TAMPER3;
	volatile unsigned int SNVS_TAMPER4;
	volatile unsigned int SNVS_TAMPER5;
	volatile unsigned int SNVS_TAMPER6;
	volatile unsigned int SNVS_TAMPER7;
	volatile unsigned int SNVS_TAMPER8;
	volatile unsigned int SNVS_TAMPER9;
	volatile unsigned int JTAG_MOD;
	volatile unsigned int JTAG_TMS;
	volatile unsigned int JTAG_TDO;
	volatile unsigned int JTAG_TDI;
	volatile unsigned int JTAG_TCK;
	volatile unsigned int JTAG_TRST_B;
	volatile unsigned int GPIO1_IO00;
	volatile unsigned int GPIO1_IO01;
	volatile unsigned int GPIO1_IO02;
	volatile unsigned int GPIO1_IO03;
	volatile unsigned int GPIO1_IO04;
	volatile unsigned int GPIO1_IO05;
	volatile unsigned int GPIO1_IO06;
	volatile unsigned int GPIO1_IO07;
	volatile unsigned int GPIO1_IO08;
	volatile unsigned int GPIO1_IO09;
	volatile unsigned int UART1_TX_DATA;
	volatile unsigned int UART1_RX_DATA;
	volatile unsigned int UART1_CTS_B;
	volatile unsigned int UART1_RTS_B;
	volatile unsigned int UART2_TX_DATA;
	volatile unsigned int UART2_RX_DATA;
	volatile unsigned int UART2_CTS_B;
	volatile unsigned int UART2_RTS_B;
	volatile unsigned int UART3_TX_DATA;
	volatile unsigned int UART3_RX_DATA;
	volatile unsigned int UART3_CTS_B;
	volatile unsigned int UART3_RTS_B;
	volatile unsigned int UART4_TX_DATA;
	volatile unsigned int UART4_RX_DATA;
	volatile unsigned int UART5_TX_DATA;
	volatile unsigned int UART5_RX_DATA;
	volatile unsigned int ENET1_RX_DATA0;
	volatile unsigned int ENET1_RX_DATA1;
	volatile unsigned int ENET1_RX_EN;
	volatile unsigned int ENET1_TX_DATA0;
	volatile unsigned int ENET1_TX_DATA1;
	volatile unsigned int ENET1_TX_EN;
	volatile unsigned int ENET1_TX_CLK;
	volatile unsigned int ENET1_RX_ER;
	volatile unsigned int ENET2_RX_DATA0;
	volatile unsigned int ENET2_RX_DATA1;
	volatile unsigned int ENET2_RX_EN;
	volatile unsigned int ENET2_TX_DATA0;
	volatile unsigned int ENET2_TX_DATA1;
	volatile unsigned int ENET2_TX_EN;
	volatile unsigned int ENET2_TX_CLK;
	volatile unsigned int ENET2_RX_ER;
	volatile unsigned int LCD_CLK;
	volatile unsigned int LCD_ENABLE;
	volatile unsigned int LCD_HSYNC;
	volatile unsigned int LCD_VSYNC;
	volatile unsigned int LCD_RESET;
	volatile unsigned int LCD_DATA00;
	volatile unsigned int LCD_DATA01;
	volatile unsigned int LCD_DATA02;
	volatile unsigned int LCD_DATA03;
	volatile unsigned int LCD_DATA04;
	volatile unsigned int LCD_DATA05;
	volatile unsigned int LCD_DATA06;
	volatile unsigned int LCD_DATA07;
	volatile unsigned int LCD_DATA08;
	volatile unsigned int LCD_DATA09;
	volatile unsigned int LCD_DATA10;
	volatile unsigned int LCD_DATA11;
	volatile unsigned int LCD_DATA12;
	volatile unsigned int LCD_DATA13;
	volatile unsigned int LCD_DATA14;
	volatile unsigned int LCD_DATA15;
	volatile unsigned int LCD_DATA16;
	volatile unsigned int LCD_DATA17;
	volatile unsigned int LCD_DATA18;
	volatile unsigned int LCD_DATA19;
	volatile unsigned int LCD_DATA20;
	volatile unsigned int LCD_DATA21;
	volatile unsigned int LCD_DATA22;
	volatile unsigned int LCD_DATA23;
	volatile unsigned int NAND_RE_B;
	volatile unsigned int NAND_WE_B;
	volatile unsigned int NAND_DATA00;
	volatile unsigned int NAND_DATA01;
	volatile unsigned int NAND_DATA02;
	volatile unsigned int NAND_DATA03;
	volatile unsigned int NAND_DATA04;
	volatile unsigned int NAND_DATA05;
	volatile unsigned int NAND_DATA06;
	volatile unsigned int NAND_DATA07;
	volatile unsigned int NAND_ALE;
	volatile unsigned int NAND_WP_B;
	volatile unsigned int NAND_READY_B;
	volatile unsigned int NAND_CE0_B;
	volatile unsigned int NAND_CE1_B;
	volatile unsigned int NAND_CLE;
	volatile unsigned int NAND_DQS;
	volatile unsigned int SD1_CMD;
	volatile unsigned int SD1_CLK;
	volatile unsigned int SD1_DATA0;
	volatile unsigned int SD1_DATA1;
	volatile unsigned int SD1_DATA2;
	volatile unsigned int SD1_DATA3;
	volatile unsigned int CSI_MCLK;
	volatile unsigned int CSI_PIXCLK;
	volatile unsigned int CSI_VSYNC;
	volatile unsigned int CSI_HSYNC;
	volatile unsigned int CSI_DATA00;
	volatile unsigned int CSI_DATA01;
	volatile unsigned int CSI_DATA02;
	volatile unsigned int CSI_DATA03;
	volatile unsigned int CSI_DATA04;
	volatile unsigned int CSI_DATA05;
	volatile unsigned int CSI_DATA06;
	volatile unsigned int CSI_DATA07;
	volatile unsigned int GRP_ADDDS;
	volatile unsigned int GRP_DDRMODE_CTL;
	volatile unsigned int GRP_B0DS;
	volatile unsigned int GRP_DDRPK;
	volatile unsigned int GRP_CTLDS;
	volatile unsigned int GRP_B1DS;
	volatile unsigned int GRP_DDRHYS;
	volatile unsigned int GRP_DDRPKE;
	volatile unsigned int GRP_DDRMODE;
	volatile unsigned int GRP_DDR_TYPE;
}IOMUX_SW_PAD_Type;

/* 
 * GPIO结构体 
 */
typedef struct 
{
	volatile unsigned int DR;							
	volatile unsigned int GDIR; 							
	volatile unsigned int PSR;								
	volatile unsigned int ICR1; 							
	volatile unsigned int ICR2; 							 
	volatile unsigned int IMR;								 
	volatile unsigned int ISR;			
	volatile unsigned int EDGE_SEL;  
}GPIO_Type;

#define CCM					((CCM_Type *)CCM_BASE)
#define CCM_ANALOG			((CCM_ANALOG_Type *)CCM_ANALOG_BASE)
#define IOMUX_SW_MUX		((IOMUX_SW_MUX_Type *)IOMUX_SW_MUX_BASE)
#define IOMUX_SW_PAD		((IOMUX_SW_PAD_Type *)IOMUX_SW_PAD_BASE)
#define GPIO1				((GPIO_Type *)GPIO1_BASE)
#define GPIO2				((GPIO_Type *)GPIO2_BASE)
#define GPIO3				((GPIO_Type *)GPIO3_BASE)
#define GPIO4				((GPIO_Type *)GPIO4_BASE)
#define GPIO5				((GPIO_Type *)GPIO5_BASE)

在编写寄存器组结构体的时候注意寄存器的地址是否连续,有些外设的寄存器地址可能不 是连续的,会有一些保留地址,因此我们需要在结构体中留出这些保留的寄存器。比如 CCM 的 CCGR6 寄存器地址为 0X020C4080,而寄存器 CMEOR 的地址为 0X020C4088。按照地址顺序 递增的原理,寄存器 CMEOR 的地址应该是 0X020C4084,但是实际上 CMEOR 的地址是 0X020C4088,相当于中间跳过了 0X020C4088-0X020C4080=8 个字节,如果寄存器地址连续的 话应该只差 4 个字节(32 位),但是现在差了 8 个字节,所以需要在寄存器 CCGR6 和 CMEOR 直接加入一个保留寄存器,第 47 行 RESERVED_3[1]的来源。 如果不添加保留为来占位的话就会导致寄存器地址错位!

②、main.c文件

#include "imx6ul.h"

/*使能 I.MX6U 所有外设时钟 */
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;
}

/* 初始化 LED 对应的 GPIO */

void led_init(void)
{
     /* 1、初始化 IO 复用, 复用为 GPIO1_IO03 */ 
     IOMUX_SW_PAD->GPIO1_IO03 =0x5;

      /* 2、配置 GPIO1_IO03 的 IO 属性 */
     IOMUX_SW_PAD->GPIO1_IO03 = 0x10b0;

      /* 3、初始化 GPIO, GPIO1_IO03 设置为输出 */ 
      GPIO1->GDIR = 0x0000008;

       /* 4、设置 GPIO1_IO03 输出低电平,打开 LED0 */ 
       GPIO1->DR = 0x0;


}

/* 打开 LED 灯 */
void led_on(void)
{ 
    /*将 GPIO1_DR 的 bit3 清零 */
    GPIO1->DR &= ~(1<<3);

}

void led_off(void)
{

   /* 将 GPIO1_DR 的 bit3 置 1 */
   GPIO1->DR |= (1<<3);

}

void delay_short(volatile unsigned int n)
{

    while (n--)
    {
        
    }
    
}

void delay(volatile unsigned int n)
{
    while(n--){

        delay_short(0x7ff);
    }
}



int main(void)
{
    clk_enable();     /* 使能所有的时钟     */ 
    led_init();        /* 初始化 led          */ 

    while (1)
    {
        led_off();    /* 关闭 LED            */ 
        delay(500);
 
        led_on();     /* 打开 LED            */ 
        delay(500);
    }
    
    return 0;
}

③、start.S文件

.global _start
.global _bss_start
_bss_start:
    .word  __bss_start

.global _bss_end
_bss_end:
    .word __bss_end

_start:

/* 进入 SVC 模式 */

    mrs r0, cpsr
    bic r0, r0, #0x1f      /* 将 r0 的低 5 位清零,也就是 cpsr 的 M0~M4    */ 
    orr r0, r0, #0x13       /* r0 或上 0x13,表示使用 SVC 模式             */ 
    msr cpsr, r0              /* 将 r0 的数据写入到 cpsr_c 中                 */ 
    
    /*qingchu BBC duan */
    ldr r0, _bss_start
    ldr r1, _bss_end
    mov r2, #0
bss_loop:
    stmia r0!, {r2}
    cmp r0, r1     /*比较r0和r1的大小*/
    ble bss_loop 

    ldr sp, =0x80200000      /* 设置栈指针             */ 
    b main                   /* 跳转到 main 函数       */ 

五、编译下载验证

①、 编写链接脚本 (imx6ul.lds)

SECTIONS {
     . = 0x87800000;
     .text :
     {
        start.o
        *(.text)
         
     }
     .rodata ALIGN(4) : {*(.rodata)}
     .data ALIGN(4) :{*(.data)}
     __bss_start=.;
     .bss ALIGN(4) : {*(.bss) *(COMMON)}
     __bss_end=.;
     
}

②、编写 Makefile

objs 	:=start.o main.o 
ld   	:=arm-linux-gnueabihf-ld
gcc  	:=arm-linux-gnueabihf-gcc
objcopy :=arm-linux-gnueabihf-objcopy
objdump :=arm-linux-gnueabihf-objdump

ledc.bin : $(objs)
	$(ld) -Timx6ul.lds -o ledc.elf  $^
	$(objcopy) -O binary -S ledc.elf $@
	$(objdump) -D -m arm ledc.elf > ledc.dis

%.o : %.c
	$(gcc) -Wall -nostdlib -c -O2 -o $@ $<

%.o : %.S
	$(gcc) -Wall -nostdlib -c -O2 -o $@ $<

clean:
	rm -rf *.o ledc.bin ledc.dis ledc.elf

③、编译下载

使用 Make 命令编译代码,编译成功以后使用软件 imxdownload 将编译完成的 ledc.bin 文 件下载到 SD 卡中,命令如下

chmod 777 imxdownload   //给予 imxdownload 可执行权限,一次即可
 ./imxdownload ledc.bin /dev/sdd  //烧写到 SD 卡中 

烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板,如果代码运行正常的 话 LED0 就会以 500ms 的时间间隔亮灭,
具体的操作烧写SD卡上请看bin文件烧写到SD卡并运行

你可能感兴趣的:(IMX6ULL)