中断不起作用 - 使用 STM32 MCU 的 DMA 控制 PWM

问题描述 投票:0回答:1

我正在研究使用 LL 库控制输出 PWM 信号以操作 STM32 MCU 上的 SK6812RGBW LED。

为了提高操作 LED 的速度并使 MCu 免于计算,我需要设置 DMA 以将 PWM 值提供给关联的比较输出寄存器。

据我了解,我需要(广义上):

  1. 在比较输出 PWM 模式下启用定时器(本例中为 TIM2)
  2. 启用 DMA 并使用通道将其与定时器连接
  3. 使能GPIO输出PWM信号(调试用)

目前我的主要问题是我无法检测到DMA的Half和Full传输中断,这导致我相信DMA设置不正确。我已将此问题与 DMA 未正确发出信号或未正确初始化隔离。 PWM 和定时器设置已验证。

目前我更新 PWM 信号的方法是等待定时器自动重新加载,此时更新事件将向外设发出信号,向 DMA 发出新数据的信号。

我在下面展示了我的 DMA 和 TIM2 初始化代码。

有关我在这件事上可能遇到的问题的任何指导都会有所帮助。

下面是我认为针对我面临的这个问题的重要代码片段。

  1. DMA初始化功能
  2. TIM2初始化函数
static void MX_DMA_Init(void)
{

  /* Init with LL driver */
  /* DMA controller clock enable */
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);

  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
  NVIC_EnableIRQ(DMA1_Channel1_IRQn);

  LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
  LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1);
  LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);

}

我为 PWM 初始化 TIM2 并具有 DMA 相关参数的代码如下:

static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */
  static int autoreloadVal = 17000;

  aCCValue[0] = (uint32_t)(((uint32_t) 75 * (autoreloadVal - 1)) / 100);
  /* Compute compare value to generate a duty cycle at 50% */
  aCCValue[1] = (uint32_t)(((uint32_t) 50 * (autoreloadVal - 1)) / 100);
  /* Compute compare value to generate a duty cycle at 25% */
  aCCValue[2] = (uint32_t)(((uint32_t) 25 * (autoreloadVal - 1)) / 100);

  /* USER CODE END TIM2_Init 0 */

  LL_TIM_InitTypeDef TIM_InitStruct = {0};
  LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);

  /* TIM2 DMA Init */

  /* TIM2_CH3 Init */
  LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMA_REQUEST_8);

  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);

  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_HIGH);

  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);

  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);

  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);

  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD); //different sizes from example but consistent sizing between mem and peripheral

  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);

  LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_1, (uint32_t)&aCCValue, (uint32_t)&TIM2->CCR3, LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1));

  LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, CC_VALUE_NB);

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  TIM_InitStruct.Prescaler = 0;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = autoreloadVal-LL_TIM_IC_FILTER_FDIV1_N2;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(TIM2, &TIM_InitStruct);
  LL_TIM_EnableARRPreload(TIM2);
  LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_OC_EnablePreload(TIM2, LL_TIM_CHANNEL_CH3);
  TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
  TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
  TIM_OC_InitStruct.CompareValue = 5;
  TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
  LL_TIM_OC_Init(TIM2, LL_TIM_CHANNEL_CH3, &TIM_OC_InitStruct);
  LL_TIM_OC_EnableFast(TIM2, LL_TIM_CHANNEL_CH3);
  LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_UPDATE);
  LL_TIM_DisableMasterSlaveMode(TIM2);

  /* USER CODE BEGIN TIM2_Init 2 */



  LL_TIM_EnableDMAReq_UPDATE(TIM2);
  LL_TIM_EnableDMAReq_CC3(TIM2);
  LL_TIM_EnableCounter(TIM2);
  LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3);

  NVIC_SetPriority(TIM2_IRQn, 0);
  NVIC_EnableIRQ(TIM2_IRQn);
  LL_TIM_EnableIT_UPDATE(TIM2);
  /* USER CODE END TIM2_Init 2 */

  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
  /**TIM2 GPIO Configuration
  PA2   ------> TIM2_CH3
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_2;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM2_Init 3 */
  /* Force update generation */
   LL_TIM_GenerateEvent_UPDATE(TIM2);
  /* USER CODE END TIM2_Init 3 */

}
c embedded stm32 mcu
1个回答
0
投票

我的代码/假设有两个问题:

  1. 我在 DMA init 中启用 DMA,同时在 TIM2 init 中拥有 DMA 的配置代码。为了解决这个问题,我在寄存器的所有配置完成后放置了启用语句。在启用外设之前配置寄存器是一个很好的做法。
  2. 我发送请求的意图是定时器 (TIM2) 溢出,但要做到这一点,我需要使用不同的通道。见下图:

我选择了通道 1,而通道 2 给出了这种行为,因为它保存了 TIM2_UP 请求。通道 1 中的请求针对 CH3(我在其中输出 PWM 波)。如果 CH3 与 CH3 比较值交叉,则该通道会收到请求,当我通过

LL_TIM_EnableDMAReq_CC3 
启用适当的请求时,该请求起作用。

希望这对遇到类似问题的人有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.