请选择 进入手机版 | 继续访问电脑版
查看: 497|回复: 0

[原创] 使用 PIT 周期通过 DMA 读取 GPIO 状态

[复制链接]

该用户从未签到

691

主题

6349

帖子

0

超级版主

Rank: 8Rank: 8

积分
23124
最后登录
2025-2-13
发表于 2024-11-18 17:32:50 | 显示全部楼层 |阅读模式
本帖最后由 小恩GG 于 2024-11-18 17:36 编辑

使用 PIT 周期通过 DMA 读取GPIO 状态

在嵌入式系统开发中,在很多应用场景中,需要实时准确地获取GPIO 状态,对于系统的控制和监测至关重要。传统读取GPIO方式不仅占用CPU资源,效率也低。本文介绍的方案主要基于 MIMXRT1170-EVKB开发板 ,利用 PIT(PeriodicInterrupt Timer)周期触发,通过DMA(directmemory access)方式读取GPIO状态技术来实现这一目标。因为DMA工作时无需CPU的干预,可以在保证数据及时性的同时,极大减轻CPU 负担,提高系统稳定性和可靠性。
一、简介GPIO、PIT 和 DMA
i.MX RT跨界MCU集易用性和高性能处理功能于一身,是一款功能强大的微控制器,具备丰富的外设资源,i.MX RT系列提供多种型号,适用于消费电子、工业和汽车市场,同时提供高集成度和安全性,并具有低功耗。本文验证平台是i.MX RT系列i.MX RTMIMXRT1170-EVKB开发板实现。
Picture1.png

图1 方案逻辑流程图
(一)GPIO
GPIO(GeneralPurpose Input/Output) 的每个引脚都可以配置为输入或输出模式,并可通过相对应的寄存器进行读写操作。在本文介绍的应用中是读取特定引脚状态。
(二)PIT
PIT(PeriodicInterrupt Timer) 是周期定时器,开发者可以根据任务开发需求,预设周期时间产生定时中断。本文实验采用的是PIT产生的周期信号将触发DMA 传输,以便实现周期性地读取GPIO 状态。其他应用场景中可以周期读取ADC数值、周期触发通信(SPI、UART、I2C等)、周期采集气压\温湿度等传感器数值。
本文介绍方法是通过配置PIT 的计数周期,可以精确控制读取GPIO 状态的时间间隔。
需要注意的是PIT的计数周期一定大于DMA传输数据的时间。
(三)DMA
DMA(directmemory access) 允许在不经过CPU 干预的情况下,直接在内存和外设之间传输数据。对于读取GPIO 状态这一操作,利用DMA 可以将 GPIO数据寄存器的值直接传输到内存中的指定缓冲区,大大提高了数据传输效率。
二、验证步骤
(一)PIT 主要配置
1: void PIT_Init(PIT_Type *base, const pit_config_t *config)
PIT 模块进行初始化,设置PIT 的时钟源,合适的系统时钟分频值来确定PIT 的计数频率,确保定时器正常运行。
2:static inline void PIT_SetTimerPeriod(PIT_Type *base,pit_chnl_t channel, uint32_t count)
设置满足开发需求的配置PIT 的周期值。根据需要读取的GPIO 状态读取频率,计算并设置PIT 的计数值。
3:static inline voidPIT_EnableInterrupts(PIT_Type *base, pit_chnl_t channel, uint32_t mask)
使能 PIT 中断,并将中断服务程序与PIT 中断关联起来。当中断发生触发后续的DMA 操作。
4:static inline void PIT_StartTimer(PIT_Type *base,pit_chnl_t channel)
启动PIT周期定时器。
(二)DMA主要 配置
1:void EDMA_Init(DMA_Type *base, const edma_config_t *config)
初始化 DMA 控制器,设置DMA 的工作模式。
2:voidEDMA_PrepareTransfer(edma_transfer_config_t *config,
void *srcAddr,
uint32_t srcWidth,
void *destAddr,
uint32_t destWidth,
uint32_t bytesEachRequest,
uint32_t transferBytes,
edma_transfer_type_t transferType)
a.      DMA 的源地址设置为对应GPIO接口的数据寄存器的地址(GPIOdata register (DR))。DMA GPIO data register (DR)获取数据。
b.      DMA 的目标地址设置为内存中预先分配的缓冲区地址。这个缓冲区将用于存储读取到的GPIO 状态数据。
c.      DMA 的传输数据大小和数据宽度设置。根据GPIO 数据寄存器的宽度和一次传输的数据量来确定。因为MIMXRT170MCU的GPIO 数据寄存器DR是 32 位,每次读取一个32 位,即4字节长度的值,需要相应地设置好这些参数。
需要注意的是源地址是GPIO数据寄存器地址,数据宽度是32bit(4Bytes),数据地址和数据宽度一定是一致的,否则会报错。
d.   void EDMA_StartTransfer(edma_handle_t *handle)
使能 DMA 通道,并将其与PIT 中断触发源相关联。当PIT 产生中断时,触发DMA 传输。
(三)GPIO 配置
1voidGPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *Config)
设置需要读取状态的GPIO 引脚,配置为输入模式。根据开发板外部电路的电气特性,为保证输入引脚信号的可靠精确性,可能需要设置上拉或下拉电阻等配置。
注意:高速GPIO不支持DMA方式读取。
三、软件分析和数据处理
(一)软件分析
本方案实现最重要的一个接口函数是EDMA_PrepareTransfer函数。

