GPIO Latch

该示例使用ENH_TIM0,实现GPIO触发锁存器状态,并记录计数器计数的功能。P2_4设定为GPIO输出引脚,设定P2_4引脚电平随时间变化不断翻转。

P2_2设定为GPIO输入引脚,同时将该引脚设定为ENHTIM的计数触发引脚。将P2_2与P2_4引脚连接,P2_2电压变化会触发计数,进入ENH_TIM0中断,并打印触发时计数器数值。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL87x2G HDK

RTL87x2G EVB

更多信息请参考 快速入门

硬件连线

连接P4_4和P2_2。

编译和下载

该示例的工程路径如下:

Project file: samples\peripheral\enhtimer\latch_gpio\proj\rtl87x2g\mdk

Project file: samples\peripheral\enhtimer\latch_gpio\proj\rtl87x2g\gcc

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 Quick StartGenerating App Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bingcc\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 Quick StartMPTool Download 给出的步骤将app bin烧录至EVB内。

  5. 按下复位按键,开始运行。

测试验证

  1. 当EVB启动后,在DebugAnalyzer工具内观察如下LOG。

    Start latch_gpio test!
    
  2. 当P2_2和P2_4引脚连接后,在DebugAnalyzer工具上,会不断打印GPIO触发锁存时的计数器数值。

这里应该是GPIO触发锁存的计数值

GPIO触发锁存的计数值

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  1. 工程路径: sdk\samples\peripheral\enhtimer\latch_gpio\proj

  2. 源码路径: sdk\samples\peripheral\enhtimer\latch_gpio\src

该工程的工程文件代码架构如下:

└── Project: input_polling
    └── secure_only_app
        └── Device                   includes startup code
            ├── startup_rtl.c
            └── system_rtl.c
        ├── CMSIS                    includes CMSIS header files
        ├── CMSE Library             Non-secure callable lib
        ├── Lib                      includes all binary symbol files that user application is built on
            └── rtl87x2g_io.lib
        ├── Peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl_rcc.c
            ├── rtl_pinmux.c
            ├── rtl_gpio.c
            ├── rtl_nvic.c
            └── rtl_enh_tim.c
        └── APP                      includes the ble_peripheral user application implementation
            ├── main_ns.c
            └── io_latch_gpio.c

初始化

初始化流程包括了 board_gpio_init , driver_gpio_initdriver_enhance_timer_init


board_gpio_init 中包含了PAD与PINMUX设置。

  1. 配置PAD:设置引脚、PINMUX模式、PowerOn、内部上拉。

  2. 配置PINMUX:分配引脚为GPIO功能。


driver_gpio_init 包含了对GPIO外设的初始化。

  1. 使能PCC时钟。

  2. 设置GPIO的输出引脚 GPIO_Pin 为P2_4。

  3. 在GPIO初始化中,设置 GPIO_Dir 为输出模式。

RCC_PeriphClockCmd(APBPeriph_GPIOA, APBPeriph_GPIOA_CLOCK, ENABLE);
...
GPIO_InitStruct.GPIO_Pin  = GPIO_PIN_OUTPUT;
GPIO_InitStruct.GPIO_Dir  = GPIO_DIR_OUT;

driver_enhance_timer_init 包含了对ENHTIM外设的初始化。

  1. 使能PCC时钟。

  2. 设置 ENHTIM_ClockDiv 为ENHTIM_CLOCK_DIVIDER_1,即一分频模式。

  3. 设置 ENHTIM_Mode 为ENHTIM_MODE_FreeRun,即自由运行模式。

  4. 设置 ENHTIM_LatchCountEn[0] 为ENABLE,即开启GPIO触发锁存功能。

  5. 设置 ENHTIM_LatchCountTrigger[0] 为TRIGGER_RISING_EDGE,即上升沿触发。

  6. 设置 ENHTIM_LatchCountThd 为3,即触发中断FIFO阈值为3。

  7. 设置 ENHTIM_LatchTriggerPad 为INPUT_PIN。

  8. 设置 ENHTIM_TimerGPIOTriggerEn 为ENABLE,即使能GPIO触发计时功能。

  9. 配置ENHTIM中断;使能ENHTIM计时中断以及达到FIFO阈值中断;使能ENHTIM外设。

