cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f207 DMA+ADC , captures only one channel only once

Javier1
Principal

Hola, i have been succesfully using DMA+ADC in stm32f072/f103/f105.

ADC in Scan+Continuous mode. (15 channels enabled)

But now im trying to use stm32f207 (NUCLEO-f207zg) , the DMA works one time(first channel) and dies.

0693W00000GVufQQAT.png 

DMA interrupt IRQ is only triggered 2 times (mid transfer and transfer completed of the first adc channel)

0693W00000GVucvQAD.png 

What am i missing , what is different in stm32f207?

0693W00000GVui5QAD.png 

0693W00000GVuieQAD.png 

we dont need to firmware by ourselves, lets talk
1 ACCEPTED SOLUTION

Accepted Solutions

As @Bruno_ST​ pointed out here all this buzz happened because cubeMx tries to config the DMA before its clock is enabled.

0693W00000GWS5bQAH.pngI just changed the order of how DMA and ADC are initialiced and it works now.

0693W00000GWSDaQAP.png0693W00000GWSMmQAP.gif

we dont need to firmware by ourselves, lets talk

View solution in original post

10 REPLIES 10

Javier,

Look at the ADCx_CR2.DDS bit description in RM. I don't use CubeMX so you have to find how this maps there, I'd guess it is the DMA Continuous Requests tickbox.

JW

DMA would need to be in circular mode, so it restarts after TC

Double check DMA error/status.

Avoid blocking code in the interrupt. Toggle a GPIO, it is far less invasive and time consuming, especially with short buffers.

Check none of the call-back code stops the DMA/ADC

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TNish.2
Associate II

I had the same symptoms.

When I used TIM3 as an ADC trigger and enabled TIM3 global interrupts, I had the same symptoms as you.

At this time, disabling TIM3's global interrupt solved the problem.

From RM003 page 224

...

10.8.1 Using the DMA

Since converted regular channel values are stored into a unique data register, it is useful to

use DMA for conversion of more than one regular channel. This avoids the loss of the data

already stored in the ADC_DR register.

When the DMA mode is enabled (DMA bit set to 1 in the ADC_CR2 register), after each

conversion of a regular channel, a DMA request is generated. This allows the transfer of the

converted data from the ADC_DR register to the destination location selected by the

software.

Despite this, if data are lost (overrun), the OVR bit in the ADC_SR register is set and an

interrupt is generated (if the OVRIE enable bit is set). DMA transfers are then disabled and

DMA requests are no longer accepted. In this case, if a DMA request is made, the regular

conversion in progress is aborted and further regular triggers are ignored. It is then

necessary to clear the OVR flag and the DMAEN bit in the used DMA stream, and to reinitialize

both the DMA and the ADC to have the wanted converted channel data transferred

to the right memory location. Only then can the conversion be resumed and the data

transfer, enabled again. Injected channel conversions are not impacted by overrun errors.

When OVR = 1 in DMA mode, the DMA requests are blocked after the last valid data have

been transferred, which means that all the data transferred to the RAM can be considered

as valid.

At the end of the last DMA transfer (number of transfers configured in the DMA controller’s

DMA_SxNDTR register):

No new DMA request is issued to the DMA controller if the DDS bit is cleared to 0 in the

ADC_CR2 register (this avoids generating an overrun error). However the DMA bit is

not cleared by hardware. It must be written to 0, then to 1 to start a new transfer.

• Requests can continue to be generated if the DDS bit is set to 1. This allows

configuring the DMA in double-buffer circular mode.

To recover the ADC from OVR state when the DMA is used, follow the steps below:

1. Reinitialize the DMA (adjust destination address and NDTR counter)

2. Clear the ADC OVR bit in ADC_SR register

3. Trigger the ADC to start the conversion.

 ...

I am debugging that ADC1->CR2.DDS register but it appears to be set to 0 the whole time

we dont need to firmware by ourselves, lets talk

> DMA would need to be in circular mode, so it restarts after TC

it already is

