STM32 PWM DMA работает правильно, только если я повторно инициализирую каждый раз при передаче, в противном случае отбрасывает первые несколько импульсов - PullRequest
2 голосов
/ 04 августа 2020

Как сказано в заголовке, если я не включу вызов HAL_DMA_Init(&hdma_tim2_ch1) в WS2812_DMA_Stop, моя первая передача будет работать нормально, но во всех последующих передачах отсутствуют первые (1-4, обычно 3) импульсы.

Настройки DMA:

    hdma_tim2_ch1.Instance = DMA1_Channel5;
    hdma_tim2_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim2_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim2_ch1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim2_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_tim2_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_tim2_ch1.Init.Mode = DMA_CIRCULAR;
    hdma_tim2_ch1.Init.Priority = DMA_PRIORITY_HIGH;

Полный код прилагается ниже:

void WS2812_DMA_Stop() {
    __HAL_TIM_DISABLE_DMA(&htim2, TIM_DMA_CC1);
    TIM_CCxChannelCmd(htim2.Instance, TIM_CHANNEL_1, TIM_CCx_DISABLE);
    __HAL_TIM_DISABLE(&htim2);
    HAL_DMA_Init(&hdma_tim2_ch1);
    ws2812_busy = 0;
}

void WS2812_DMA_ISR(uint8_t tc_flag) {
    if (ws2812_current_led < WS2812_NUM_LEDS) {
        if (tc_flag) {
            WS2812_fill_buffer(ws2812_current_led, &ws2812_dma_buffer[WS2812_DMA_LED_SIZE]);
        } else {
            WS2812_fill_buffer(ws2812_current_led, &ws2812_dma_buffer[0]);
        }
    } else if (ws2812_current_led < (WS2812_NUM_LEDS + WS2812_RESET_PULSE_LEN)) {
        if (tc_flag) {
            memset(&ws2812_dma_buffer[WS2812_DMA_LED_SIZE], 0, sizeof(ws2812_dma_buffer[0]) * WS2812_DMA_LED_SIZE);
        } else {
            memset(&ws2812_dma_buffer[0], 0, sizeof(ws2812_dma_buffer[0]) * WS2812_DMA_LED_SIZE);
        }
    } else {
        WS2812_DMA_Stop();
    }
    ws2812_current_led++;
}

void WS2812_DMA_HT(DMA_HandleTypeDef *hdma) {
    WS2812_DMA_ISR(0);
}

void WS2812_DMA_TC(DMA_HandleTypeDef *hdma) {
    WS2812_DMA_ISR(1);
}

void WS2812_DMA_Error(DMA_HandleTypeDef *hdma) {
    _Error_Handler(__FILE__, __LINE__);
}

void WS2812_DMA_Start() {
    ws2812_busy = 1;
    for (ws2812_current_led = 0; ws2812_current_led < WS2812_DMA_NUM_LEDS; ws2812_current_led++) {
        WS2812_fill_buffer(ws2812_current_led, &ws2812_dma_buffer[ws2812_current_led * WS2812_DMA_LED_SIZE]);
    }
    htim2.hdma[TIM_DMA_ID_CC1]->XferCpltCallback = WS2812_DMA_TC;
    htim2.hdma[TIM_DMA_ID_CC1]->XferHalfCpltCallback = WS2812_DMA_HT;
    htim2.hdma[TIM_DMA_ID_CC1]->XferErrorCallback = WS2812_DMA_Error;
    HAL_DMA_Start_IT(htim2.hdma[TIM_DMA_ID_CC1], (uint32_t)(&ws2812_dma_buffer[0]), (uint32_t)(&(htim2.Instance->CCR1)), WS2812_DMA_BUF_LEN);
    __HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_CC1);
    TIM_CCxChannelCmd(htim2.Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
    __HAL_TIM_ENABLE(&htim2);
}

1 Ответ

0 голосов
/ 08 августа 2020

Ну, все еще не уверен на 100%, почему, но похоже, что ключевой строкой из HAL_DMA_Init является hdma->State = HAL_DMA_STATE_READY;. Замена вызова Init только этой строкой также решает проблему.

...