Skip to content

Conversation

@crasbe
Copy link
Contributor

@crasbe crasbe commented Feb 19, 2025

Contribution description

Most of the issue was described in #21222.
tl;dr: The initialization sequence was not entirely correct and at least for the STM32C0, changing the resolution did not work.

I rewrote the calibration and initialization sequence to follow the guides outlined in the reference manuals more closely.
It should be noted here that the reference manuals involve more steps and checks the newer the devices gets. The sequence for the F0 is very simple [1], for the G0 more complicated [2] and quite involved for the C0 [3].

Currently I don't have a STM32G0 nucleo, so the changes are untested for that family. Soon(ish) I'll buy one though.
It arrived and everything works as it should :)

Tested with:

Additional Tests:

  • Test the STM32G0 with periph_vbat enabled.

Testing procedure

I recommend to apply #21223 as well to check all resolutions at once. The updated test is now in master and I rebased this PR.
For some STM32C0xx boards, PR #20939 has to be applied with my proposed changes as well if you want to use the NUCLEO-C071 (not really convenient). The NUCLEO-C031 is supported by master already.
In both cases, PR #20971 has to be applied to set the correct values to the resolution register.

You can simply use the adc test BOARD=nucleo-f030r8 make flash term.

Before this PR with the STM32C071RB (Pin A0 connected to 3.3V, all samples have the same resolution):

main(): This is RIOT! (Version: 2024.10-devel-351-gbf1684-stm32c0-additions)

RIOT ADC peripheral driver test

This test will sample all available ADC lines once every 100ms with
6 to 16-bit resolution and print the sampled results to STDOUT.
Not all MCUs support all resolutions, unsupported resolutions
are printed as -1.

Successfully initialized ADC_LINE(0)
Successfully initialized ADC_LINE(1)
Successfully initialized ADC_LINE(2)
Successfully initialized ADC_LINE(3)
Successfully initialized ADC_LINE(4)
Successfully initialized ADC_LINE(5)
ADC_LINE(0): 1680 4095 4095 4094    -1    -1
ADC_LINE(1): 1563 1161  958  859    -1    -1
ADC_LINE(2): 1125 1016  959  937    -1    -1
ADC_LINE(3): 1032 970  934  919    -1    -1
ADC_LINE(4): 1024 962  928  914    -1    -1
ADC_LINE(5): 1082 1026 1005  985    -1    -1

ADC_LINE(0): 4095 4095 4095 4095    -1    -1
ADC_LINE(1): 1345 1038  905  840    -1    -1
ADC_LINE(2): 923 921  923  924    -1    -1
ADC_LINE(3): 885 900  907  908    -1    -1
ADC_LINE(4): 954 925  912  907    -1    -1
ADC_LINE(5): 961 967  969  972    -1    -1

ADC_LINE(0): 4095 4095 4095 4095    -1    -1
ADC_LINE(1): 1373 1051  909  842    -1    -1
ADC_LINE(2): 971 941  931  926    -1    -1
ADC_LINE(3): 920 913  912  911    -1    -1
ADC_LINE(4): 963 927  914  909    -1    -1
ADC_LINE(5): 956 967  969  971    -1    -1

With this PR on STM32F030R8 and STM32C071RB (Pin A3 connected to +3.3V, samples have different resolution):

ADC_LINE(0): 31 1òmain(): This is RIOT! (Version: 2024.04-devel-2100-gc6897-pr/stm32f0g0c0_adc)

RIOT ADC peripheral driver test

This test will sample all available ADC lines once every 100ms with
6 to 16-bit resolution and print the sampled results to STDOUT.
Not all MCUs support all resolutions, unsupported resolutions
are printed as -1.

Successfully initialized ADC_LINE(0)
Successfully initialized ADC_LINE(1)
Successfully initialized ADC_LINE(2)
Successfully initialized ADC_LINE(3)
Successfully initialized ADC_LINE(4)
Successfully initialized ADC_LINE(5)
ADC_LINE(0): 14  80  383 1688    -1    -1
ADC_LINE(1): 30 118  473 1887    -1    -1
ADC_LINE(2): 17  83  369 1593    -1    -1
ADC_LINE(3): 63 255 1023 4095    -1    -1
ADC_LINE(4): 37 134  509 1961    -1    -1
ADC_LINE(5): 31 121  477 1913    -1    -1

