cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4 ADC+DMA how to get an interrupt when the buffer is filled?

HBida
Associate III

HI, i am using STM32L476RG and need to acquire data at 1.5MSPS in a buffer, size 2048. Everything is working however i cant see how to get an interrupt once the buffer is filled.

I thought the TC flag could be used but when i check in the DMA interrupt i find this function : HAL_DMA_IRQHandler(AdcHandle.DMA_Handle); which it totally managed by the HAL, so i wonder how to get a flag or an interrupt once the buffer is fileld, because i will have to change the buffer in order to allow continuous acquisition while the filled buffer is processed with DSP instructions.

Thanks

14 REPLIES 14
HBida
Associate III

so, there is no double buffering in the STM32L4 DMA, contrary to F4 and other series. So i guess the only way is to do it by hand. I noticed that HAL_ADC_ConvCpltCallback(hadc); was only weakly defined and not actually used by the HAL, so i declared it in my main, and indeed it is called at TC.

So i crudely used it to stop DMA, set the other buffer and restart DMA (the GPIO toggle is for debug, the incremented tc flag is for cycles counting). Of course there is quite an overhead to do that, with a 1024 buffer it cost about 1400 cycles (26550 with DB, 25125 without DB) or 28uS (331uS vs 313uS) . so some samples are lost in the process (sampling rate is 1.334MSPS). If anyone has a better idea it will be much appreaciated.

N.B i dont understand why the HAL has to use extensively ISRs internally for continuous ADC acquisition via DMA, what is the point of having DMA if the MCU is overwhelmed by ISRs?

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc){
 
	HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
	tc+=1;
	HAL_ADC_Stop_DMA(&AdcHandle);
	if(!bfr){bfr=1; HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*) bfrA, 1024); }
	else{bfr=0; HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*) bfrB, 1024); }
}

HBida
Associate III

oh ok that makes sense, since then i found the callback i should use (HAL_ADC_ConvCpltCallback) and it works fine with it, but you are right, the HAL adds a lot of overhead. For now the first concern now is to improve the buffer switching, since there is no double buffering mecanism in the STM32L4 DMA engine i have to do it by hand and currently it costs 1400 cycle / 28uS. Also for some reason the SD card write speed is very low, in 4 bit mode with DMA when i write a 2048 byte buffer it takes 316107 Cycles / 3951 uS, which is ±0.5MB/S.

RMcCa
Senior II

Does the l4 have half and buffer full interrupts? It's the same thing as double buffering, just use a buffer that is twice the required size, that way the buffer half or full​ interrupt is telling you that you can start processing the data in either lower or upper half of the buffer. Voila! Double buffering!

And once again, don't use hal. You are declaring the wrong isr. If you want a quick & lean isr you need to use the very lowest level and set/clear register bits yourself. I've just reexplained the same thing like 3 times in this thread. At some point you need to think for yourself. It's called learning.​

HBida
Associate III

i am not so sure it is safe to access the same buffer as the DMA at the same time tho (even if it is not the samehalf). F4 serie (and others) have some specific DMA function for double buffering (one can provide two different buffers), if there is no difference between that and using the HC and TC flags with a single buffer then i wonder why they bothered to add such mecanism.

You are declaring the wrong isr

Not sure what you mean, HAL_ADC_ConvCpltCallback is defined weak and called from within ADC_DMAConvCplt, since it is not used by the HAL it is actually the callback for user (provided that ADC_DMAConvCplt is already used by the HAL). And indeed when declared it is called at the right time and does the job.

if I can actually transfer datas from first buffer half when the DMA is writing the second half, i then just use HAL_ADC_ConvHalfCpltCallback and dont switch buffers, no overhead, no samples lost.

To get rid of the HAL ISRs and use own ISR + direct register access one has to rewrite not only ISRs but the whole ADC+DMA implementation, because ADC, DMA and ISRs are tied together and a lot of things are configured / handled by the HAL. Here the problem was to get the callback with what is already in place, and the answer to that is : use HAL_ADC_ConvCpltCallback, quite simple. Using low level ISR may incidently adress the issue, but at the cost of reimplementing everything by hand, I dont see the need for that here.

RMcCa
Senior II

Ok.

Do whatever you want, but if you are interested in writing fast & efficient embedded code you are going about it the wrong way.

Over & out.​