0
\$\begingroup\$

I'm currently trying to adapt the example project TIM_DMA of the F769I_EVAL to the STM32F746G discovery board. I'm quite new to STM32 and this might be an obvious error.

The code creates a timer and configures it with DMA.
I changed it to use TIM2 on pin PB_8 and to use the DMA2 (Stream 0) instead of DMA1 (I've read somewhere in the documentation that DMA1 is mostly for memory-to-memory)

Generating the PWM signal works, but it stays at the first value (75% duty cycle). I don't know why that's the case.

My config is

#define TIMx                             TIM4
#define TIMx_CLK_ENABLE                  __HAL_RCC_TIM4_CLK_ENABLE
#define DMAx_CLK_ENABLE                  __HAL_RCC_DMA2_CLK_ENABLE
#define TIMx_CHANNEL3_GPIO_CLK_ENABLE    __HAL_RCC_GPIOB_CLK_ENABLE
#define TIMx_GPIO_CHANNEL3_PORT          GPIOB
#define GPIO_PIN_CHANNEL3                GPIO_PIN_8
#define GPIO_AF_TIMx                     GPIO_AF2_TIM4
#define TIMx_CC3_DMA_INST                DMA2_Stream0
#define TIMx_DMA_IRQn                    DMA2_Stream0_IRQn
#define TIMx_DMA_IRQHandler              DMA2_Stream0_IRQHandler

my main function

int main(void) {
    CPU_CACHE_Enable();
    HAL_Init();
    SystemClock_Config();
    BSP_LED_Init(LED1);

    uwTimerPeriod = (uint32_t)(((SystemCoreClock/2) / 17570) - 1);
    aCCValue_Buffer[0] = (uint32_t)(((uint32_t) 75 * (uwTimerPeriod - 1)) / 100);
    aCCValue_Buffer[1] = (uint32_t)(((uint32_t) 50 * (uwTimerPeriod - 1)) / 100);
    aCCValue_Buffer[2] = (uint32_t)(((uint32_t) 25 * (uwTimerPeriod - 1)) / 100);

    /*-1- Configure the TIM peripheral */
    TimHandle.Instance = TIMx;
    TimHandle.Init.Period            = uwTimerPeriod;
    TimHandle.Init.RepetitionCounter = 3;
    TimHandle.Init.Prescaler         = 0;
    TimHandle.Init.ClockDivision     = 0;
    TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK) {
        Error_Handler();
    }

    /*-2- Configure the PWM channel 3 */
    sConfig.OCMode       = TIM_OCMODE_PWM1;
    sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
    sConfig.Pulse        = aCCValue_Buffer[0];
    sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
    sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
    sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;
    sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_3) != HAL_OK) {
        Error_Handler();
    }

    /*-3- Start PWM signal generation in DMA mode */
    if (HAL_TIM_PWM_Start_DMA(&TimHandle, TIM_CHANNEL_3, aCCValue_Buffer, 3) != HAL_OK) {
        Error_Handler();
    }

    while (1) {
    }
}

the interrupt function

void TIMx_DMA_IRQHandler(void) {
    HAL_DMA_IRQHandler(TimHandle.hdma[TIM_DMA_ID_CC3]);
}

and the PWM MSP initialization function

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) {
    GPIO_InitTypeDef   GPIO_InitStruct;
    static DMA_HandleTypeDef  hdma_tim;

    /*-1- Enable peripherals and GPIO Clocks */
    TIMx_CLK_ENABLE();
    TIMx_CHANNEL3_GPIO_CLK_ENABLE();
    DMAx_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_CHANNEL3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF_TIMx;
    HAL_GPIO_Init(TIMx_GPIO_CHANNEL3_PORT, &GPIO_InitStruct);

    hdma_tim.Init.Channel = DMA_CHANNEL_3;
    hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD ;
    hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD ;
    hdma_tim.Init.Mode = DMA_CIRCULAR;
    hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_tim.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;

    hdma_tim.Instance = TIMx_CC3_DMA_INST;

    __HAL_LINKDMA(htim, hdma[TIM_DMA_ID_CC3], hdma_tim);

    /* Initialize TIMx DMA handle */
    if(HAL_DMA_Init(htim->hdma[TIM_DMA_ID_CC3]) != HAL_OK) {
        Error_Handler();
    }

    /*-2- Configure the NVIC for DMA */
    HAL_NVIC_SetPriority(TIMx_DMA_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIMx_DMA_IRQn);
}

The output looks like this:

Saleae Output

What exactly am I missing? Won't the TIM4 work with the DMA2 or do I have to use specific Interrupt handlers?

\$\endgroup\$
  • 1
    \$\begingroup\$ Did you refer to the tables on p.226 of the ref manual when choosing the DMA stream & channel? I don't see any reference to TIM2 for DMA2/Stream0. It looks like TIM2 needs to be linked with one of the DMA1 streams. \$\endgroup\$ – brhans May 9 '18 at 14:52
  • \$\begingroup\$ @brhans thank you so much! i've changed it to DMA1 stream 7 channel 2 and it works :) \$\endgroup\$ – thomasguenzel May 9 '18 at 15:01
  • \$\begingroup\$ What is the DMA trigger? \$\endgroup\$ – P__J__ May 9 '18 at 23:03
  • \$\begingroup\$ BTW TIM2 has its own mechanism for it. it is called "the burst mode" \$\endgroup\$ – P__J__ May 10 '18 at 15:01
  • \$\begingroup\$ @PeterJ_01 I thought the DMA is triggered by the timer? What exactly is burst mode for? \$\endgroup\$ – thomasguenzel May 10 '18 at 16:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.