GPIO与外部中断

今天看了看RT1052的GPIO,感觉这玩意比STM32复杂多了,今天我们来尝试了解一下它先从LED点灯开始。

<ignore_js_op>

<ignore_js_op>


可以看出飞凌底板上的LED是连接的GPIO1_IO02脚。 首先放出例程的配置方式(删除了注释)

  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_09_GPIO1_IO09,  0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_09_GPIO1_IO09,  0x10B0u);                              

其中
#define IOMUXC_GPIO_AD_B0_09_GPIO1_IO09
 0x401F80E0U0x5U, 0, 0, 0x401F82D0U

这红色的字体就是这次配置的关键了。首先看IOMUXC_SetPinMux函数
static inline void IOMUXC_SetPinMux(uint32_t muxRegister,
                                    uint32_t muxMode,
                                    uint32_t inputRegister,
                                    uint32_t inputDaisy,
                                    uint32_t configRegister,
                                    uint32_t inputOnfield)
{
    *((volatile uint32_t *)muxRegister) =
        IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(muxMode) | IOMUXC_SW_MUX_CTL_PAD_SION(inputOnfield);

    if (inputRegister)
    {
        *((volatile uint32_t *)inputRegister) = inputDaisy;
    }
}

#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_MASK      (0x7U)
#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_SHIFT     (0U)
#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(x)        (((uint32_t)(((uint32_t)(x)) << IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_SHIFT)) & IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_MASK)
#define IOMUXC_SW_MUX_CTL_PAD_SION_MASK          (0x10U)
#define IOMUXC_SW_MUX_CTL_PAD_SION_SHIFT         (4U)
#define IOMUXC_SW_MUX_CTL_PAD_SION(x)            (((uint32_t)(((uint32_t)(x)) << IOMUXC_SW_MUX_CTL_PAD_SION_SHIFT)) & IOMUXC_SW_MUX_CTL_PAD_SION_MASK)
可以看出,我们配置了0x401F80E0U的第0—2位为0x5U,第4位为0

我们来看一下这个0x401F80E0U到底是个什么地址
<ignore_js_op>
可以看出来,第4位为0时可以设置功能复用,而0—2位设置的是功能复用,这里设置为GPIO1功能

然后是IOMUXC_SetPinConfig函数
static inline void IOMUXC_SetPinConfig(uint32_t muxRegister,
                                       uint32_t muxMode,
                                       uint32_t inputRegister,
                                       uint32_t inputDaisy,
                                       uint32_t configRegister,
                                       uint32_t configValue)
{
    if (configRegister)
    {
        *((volatile uint32_t *)configRegister) = configValue;
    }
}
可以看出是配置0x401F82D0U0x10B0u
我们来看一下0x401F82D0U是什么
<ignore_js_op>
<ignore_js_op>
可以看出来这里是对引脚功能的设置,这里的0x10B0u就是设置为 转化速率慢,驱动强度为R0/6,速度100MHz,关闭开漏,开启拉/保持器,选择为保持,100K下拉(无用),关闭滞回。
感觉写这么一个数不好理解,我改写了一下这个函数

//转换速率       0 慢     1 快
//驱动强度       0 无     1 R0     2 R0/2   3 R0/3    4 R0/4    5 R0/5    6 R0/6    7 R0/7
//输出速度       0 50MHz  1 100MHz   2 100MHz   3 200MHz
//开漏输出       0 关闭   1 开启
//拉/保持器      0 关闭   1 开启
//拉/保持器设置  0 保持    1 拉
//上下拉电阻     0 100K下拉   1 47K上拉   2 100K上拉   3 22K上拉
//滞回器设置     0 关闭       1开启
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_02_GPIO1_IO02, IOMUXC_SW_PAD_CTL_PAD_SRE(0)    //转换速率慢
                                                                                        |IOMUXC_SW_PAD_CTL_PAD_DSE(6)    //驱动强度R0/6
                                                                                        |IOMUXC_SW_PAD_CTL_PAD_SPEED(2)  //速度100MHz
                                                                                        |IOMUXC_SW_PAD_CTL_PAD_ODE(0)    //关闭开漏
                                                                                        |IOMUXC_SW_PAD_CTL_PAD_PKE(1)    //拉/保持器开启
                                                                                        |IOMUXC_SW_PAD_CTL_PAD_PUE(0)    //选择为保持
                                                                                        |IOMUXC_SW_PAD_CTL_PAD_PUS(0)    //100K下拉(没用到)
                                                                                        |IOMUXC_SW_PAD_CTL_PAD_HYS(0));  //关闭滞回
感觉这样更容易理解,更容易操作一点。

接下来就是配置GPIO了,下面只放出关键程序

gpio_pin_config_t led_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode}; //设为输出 默认输出0 无中断
GPIO_PinInit(GPIO1, 2, &led_config);

这两句很好理解,首先设置led_config

typedef struct _gpio_pin_config
{
    gpio_pin_direction_t direction;                 //设置输出方向
    uint8_t outputLogic;                               //设置初始电平
    gpio_interrupt_mode_t interruptMode;     //设置中断模式
} gpio_pin_config_t;