ADC_LINE(0): 30 119  474 1896    -1    -1
ADC_LINE(1): 32 122  481 1902    -1    -1
ADC_LINE(2): 17  82  367 1580    -1    -1
ADC_LINE(3): 63 255 1023 4095    -1    -1
ADC_LINE(4): 36 134  506 1951    -1    -1
ADC_LINE(5): 31 121  474 1911    -1    -1

ADC_LINE(0): 31 122  478 1907    -1    -1
ADC_LINE(1): 32 123  482 1912    -1    -1
ADC_LINE(2): 17  81  364 1579    -1    -1
ADC_LINE(3): 63 255 1023 4095    -1    -1
ADC_LINE(4): 36 133  507 1951    -1    -1
ADC_LINE(5): 31 122  479 1908    -1    -1

Issues/PRs references

Fixes #21222.

[1] https://www.st.com/resource/en/reference_manual/rm0360-stm32f030x4x6x8xc-and-stm32f070x6xb-advanced-armbased-32bit-mcus-stmicroelectronics.pdf p. 185 section 12.3.2 and 12.3.3
[2] https://www.st.com/resource/en/reference_manual/rm0454-stm32g0x0-advanced-armbased-32bit-mcus-stmicroelectronics.pdf p. 278 section 14.3.3 and 14.3.4
[3] https://www.st.com/resource/en/reference_manual/rm0490-stm32c0-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf p. 290 section 16.4.3 and section 16.4.4

@github-actions github-actions bot added Platform: ARM Platform: This PR/issue effects ARM-based platforms Area: cpu Area: CPU/MCU ports labels Feb 19, 2025
@crasbe crasbe force-pushed the pr/stm32f0g0c0_adc branch from c6897e0 to 6ba243d Compare February 20, 2025 10:33
@benpicco benpicco added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Feb 21, 2025
@riot-ci
Copy link

riot-ci commented Feb 21, 2025

Murdock results

✔️ PASSED

05eda72 cpu/stm32{f0,g0,c0}: fix ADC initialization sequence

Success Failures Total Runtime
10271 0 10271 12m:41s

Artifacts

@crasbe
Copy link
Contributor Author

crasbe commented Feb 21, 2025

I applied some ideas from the STM32WL PR to this one, namingly giving _disable_adc a return value as well and skipping the initialization if the ADC already has been initialized.

Tested again with the nucleo-f030r8 and nucleo-c071rb boards.

@crasbe
Copy link
Contributor Author

crasbe commented Feb 26, 2025

The Nucleo-G071RB and Nucleo-C031C6 arrived today for testing.

Apparently there is an unrelated bug since the G071RB does not even boot with RIOT. Not the tests/periph/adc test nor the tests/leds test nor the examples/essentials/blinky example. The LEDs don't blink and there's nothing on the UART.

So I'll have to investigate when it broke and why. The support for this Nucleo was introduced in Release 2020.10, so that's only... a lot of releases to go through 😅


The C031C6 has an interesting behavior with master:

main(): This is RIOT! (Version: 2025.04-devel-132-g88f2e)

RIOT ADC peripheral driver test

This test will sample all available ADC lines once every 100ms with
6 to 16-bit resolution and print the sampled results to STDOUT.
Not all MCUs support all resolutions, unsupported resolutions
are printed as -1.

Successfully initialized ADC_LINE(0)
Successfully initialized ADC_LINE(1)
Successfully initialized ADC_LINE(2)
Successfully initialized ADC_LINE(3)
Successfully initialized ADC_LINE(4)
Successfully initialized ADC_LINE(5)
ADC_LINE(0): 2000 4095 4095 4095  4095  4095
ADC_LINE(1): 4095 1465 1052  866   793   768
ADC_LINE(2): 779 869  875  877   878   880
ADC_LINE(3): 885 865  885  890   892   891
ADC_LINE(4): 905 923  919  918   918   920
ADC_LINE(5): 937 451  737  844   889   908

ADC_LINE(0): 946 4095 4095 4095  4095  4095
ADC_LINE(1): 4095 1362  999  841   784   766
ADC_LINE(2): 778 852  871  877   880   881
ADC_LINE(3): 898 917  902  898   896   895
ADC_LINE(4): 914 1017  964  939   930   925
ADC_LINE(5): 933 890  910  918   921   922