RCC_PeriphClockCmd(APBPeriph_ENHTIMER, APBPeriph_ENHTIMER_CLOCK, ENABLE);
...
ENHTIM_InitStruct.ENHTIM_ClockDiv             = ENHTIM_CLOCK_DIVIDER_1;
ENHTIM_InitStruct.ENHTIM_Mode                 = ENHTIM_MODE_FreeRun;
ENHTIM_InitStruct.ENHTIM_LatchCountEn[0]      = ENABLE;
ENHTIM_InitStruct.ENHTIM_LatchCountTrigger[0] = ENHTIM_LATCH_TRIGGER_RISING_EDGE;
ENHTIM_InitStruct.ENHTIM_LatchCountThd        = 3;
ENHTIM_InitStruct.ENHTIM_LatchTriggerPad      = INPUT_PIN;

/*  Enable ENHTIM IRQ  */
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = ENHTIMER_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

ENHTIM_ClearINTPendingBit(ENHTIMER_NUM, ENHTIM_INT_TIM);
ENHTIM_INTConfig(ENHTIMER_NUM, ENHTIM_INT_TIM, ENABLE);

ENHTIM_ClearINTPendingBit(ENHTIMER_NUM, ENHTIM_INT_LATCH_CNT_FIFO_FULL);
ENHTIM_INTConfig(ENHTIMER_NUM, ENHTIM_INT_LATCH_CNT_FIFO_FULL, ENABLE);

ENHTIM_ClearINTPendingBit(ENHTIMER_NUM, ENHTIM_INT_LATCH_CNT_FIFO_THD);
ENHTIM_INTConfig(ENHTIMER_NUM, ENHTIM_INT_LATCH_CNT_FIFO_THD, ENABLE);

ENHTIM_Cmd(ENHTIMER_NUM, ENABLE);

功能实现

ENHTIM定时时间到或者GPIO输入引脚上升沿触发次数达到FIFO设定阈值,触发中断,进入中断处理函数 Enhanced_Timer0_Handler

  1. 判断中断状态位。

  2. 若为ENHTIM_INT_TIM,即ENHTIM定时中断,打印中断状态,清除中断标志位。

  3. 若为ENHTIM_INT_LATCH_CNT_FIFO_THD,即GPIO上升沿触发次数达到设定FIFO阈值,产生中断,打印中断信息,打印及FIFO中数据数量和计数器当前数值。

void Enhanced_Timer0_Handler()
{
    if (ENHTIM_GetINTStatus(ENH_TIM0, ENHTIM_INT_TIM))
    {
        APP_PRINT_INFO0("ENH_TIM0 ENHTIM_INT_TIM\r\n");
        ENHTIM_ClearINTPendingBit(ENH_TIM0, ENHTIM_INT_TIM);
    }
    if (ENHTIM_GetINTStatus(ENH_TIM0, ENHTIM_INT_LATCH_CNT_FIFO_FULL))
    {
        APP_PRINT_INFO0("ENH_TIM0 ENHTIM_INT_LATCH_CNT2_FIFO_FULL\r\n");
        ENHTIM_ClearINTPendingBit(ENH_TIM0, ENHTIM_INT_LATCH_CNT_FIFO_FULL);
    }
    if (ENHTIM_GetINTStatus(ENH_TIM0, ENHTIM_INT_LATCH_CNT_FIFO_THD))
    {
        APP_PRINT_INFO0("ENH_TIM0 ENHTIM_INT_LATCH_CNT2_FIFO_THD\r\n");
        ENHTIM_INTConfig(ENHTIMER_NUM, ENHTIM_INT_LATCH_CNT_FIFO_THD, DISABLE);
        uint8_t length = ENHTIM_GetLatchCountFIFOLength(ENH_TIM0);
        uint32_t data[4] = {0};
        ENHTIM_ReadLatchCountFIFO(ENH_TIM0, data, length);
        /* Only for debugging, removed in actual application. */
        APP_PRINT_INFO1("ENH_TIM0 fifo length = %d\r\n", length);
        for (uint8_t i = 0; i < length; i++)
        {
            /* Only for debugging, removed in actual application. */
            APP_PRINT_INFO2("ENH_TIM0 data[%d] = 0x%x\r\n", i, data[i]);
        }

        ENHTIM_ClearINTPendingBit(ENH_TIM0, ENHTIM_INT_LATCH_CNT_FIFO_THD);
        ENHTIM_INTConfig(ENH_TIM0, ENHTIM_INT_LATCH_CNT_FIFO_THD, ENABLE);
    }
}