MCXC444无GPIO中断?教你用 FlexIO“曲线救国”,轻松实现边沿捕捉!

总体概述

在MCU开发中,我们经常需要对外部信号的上升沿或下降沿进行检测,并据此触发中断。但在实际项目中,你可能会遇到这样的问题:

某些引脚(例如MCXC444的PortE)并不支持GPIO中断功能。

这时候,如果再调整硬件已经来不及,该怎么办?

一个非常实用的思路是:借助FlexIO来“模拟中断”。

FlexIO本质上是一个高度可编程的外设,不仅可以模拟UART、SPI、I²C,还能灵活实现:

  • 波形捕捉

  • 边沿检测

  • 自定义时序逻辑

本文就带你一步步实现:

利用FlexIO Timer,在FLEXIO_D4(PTE20)引脚上捕捉上升沿并触发中断~

一、设计思路

FlexIO Timer的核心机制如下:

  • PinSelect

    → 选择输入引脚(FLEXIO_D4 ↔ PTE20)

  • TimerDecrement

    → 由引脚电平驱动计数

  • TimerReset

    → 在上升沿复位计数器

  • TimerCompare

    → 计数达到比较值时置位中断标志

这样就能实现:每检测到一次上升沿,就触发一次中断

二、实现步骤

2.1 时钟配置

为FlexIO模块开启时钟。

/* Set FLEXIO clock source. */  
CLOCK_SetFlexio0Clock(SIM_FLEXIO_CLK_SEL_IRC48M_CLK);

2.2 配置引脚

  • PTE20 → 复用为 FLEXIO0_D4 输入

  • PTE30 → GPIO 输出(用于产生测试波形)

/* PORTE20 (pin 9) is configured as FXIO0_D4 */   
    PORT_SetPinMux(PORTE, 20U, kPORT_MuxAlt6); 
/* PORTE30 (pin 18) is configured as PTE30 */   
    PORT_SetPinMux(PORTE, 30U, kPORT_MuxAsGpio);

2.3 配置 FlexIO Timer

flexio_config_t flexioConfig;  
flexio_timer_config_t timerConfig;    
/* 3. 初始化 FlexIO 模块 */  
FLEXIO_GetDefaultConfig(&flexioConfig);  
FLEXIO_Init(BOARD_FLEXIO_BASE, &flexioConfig);            
memset(&timerConfig, 0, sizeof(timerConfig));             
timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;             
timerConfig.pinSelect = 4;             
timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;              
timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(FLEXIO_PIN);            
timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh; // rising edge            
timerConfig.triggerSource   = kFLEXIO_TimerTriggerSourceExternal;             
timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;             
timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;            
timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;            
timerConfig.timerDecrement= kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;            
timerConfig.timerReset = kFLEXIO_TimerResetOnTimerPinRisingEdge;            
timerConfig.timerDisable = kFLEXIO_TimerDisableNever;            
timerConfig.timerEnable = kFLEXIO_TimerEnabledAlways;            
timerConfig.timerCompare = 0x0001;            
FLEXIO_SetTimerConfig(BOARD_FLEXIO_BASE, 0, &timerConfig);             
FLEXIO_EnableTimerStatusInterrupts(BOARD_FLEXIO_BASE, 1U << 0);            
EnableIRQ(UART2_FLEXIO_IRQn);            
NVIC_SetPriority(UART2_FLEXIO_IRQn, 2);

关键点说明:

  • triggerSelect

    FLEXIO_TIMER_TRIGGER_SEL_PININPUT(FLEXIO_PIN);

引脚输入作为触发源

  • timerReset

    kFLEXIO_TimerResetOnTimerPinRisingEdge,确保每次上升沿都会触发

  • timerDecrement

    kFLEXIO_TimerResetOnTimerPinRisingEdge, 由外部引脚驱动计数

  • pinConfig/pinSelect

    指定输入引脚为FlexIO_D4

  • timerMode

    单次计数模式,适合捕捉事件

  • timerCompare = 0x01, 确保每次边沿都会立刻触发中断。值太大会导致需要多次脉冲才触发

每次边沿立即产生中断(非常关键!)

注意:
MCXC444没有单独的 FLEXIO_IRQn, 而是复用在:UART2_FLEXIO_IRQn

2.4 中断服务函数

void UART2_FLEXIO_IRQHandler(void)
{   
    uint32_t flags = FLEXIO_GetTimerStatusFlags(BOARD_FLEXIO_BASE);   
    if (flags & (1U << FLEXIO_TIMER))   
    {      
        FLEXIO_ClearTimerStatusFlags(BOARD_FLEXIO_BASE, 1U << FLEXIO_TIMER);      
         PRINTF("FlexIO: Rising edge detected!\r\n");   
     }
 };

三、实验结果

当外部信号接入PTE20(FLEXIO0_D4)并产生上升沿时:

  • FlexIO Timer 成功捕获

  • 中断被触发

  • 串口打印提示信息

实验证明:
FlexIO完全可以作为“软件定义的外部中断模块”使用

四、重点优化

很多人认为:
没有GPIO中断=无法检测外部事件

但实际上,通过FlexIO,你可以:

  • 自定义触发条件

  • 灵活绑定任意引脚

  • 实现比传统 GPIO 更复杂的逻辑

本质上,FlexIO提供的是一种“更高级的硬件编程能力”。当GPIO中断受限时,FlexIO就是你的“外挂神器”——不仅能替代,还能做得更强。

TIC: Harry Zhang

来源:恩智浦MCU加油站

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。