The reason for this lies in #20971, as the resolution defines are not defined for the STM32C0 at all and just set to 0-5 for 6 to 16-bit, which aren't legal values to put into the registers: https://github.com/RIOT-OS/RIOT/pull/20971/files#diff-536800c2dc2fdcbba4197ce4fc78f7da0a9f660b4c5e6951f411d86a7ccc448e

Apparently I applied the resolution PR to the C0 PR for testing already and failed to mention it in the testing procedure..

With just #20971 applied to master, the resolution is stuck in 12-bit mode as expected:

main(): This is RIOT! (Version: 2025.04-devel-132-g88f2e)

RIOT ADC peripheral driver test

This test will sample all available ADC lines once every 100ms with
6 to 16-bit resolution and print the sampled results to STDOUT.
Not all MCUs support all resolutions, unsupported resolutions
are printed as -1.

Successfully initialized ADC_LINE(0)
Successfully initialized ADC_LINE(1)
Successfully initialized ADC_LINE(2)
Successfully initialized ADC_LINE(3)
Successfully initialized ADC_LINE(4)
Successfully initialized ADC_LINE(5)
ADC_LINE(0): 2000 4095 4095 4095    -1    -1
ADC_LINE(1): 1400 1017  850  786    -1    -1
ADC_LINE(2): 876 879  880  881    -1    -1
ADC_LINE(3): 861 881  888  893    -1    -1
ADC_LINE(4): 890 906  915  919    -1    -1
ADC_LINE(5): 461 740  848  892    -1    -1

ADC_LINE(0): 4095 4095 4095 4095    -1    -1
ADC_LINE(1): 1342 988  837  784    -1    -1
ADC_LINE(2): 860 874  880  880    -1    -1
ADC_LINE(3): 914 902  897  897    -1    -1
ADC_LINE(4): 1010 960  940  929    -1    -1
ADC_LINE(5): 886 909  917  921    -1    -1

With both PRs applied, the output is as it should be:

main(): This is RIOT! (Version: 2025.04-devel-134-ge1ac1-pr/stm32f0g0c0_adc)

RIOT ADC peripheral driver test

This test will sample all available ADC lines once every 100ms with
6 to 16-bit resolution and print the sampled results to STDOUT.
Not all MCUs support all resolutions, unsupported resolutions
are printed as -1.

Successfully initialized ADC_LINE(0)
Successfully initialized ADC_LINE(1)
Successfully initialized ADC_LINE(2)
Successfully initialized ADC_LINE(3)
Successfully initialized ADC_LINE(4)
Successfully initialized ADC_LINE(5)
ADC_LINE(0): 63 255 1023 4095    -1    -1
ADC_LINE(1): 12  40  156  617    -1    -1
ADC_LINE(2): 11  45  182  725    -1    -1
ADC_LINE(3): 11  46  188  752    -1    -1
ADC_LINE(4): 12  49  196  780    -1    -1
ADC_LINE(5):  5  41  185  770    -1    -1

ADC_LINE(0): 63 255 1023 4095    -1    -1
ADC_LINE(1): 10  39  155  618    -1    -1
ADC_LINE(2): 11  45  181  725    -1    -1
ADC_LINE(3): 11  46  188  752    -1    -1
ADC_LINE(4): 13  51  198  783    -1    -1
ADC_LINE(5): 12  49  197  786    -1    -1

@crasbe
Copy link
Contributor Author

crasbe commented Feb 26, 2025

Okay, there is nothing wrong with the Nucleo-G071RB board. Apparently there is a bug with the ST-Link that the file upload does not work correctly for the G071RB. I tested a simple Arduino program and it didn't work either. With SWD, it runs as it should.

With master:

RIOT ADC peripheral driver test

This test will sample all available ADC lines once every 100ms with
6 to 16-bit resolution and print the sampled results to STDOUT.
Not all MCUs support all resolutions, unsupported resolutions
are printed as -1.

