cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L151c8t6: Stopping and Starting ADC with DMA with HAL functions screws up channel order when using tickless Idle of FreeRtos.

stst9180
Associate III

I use ADC with DMA in cirular scan mode to convert two audio-channels triggered by a timer.

This all works well with expected results and quality most of the time.

For power-saving reasons I have to change the clock tree in runtime. This may screw up channels as dma clock will not be continuous in this case. Therefore I tried to Stop and Start the ADC-DMA-Conversion with HAL functions whenever clock tree has changed.

But I realize that also when no clock tree changes are made. (disabled that code) The stopping and immediate starting of ADC-DMA conversion may lead to mixed up channels (so rank 0 being on pos 1 in mem and rank 1 being on pos 0). In my case this may lead to total malfunction of the device as audio channels are swapped.

However I even don't find a way to detect if that issue happened. There are no Error-IRQ's or something fired neither on DMA nor on ADC. All registers are looking the same as if there was no error.

The only dirty work-around I can imagine for now is to configure the corresponding adc-channels to an output to get two fixed values while starting the adc and first check if the values are in range. If this is not the case one can again restart the adc which would fix the issue with a good propability.

Within further digging in I realized that this only happens if there is a task with a longer delay and no other task running in FreeRTOS, so I belive that there is a relation to the "Tickless Idle" which puts the processor into stop mode via WFI when there is a bigger task delay.

And et voila: If I disable "Tickless Idle" in FreeRtos this issue does not occur.

Unfortunately we need this as we need the power saving here.

Also a complete re-initialization using HAL_ADC_Init and HAL_ADC_DeInit when starting/stopping does not solve the problem.

If already digged the community and google, there are issues of swapped channels but I don't find a bigger correlation to my problem.

So I'm currently out of ideas:

  1. What may lead to that issue
  2. How could that issue be detected to fix it by re-initializing the peripherals.

Best Regards

Pascal

6 REPLIES 6
stst9180
Associate III

I narrowed down the issue to a minimal project with following application code:

#include <main.h>
#include <adc.h>
#include <tim.h>
#include <cmsis_os.h>
#include <stdbool.h>
 
#define AUDIO_SAMPLES 80
#define AUDIO_CHANNELS 2
#define BUFFER_SIZE (AUDIO_SAMPLES * AUDIO_CHANNELS)
 
uint16_t adc_buffer[BUFFER_SIZE];
 
static void ConvCpltCallback(ADC_HandleTypeDef *adc) {
	for(int i = 0; i < AUDIO_SAMPLES;i++) {
		// 2nd channel should never have a bigger value
		if(adc_buffer[2*i + 1] > 20) {
			Error_Handler(); // when this happens, channels are swapped
		}
	}
}
 
static void ErrorCallback(ADC_HandleTypeDef *adc) {
	Error_Handler();
}
 
void ApplicationTask(void const * argument) {
 
	HAL_ADC_RegisterCallback(&hadc, HAL_ADC_CONVERSION_COMPLETE_CB_ID, ConvCpltCallback);
	HAL_ADC_RegisterCallback(&hadc, HAL_ADC_ERROR_CB_ID, ErrorCallback);
	HAL_TIM_Base_Start(&htim9);
 
	// configure adc pin to push-pull to see a defined level here
	GPIO_InitTypeDef  GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
 
 
	while(true) {
		HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_buffer, BUFFER_SIZE);
		osDelay(500);
		HAL_ADC_Stop_DMA(&hadc);
	}
}

 It also seems that it only appears if we go to WFI to fast after the ADC + DMA has started.

So with the following code the issue does not occur:

...		
HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_buffer, BUFFER_SIZE);
for(int i = 0; i<500;i++);
osDelay(500);
HAL_ADC_Stop_DMA(&hadc);
...

Lower values in the active-wait loop will make the issue occur.

stst9180
Associate III

This project will show the malicous behaviour.

I'll try to also move that project to an discovery board as soon as I received one.

Piranha
Chief II

If both ADC and DMA are restarted properly, the other thing, that can skip the channels, is ADC overrun. When that happens, the ADC has to stop and for a correct channel order the ADC and DMA have to be restarted.

stst9180
Associate III

Well, as one can see in the example code, I use the HAL to start the ADC + DMA where I suppose this is the correct way to do that. On the other hand I registered the error callback where I suppose it should be called whenever an overrun occurs. So both of that issues seem to be disproved. Nevertheless it may be that other errors do lead to an overrun which will not call that callback ?!

I did also not find any reason for this behavior in the silicon-errata.

Maybe someone (maybe of the st-guys) can approve the test-project leads to the explained behaviour. I'll also add another testproject with the 152 nucleo board used next week.

Best Regards Pascal

stst9180
Associate III

I now just got a Nucleo STM32L152 board and created a test project, which can be used without any external connection and will show that issue.

I would be very happy if s.o. may have a look at that.

Regards Pascal

Piranha
Chief II

> I use the HAL ... where I suppose this is the correct way to do that. ... where I suppose it should be called whenever an overrun occurs. So both of that issues seem to be disproved.

Post edited to adhere community guidelines.