里面有这三个成员 取值如下

typedef enum _gpio_pin_direction
{
    kGPIO_DigitalInput = 0U,  //输入
    kGPIO_DigitalOutput = 1U, //输出
} gpio_pin_direction_t;

typedef enum _gpio_interrupt_mode
{
    kGPIO_NoIntmode = 0U,                 //无中断
    kGPIO_IntLowLevel = 1U,                //低电平中断
    kGPIO_IntHighLevel = 2U,               //高电平中断
    kGPIO_IntRisingEdge = 3U,              //上升沿中断
    kGPIO_IntFallingEdge = 4U,             //下降沿中断
    kGPIO_IntRisingOrFallingEdge = 5U, //上升下降沿中断
} gpio_interrupt_mode_t;

就是把GPIO1_2配置为输出模式,默认输出1,无中断。(这里的寄存器也没啥好分析的,接下来就不讨论了寄存器了)

GPIO_PinWrite(GPIO1, 2, 0U);//点亮LED
delay(10);
GPIO_PinWrite(GPIO1, 2, 1U);//熄灭LED
delay(10);

相当简单的程序 运行结果就是灯一闪一闪的,效果见视频附件

接下来是GPIO输入 参考原理图



<ignore_js_op>
<ignore_js_op>

嗯,这GPIO5_0就是我们要的。对他进行配置



IOMUXC_SetPinMux(IOMUXC_SNVS_WAKEUP_GPIO5_IO00, 0U);         //复用为GPIO
IOMUXC_SetPinConfig(IOMUXC_SNVS_WAKEUP_GPIO5_IO00,   IOMUXC_SW_PAD_CTL_PAD_SRE(0)    //转换速率慢
                                                                                          |IOMUXC_SW_PAD_CTL_PAD_DSE(0)    //无驱动强度
(没用到)
                                                                                          |IOMUXC_SW_PAD_CTL_PAD_SPEED(2)  //速度100MHz
(没用到)
                                                                                          |IOMUXC_SW_PAD_CTL_PAD_ODE(0)    //关闭开漏(没用到)
                                                                                          |IOMUXC_SW_PAD_CTL_PAD_PKE(1)    //拉/保持器开启
                                                                                          |IOMUXC_SW_PAD_CTL_PAD_PUE(1)    //选择为拉
                                                                                          |IOMUXC_SW_PAD_CTL_PAD_PUS(3)    //22K上拉
                                                                                          |IOMUXC_SW_PAD_CTL_PAD_HYS(0));  //关闭滞回

这里我们把它设为了22K上拉(这里只能配置为,拉/保持器开启,选择为拉。具体原因应该是RT1052把使能上下拉设为了输入专用了。而输出使用的是配置开漏,和配置驱动能力)。下面是main里程序(省略很多)


gpio_pin_config_t key_config = {kGPIO_DigitalInput, 0, kGPIO_NoIntmode};  //设为输入 默认输出0 无中断
GPIO_PinInit(GPIO5, 0, &key_interrupt_config);
while(1)
{
        GPIO_PinWrite(GPIO1, 2, GPIO_PinReadPadStatus(GPIO5,0));
}

补充一句,如果设置为输入模式那么默认输出电平就不起作用
这里的GPIO_PinReadPadStatus是一个读取引脚电平的函数,运行结果是按住按键灯亮,松开灭。


接下来是配置外部中断。参考MIMXRT1052.h


<ignore_js_op>

可以发现包含GPIO5_0的中断是GPIO5_Combined_0_15_IRQn,中断回调函数是GPIO5_Combined_0_15_IRQHandler(MIMXRT1052.s有定义)
还是和刚才一样配置引脚模式,下面是main里程序(省略很多)

        gpio_pin_config_t key_interrupt_config = {kGPIO_DigitalInput, 1, kGPIO_IntFallingEdge};  //设为输入 默认输出0 下降沿中断

        EnableIRQ(GPIO5_Combined_0_15_IRQn);//使能中断
        GPIO_PinInit(GPIO5, 0, &key_interrupt_config);
        GPIO_PortEnableInterrupts(GPIO5, 1U << 0); //使能特定引脚中断

中断回调函数

void GPIO5_Combined_0_15_IRQHandler(void)
{
        delay(1);          //消除抖动
    if(GPIO_PinReadPadStatus(GPIO5, 0) == 0)  //二次判断
                GPIO_PortToggle(GPIO1,1<<2);      //灯取反
        GPIO_PortClearInterruptFlags(GPIO5, 1 << 0);  //清除中断标志位
    __DSB();
}


这里的代码和普通的代码差不多,就不分析了。
比较有意思的是这个__DSB();它的作用是只有CPU把这句话之前的代码全部执行完毕后才能继续向下执行。
最后的效果是按下按键后灯转换状态补充一点如果不需要go to什么的,可以把output里的两个输出去掉,大大加快了编译速度
<ignore_js_op>
最后不得不吐槽一句底板的绿灯有点太亮了。。。。。晚上拍的视频看着特别显眼。

posted on 2022-06-15 21:17  张凌001  阅读(102)  评论(0编辑  收藏  举报

导航