>Avoid blocking code in the interrupt. Toggle a GPIO, it is far less invasive and time consuming, especially with short buffers.

the error was there before i placed the uart print code, but i took it out again just in case.

>Check none of the call-back code stops the DMA/ADC

So far all callbacks are default generated by cubeMX, ill check

we dont need to firmware by ourselves, lets talk

im trying different triggers ,even continuous mode (triggerless)

NVIC interrupts for the triggers are not enabled in any of my tests.

So note taken but it must be something else

we dont need to firmware by ourselves, lets talk
Javier1
Principal

I tried different trigger sources

HAL_TIM_Base_Start(&htim2);//TIMER2 Trigger out event
//HAL_TIM_Base_Start_IT(&htim2);//TIMER2 Trigger out event, the TIM2_IRQHandler is reached prediodically as expected
//HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);//TIMER2 Trigger out event
//HAL_TIM_OC_Start(&htim2, TIM_CHANNEL_2);//TIMER2 Trigger capture compare 2 event
  • They all produce the same result, ADC triggered only one time, so it doesnt look like a trigger problem.

  • Then i enabled ADC interruptions and to my surprise the ADC_IRQHandler is being reached periodically as expected, so it doesnt look like an ADC problem.

  • Im trying different unit casting just in case the DMA is badly configured.

The DMA is set to retrieve 16bits because ADC resolution is 12bits

0693W00000GWR72QAH.png 

//in main.c
/* USER CODE BEGIN PV */
uint16_t ADC_buffer[16];
....
  /* USER CODE BEGIN 2 */
HAL_ADC_Start_DMA(&hadc1, (uint16_t*) ADC_buffer, 16);
...

hdma_adc1->ErrorCode returns always 0

we dont need to firmware by ourselves, lets talk
  • ADC_DMAError() is never reached

  • following void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)

...

       /* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */

       if((hdma->Instance->CR & DMA_SxCR_CIRC) == RESET)

       {

         /* Disable the half transfer interrupt */

         hdma->Instance->CR &= ~(DMA_IT_HT);//this code is reached but my DMA mode IS CIRCULAR

       }

....

... ...

     /* Disable the transfer complete interrupt if the DMA mode is not CIRCULAR */

     else

     {

       if((hdma->Instance->CR & DMA_SxCR_CIRC) == RESET)

       {

         /* Disable the transfer complete interrupt */

         hdma->Instance->CR &= ~(DMA_IT_TC);//this code is also reached but my DMA mode IS CIRCULAR

.....

  • inside void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
/* ADC1 DMA Init */
    /* ADC1 Init */
    hdma_adc1.Instance = DMA2_Stream0;
    hdma_adc1.Init.Channel = DMA_CHANNEL_0;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc1.Init.Mode = DMA_CIRCULAR;//<----------------------------------------------------:D
    hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
    hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

  • Inside HAL_DMA_Init

0693W00000GWRfOQAX.png 

/* Write to DMA Stream CR register */
  hdma->Instance->CR = tmp;//  <---- hdma->Instance->CR  doesnt get tmp value for some reason, it remains 0

 I cannot change the value manually in the Debugger Expressions window.......

Something is preventing this memory to being written, something is preventing the init code to write the configurations in the DMA2 Stream0 registers.0693W00000GWRh5QAH.pngThat memory addr 0x40026410 happens to be where DMA2 Stream 0 peripheral is mapped, as expected in my cubeMX configuration.

0693W00000GWRjkQAH.png0693W00000GWRlIQAX.png 

I just opened a question about this https://community.st.com/s/question/0D53W00001B0menSAB/why-cant-i-write-into-mem-0x40026410

we dont need to firmware by ourselves, lets talk

As @Bruno_ST​ pointed out here all this buzz happened because cubeMx tries to config the DMA before its clock is enabled.

0693W00000GWS5bQAH.pngI just changed the order of how DMA and ADC are initialiced and it works now.

0693W00000GWSDaQAP.png0693W00000GWSMmQAP.gif

we dont need to firmware by ourselves, lets talk