Skip to main content
Associate
Nov 7, 2024 9:29 PM UTC
Question

DMA for Quadtrature Encoder not working (stm32g0x1)

I am working with a Quadrature Encoder that uses TIM2 (encoder mode). The encoder mode automatically captures an increase in the register htim2.Instance->CNT

I am trying to use DMA to fill a buffer with the CNT values however it does not seem to work. 

I would really appreciate any help!

My relevant code: 

 

initializations: 
 TIM_HandleTypeDef htim2;
 TIM_HandleTypeDef htim3;
 TIM_HandleTypeDef htim16;
 DMA_HandleTypeDef hdma_tim16_com;

 int32_t count_buf[COUNT_BUF_CAPACITY];

main: 

 MX_DMA_Init();
 MX_TIM2_Init();
 MX_TIM16_Init();

 HAL_TIM_Base_Start_IT(&htim16);
 HAL_TIM_Encoder_Start_IT(&htim2, TIM_CHANNEL_ALL);

 HAL_DMA_Start(&hdma_tim16_com,&htim2.Instance->CNT,count_buf,4);


static void MX_DMA_Init(void)
{

 /* DMA controller clock enable */
 __HAL_RCC_DMA2_CLK_ENABLE();

 /* DMA interrupt init */
 /* DMA1_Ch4_7_DMA2_Ch1_5_DMAMUX1_OVR_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA1_Ch4_7_DMA2_Ch1_5_DMAMUX1_OVR_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(DMA1_Ch4_7_DMA2_Ch1_5_DMAMUX1_OVR_IRQn);

}

static void MX_TIM16_Init(void)
{

 /* USER CODE BEGIN TIM16_Init 0 */

 /* USER CODE END TIM16_Init 0 */

 /* USER CODE BEGIN TIM16_Init 1 */

 /* USER CODE END TIM16_Init 1 */
 htim16.Instance = TIM16;
 htim16.Init.Prescaler = 63;
 htim16.Init.CounterMode = TIM_COUNTERMODE_UP;
 htim16.Init.Period = 99;
 htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 htim16.Init.RepetitionCounter = 0;
 htim16.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
 if (HAL_TIM_Base_Init(&htim16) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN TIM16_Init 2 */

 /* USER CODE END TIM16_Init 2 */

}

static void MX_TIM2_Init(void)
{

 /* USER CODE BEGIN TIM2_Init 0 */

 /* USER CODE END TIM2_Init 0 */

 TIM_Encoder_InitTypeDef sConfig = {0};
 TIM_MasterConfigTypeDef sMasterConfig = {0};

 /* USER CODE BEGIN TIM2_Init 1 */

 /* USER CODE END TIM2_Init 1 */
 htim2.Instance = TIM2;
 htim2.Init.Prescaler = 0;
 htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
 htim2.Init.Period = 4294967295;
 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
 sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
 sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
 sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
 sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
 sConfig.IC1Filter = 0;
 sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
 sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
 sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
 sConfig.IC2Filter = 0;
 if (HAL_TIM_Encoder_Init(&htim2, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
 if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN TIM2_Init 2 */

 /* USER CODE END TIM2_Init 2 */

}

 

 

This topic has been closed for replies.

3 replies

Uwe Bonnes
Chief
Nov 8, 2024 11:01 AM UTC

What is your intention? What use is information that the encoder has changed? Normally you sample the encoder when you need to process the actual value and also at a slow rate so no overflow happens.
Otherwise, not looking at your code:
- What event should trigger the DMA transfer from encoder counter to the dma memory?

shadjAuthor
Associate
Nov 8, 2024 12:40 PM UTC

Thank you for the reply. 

My intention is to update a buffer, from the CNT register using DMA. It should not occur based on a specific event, it should always read the value of the register.

Uwe Bonnes
Chief
Nov 8, 2024 1:45 PM UTC

You need some event to trigger a DMA transaction. What about setting up an EXTI interrupt on one of the decoder pins and transfer in the interrupt routine?