Arm PWM DMA到整个GPIO

Arm PWM DMA到整个GPIO,arm,stm32,gpio,dma,pwm,Arm,Stm32,Gpio,Dma,Pwm,我有一个STM32F4,我想用PWM调制一个GPIO端口,这个端口已经被屏蔽了 所以,也许我们想在200khz下对0b00100010进行一段时间的脉宽调制,但是,10khz之后,我们现在想对0b00010001进行脉宽调制……然后,10khz之后,我们想对同一GPIO上的其他掩模进行脉宽调制 我的问题是,如何使用DMA实现这一点?我试图触发一个DMA传输,将所有位设置在上升沿上,然后另一个DMA传输将清除下降沿上的所有位 我还没有找到一个好的方法来做到这一点(至少在CubeMX和我有限的C&S

我有一个STM32F4,我想用PWM调制一个GPIO端口,这个端口已经被屏蔽了

所以,也许我们想在200khz下对
0b00100010
进行一段时间的脉宽调制,但是,10khz之后,我们现在想对
0b00010001
进行脉宽调制……然后,10khz之后,我们想对同一GPIO上的其他掩模进行脉宽调制

我的问题是,如何使用DMA实现这一点?我试图触发一个DMA传输,将所有位设置在上升沿上,然后另一个DMA传输将清除下降沿上的所有位

我还没有找到一个好的方法来做到这一点(至少在CubeMX和我有限的C&STM32经验方面),因为看起来我只有机会在上升的边缘做一些事情

我主要关心的一个问题是CPU时间,因为尽管我在上面的例子中提到了数百千赫,但我想让这个框架非常健壮,因为它不会浪费CPU资源…这就是为什么我喜欢DMA的想法,因为它是专用的硬件,可以无意识地将这里的一个单词提升到那里的一个单词,CPU可以做其他事情,比如为PID或其他东西计算数字

编辑 为清晰起见:我有一组6个值,可以写入GPIO。它们存储在一个数组中。 我想做的是设置一个PWM定时器,在PWM的正宽度期间设置GPIO,然后我希望GPIO在PWM的低周期宽度期间设置为0b00000000。
因此,我需要看到上升沿何时为,快速写入gpio,然后看到下降沿何时为,并将0写入gpio

什么是PWM 0b00100010?PWM是一种具有一定占空比的方波。使用DMA进行归档将非常困难,但您需要具有已计算值的表。例如,要使2kHz PWM具有10%的比率,您将需要10个采样,一个设置位,九个设置位为零。您可以将计时器配置为20k/sec,以循环模式触发mem到mem(GPIO必须以这种方式完成)DMA传输。引脚上有2kHz的10%波。PWM分辨率将为10%。如果您想将其设置为0.5%,则需要200个样本表和每秒40万次DMA触发


在我看来,最好使用定时器和DMA向其加载新值(阅读参考手册中定时器文档中的突发DMA模式)

不使用DMA的有限解决方案

STM32F4控制器有12个定时器,每个定时器最多有4个PWM通道,总共32个。其中一些可以同步启动,例如,您可以同时启动
TIM1
启动
TIM2
TIM3
TIM4
TIM8
。这是20个同步PWM输出。如果这还不够的话,你可以在一个从定时器是另一个的主定时器的情况下形成链,但是要保持它们完全同步是相当困难的。如果几个时钟周期的偏移是可以接受的,那么就没有那么棘手了

STM32CubeF4库示例项目部分中有几个示例,您可以从中拼凑设置,查看
projects/*\u EVAL/examples/TIM/*Synchro*

通用解决方案

当计数器达到重新加载值(更新事件)和当计数器等于任何比较值(捕获/比较事件)时,通用或高级计时器(除
TIM6
TIM7
之外)可以触发DMA传输

其思想是让DMA在比较事件中将所需的位模式写入
BSRR
的低(设置)一半,在更新事件中将相同的位写入
BSRR
的高(重置)一半

但是存在一个问题,
DMA1
根本无法访问连接GPIO寄存器的AHB总线(参见参考手册中的图1或图2)。因此,我们必须使用
DMA2
,这就给我们留下了高级定时器
TIM1
TIM8
。事情变得更加复杂,因为来自这些定时器的更新和比较事件导致的DMA请求最终会出现在不同的DMA流上(参见RM中的表43)。为了使它更简单,我们可以使用DMA 2、流6或流2、通道0,它们组合了来自3个计时器通道的事件。我们可以将一个计时器通道上的比较寄存器设置为0,而不是使用更新事件

将所选计时器的DMA流设置为

  • 频道0
  • 单次传输(无突发)
  • 内存数据大小16位
  • 外围数据大小16位
  • 内存增量
  • 外围地址增量
  • 循环模式
  • 外设存储器
  • 外围流量控制器:我不知道,实验
  • 数据项数2
  • 外围地址
    GPIOx->BSRR
  • 内存地址指向输出位模式
  • 直接模式
  • 最后,启用通道
现在,设置计时器

  • 如果需要,设置预分频器并生成更新事件
  • 设置自动重新加载值以达到所需频率
  • 将通道1的比较值设置为0
  • 将通道2的比较值设置为所需的占空比
  • 为两个通道启用DMA请求
  • 在两个通道上启用比较输出
  • 启用计数器
这样,每个定时器可以控制16个引脚,如果在主从模式下同时使用这两个引脚,则可以控制32个引脚

要一次控制更多引脚(最多64个),请为通道4比较和计时器更新事件配置额外的DMA流,将数据项数设置为1,并使用
((uint32_t)&GPIOx->BSRR)+2
作为更新流的外围地址

通道2和4可用作常规PWM输出,为您提供更多的4个引脚。也许第三频道也是

您仍然可以使用
TIM2
TIM3
TIM4
,和
TIM5
(每个都可以从属于
TIM1