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 0x401F80E0U, 0x5U, 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; } } 可以看出是配置0x401F82D0U为0x10B0u。 我们来看一下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> 最后不得不吐槽一句底板的绿灯有点太亮了。。。。。晚上拍的视频看着特别显眼。 |