Successfully initialized ADC_LINE(0)
Successfully initialized ADC_LINE(1)
Successfully initialized ADC_LINE(2)
Successfully initialized ADC_LINE(3)
Successfully initialized ADC_LINE(4)
Successfully initialized ADC_LINE(5)
Successfully initialized ADC_LINE(6)
ADC_LINE(0): 528 4093 4095 4094  4095  4093
ADC_LINE(1): 4095 1911 1570 1541  1535  1527
ADC_LINE(2): 1526 1332 1299 1290  1287  1287
ADC_LINE(3): 1286 1535 1567 1575  1580  1579
ADC_LINE(4): 1575 1603 1650 1655  1657  1655
ADC_LINE(5): 1654 1710 1646 1646  1645  1644
ADC_LINE(6): 1637 526  179    4     0     0

ADC_LINE(0): 302 4094 4094 4095  4094  4095
ADC_LINE(1): 4091 1881 1570 1541  1538  1540
ADC_LINE(2): 1542 1316 1295 1287  1287  1287
ADC_LINE(3): 1291 1533 1568 1578  1582  1578
ADC_LINE(4): 1573 1599 1650 1658  1659  1658
ADC_LINE(5): 1647 1640 1643 1642  1646  1642
ADC_LINE(6): 1646 532  186    8     0     0

With master and #20971:

main(): This is RIOT! (Version: 2025.04-devel-142-g06eb1c)

RIOT ADC peripheral driver test

This test will sample all available ADC lines once every 100ms with
6 to 16-bit resolution and print the sampled results to STDOUT.
Not all MCUs support all resolutions, unsupported resolutions
are printed as -1.

Successfully initialized ADC_LINE(0)
Successfully initialized ADC_LINE(1)
Successfully initialized ADC_LINE(2)
Successfully initialized ADC_LINE(3)
Successfully initialized ADC_LINE(4)
Successfully initialized ADC_LINE(5)
Successfully initialized ADC_LINE(6)
ADC_LINE(0): 528 4093 4095 4093    -1    -1
ADC_LINE(1): 1869 1567 1535 1530    -1    -1
ADC_LINE(2): 1350 1304 1289 1286    -1    -1
ADC_LINE(3): 1485 1562 1575 1576    -1    -1
ADC_LINE(4): 1573 1646 1655 1655    -1    -1
ADC_LINE(5): 1657 1642 1645 1642    -1    -1
ADC_LINE(6): 527 174    5    0    -1    -1

ADC_LINE(0): 4095 4095 4095 4095    -1    -1
ADC_LINE(1): 1855 1565 1535 1529    -1    -1
ADC_LINE(2): 1293 1285 1287 1285    -1    -1
ADC_LINE(3): 1512 1567 1575 1579    -1    -1
ADC_LINE(4): 1621 1653 1655 1655    -1    -1
ADC_LINE(5): 1630 1637 1641 1642    -1    -1
ADC_LINE(6): 531 179    7    0    -1    -1

With this PR and #20971:

main(): This is RIOT! (Version: 2025.04-devel-134-ge1ac1-pr/stm32f0g0c0_adc)

RIOT ADC peripheral driver test

This test will sample all available ADC lines once every 100ms with
6 to 16-bit resolution and print the sampled results to STDOUT.
Not all MCUs support all resolutions, unsupported resolutions
are printed as -1.

Successfully initialized ADC_LINE(0)
Successfully initialized ADC_LINE(1)
Successfully initialized ADC_LINE(2)
Successfully initialized ADC_LINE(3)
Successfully initialized ADC_LINE(4)
Successfully initialized ADC_LINE(5)
Successfully initialized ADC_LINE(6)
ADC_LINE(0): 63 255 1023 4095    -1    -1
ADC_LINE(1): 19  81  324 1294    -1    -1
ADC_LINE(2): 18  68  272 1083    -1    -1
ADC_LINE(3): 20  85  340 1357    -1    -1
ADC_LINE(4): 21  90  362 1448    -1    -1
ADC_LINE(5): 22  89  357 1425    -1    -1
ADC_LINE(6):  0   0    0    0    -1    -1

ADC_LINE(0): 63 255 1023 4095    -1    -1
ADC_LINE(1): 20  81  323 1296    -1    -1
ADC_LINE(2): 17  68  272 1084    -1    -1
ADC_LINE(3): 21  85  341 1359    -1    -1
ADC_LINE(4): 22  90  362 1450    -1    -1
ADC_LINE(5): 22  89  357 1427    -1    -1
ADC_LINE(6):  0   0    0    0    -1    -1

@crasbe
Copy link
Contributor Author

crasbe commented Feb 26, 2025

