我正在研究使用 LL 库控制输出 PWM 信号以操作 STM32 MCU 上的 SK6812RGBW LED。
为了提高操作 LED 的速度并使 MCu 免于计算,我需要设置 DMA 以将 PWM 值提供给关联的比较输出寄存器。
据我了解,我需要(广义上):
目前我的主要问题是我无法检测到DMA的Half和Full传输中断,这导致我相信DMA设置不正确。我已将此问题与 DMA 未正确发出信号或未正确初始化隔离。 PWM 和定时器设置已验证。
目前我更新 PWM 信号的方法是等待定时器自动重新加载,此时更新事件将向外设发出信号,向 DMA 发出新数据的信号。
我在下面展示了我的 DMA 和 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 */
}
我的代码/假设有两个问题:
我选择了通道 1,而通道 2 给出了这种行为,因为它保存了 TIM2_UP 请求。通道 1 中的请求针对 CH3(我在其中输出 PWM 波)。如果 CH3 与 CH3 比较值交叉,则该通道会收到请求,当我通过
LL_TIM_EnableDMAReq_CC3
启用适当的请求时,该请求起作用。
希望这对遇到类似问题的人有所帮助。