ADC init bug with optimization >= O1 (STM32L4)
ADC channel is erroneously initialized as differential if optimization is O1 or higher (O2, O3).
- STM32CubeMX 4.26.1
- FW_L4_V1.12.0
- Create blank project for NUCLEO-L476RG
- PC5 in ADC1 IN14 Single-ended, Rank 1 640.5 Cycles, everything else default
- Project for SW4STM32
ADC Init looks fine:
sConfig.Channel = ADC_CHANNEL_14;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;Simple readout:
while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
printf("%lu\n", HAL_ADC_GetValue(&hadc1));
HAL_Delay(500);
}Everything ok.
Now if I change optimization to O1 or higher, I get wrong values. After a long debugging session, I found DIFSEL register != 0 which set the channel to differential. Setting DIFSEL to 0 in debugger solves the problem.
The code in stm32l4xx_hal_adc.c :2694 where this wrong value in DIFSEL is set (found with debugger, register value changes after this call):
LL_ADC_SetChannelSingleDiff(hadc->Instance, sConfig->Channel, sConfig->SingleDiff);I don't see a problem here. Code and variable values are the same with both optimizations, but with O0 there is no change to DIFSEL, with O1 DIFSEL gets changed.
What is the reason for this bug? I suspect something in the HAL library isn't marked volatile so the compiler "optimizes" something it shouldn't. Perhaps a look at the disassembly could help here, but I'm no expert here.
Bugs like these are really hard to find as the symptom are just wrong ADC values.
