IMX6ULL裸机开发——点亮LED灯

一、汇编LED实验

1.GPIO详解

1.1 STM32 GPIO

STM32初始化GPIO有以下步骤

  1. 使能指定GPIO的时钟
  2. 初始化GPIO,比如输出功能、上拉、速度等等。
  3. IO复用
  4. 设置GPIO输出高电平和低电平

1.2 IO命名

打开IMUX6ULL参考手册的32章 IOMUX Controlled(IOMUXC)。

在IOMUXC Memory Map/Register Definition下,IOMUXC下,形如"IOMUXC_SW_MUC_CTL_PAD_GPIO1_IO00"就是GPIO命名。

1.3 IO复用配置

以GPIO01为例,查看PAD,寄存器32位,但只用到5位,其中bit0~bit3用来设置复用功能,GPIO01一共可以复用9种功能IO。

1.4 IO属性配置

GPIO有两个相关的寄存器:MUX和PAD。而MUX用来配置复用功能。

PAD也是32位寄存器,但是只用到17位。PAD主要是用来配置速度,驱动能力,压摆率等等。

1.5 GPIO配置

当IO用作GPIO时,需要设置的寄存器有8个。

DR、GDIR、PSR、ICR1、ICR2、EDGE_SEL、IMR和ISR。

DR 数据集寄存器

DR寄存器是32位,一个GPIO组最大有32给IO,故DR的每个位都对应一个IO。

若设置GPIO1_IO00输出高电平,那么设置GPIO1.DR=1。

GDIR 方向寄存器

用来设置GPIO的工作方式,输入/输出。

例如,要设置GPIO1_IO00为输入,则GPIO1.GDIR=0。

PSR 状态寄存器

ICR 中断控制寄存器

IMR 中断屏蔽寄存器

ISR 中断状态寄存器

1.6 GPIO时钟使能

参考 Clock Controller Module(CCM)

只关注外设时钟使能寄存器,CCGR。

CCGR0~CCGR6这7个寄存器,控制着IMUX6U的所有外设时钟开关。

CCM_CCGR0也是32位寄存器,每2位控制一个外设的时钟。例如,bit31:30控制GPIO2的外设时钟。

2.小节

IMU6U的IO作为GPIO使用,需要以下几步

  1. 使能GPIO对应的时钟。
  2. 设置寄存器MUX_PAD,设置IO复用功能,使其复用成GPIO功能。
  3. 设置寄存器PAD_PAD,设置IO的上下拉、速度等等。
  4. 设置GPIO的8个寄存器,例如设置输入/输出,中断等。

3.程序编写

1、使能外设时钟

查看芯片手册CCM_CCGR0,address为20C_4068h

则要对地址0x020c4068写入数据0xffffffff,使能所有外设时钟。

而CCGR也是32位寄存器,也就是4字节,故相邻寄存器间的偏移量位0x04(地址编排的单位是字节)。

那么CCGR1的地址为0x020C406C,然后写入数据0xffffffff,使能所有外设时钟。同理其他的CCGR。

2、IO复用成GPIO

查看芯片手册IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03

address为20E_0068h

ALT5:复用成GPIO1,0101

故对0x020e0068写入0x5即可。

3、配置IO的电气属性

查看芯片手册IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03

address为20E_02F4h

对IO做以下配置:

bit0: 0 低速。

bit5:3 110 R0/6驱动能力,R0为260欧姆电阻。

bit7:6 10 100MHz速度

bit11: 0 关闭开路输出

bit12: 1 使能pull/kepper

bit13: 0 kepper

bit15:14 00 100K下拉

bit16: 0 关闭hys

也就是:0 00 0 1 0 000 10 110 00 0

换算成16进制:0x10B0

将0x10B0写入0x020e02f4。

4、设置GPIO的寄存器

查看参考手册中GPIO Memory Map/Register

GPIO1_DR的地址为:209_C000

打开LED,只要让DR的值为0即可,即对0x0209c000写入0.

GPIO1_GDIR的地址为:基地址+4h,即209_C004

设置GPIO1_IO03为输出,也就是GDIR的3bit设置为1,即0x8。

对0x0209c0000写入0x8。

二、C语言LED实验

1.汇编搭建C环境

1.1 设置处理器模式

CPSR状态寄存器的M[4:0]后5位用来设置处理器模式,先将这5位置0,再与0x13求或,此时为SVC模式。

1.2 设置栈地址

开发板的DDR3的地址范围为:0X80000000~0X90000000(256MB)

0x100000000也就是231b=211Mb=2^8MB=256MB

栈的大小为2MB,也就是栈地址0x80200000。

