PWM DMA到整个GPIO

PWM DMA to a whole GPIO

我有一个 STM32F4,我想对一个 GPIO 端口进行 PWM,该端口已经用掩码进行了或运算..

所以,也许我们想在 200khz 下 PWM 0b00100010 一段时间,但是,10khz 之后,我们现在想要 PWM 0b00010001...然后,10kHz 之后,我们想要 PWM同一 GPIO 上的一些其他掩码。

我的问题是,如何使用 DMA 执行此操作?我正在尝试触发一个 DMA 传输,它将所有位设置为上升沿,然后另一个 DMA 传输将在下降沿清除所有位。

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

我主要关心的问题之一是 CPU 时间,因为虽然我在上面的例子中提到了数百千赫兹,但我想让这个框架非常健壮,因为它不是会浪费 CPU 资源...这就是我喜欢 DMA 想法的原因,因为它是专用硬件,可以将这里的一个词无意识地提升到那里的一个词类型,并且 CPU 可以做其他事情,比如 PID 的紧缩数字或其他东西。

编辑 为清楚起见:我有一组 6 个值可以写入 GPIO。这些存储在数组中。 我想做的是设置一个 PWM 定时器,在 PWM 的正宽度期间设置 GPIO,然后我希望 GPIO 在低周期宽度期间设置为 0b00000000,如果 pwm. 所以,我要看什么时候是上升沿,赶紧写到gpio,再看什么时候是下降沿,就往gpio里写0。

PWM 0b00100010 是什么意思? PWM 是具有一定占空比的方波。使用 DMA 存档将非常困难,但您需要 table 具有已计算的值。例如,要获得 10% 比率的 2kHz PWM,您需要有 10 个样本,其中一个样本设置为位,九个样本为零。您将定时器配置为 20k / 秒触发 mem-to-mem(GPIO 必须以这种方式完成)循环模式下的 DMA 传输。在引脚上,您将有 2kHz 10% 的波。 PWM 分辨率将为 10%。如果你想让它成为 0.5%,你将需要 200 个样本 table 并且 DMA 每秒触发 400k 次。

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

有限解决方案 无 DMA

STM32F4 控制器有 12 个定时器,每个定时器最多有 4 个 PWM 通道,总共 32 个。其中一些可以同步启动,例如您可以让 TIM1 同时启动 TIM2TIM3TIM4TIM8。那是 20 个同步 PWM 输出。如果这还不够,您可以形成链,其中一个从定时器是另一个主定时器,但是要使所有定时器完全同步会非常棘手。如果几个时钟周期的偏移量是可以接受的,那就没那么棘手了。

STM32CubeF4 库示例项目部分有几个示例,您可以从中拼凑您的设置,查看 Projects/*_EVAL/Examples/TIM/*Synchro*

一般解

通用或高级定时器(除TIM6TIM7外的所有定时器)可以在计数器达到重载值(更新事件)时触发DMA传输 当计数器等于任何比较值时(capture/compare 事件)。

想法是让 DMA 在比较事件中将所需的位模式写入 BSRR 的低(设置)一半,并将相同的位写入 [=18= 的高(重置)一半] 在更新事件上。

但是有一个问题,DMA1根本无法访问连接GPIO寄存器的AHB总线(参见参考手册中的图1或图2)。因此我们必须使用 DMA2,这就给我们留下了高级计时器 TIM1TIM8。事情变得更加复杂,因为来自这些定时器的更新和比较事件导致的 DMA 请求最终在不同的 DMA 流上结束(参见 RM 中的 Table 43)。为了使其更简单,我们可以使用 DMA 2,Stream 6 或 Stream 2,Channel 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 个更多的引脚。也许第 3 频道也是。

您仍然可以使用 TIM2TIM3TIM4TIM5(每个都可以从属于 TIM1TIM8 ) 用于 16 个 PWM 输出,如我的 post 的第一部分所述。如果你能找到合适的主从设置,也许 TIM9TIM12 也可以,再增加 4 个。

这是一次切换 90 个引脚。注意总电流限制。