GPIO Latch
该示例通过使用 ENHTIM,实现 GPIO 触发锁存器状态,并记录计数器计数值的功能。
P2_4 设定为 GPIO 输出引脚,设定 P2_4 引脚电平随时间变化不断翻转。
P2_2 设定为 GPIO 输入引脚,同时将该引脚设定为 ENHTIM 的计数触发引脚。
将 P2_2 与 P2_4 引脚连接,当 P2_2 电压发生上升沿变化时会触发计数。累计变化三次后,触发 ENHTIM 中断,在中断函数内打印三次触发时计数器数值。
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL8752H HDK |
RTL8752H EVB |
更多信息请参考 快速入门。
硬件连线
连接 P2_4(GPIO 输出)和 P2_2(GPIO 输入)。
编译和下载
该示例的工程路径如下:
Project file: board\evb\io_sample\TIM_ENHANCE\Latch_GPIO\mdk
Project file: board\evb\io_sample\TIM_ENHANCE\Latch_GPIO\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译 APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下 reset 按键,开始运行。
测试验证
当 P2_2 和 P2_4 引脚连接后,在 Debug Analyzer 工具上,会不断打印 GPIO 触发锁存时的计数器数值,计数值不断递增。
ENH_TIM0 ENHTIM_INT_LATCH_CNT2_FIFO_THD
ENH_TIM0 fifo length = 3
ENH_TIM0 data[0] = 0x2f5
ENH_TIM0 data[1] = 0x125c6c
ENH_TIM0 data[2] = 0x1e91a7
...
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\board\evb\io_sample\TIM_ENHANCE\Latch_GPIO
源码路径:
sdk\src\sample\io_sample\TIM_ENHANCE\Latch_GPIO
该工程的工程文件代码结构如下:
└── Project: latch_gpio
└── secure_only_app
└── include
├── app_define.h
└── rom_uuid.h
├── cmsis includes CMSIS header files and startup files
├── overlay_mgr.c
├── system_rtl876x.c
└── startup_rtl876x.s
├── lib includes all binary symbol files that user application is built on
├── rtl8752h_sdk.lib
├── gap_utils.lib
└── ROM.lib
├── peripheral includes all peripheral drivers and module code used by the application
├── rtl876x_rcc.c
├── rtl876x_pinmux.c
├── rtl876x_nvic.c
├── rtl876x_gpio.c
└── rtl876x_enh_tim.c
├── profile
└── app includes the ble_peripheral user application implementation
└── main.c
初始化
当 EVB 复位启动时,执行 main
函数,执行以下流程:
int main(void)
{
__enable_irq();
enhance_tim_demo();
while (1)
{
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
}
}
在 enhance_tim_demo
中,包含 PAD/PINMUX 设置,GPIO 和 ENHTIM 外设的初始化等流程。
void enhance_tim_demo(void)
{
board_gpio_enhtim_init();
driver_gpio_enhtim_init();
driver_enhance_timer_init();
/* GPIO output is only used to simulate the input signal, only for demo debugging. */
board_gpio_init();
driver_gpio_init();
...
}
board_gpio_enhtim_init
为 GPIO 输入相关的 PAD/PINMUX 设置,包含如下流程:
配置 PAD:设置引脚,PINMUX 模式,PowerOn,内部上拉,失能输出。
配置 PINMUX:配置引脚为 DWGPIO 功能。
void board_gpio_enhtim_init(void) { Pad_Config(GPIO_INPUT_PIN_0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH); Pinmux_Config(GPIO_INPUT_PIN_0, DWGPIO); }
board_gpio_init
为 GPIO 输出相关的 PAD/PINMUX 设置,包含如下流程:
配置 PAD:设置引脚,PINMUX 模式,PowerOn,内部上拉,输出高。
配置 PINMUX:配置引脚为 DWGPIO 功能。
void board_gpio_init(void) { Pad_Config(GPIO_OUTPUT_PIN_0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_HIGH); Pinmux_Config(GPIO_OUTPUT_PIN_0, DWGPIO); }
driver_gpio_enhtim_init
为 GPIO 输入外设的初始化,包含如下流程:
使能 RCC 时钟。
设置 GPIO 的引脚为输入模式。
void driver_gpio_enhtim_init(void) { /* Initialize GPIO peripheral */ RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_PIN_INPUT_0; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; GPIO_Init(&GPIO_InitStruct); GPIO_WriteBit(GPIO_PIN_OUTPUT_0, (BitAction)(1)); }
driver_gpio_init
为 GPIO 输出外设的初始化,包含如下流程:
使能 RCC 时钟。
设置 GPIO 的引脚为输出模式。
void driver_gpio_init(void) { /* Initialize GPIO peripheral */ RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_PIN_OUTPUT_0; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_Init(&GPIO_InitStruct); GPIO_WriteBit(GPIO_PIN_OUTPUT_0, (BitAction)(1)); }
driver_gpio_init
为 ENHTIM 外设的初始化,包含如下流程:
使能 RCC 时钟。
设置 ENHTIM 时钟一分频。
设置 ENHTIM 为自由运行模式。
设置 ENHTIM 启用 GPIO 触发锁存功能。
设置 GPIO 上升沿触发锁存,触发中断 FIFO 阈值为 3。
使能 GPIO 触发计时功能。
配置和使能 ENHTIM 的 IRQ 通道。
配置 ENHTIM 计时中断,FIFO 满中断和达到 FIFO 阈值中断。
使能 ENHTIM 外设。
void driver_enhance_timer_init(void) { RCC_PeriphClockCmd(APBPeriph_ENHTIMER, APBPeriph_ENHTIMER_CLOCK, ENABLE); ENHTIM_InitTypeDef ENHTIM_InitStruct; ENHTIM_StructInit(&ENHTIM_InitStruct); ENHTIM_InitStruct.ENHTIM_ClockDiv = ENHTIM_CLOCK_DIVIDER_1; ENHTIM_InitStruct.ENHTIM_Mode = ENHTIM_MODE_FreeRun; /* Only enhtim_ ENHTIM_LatchCountEn[2] latch triggered by GPIO. */ ENHTIM_InitStruct.ENHTIM_LatchCountEn[2] = ENHTIM_LATCH_COUNT_ENABLE; ENHTIM_InitStruct.ENHTIM_LatchCountTrigger[2] = ENHTIM_LATCH_TRIGGER_RISING_EDGE; ENHTIM_InitStruct.ENHTIM_LatchCount2Thd = 3; ENHTIM_InitStruct.ENHTIM_LatchTriggerPad = GPIO_INPUT_PIN_0; ENHTIM_InitStruct.ENHTIM_TimerGPIOTriggerEn = ENABLE; ENHTIM_Init(ENHTIMER_NUM, &ENHTIM_InitStruct); /* Enable TIMER 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_CNT2_FIFO_FULL); ENHTIM_INTConfig(ENHTIMER_NUM, ENHTIM_INT_LATCH_CNT2_FIFO_FULL, ENABLE); ENHTIM_ClearINTPendingBit(ENHTIMER_NUM, ENHTIM_INT_LATCH_CNT2_FIFO_THD); ENHTIM_INTConfig(ENHTIMER_NUM, ENHTIM_INT_LATCH_CNT2_FIFO_THD, ENABLE); ENHTIM_Cmd(ENHTIMER_NUM, ENABLE); }
功能实现
在主函数内循环执行
GPIO_WriteBit()
,将 GPIO 输出引脚 P2_4 循环输出高低电平。void enhance_tim_demo(void) { .. while (1) { /* Simulate GPIO trigger signal */ for (uint32_t i = 0; i < 100000; i++); GPIO_WriteBit(GPIO_PIN_OUTPUT_0, (BitAction)(1)); for (uint32_t i = 0; i < 100000; i++); GPIO_WriteBit(GPIO_PIN_OUTPUT_0, (BitAction)(0)); } }
将 P2_4(GPIO 输出)和 P2_2(GPIO 输入)引脚相连后,每次 P2_2 检测到 P2_4 输出上升沿时,触发 ENHTIM 的锁存计数功能。累计三次达到阈值时,触发
ENHTIM_INT_LATCH_CNT2_FIFO_THD
中断,进入中断处理函数Enhanced_Timer0_Handler
。读取 ENHTIM 锁存计数 FIFO 内的数据长度,读取锁存计数值并打印。
清除中断标志位,重新使能中断。
void Enhanced_Timer0_Handler() { ... if (ENHTIM_GetINTStatus(ENH_TIM0, ENHTIM_INT_LATCH_CNT2_FIFO_THD)) { APP_PRINT_INFO0("ENH_TIM0 ENHTIM_INT_LATCH_CNT2_FIFO_THD\r\n"); ENHTIM_INTConfig(ENHTIMER_NUM, ENHTIM_INT_LATCH_CNT2_FIFO_THD, DISABLE); uint8_t length = ENHTIM_GetLatchCount2FIFOLength(ENH_TIM0); uint32_t data[4] = {0}; ENHTIM_ReadLatchCount2FIFO(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]); } //add user code here ENHTIM_ClearINTPendingBit(ENH_TIM0, ENHTIM_INT_LATCH_CNT2_FIFO_THD); ENHTIM_INTConfig(ENH_TIM0, ENHTIM_INT_LATCH_CNT2_FIFO_THD, ENABLE); } }