然后设置跳转到main函数。

2.C语言编写

2.1 main.h

首先的宏定义:

ifndef __MAIN_H

define __MAIN_H

用来保护重复定义。

地址的定义类型:volatile unsigned int *

定义CCM相关寄存器地址

定义IOMUX相关寄存器地址

定义GPIO1相关寄存器地址

2.2 main.c

定义函数clk_enable

使能所有的时钟

将main.h中定义好的CCM_CCGR0~6,全部赋值为0xffffffff.

定义函数led_init

初始化IO复用,即MUX=0x5

设置IO电气属性,即PAD=0x10B0

初始化GPIO为输出模式,GDIR=0X8

设置GPIO的输出为低电平,DR=0x0

设置闪烁灯

函数led_on,DR的bit3清0

DR &= ~(1<<3)

1<<3也就是1000,然后取反0111,再求与,其他位与1求与不变。

函数led_off,DR的bit3置1

DR |=(1<<3)

函数delay_short和delay用来设置延时大小。

主函数

  1. 使能时钟
  2. 初始化led
  3. 死循环中,关led,延时,开led,延时

三、驱动开发格式

1.编写结构体

将同属于一个外设的所有寄存器编写到一个结构体中,

2.定义寄存器组的基地址

寻找第一个成员变量的地址,结构体会以4字节的大小顺序寻址,从而间接的定义了结构体所有的成员变量的地址。

案例 imx6ul.h

//外设寄存器组的基地址
#define CCM_BASE	(0x020c4000)
#define GPIO1_BASE	(0X0209C000)


//CCM 寄存器结构体定义
typedef struct
{	
    volatile unsigned int CCR;	//第一个成员变量
    ...
	volatile unsigned int CCGR0;
	...
	volatile unsigned int CCGR6;
} CCM_Type;

//IOMUX 寄存器组
typedef struct
{
	volatile unsigned int BOOT_MODE0;
    ...;
  	volatile unsigned int CSI_DATA07;
} IOMUX_SW_MUX_Type;

typedef struct
{
    volatile unsigned int DRAM_ADDR00;
    ...;
    volatile unsigned int GRP_DDR_TYPE;
} IOMUX_SW_PAD_Type;

//GPIO 寄存器结构体
typedef struct{
    volatile unsigned int DR;
    ...;
    volatile unsigned int EDGE_SEL;
} GPIO_Type;

//外设指针
#define CCM		((CCM_Type *)CCM_BASE)
#define IOMUX_SW_MUX	((IOMUX_SW_Type *)IOMUX_SW_MUX_BASE)
#define IOMUX_SW_PAD	((IOMUX_SW_Type *)IOMUX_SW_PAD_BASE)
#define GPIO1	((GPIO_Type *)GPIO1_BASE)
...
    

在编写寄存器组的结构体的时候注意寄存器的地址是否连续,即有一些保留地址。

于是要写:volatile unsigned int RESERVED_3[1]

3.主函数

#include "imu6ul.h"

//使能所有时钟
void clk_enable(void){
    CCM->CCGR0 = 0XFFFFFFFF;
    CCM->CCGR1 = 0XFFFFFFFF;
    ...;
}


//初始化LED对应的GPIO
void led_init(void){
    //初始化IO复用
    IOMUX_SW_MUX->GPIO1_IO03 = 0X5;
    
    //配置IO电气属性
    IOMUX_SW_PAD->GPIO1_IO03 = 0X10B0;
    
    //初始化GPIO
    GPIO1->GDIR = 0X8;	//输出模式
    GPIO1->DR &= ~(1<<3);	//设置输出位低电平
    
}

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

//关闭LED灯
void led_off(void){
    //将DR的bit3置1
    GPIO1->DR |=(1<<3);
}

//短时间延时函数
void delay_short(volatile unsigned n){
    while(n--){}
}

//延时函数
void delay(volatile unsigned n){
    while(n--){
        delay_short(0x7ff);	//大约1ms
    }
}

//main函数
int main(void){
    clk_enable();	//使能时钟
    led_init();		//初始化LED
    
    while(1){
        led_off();
        delay(500);
        
        led_on();
        delay(500);
    }
    return 0;
}


四、官方SDK

1.SDK包

与寄存器定义相关的文件:

fsl_common.h

fsl_iomuxc.h

MCIMX6Y2.h

2.创建 cc.h 文件

cc.h文件存放一些SDK库文件需要的数据类型

#ifndef __CC_H
#define __CC_H

#define	__I		volatile
#define __O		volatile
#define	__IO	volatile

#define ON		1
#define OFF		0

