Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

cpu/stm32{f0, g0, c0}: Fix ADC #21222

Open
crasbe opened this issue Feb 18, 2025 · 0 comments · May be fixed by #21230
Open

cpu/stm32{f0, g0, c0}: Fix ADC #21222

crasbe opened this issue Feb 18, 2025 · 0 comments · May be fixed by #21230

Comments

@crasbe
Copy link
Contributor

crasbe commented Feb 18, 2025

Description

Today I received multiple Nucleo boards for testing the changes made in #20971. Similar to issue #21011, the ADC resolution is not updated and always stays at 12-bits.

Again, similar to the L0/L1 issue, the ADC is initialized incorrectly. The resolution in ADC1->CFGR1 (among other registers) is only to be set when the ADC is disabled ADEN = 0. This is violated in the adc_init function, where the ADC is enabled after the calibration sequence and the resolution is set in adc_sample.
A cause for this might be described in the errata of the STM32G071 [2]:

Writing ADC_CFGR1 register while ADEN bit is set resets RES[1:0] bitfield

Description

Modifying the ADC_CFGR1 register while ADC is enabled (ADEN set in ADC_CR) resets RES[1:0] to 00
whatever the bitfield previous value.

Workaround

Apply the following sequence:

  1. Set ADDIS to disable the ADC, and wait until ADEN is cleared.
  2. Program the ADC_CFGR1 register according to the application requirements.
  3. Set ADEN bit.

Moving the ADC enable to the adc_sample function revealed another issue though. When the ADC is enabled, the calibration will not actually start, only the first calibration is actually executed.

This is the relevant code part:

#if defined(ADC_CR_ADVREGEN)
/* calibrate ADC, per RM0454 section 14.3.3 */
/* 1. ensure ADEN=0, ADVREGEN=1, DMAEN=0 */
ADC1->CR |= ADC_CR_ADVREGEN;
ADC1->CR &= ~(ADC_CR_ADCAL | ADC_CR_ADEN );
ADC1->CFGR1 &= ~(ADC_CFGR1_DMAEN);
/* 2. Set ADCAL=1 */
ADC1->CR |= ADC_CR_ADCAL;
/* 3. Wait for ADCAL=0 (or EOCAL=1) */
while ((ADC1->ISR & ADC_ISR_EOCAL)) {}
#endif
/* enable device */
ADC1->CR = ADC_CR_ADEN;

If you actually do fix that, another problem occurs: On the second calibration run, the ADC_CR_ADCAL bit goes high immediately after the calibration was done. At least that's the case with the STM32C071R8 I'm working with.
That is apparently caused by the missing delay between enabling the voltage regulator with the ADC_CR_ADVREGEN flag and the start of the calibration process. This is explicitly required by the reference manual and t_ADCVREG_STUP = 20us for the STM32G071 [1].

Also, when I dug through the reference manual, I noticed that the STM32G071 requires a different calibration procedure. Apparently there is some issue with the calibration and it is recommended to perform eight calibration rounds and calculate an average.

Furthermore, the STM32C0 requires the calibration result to be written back to the calibration register after incrementing it by one. This is different to the STM32F0 and to the STM32G0, however I'm not sure if the STM32G0 doesn't require writing back the calibration result as well.

I have rewritten most of the adc_f0_g0_c0.c file and will prepare a PR shortly. This is just a documentation of the journey, so that I don't have to write it all down in the PR 😅.

Steps to reproduce the issue

I can't really describe each step to reproduce the issues described above.

However I think it would be really a good idea to add the changes to the tests/periph/adc program I described in #21011. Apparently nobody really tested the different resolution settings for the STM32 ADCs prior to merging, which is a bit unfortunate.

Versions

This happens with the latest master.

Links

[1] https://www.st.com/resource/en/datasheet/stm32g071c8.pdf p. 86
[2] https://www.st.com/resource/en/errata_sheet/es0418-stm32g071x8xb-device-errata-stmicroelectronics.pdf p. 2.6.2

@crasbe crasbe changed the title cpu/stm32{f0, g0, c0}: Avoid multiple ADC calibrations cpu/stm32{f0, g0, c0}: Fix ADC Feb 18, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant