cancel
Showing results for 
Search instead for 
Did you mean: 

How to setup G431 DMA for peripheral to memory single transfer

BTrem.1
Senior II

Hello,

I have a G431 working with TIM8_CH1 and TIM8_CH3 generating DMA interrupts for a peripheral to memory transfer. I am not getting the correct number of transfers on TIM8_CH1 which is a capture compare triggered by an external input pin. TIM8_CH3 DMA is triggered by a software command and is occurring at the rate I expect (every software trigger).

The TIM8_CH1 is occurring at half the rate I expect. Could this be because I am operating in circular buffer mode with a buffer size of 2? I have PINC set to disabled and MINC enabled.

Does this configuration require 2 TIM8_CH1 events for the 2 buffer entries or does 1 TIM8 event cause the DMA to read the CCRx register twice?

I will try disabling circular mode and disabling both PINC and MINC. When I do this the reference manual says the DMA needs to stopped and re-started for the next transfer. Can I do this by clearing and setting the DMA_CCRx.EN register?

Thanks,

Brian

9 REPLIES 9

>The TIM8_CH1 is occurring at half the rate I expect. 

How do you know?

What is the input signal frequency? What is the other channel' input signal frequency? What is the system clock frequency? How is input capture set, single edge of both edges? Are there other DMAs running?

JW

TDK
Guru

> Does this configuration require 2 TIM8_CH1 events for the 2 buffer entries or does 1 TIM8 event cause the DMA to read the CCRx register twice?

One event causes one transfer.

If you feel a post has answered your question, please click "Accept as Solution".

The system clock frequency is 172MHz. The input to TIM8_CH1 is a 200Hz square wave triggering a capture. I can probe this signal and see it is 200Hz.

TIM8_CH3 is also set up to capture, though I use only a software trigger on that channel that is triggered at about 190Hz.

The capture channels are set up for rising edge positive polarity. 

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};
 
  /* USER CODE BEGIN TIM8_Init 1 */
 
  /* USER CODE END TIM8_Init 1 */
  htim8.Instance = TIM8;
  htim8.Init.Prescaler = 16;    	// 10.625MHz
  htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim8.Init.Period = 65535;		// 162.127Hz
  htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim8) != HAL_OK) // enables timer in RCC register // what is HAL_TIM_IC_Init
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;  // added 4/30
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim8, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_ConfigChannel(&htim8, &sConfigIC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }

Internal the code I have a process that generates a sine wave of about 190Hz in a fast interrupt routine that is executed every 45us. At the 45us update rate of the sine wave I convert it to a two-level signal by looking for the zero crossing using a "relay" non-linearity. At each transition (380Hz), I execute a software TIM8_CH3 capture from within the fast ISR. This signal is output to Debug_DAC1 and I can see a 190Hz square wave.

In the DMA1_Channel1 IRQ I toggle a flag that is output to Debug_DAC2. This signal is only 50Hz. The transitions are at 100Hz. This is a 10ms period which is half the rate of my 200Hz ref signal.

So it appears when the DMA is setup for Circular Buffer enabled with a buffer size of 2 the DMA occurs at half the rate.

Thanks for the feedback, this may explain what I am seeing.

I did try changing to non-circular mode but the code crashed so I am debugging that. From what I read in the Ref Man I think with a single transfer the DMA is then stopped and I need to re-start each time. My first attempt at this caused the crash.

For this would I use HAL_DMA_Start_IT followed by HAL_DMA_DeInit from within the DMA IRQ?

Your math is off here:

  htim8.Instance = TIM8;
  htim8.Init.Prescaler = 16;    	// 10.625MHz
  htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim8.Init.Period = 65535;		// 162.127Hz

If your timer clock is 172MHz, this would be a period of 172 MHz / (16 + 1) / (65535 + 1) = 154 Hz. Don't think that affects anything you've shown though. It's a bit hard to understand everything you've described going on.

If you feel a post has answered your question, please click "Accept as Solution".

The external 200Hz (f1) a reference signal, and the 190Hz (f2) is a feedback from a motor. I am using these as inputs to a phase-frequency detector (PFD). TIM8 as shown is set up as 162.1Hz but I believe I will need to make this slower than 100Hz. The PFD is a classic dual latch type. A rising edge on f1 causes a "pump-up" flag and a rising edge on f2 causes a "pump-down" flag. At each rising edge I get a DMA event that captures the TIM8 count and I look to see if PU and PD are both set. If they are I use the captured counts to compute the differences which is equivalent to a phase error. For this to work the period of TIM8 needs be be less than half the period of f1 or f2 so I avoid a phase rollover error. I have implemented something very similar in an FPGA deign and it works well.

Capturing rising edges of a 200Hz signal means 200 captures per second, if you set NDTR to 2, you have 100 Transfer Complete interrupts per second, if you toggle a pin in that interrupt, you have a 50Hz output.

> I did try changing to non-circular mode 

How would that change the rate of captures or DMA Transfer Complete interrupts?

JW

BTrem.1
Senior II

I am using NDTR set to BUFFER_SIZE. In circular mode I used BUFFER_SIZE== NDTR==2; In normal mode I have BUFFER_SIZE == NDTR == 1

I'm in the process of trying to determine how to stop/re-start the DMA in normal mode.

On the first entry into the DMA ISR for hdma_tim8_ch1 CNDTR is 0. I did try resetting CNDTR to 1 within the DMA ISR but it was not set. I also tried calling HAL_DMA_DeInit(&hdam_tim8_ch1) followed by HAL_Dma_Init(&hdma_tim8_ch1) within the DMA ISR but after returning from HAL_Dma_Init() the value of CNDTR is still 0.

Bottom line, in normal mode my ISR's are getting executed only once and I haven't figured out how to re-start the DMA,

p.s. I also just tried adding HAL_DMA_Start_IT() after the HAL_DMA_DeInit and HAL_DMA_Init() and it still only called the DMA ISR once :(

Brian