typedef signed char			int8_t;
typedef signed short int	int16_t;
...;

#endif

fsl_iomuxc.h

static inline void IOMUXC_SetPinMux(uint32_t muxRegister,
                                    uint32_t muxMode,
                                    uint32_t inputRegister,
                                    uint32_t inputDaisy,
                                    uint32_t configRegister,
                                    uint32_t inputOnfield)
    
static inline void IOMUXC_SetPinConfig(uint32_t muxRegister,
                                       uint32_t muxMode,
                                       uint32_t inputRegister,
                                       uint32_t inputDaisy,
                                       uint32_t configRegister,
                                       uint32_t configValue)

IO复用的函数

IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0),传入寄存器地址和IO使能,其他参数可以不用设置。

IO电气设置的函数

IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0)

而IOMUXC_GPIO1_IO03_GPIO1_IO03是fsl_iomuxc.h定义的宏。

而GPIO1_IO03 有9个宏定义,例如IOMUXC_GPIO1_IO03_I2C1_SDA

五、BSP工程管理实验

1.结构

一般来说工程结构应该如下:

-bsp

-imx6ul

-obj

-project

  • 其中bsp用来存放驱动文件

  • imx6ul存放芯片有关的文件,例如SDK文件

  • obj存放编译生成的.o文件

  • project存放start.S和main.c文件

  • 将上一章的实验中的:

    cc.h fsl_common.h fsl_iomuxc.h MCIMX6Y2.h

    拷贝到文件imx6ul中

    将start.S和main.c存放到project中

    将函数clk_enable led_init delay写到bsp中

    2.各文件创建

    2.1 imx6ul.h

    #ifndef __IMX6UL_H
    #define __IMX6UL_H
    
    #include "cc.h"
    #include "MCIMX6Y2.h"
    #include "fsl_common.h"
    #include "fsl_iomuxc.h"
    
    #endif
    

    该文件只是引用了一些芯片相关的头文件。

    2.2 编写led驱动代码

    bsp_led.h

    #ifndef __BSP_LED_H
    #define __BSP_LED_H
    
    #include "imx6ul.h"
    
    #define LED0 0
    
    //函数声明
    void led_init(void);
    void led_switch(int led, int status);
    
    #endif
    

    bsp_led.c

    #include "bsp_led.h"
    
    void led_init(void){
        //IO复用
        IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);
            
        //IO属性
        IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0);
        
        //GPIO设置为输出
        GPIO->GDIR |= (1<<3);
        
        //GPIO输出为低电平
        GPIO->DR &= ~(1<<3);
    }
    
    void led_switch(int led, int status)
    {
        switch(led){
            case LED0:
                if(status == ON)
                    GPIO1->DR &= ~(1<<3);
                else if(status == OFF)
                    GPIO1->DR |= (1<<3);
                break;
        }
    }
    

    2.3 编写时钟驱动

    bsp_clk.h

    #ifndef __BSP_CLK_H
    #define __BSO_CLK_H
    
    #include "imx6ul.h"
    
    void clk_enable(void)
        
    #endif
    

    bsp_clk.c

    #include "bsp_clk.h"
    
    void clk_enable(void){
        CCM->CCG0 = 0XFFFFFFFF;
        CCM->CCG1 = 0XFFFFFFFF;
        CCM->CCG2 = 0XFFFFFFFF;
        CCM->CCG3 = 0XFFFFFFFF;
        CCM->CCG4 = 0XFFFFFFFF;
        CCM->CCG5 = 0XFFFFFFFF;
        CCM->CCG6 = 0XFFFFFFFF;
    }
    

    2.4 编写延时驱动

    bsp_delay.h

    #ifndef __BSP_DELAY_H
    #define __BSP_DELAY_H
    
    #include "imx6ul.h"
    
    void delay(volatile unsigned int n);
    
    #endif
    

    bsp_delay.c

    #include "bsp_delay.h"
    
    void delay_short(volatile unsigned int n){
        while(n--){}
    }
    
    void delay(volatile unsigned int n){
        while(n--){
            delay_short(0x7ff);
        }
    }
    

    2.5 修改main.c

    #include "bsp_clk.h"
    #include "bsp_led.h"
    #include "bsp_delay.h"
    
    int main(void){
        clk_enable();
        led_init();
        
        while(1){
            led_switch(LED0,0N);
            delay(500);
            
            led_switch(LED0,OFF);
            delay(500);
        }
        return 0;
    }
    

    作者:年轮不改

    物联沃分享整理
    物联沃-IOTWORD物联网 » IMX6ULL裸机开发——点亮LED灯

    发表回复