cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G0 TIM2 with DMA Burst Transfer (not working)

a34fheuak
Associate II

I have a STM32G071 nucleo and want to generate an arbitrary waveform on PA0 via TIM2-CH1.

I am using the HAL_TIM_DMABurst_MultiWriteStart API: it should do bursts of 3 writes to multiple registers (ARR and CCR1).

Problem is, the DMA only updates the ARR (instead of ARR + RCR + CCR1) and only once (instead of two bursts). If I change the base register to CCR1 it only updates the CCR1 once.

I see this, because I freeze the timer when the core is halted and I added breakpoints to HAL_TIM_PeriodElapsedHalfCpltCallback and HAL_TIM_PeriodElapsedCallback (and the output waveform is BS).

Normal or circular mode have the same effect.

This is the main code:

__HAL_DBGMCU_FREEZE_TIM2();
uint32_t buffer32b[6] = {10, 0, 30, 100, 0, 300};
HAL_StatusTypeDef result;
result = HAL_TIM_DMABurst_MultiWriteStart(&htim2, TIM_DMABASE_ARR, TIM_DMA_UPDATE, buffer32b, TIM_DMABURSTLENGTH_3TRANSFERS, 6);
result = HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);

All the registers I checked looked fine to me.

Could this be a hardware problem?

Full code is attached below (it only sets up the HSI for 64MHz operation and configures TIM2 and DMA accordingly and then starts the TIM-DMA operation):

#include "main.h"
 
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
DMA_HandleTypeDef hdma_tim2_up;
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM2_Init(void);
 
 
int main(void)
{
  HAL_Init();
 
  SystemClock_Config();
 
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM2_Init();
 
__HAL_DBGMCU_FREEZE_TIM2();
uint32_t buffer32b[6] = {10, 0, 30, 100, 0, 300};
HAL_StatusTypeDef result;
result = HAL_TIM_DMABurst_MultiWriteStart(&htim2, TIM_DMABASE_ARR, TIM_DMA_UPDATE, buffer32b, TIM_DMABURSTLENGTH_3TRANSFERS, 6);
result = HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
 
  while (1)
  {
  }
}
 
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
  RCC_OscInitStruct.PLL.PLLN = 8;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_TIM2_Init(void)
{
 
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
 
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 63;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 10000;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
 
  HAL_TIM_MspPostInit(&htim2);
}
 
static void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
 
}
 
static void MX_GPIO_Init(void)
{
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
 
}
 
void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}
 
 
 
 
void HAL_MspInit(void)
{
  __HAL_RCC_SYSCFG_CLK_ENABLE();
  __HAL_RCC_PWR_CLK_ENABLE();
 
  /* System interrupt init*/
 
  /** Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
  */
  HAL_SYSCFG_StrobeDBattpinsConfig(SYSCFG_CFGR1_UCPD1_STROBE | SYSCFG_CFGR1_UCPD2_STROBE);
 
}
 
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM2)
  {
    /* Peripheral clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();
 
    /* TIM2 DMA Init */
    /* TIM2_UP Init */
    hdma_tim2_up.Instance = DMA1_Channel1;
    hdma_tim2_up.Init.Request = DMA_REQUEST_TIM2_UP;
    hdma_tim2_up.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_tim2_up.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim2_up.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim2_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_tim2_up.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_tim2_up.Init.Mode = DMA_CIRCULAR;
    hdma_tim2_up.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_tim2_up) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_UPDATE],hdma_tim2_up);
  }
}
 
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(htim->Instance==TIM2)
  { 
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM2 GPIO Configuration
    PA0     ------> TIM2_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }
}

1 ACCEPTED SOLUTION

Accepted Solutions
a34fheuak
Associate II

Not watching the registers in the debugger (e.g. in half complete callback) is a good tip!

The error was that the DMA transfer direction was wrong (peripheral to memory instead of memory to peripheral).

View solution in original post

3 REPLIES 3

> All the registers I checked looked fine to me.

Show.

Btw. you don't observe the TIM registers in debugger, do you?

JW

a34fheuak
Associate II

Not watching the registers in the debugger (e.g. in half complete callback) is a good tip!

The error was that the DMA transfer direction was wrong (peripheral to memory instead of memory to peripheral).

Thanks for coming back with the solution.

Please select your post as Best so that the thread is marked as solved.

JW