cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 while loop problem (using ADC DMA)

Maxime Benchemoul
Associate II
Posted on February 20, 2018 at 16:22

Hi everyone,

I'm trying to get working a very simple program on my Nucleo STM32L452RE-P but I have some unexpected problems...

I'm using CubeMX with Atollic TrueStudio V9.0. I configured the ADC in DMA mode and also the DAC in DMA mode. The aim: read values on the ADC and write them on the DAC.

Basically, my main.c looks like:

#define ADC1_Buffer_Size ((uint32_t) 8192)

#define DAC1_Buffer_Size ((uint32_t) 8192)

uint32_t ADC1_Buffer[ADC1_Buffer_Size];

uint8_t flag_adc_complete = 0;

uint8_t flag_adc_calibration = 0;

uint8_t flag_init = 0;

uint8_t flag_while = 0;

uint8_t flag_callback = 0;

uint8_t incr = 0;

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_DMA_Init(void);

static void MX_ADC1_Init(void);

static void MX_DAC1_Init(void);

static void MX_TIM6_Init(void);

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){

   flag_callback = 1;

   flag_adc_complete = 1;

   HAL_ADC_Stop_DMA(&hadc1);

   HAL_TIM_Base_Start(&htim6);

   HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);

   HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, ADC1_Buffer, ADC1_Buffer_Size, DAC_ALIGN_12B_R);

   flag_callback = 0;

}

int main(void)

{

   flag_init = 1;

   HAL_Init();

   SystemClock_Config();

   MX_GPIO_Init();

   MX_DMA_Init();

   MX_ADC1_Init();

   MX_DAC1_Init();

   MX_TIM6_Init();

   flag_adc_calibration = 1;

   if(HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK){

      Error_Handler();

   }

   flag_adc_calibration = 0;

   if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC1_Buffer, ADC1_Buffer_Size) != HAL_OK){

      Error_Handler();

   }

   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);

   HAL_Delay(1000);

   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);

   flag_init = 0;

   while (1)

   {

      flag_while = 1;

      if(flag_adc_complete == 1){

         while(incr < 255){

            incr++;

         }

         incr = 0;

         flag_adc_complete = 0;

      }

      flag_while = 0;

   }

}

At the beginning, I tried this program without anything in the while loop and the program worked well: after filling ADC1_Buffer once, the values were written on the DAC continuously. I checked it on an oscilloscope.

Then I wanted to read the buffer using STM Studio. I add a for loop inside the main while(1) loop to read each item of the buffer through a temporary variable but it didn't work. So I removed the code because I thought I was doing it wrong...

Then I add this small counter which increment the incr variable up to 255, only to debug the program.

I expected to visualize this counter on STM Studio and I realized that my program didn't go in the main while(1) loop.

Actually, I got the impression that the program acts really weirdly. As you can see I put many flags to check the evolution of the program on STM Studio. 

flag_init is set to 1 when I reset the board and is never reset.

flag_adc_complete is set to 1 quickly (too quickly...) after reseting the board and is never reset.

flag_adc_calibration and flag_callback are never set to 1.

flag_while is unadressed.

incr is not incremented.

However the LED (GPIOB, PIN13 set during 1000ms before the while) works well...

If someone can help me, it could be very nice. I'm going mad, it should not be as complicated...

Do you think it could be a problem with STM Studio? In CubeMX I activated the debug 'trace asynchronous sw'. In STM Studio I selected ST-Link SWD and I display all data and acquire only variables used by visible viewers. All the other settings are let by default.

Thank you very much!!

Maxime

3 REPLIES 3
AvaTar
Lead
Posted on February 20, 2018 at 16:42

Not gonna wade through Cube code, that gives me a headache.

uint8_t flag_adc_complete = 0;

uint8_t flag_adc_calibration = 0;

uint8_t flag_init = 0;

...

When using variables (flags) in multiple places and especially from asynchronous code (interrupts), use

volatile

.

Take care that you don't DMA into the stack.

For simplicity (and without Cube), I would have setup the ADC in continuous mode with DMA, and a timer with interrupt, where I push the results to the DAC.

Posted on February 20, 2018 at 17:08

Thank you for your reply.

I note the advice with the variables!

In fact I don't really need of the DAC; that was only to check if the ADC works well with high frequency signals (400kHz in my case) with very low amplitudes. In the future, I will only need to sample data during a short period of time once and do my stuffs with the collected data. So I think I won't modify this part of the code since it works for the moment.

I moved the DAC/Timer start lines from the HAL_ADC_ConvCpltCallback function and I put them inside the while(1) loop, right after testing the variable flag_adc_complete.  Now the program goes well inside the main while(1) loop and the DAC is still working. Weird, isn't?

However, I still can't see the incr variable be incremented and the flag_callback variable is not moving in STM Studio. Maybe STM Studio is to slow in regards to the MCU? 

Maxime

AvaTar
Lead
Posted on February 20, 2018 at 19:42

Now the program goes well inside the main while(1) loop and the DAC is still working. Weird, isn't?

The DAC, once configured, holds the last value until you write a new one.

BTW, 400kHz is usually too fast for ST's DAC implementation. You can write that fast to DAC->DR, but the converter logic can't follow.

However, I still can't see the incr variable be incremented and the flag_callback variable is not moving in STM Studio. Maybe STM Studio is to slow in regards to the MCU? 

The while(1) -  loop is currently void of any deeper meaning, I guess it's where you main processing loop is supposed to go.

But do you honestly expect to see a variable incrementing in such a tight loop in real time ?

The execution takes a few microseconds, if the compiler has not optimized it out at all.

In general, debugger view update rates are not synchronized with execution, most debuggers do not update watches at all during run.

And your eyes could never follow that fast.

If you talking about single-step, see the comment about optimization above.

Use the volatile modifier again if you want to see it.