Picture2.png

Picture3.png


Picture4.png

因为源地址是GPIODR数据寄存器是32位,因此目标地址缓冲Buffer定义的类型是无符号32位。每次搬运4字节,一共搬运EXAMPLE_DESTADDR_LENGTH*4字节,即获取16次GPIO状态。
GPIO DR数据寄存器获取到的32bit数据,对应当前这个GPIO的32个PIN引脚状态(前提是引脚配置为GPIO模式)。
Picture5.png
图2 DR寄存器
由上可知我们需要拆分具体GPIO对应的位,举例如下:
1:本验证程序读取的是MIMXRT1170-EVKB开发板SW7按键的状态,该GPIO是GPIO13第0引脚,对应GPIO13->DR寄存器第0位。
Picture6.png
2:假设读取的GPIO是GPIO9 第3引脚,那函数EDMA_PrepareTransfer第二个形参需要修改为&(GPIO9->DR),对应GPIO9->DR寄存器第3Bit。
Picture7.png
如果开发项目需求要求实现读取多个GPIO引脚状态,比较建议将引脚集中设计在同一个GPIO组中,这样软件实现更为高效便捷。
(二)数据处理
本文介绍的方案没有考虑DMA传输失败情况,实际应用中需要添加当检测到DMA传输失败错误时,需要取消当前DMA传输以及处理错误异常逻辑,并重新开始PIT触发DMA读取GPIO状态流程。
如果需要处理读取的GPIO状态数据逻辑耗时较长,或者其他原因需要占用目标地址缓存,可以考虑将DMA的目标地址设置的缓冲区设置成双缓存,即PingPong 缓冲区。这种方案可以保证其中一个缓冲区正在接收GPIO数据,令外一个缓冲区可以逻辑处理已接收GPIO数据,提高数据处理效率。
通过PIT 周期触发 DMA读取 GPIO 状态的方法,可以准确、高效获取外部GPIO信号信息。这种方案在需要实时监测大量GPIO 引脚状态的应用中具有很大的优势。可以极大减轻芯片CPU的负担,同时能够保证数据采集的及时性和Robust性,为嵌入式系统的可靠运行提供了有力支持。在实际应用中,需要根据具体的硬件和软件环境对PIT、DMA 和 GPIO 的配置参数进行调整和优化,以满足不同应用场景的要求。
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /2 下一条

Archiver|手机版|小黑屋|恩智浦技术社区

GMT+8, 2025-2-18 17:33 , Processed in 0.100138 second(s), 19 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表