From my side this is complete now and I can squash it if requested.

@crasbe
Copy link
Contributor Author

crasbe commented Feb 27, 2025

One additional thing to test (even though it doesn't really have to do with this PR): Test the STM32G0 with periph_vbat enabled. The F0 and C0 don't have a VBAT feature.

@crasbe
Copy link
Contributor Author

crasbe commented Feb 28, 2025

Nucleo-G071RB with periph_vbat enabled works as well. The measured value seems to be a bit low, it should be 4095/3 = 1365. However I don't think this is within the scope of this PR.

Measuring the VBat with another ADC pin (by bridging the two pins) shows that in fact it has 3.3V.

main(): This is RIOT! (Version: 2025.04-devel-134-ge1ac1-pr/stm32f0g0c0_adc)

RIOT ADC peripheral driver test

This test will sample all available ADC lines once every 100ms with
6 to 16-bit resolution and print the sampled results to STDOUT.
Not all MCUs support all resolutions, unsupported resolutions
are printed as -1.

Successfully initialized ADC_LINE(0)
Successfully initialized ADC_LINE(1)
Successfully initialized ADC_LINE(2)
Successfully initialized ADC_LINE(3)
Successfully initialized ADC_LINE(4)
Successfully initialized ADC_LINE(5)
Successfully initialized ADC_LINE(6)
ADC_LINE(0): 63 255 1023 4095    -1    -1
ADC_LINE(1): 19  80  323 1291    -1    -1
ADC_LINE(2): 14  66  269 1077    -1    -1
ADC_LINE(3): 20  84  339 1354    -1    -1
ADC_LINE(4): 21  90  361 1446    -1    -1
ADC_LINE(5): 21  88  356 1421    -1    -1
ADC_LINE(6): 13  55  223  885    -1    -1

ADC_LINE(0): 63 255 1023 4095    -1    -1
ADC_LINE(1): 20  81  323 1291    -1    -1
ADC_LINE(2): 14  65  269 1079    -1    -1
ADC_LINE(3): 20  84  339 1355    -1    -1
ADC_LINE(4): 21  90  361 1444    -1    -1
ADC_LINE(5): 23  89  355 1423    -1    -1
ADC_LINE(6): 13  55  222  884    -1    -1

The voltage reported by tests/periph/vbat is low as well:

main(): This is RIOT! (Version: 2025.04-devel-134-ge1ac1-pr/stm32f0g0c0_adc)

RIOT backup battery monitoring test

This test will sample the backup battery once a second


VBAT: 1827[mV]
VBAT: 1820[mV]
VBAT: 1820[mV]
VBAT: 1820[mV]
VBAT: 1827[mV]
VBAT: 1822[mV]
VBAT: 1815[mV]
VBAT: 1820[mV]
VBAT: 1822[mV]
VBAT: 1825[mV]
VBAT: 1822[mV]

The STM32WL55 has the same behavior, as documented in #21238. Perhaps I'll create another issue for this to document it.
To be honest I'm starting to lose motivation to dig deeper into this rabbit hole 😅

Let's get this and the other related PRs merged first.

@crasbe crasbe force-pushed the pr/stm32f0g0c0_adc branch from 58db884 to db9d7f3 Compare March 2, 2025 18:16
@crasbe crasbe force-pushed the pr/stm32f0g0c0_adc branch from db9d7f3 to 05eda72 Compare March 12, 2025 12:50
@crasbe
Copy link
Contributor Author

crasbe commented Mar 12, 2025

I think for this PR, I don't want to conditionally set the sampling time for VBat as the current implementation on Master already has quite a high sampling time and nobody complained so far 😅
Don't fix if ain't broken, I guess?

But let me know if I should change and test it.

Other than that, this is squashed and ready for review.

@maribu maribu added this pull request to the merge queue Apr 2, 2025
Merged via the queue into RIOT-OS:master with commit b1932dd Apr 2, 2025
26 checks passed
@crasbe
Copy link
Contributor Author

crasbe commented Apr 2, 2025

Thanks :)

@crasbe crasbe deleted the pr/stm32f0g0c0_adc branch April 2, 2025 14:36
@mguetschow mguetschow added this to the Release 2025.04 milestone Apr 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: cpu Area: CPU/MCU ports CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: ARM Platform: This PR/issue effects ARM-based platforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

5 participants