内容覆盖:

  1. GPIO概述(5组124个引脚,命名规则对比STM32)
  2. IO配置三步走:CCM时钟 → IOMUXC MUX → IOMUXC PAD
  3. 8个GPIO寄存器:DR、GDIR、PSR、ICR1/2、EDGE_SEL、IMR、ISR
  4. 寄存器地址表(5组GPIO基地址+偏移)
  5. 完整代码示例(LED控制,C语言)
  6. 与STM32关键区别对比
  7. 常见问题(原子操作、PSR vs DR、EDGE_SEL优先级)

GPIO 是什么

GPIO = General Purpose Input/Output(通用输入输出

芯片通过 GPIO 引脚外部世界交互

  • 输出:芯片控制外部设备(LED、电机、蜂鸣器)

  • 输入:芯片读取外部信号(按键、传感器)

  GPIO结构示意一:

说明:

1. IOMUXC:    io mux controller        : IO复用控制器(硬件模块)

   SW_MUX:   software mux control  :软件复用控制寄存器(软件配置接口)

   IOMUXC模块名SW_MUX 是其中的寄存器名

2. Pin指芯片封装好后的管脚,即用户能够看到的管脚PAD是硅片的管脚,是封装在芯片内部的,用户看不到。PADPIN之间还有一段导线连接的。

一、i.MX6ULL GPIO 概述

1.1 GPIO 分组

i.MX6ULL 共有 5组GPIO,总计 124个引脚

注:除了124个GPIO功能引脚,i.MX6ULL 还有165个其它功能引脚,共计289个物理引脚

GPIO组 引脚数量 说明
GPIO1 32个 IO0~IO31
GPIO2 22个 IO0~IO21
GPIO3 29个 IO0~IO28
GPIO4 29个 IO0~IO28
GPIO5 12个 IO0~IO11

注:GDIR是 GPIO 方向寄存器,每一位对应一个 IO 引脚的 方向:置 1 = 输出,置 0 = 输入。

列:

/*Direction:Output*/
GPIO1 ->GDIR |= (1 << 27); // 第一组GPIO中,第27个引脚(管脚) 设置为 1(输出模式)。

1.2 命名规则(与STM32不同!)

STM32 (命名:端口+编号):PA0~PA15, PB0~PB15...

i.MX6ULL (命名:引脚功能):GPIO1_IO00, GPIO5_IO03, UART1_TX_DATA...

  • 命名依据引脚的功能,而不是端口+编号

  • 看到 GPIO1_IO00 → 知道这是GPIO功能

  • 看到 UART1_TX_DATA → 知道这是串口发送功能。

  • 同一个引脚可以复用作GPIO,具体某个引脚能复用哪些功能,必须数据手册确认。

GPIO功能通用输入输出,软件直接控制电平高低,简单灵活。
串口发送功能硬件专用功能,自动处理时序、波特率、数据格式,高效可靠。

1.3 两类IO

  • SNVS域:SNVS_TAMPER0~SNVS_TAMPER9(低功耗域,始终供电)

  • 通用域:其余所有IO(GPIO1~GPIO5)

二、IO配置三步走(与STM32流程对比)

IO配置本质:

      1.每个寄存器32位(二进制),每位对应一个IO(管脚)或一个属性

      2.IO配置:按手册,设置对应寄存器对应位为0或1.

补充:

       1.位域: 一个功能可能占多位(如DSE占3位),不是简单的0/1

      2.保留位未定义位必须写0,否则可能出错

      3.原子性修改某位时不能影响其他位(读-改-写)

配置流程对比

步骤 STM32 i.MX6ULL
1. 使能时钟 RCC寄存器 CCM_CCGR0~6(可选,默认打开的)
2. 设置复用功能 MODER/AFR IOMUXC MUX寄存器
3. 配置电气属性 PUPDR/OSPEEDR IOMUXC PAD寄存器   (可选,可以用默认设置)
4. 配置输入/输出 MODER GPIO_GDIR (默认值是0-->输入模式)
5. 读写数据 ODR/IDR/BSRR GPIO_DR

2.1 第一步:使能GPIO时钟(CCM)

CCM(Clock Controller Module)控制所有外设时钟。

7个时钟使能寄存器:CCM_CCGR0 ~ CCM_CCGR6

每个CCM_CCGR是32位,每2位控制一个外设的时钟:
00 = 所有模式关闭
01 = 仅运行模式开启
10 = 保留
11 = 除停止模式外一直开启

各GPIO时钟配置位置

GPIO组 寄存器 基地址
GPIO1 CCGR1 CG13 (bit26:27) 0x020C406C
GPIO2 CCGR0 CG15 (bit30:31) 0x020C4068
GPIO3 CCGR2 CG13 (bit26:27) 0x020C4070
GPIO4 CCGR3 CG6 (bit12:13) 0x020C4074
GPIO5 CCGR1 CG15 (bit30:31) 0x020C406C
// 示例:开启GPIO1时钟
// 心脏==>时钟信号 设置为 11 模式 :除了暂停模式,其它模式一直运行
// #define CCM_CCGR1 *((volatile unsigned int *)0x20C406C)
CCM_CCGR1 |= (0x3 << 26);  // CCGR1的bit26:27设为11(二进制)

2.2 第二步:设置IO复用功能(IOMUXC MUX)

每个IO都有一个 MUX寄存器,决定这个引脚做什么功能。

寄存器命名IOMUXC_SW_MUX_CTL_PAD_<PAD NAME> :用来配置管脚的复用功能        

寄存器结构(32位,只用低5位):

名称 说明
bit[3:0] MUX_MODE ALT0~ALT8,选择复用功能
bit[4] SION 输出模式下开启输入通道(回环)

MUX_MODE 值对应功能

模式 说明
0000 ALT0 默认功能
0001 ALT1 功能1
... ... ...
0101 ALT5 作为GPIO功能
// 示例:
// *GPIO MODE *:配置管脚的复用功能
// 配置 第一组管脚的 第27个管脚 为GPIO模式(通用输入输出模式)
// #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO27 *((volatile unsigned int *)0x20E00B0)
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO27 &= ~(0xf << 0);  // 最后4位 清零
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO27 |=  (0x5 << 0);  // 设置为 5(101):GPIO模式
  • 查手册第32章(IOMUX Controller)

  • 搜索 IOMUXC_SW_MUX_CTL_PAD_GPIOx_IOxx

  • 找到寄存器地址ALT值

3. 第三步:配置PAD电气属性(IOMUXC PAD)

每个IO还有一个 PAD寄存器配置电气特性。

寄存器命名IOMUXC_SW_PAD_CTL_PAD_XXXX

寄存器结构(32位,用低17位):

名称 说明 默认
bit[16] HYS 迟滞比较器(施密特触发器),输入整形用   0 :滞后功能已禁用
bit[15:14] PUS 上下拉电阻选择 00 :100 千欧下拉电阻
bit[13] PUE 0=状态保持器,1=上下拉   0 :状态保持
bit[12] PKE 使能上下拉/保持器   1 : 上下拉取 / 保持器功能启用
bit[11] ODE 开漏输出(0=禁止,1=使能)   0 :禁止
bit[7:6] SPEED 输出速度  10 :中速 100MHz
bit[5:3] DSE 驱动能力(8档) 110 :6档 驱动能力
bit[0] SRE 压摆率控制    0 :低转换速率

PUS 上下拉选择

说明
00 100K 下拉电阻
01 47K 上拉电阻
10 100K 上拉电阻
11 22K 上拉电阻

SPEED 输出速度

速度
00 低速 50MHz
01/10 中速 100MHz
11 高速 200MHz

DSE 驱动能力(000~111,8档,值越大驱动越强)

    // 配置 GPIO1_IO04 引脚 电器属性
    // 功能:47K上拉 + 中速 + 中等驱动能力
    // 寄存器:SW_PAD_CTL_PAD_GPIO1_IO04 (地址 0x020E02F8)
    // 写入值:0x7071 = 0b0 0111 0000 0111 0001
    // 
    // 位定义:
    //   bit16 HYS=0  (迟滞关闭)
    //   bit15-14 PUS=01 (47K上拉)
    //   bit13 PUE=1  (使用上下拉)
    //   bit12 PKE=1  (keeper使能)
    //   bit11 ODE=0  (开漏关闭)
    //   bit7-6 SPEED=01 (中速)
    //   bit5-3 DSE=110 (R0/6驱动能力)
    //   bit0 SRE=1   (快速压摆率)
    *(volatile unsigned long*)0x020E02F8 = 0x7071;

    三、GPIO核心寄存器(8个32位寄存器)

    i.MX6ULL 每组GPIO有 8个寄存器

    寄存器 缩写 功能 读/写
    Data Register DR 输出/输入数据 R/W
    Direction Register GDIR 设置输入/输出方向 R/W
    Pad Sample Register PSR 读取引脚当前状态 只读
    Interrupt Config 1 ICR1 低16位中断配置 R/W
    Interrupt Config 2 ICR2 高16位中断配置 R/W
    Edge Select Register EDGE_SEL 边沿选择(覆盖ICR) R/W
    Interrupt Mask Register IMR 中断使能/屏蔽 R/W
    Interrupt Status Register ISR 中断状态标志 R/W(写1清除)

    3.1 DR(Data Register)数据寄存器

    32位,每个bit对应一个GPIO引脚

    输出模式(GDIR=1):写DR控制引脚输出高低电平

    输入模式(GDIR=0):读DR获取引脚输入电平

    // 点亮LED0:设置GPIO1_IO27输出高电平
    // 
    // 原理:
    //   GPIO1->DR 是数据寄存器(Data Register),地址 0x0209C000
    //   每位控制一个引脚:1=高电平(3.3V),0=低电平(0V)
    //   LED0连接在GPIO1的第27引脚,对应寄存器的第27位
    //
    // 操作:|= (1 << 27) 表示"只把第27位置1,其他位保持原样"
    //
    /*
    typedef struct
    {
          __IO uint32_t DR;        // GPIO data register,                     地址偏移: 0x0  (0个字节)
          __IO uint32_t GDIR;      // GPIO direction register,                地址偏移: 0x4  (4个字节) 
          __IO uint32_t PSR;       // GPIO pad status register,               地址偏移: 0x8  (8个字节)
          __IO uint32_t ICR1;      // GPIO interrupt configuration register1, 地址偏移: 0xC  (12个字节) 
          __IO uint32_t ICR2;      // GPIO interrupt configuration register2, 地址偏移: 0x10 (16个字节) 
          __IO uint32_t IMR;       // GPIO interrupt mask register,           地址偏移: 0x14 (20个字节) 
          __IO uint32_t ISR;       // GPIO interrupt status register,         地址偏移: 0x18 (24个字节) 
          __IO uint32_t EDGE_SEL;  // GPIO edge select register,              地址偏移: 0x1C (28个字节)
    } GPIO_Type;
    */
    // uint32_t  占4字节,所以,指针+1,地址+4字节
    // #define GPIO1_BASE (0x209C000u)
    // #define GPIO1 ((GPIO_Type *)GPIO1_BASE) // 强转 指针类型
    GPIO1->DR |= (1 << 27);  // 第27位写1 ==> LED0点亮

    注意:写DR是直接写整个32位,不像STM32有BSRR原子操作。

    3.2 GDIR(GPIO Direction Register)方向寄存器

    32位,每个bit对应一个GPIO引脚

    bit值 方向
    0 输入模式
    1 输出模式
    // 示例:设置GPIO1_IO27为输出模式
    // 操作:|= (1 << 27) 表示"只把第27位置1,其他位保持原样"
    // 27 : 指的是第27个管脚
    GPIO1->GDIR |= (1 << 27);  // 方向设置为 输出模式 1 => 27位为1

    3.3 PSR(Pad Sample Register)引脚状态寄存器

    32位,只读

    • 无论GDIR设置为何值,PSR始终反映引脚当前的电平状态

    • 电平状态:1 => 高电平 , 0 => 低电平

    • 输出模式下,如果MUX开启了SION(回环),可以通过PSR读回输出状态

     // 读取GPIO1_IO26的当前电平
     // 1 => 高电平 , 0 => 低电平
     int level = GPIO1->PSR & (1 << 26); 

    3.4 ICR1/ICR2(Interrupt Configuration Registers)中断配置

    ICR1:配置低16位(IO0~IO15)的中断触发方式

    ICR2:配置高16位(IO16~IO31)的中断触发方式

    每个GPIO用2个bit配置中断触发方式:

    bit值 触发方式
    00 低电平触发
    01 高电平触发
    10 上升沿触发
    11 下降沿触发
    // 示例:设置GPIO1_IO15为上升沿触发
    // IO15在ICR1中,占用bit30:31
    // 上升沿 = 10(二进制)
     GPIO1.ICR1 |= (2 << 30);  // 2 = 0b10

    3.5 EDGE_SEL(Edge Select Register)边沿选择

    32位,每个bit对应一个GPIO

    • 当bit=1时,对应GPIO设置为双边沿触发(上升+下降都触发)

    • 会覆盖ICR1/ICR2的设置

    // 设置GPIO1_IO00为双边沿触发
    // EDGE_SEL的bit0 = 1
    *(volatile unsigned long*)0x0209C014 |= (1 << 0);

    3.6 IMR(Interrupt Mask Register)中断屏蔽

    32位,每个bit对应一个GPIO

    bit值 中断状态
    0 中断被屏蔽(禁用)
    1 中断使能
    // 使能GPIO1_IO00的中断
    *(volatile unsigned long*)0x0209C010 |= (1 << 0);

    3.7 ISR(Interrupt Status Register)中断状态

    32位,每个bit对应一个GPIO

    • 中断发生时,对应bit被硬件置1

    • 清除方法:向对应bit写1(写1清零)

    // 检查GPIO1_IO00是否发生中断
    uint32_t isr = *(volatile unsigned long*)0x0209C00C;
    if (isr & (1 << 0)) {
        // 发生中断,清除标志
        *(volatile unsigned long*)0x0209C00C = (1 << 0);  // 写1清零
    }

    四、GPIO寄存器地址表

    4.1 GPIO基地址

    GPIO组 基地址
    GPIO1 0x0209C000
    GPIO2 0x020A0000
    GPIO3 0x020A4000
    GPIO4 0x020A8000
    GPIO5 0x020AC000

    4.2 寄存器偏移

    寄存器 偏移 完整地址示例(GPIO5)
    DR +0x00 0x020AC000
    GDIR +0x04 0x020AC004
    PSR +0x08 0x020AC008
    ICR1 +0x0C 0x020AC00C
    ICR2 +0x10 0x020AC010
    IMR +0x14 0x020AC014
    ISR +0x18 0x020AC018
    EDGE_SEL +0x1C 0x020AC01C

    五、完整配置示例(LED控制)

    5.1 硬件示例

    电路图:

    如图,信号UART3_RTS,链接管脚是GPIO1_IO[27](第一组管脚的第27个管脚)

    目标:让信号UART3_RTS 输出高低电平 来控制LED灯亮灭

            信号 UART3_RTS 输出 高电平 => LED灯亮,

            信号 UART3_RTS 输出 低电平 => LED灯灭

    5.2 C语言代码

    // imx6ull.h
    // #define CCM_CCGR1 *((volatile unsigned int *)0x20C406C)
    // #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO27 *((volatile unsigned int *)0x20E00B0)
    /* GPIO - Register Layout Typedef */
    /*
    typedef struct
    {
          __IO uint32_t DR;        // GPIO data register,                     地址偏移: 0x0  (0个字节)
          __IO uint32_t GDIR;      // GPIO direction register,                地址偏移: 0x4  (4个字节) 
          __IO uint32_t PSR;       // GPIO pad status register,               地址偏移: 0x8  (8个字节)
          __IO uint32_t ICR1;      // GPIO interrupt configuration register1, 地址偏移: 0xC  (12个字节) 
          __IO uint32_t ICR2;      // GPIO interrupt configuration register2, 地址偏移: 0x10 (16个字节) 
          __IO uint32_t IMR;       // GPIO interrupt mask register,           地址偏移: 0x14 (20个字节) 
          __IO uint32_t ISR;       // GPIO interrupt status register,         地址偏移: 0x18 (24个字节) 
          __IO uint32_t EDGE_SEL;  // GPIO edge select register,              地址偏移: 0x1C (28个字节)
    } GPIO_Type;
    */
    // uint32_t  占4字节,所以,指针+1,地址+4字节
    // #define GPIO1_BASE (0x209C000u)
    // #define GPIO1 ((GPIO_Type *)GPIO1_BASE) // 强转 指针类型
    #include "imx6ull.h"
    
    // LED灯 初始化
    void led_init(void)
    {
         // 1. 开启GPIO1 时钟
        // 心脏==>时钟信号 设置为 11 模式 :除了暂停模式,其它模式一直运行
        CCM_CCGR1 |= (0x3 << 26);  // CCGR1的bit26:27 设为11(二进制)
    
        // 2. 配置GPIO1_IO27管脚的 复用功能
        // 配置第一组管脚的 第27个管脚为 GPIO模式(通用输入输出模式)
        IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO27 &= ~(0xf << 0);  // 最后4位 清零
        IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO27 |=  (0x5 << 0);  // 设置为 5(101):GPIO模式
    
        // 3. GPIO1_IO27管脚的电器属性,使用的是默认值。所以,没有配置
    
        // 4. 设置GPIO1_IO27为 输出模式
        // 操作:|= (1 << 27) 表示"只把第27位置1,其他位保持原样"
        // 27 : 指的是第27个管脚
        GPIO1->GDIR |= (1 << 27);  // 方向设置为 输出模式 1 => 27位为1
    
    }
    
    // LED灯 亮
    void led_on(void)
    {
        // 点亮LED灯:设置GPIO1_IO27输出高电平
        // 信号连接在GPIO1的第27引脚,对应寄存器的第27位
        // 操作:|= (1 << 27) 表示"只把第27位置1,其他位保持原样"
        GPIO1->DR |= (1 << 27); // 设置为高电平 :27位为1 ==> MOS管连通 ==> LED灯亮
    }
    
    // LED灯 灭
    void led_off(void)
    {
        // 熄灭LED灯:设置GPIO1_IO27输出低电平
        // 信号连接在GPIO1的第27引脚,对应寄存器的第27位
        // 操作:&= ~(1 << 27) 表示"只把第27位置0,其他位保持原样"
        GPIO1->DR &= ~(1 << 27); // 设置为低电平 :27位为0 ==> MOS管断开 ==> LED灯灭
    }
    
    // 延迟 time 时间
    void delay_time(uint32_t time)
    {
        int i;
        int j;
    
        for(i = 0;i < time * 1000;i ++){
            for(j = 0;j < 50000;j ++){
            }
        }
    
        return;
    }
    
    // LED灯 测试
    void led_test(void)
    {
        led_init();     // LED灯 初始化   
        while(1){
            led_on();       // LED灯 亮
            delay_time(1);  // 延迟1秒
    
            led_off();      // LED灯 灭
            delay_time(1);  // 延迟1秒
        }
    
        return;
    }
    

    六、i.MX6ULL vs STM32 关键区别总结

    特性 STM32 i.MX6ULL
    GPIO命名 PA0~PA15 GPIO1_IO00
    时钟使能 RCC CCM_CCGR0~6
    复用配置 MODER + AFR IOMUXC MUX寄存器
    PAD配置 PUPDR, OSPEEDR等 IOMUXC PAD寄存器
    方向设置 MODER GDIR寄存器
    输出数据 ODR DR寄存器
    输入读取 IDR DR寄存器(或PSR)
    原子操作 BSRR(置位/复位分离) 无,需用 &= ~ 和
    中断配置 EXTI + NVIC ICR1/2 + IMR + ISR
    边沿选择 EXTI寄存器 EDGE_SEL(覆盖ICR)
    CPU架构 Cortex-M(单片机) Cortex-A7(应用处理器)
    操作系统 裸机/RTOS 通常跑Linux

    七、常见问题

    Q1: i.MX6ULL没有BSRR,怎么原子操作?

    原子操作(Atomic Operation) 指的是不可被中断的最小操作单位。

    没有。直接读-改-写DR:

    // 置高GPIO5_IO03
    *GPIO5_DR_BASE |= (1 << 3);
    
    // 置低GPIO5_IO03
    *GPIO5_DR_BASE &= ~(1 << 3);

    如果在Linux下,需要加锁保护(spin_lock)。

    Q2: 为什么有的IO有MUX,有的没有?

    所有IO都有MUX。普通IO的MUX在IOMUXC模块,SNVS域的IO的MUX在IOMUXC_SNVS模块(地址不同)。

    Q3: PSR和DR读取有什么区别?

    • DR:读的是输出寄存器(输出模式下是你要输出的值)

    • PSR:读的是引脚实际电平(始终反映真实状态)

    • 输入模式下,两者都反映输入电平

    • 输出模式下,只有开启SION才能在PSR读回输出值

    Q4: EDGE_SEL和ICR1/ICR2冲突吗?

    EDGE_SEL优先级更高。如果EDGE_SEL某位=1,对应ICR配置被覆盖,强制双边沿触发。

    八、寄存器地址速查(GPIO5为例)

    GPIO5基地址:0x020AC000
    
    GPIO5_DR       = 0x020AC000  // 数据寄存器
    GPIO5_GDIR     = 0x020AC004  // 方向寄存器
    GPIO5_PSR      = 0x020AC008  // 引脚状态
    GPIO5_ICR1     = 0x020AC00C  // 中断配置(低16位)
    GPIO5_ICR2     = 0x020AC010  // 中断配置(高16位)
    GPIO5_IMR      = 0x020AC014  // 中断屏蔽
    GPIO5_ISR      = 0x020AC018  // 中断状态
    GPIO5_EDGE_SEL = 0x020AC01C  // 边沿选择
    
    时钟:CCM_CCGR1 (0x020C406C) bit30:31 = 11
    MUX :IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 (0x02290014)
    PAD :IOMUXC_SNVS_SW_PAD_CTL_PAD_SNVS_TAMPER3 (0x02290058)

    Logo

    DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

    更多推荐