Skip to content

cpu/stm32{f3,l4,wb,wl}: Replace ztimer with busy_wait, fix VBat sampling time and {wl only} fix initialization sequence #21238

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 2, 2025

Conversation

crasbe
Copy link
Contributor

@crasbe crasbe commented Feb 21, 2025

Contribution description

This PR fixes some issues with the ADC of the STM32WL55 and the ADC of the STM32F3, L4 and WB series.

  1. All: The ADC initialization routine used ztimer for an uncritical delay, which caused issues (a crash) when it was called from the early reset vector to check the battery status. I explained it here in greater detail: boards/nucleo-wl55jc: add ADC configuration #21235 (comment)
    Using ztimer for an uncritical delay is not really necessary, especially since the intended delay is 20µs and if only ZTIMER_MSEC was available instead of ZTIMER_USEC, the delay was extended to 1ms.
    I replaced it with busy_wait and added a factor of 2, because busy_wait is not really accurate. We can wait longer, but we shouldn't push our luck by waiting shorter.
    This was present in the F3, L4, WB and WL series.

  2. All: Reading out the VBat voltage takes some time for the analog switch to fully switch. This was not taken into consideration, leading to incorrect voltage readings. This PR conditionally increases the sample time when the VBat module is used.

  3. WL55: Similar to the L0, L1 and F0/G0/C0 ADC implementations, the initialization order was incorrect. The resolution setting will be ignored when the ADC is already enabled, as described in the Errata [1].
    I adapted the _adc_enable and _adc_disable functions from PR cpu/stm32{f0,g0,c0}: fix ADC initialization sequence #21230. At this moment it is a bit pointless to have _disable_adc return something, but in the future someone (maybe me) wants to add a timeout to the somewhat dangerous infinite while loops and then it makes sense to have the return in place already.
    Also I changed the is the ADC already initialized?-test from checked the ADEN bit to checking if the sampling time has already been set.
    This should work without issues since the reset value for this register is 0.

  4. WL55: (No fix but an improvement) Similar to the F0/G0/C0 PR from cpu/stm32{f0,g0,c0}: fix ADC initialization sequence #21230, I added the RS-register guard to avoid setting or resetting a flag that shouldn't be touched.
    The issue here is that sometimes a flag is set by writing a 1 to it (typical behavior) and sometimes it is reset by writing a 1 to it. A typical RMW-cycle could potentially reset a flag, which is why the original STM32-HAL uses these guards.
    The older documentation does not say that this is required, but it can't hurt. The initialization is not really time critical so we don't have to save cycles.

Testing procedure

WL55: The testing procedure is a bit of a hen-egg-problem, because for some reason the Nucleo-WL55 did not have the ADC lines configured, so PR #21235 has to be applied as well as this one. I recommend checking out PR #21235 and manually copying cpu/stm32/periph/adc_wl.c from this PR.

F3, L4, WB: The tests can be run without any further modifications.

The first part of this PR can be easily tested with tests/periph/vbat with BOARD=nucleo-wl55jc make -C tests/periph/vbat flash term.

With current master (F3, L4, WB, WL):

0x8001741 => *** RIOT kernel panic:
FAILED ASSERTION.

*** halted.

With this PR (before applying the fix for VBat):

main(): This is RIOT! (Version: 2025.04-devel-142-g04340-nucleo-wl55jc-ADC)

RIOT backup battery monitoring test

This test will sample the backup battery once a second


VBAT: 386[mV]
VBAT: 1598[mV]
VBAT: 1658[mV]
VBAT: 1670[mV]
VBAT: 1668[mV]
VBAT: 1668[mV]
VBAT: 1670[mV]
VBAT: 1665[mV]
...

With this PR (after applying the fix):

main(): This is RIOT! (Version: 2024.04-devel-2120-ge787a-pr/fix_stm32wl_adc)

RIOT backup battery monitoring test

This test will sample the backup battery once a second


VBAT: 3304[mV]
VBAT: 3304[mV]
VBAT: 3300[mV]
VBAT: 3302[mV]
VBAT: 3304[mV]
VBAT: 3302[mV]

The second part of this PR can be tested with tests/periph/adc with with BOARD=nucleo-wl55jc make -C tests/periph/adc flash term.

With master:

main(): This is RIOT! (Version: 2025.04-devel-142-g04340-nucleo-wl55jc-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): 4095 4095 4095 4094    -1    -1
ADC_LINE(1): 1675 1572 1554 1550    -1    -1
ADC_LINE(2): 1335 1503 1542 1561    -1    -1
ADC_LINE(3): 2086 1902 1750 1703    -1    -1
ADC_LINE(4): 1483 1533 1546 1558    -1    -1
ADC_LINE(5): 1473 1526 1538 1550    -1    -1
ADC_LINE(6): 440 156   39    0    -1    -1

ADC_LINE(0): 4095 4095 4095 4094    -1    -1
ADC_LINE(1): 1834 1609 1560 1551    -1    -1
ADC_LINE(2): 1457 1535 1551 1563    -1    -1
ADC_LINE(3): 1663 1674 1679 1680    -1    -1
ADC_LINE(4): 1543 1557 1560 1563    -1    -1
ADC_LINE(5): 1523 1539 1551 1553    -1    -1
ADC_LINE(6): 423 143   34    0    -1    -1

With this PR:

main(): This is RIOT! (Version: 2025.04-devel-142-g04340-nucleo-wl55jc-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): 19  85  348 1399    -1    -1
ADC_LINE(1): 19  84  340 1362    -1    -1
ADC_LINE(2): 20  86  347 1393    -1    -1
ADC_LINE(3): 32 104  394 1550    -1    -1
ADC_LINE(4): 21  86  347 1390    -1    -1
ADC_LINE(5): 63 255 1023 4095    -1    -1
ADC_LINE(6): 18  70  274 1075    -1    -1

ADC_LINE(0): 20  86  349 1400    -1    -1
ADC_LINE(1): 20  84  340 1364    -1    -1
ADC_LINE(2): 20  86  347 1393    -1    -1
ADC_LINE(3): 23  95  384 1538    -1    -1
ADC_LINE(4): 21  86  346 1390    -1    -1
ADC_LINE(5): 63 255 1023 4095    -1    -1
ADC_LINE(6): 18  70  275 1074    -1    -1

Issues/PRs references

This has to be merged before #20971 can be merged (and tested...).

See also

[1] https://www.st.com/resource/en/errata_sheet/es0500-stm32wl55xx-stm32wl54xx-device-errata-stmicroelectronics.pdf p.13 section 2.3.2

@github-actions github-actions bot added Platform: ARM Platform: This PR/issue effects ARM-based platforms Area: cpu Area: CPU/MCU ports labels Feb 21, 2025
@crasbe
Copy link
Contributor Author

crasbe commented Feb 21, 2025

(Totally unrelated: I still don't love git.)

Copy link
Member

@dylad dylad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have such board to test but I like the overall idea.
Could you also remove the ztimer dependency for WL family here while at it ?

@crasbe
Copy link
Contributor Author

crasbe commented Mar 2, 2025

Could you also remove the ztimer dependency for WL family here while at it ?

It seems like no other module depends on ztimer, so the dependency can be removed:

~/RIOTstuff/riot-stm32wl55/RIOT/tests/minimal$ BOARD=nucleo-wl55jc make -j12
Building application "tests_minimal" for "nucleo-wl55jc" with CPU "stm32".

"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/pkg/cmsis/
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/boards/common/init
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/boards/nucleo-wl55jc
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/core
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/core/lib
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/cpu/stm32
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/drivers
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/sys
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/boards/common/nucleo
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/drivers/periph_common
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/cpu/cortexm_common
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/sys/div
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/cpu/stm32/periph
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/sys/libc
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/cpu/stm32/stmclk
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/cpu/stm32/vectors
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/sys/malloc_thread_safe
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/sys/newlib_syscalls_default
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/sys/pm_layered
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/sys/stdio
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/sys/stdio_null
"make" -C /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/cpu/cortexm_common/periph
   text    data     bss     dec     hex filename
   9064     112     996   10172    27bc /home/cbuec/RIOTstuff/riot-stm32wl55/RIOT/tests/minimal/bin/nucleo-wl55jc/tests_minimal.elf

@crasbe crasbe force-pushed the pr/fix_stm32wl_adc branch from 48bc726 to 911bd8b Compare March 2, 2025 21:57
@crasbe crasbe changed the title cpu/stm32wl: Replace ztimer with busy_wait and fix initialization sequence cpu/stm32{f3,l4,wb,wl}: Replace ztimer with busy_wait and {wl only} fix initialization sequence Mar 2, 2025
@crasbe
Copy link
Contributor Author

crasbe commented Mar 2, 2025

The Makefile.dep made me suspicious that the F3 and L4/WB had the same issue and guess what, they do.
So I extended the PR to address this as well.

One thing I would like to do is to change the sampling time for the WL to the same pattern that the other implementations have with the define and the condition based on IS_USED(MODULE_PERIPH_VBAT).

Perhaps the F3 and L4/WB should be changed to the register defintions like the F3 to avoid the magic number.

Also it still has to be tested with an L4 board.

The resources for the register descriptions and delays of VBat sampling:
https://www.st.com/resource/en/reference_manual/rm0365-stm32f302xbcde-and-stm32f302x68-advanced-armbased-32bit-mcus-stmicroelectronics.pdf page 372
https://www.st.com/resource/en/datasheet/stm32f302cb.pdf p. 124 table 80

https://www.st.com/resource/en/reference_manual/rm0434-multiprotocol-wireless-32bit-mcu-armbased-cortexm4-with-fpu-bluetooth-lowenergy-and-802154-radio-solution-stmicroelectronics.pdf p. 491
https://www.st.com/resource/en/datasheet/stm32wb55cc.pdf p. 154 table 86

@crasbe crasbe force-pushed the pr/fix_stm32wl_adc branch from 911bd8b to ef4f286 Compare March 2, 2025 22:06
@krzysztof-cabaj
Copy link
Contributor

@crasbe

I checked code from this PR using nucleo-l476rg. In my opinion everything is working.

Results from tests/periph/adc:

main(): This is RIOT! (Version: 2024.04-devel-2122-gef4f28-crasbe_L4_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): 20  66  238  877    -1    -1
ADC_LINE(1): 18  61  225  834    -1    -1
ADC_LINE(2): 21  74  263  951    -1    -1
ADC_LINE(3): 18  67  252  950    -1    -1
ADC_LINE(4): 16  55  203  755    -1    -1
ADC_LINE(5): 12  44  169  650    -1    -1
ADC_LINE(6):  9  40  180  728    -1    -1

Results from tests/periph/vbat:

main(): This is RIOT! (Version: 2024.04-devel-2122-gef4f28-crasbe_L4_ADC)

RIOT backup battery monitoring test

This test will sample the backup battery once a second


VBAT: 3350[mV]
VBAT: 3370[mV]
VBAT: 3367[mV]
VBAT: 3370[mV]
VBAT: 3367[mV]
VBAT: 3367[mV]
VBAT: 3370[mV]
VBAT: 3367[mV]
VBAT: 3370[mV]
VBAT: 3367[mV]

@crasbe crasbe force-pushed the pr/fix_stm32wl_adc branch 2 times, most recently from ad8af3e to 997a168 Compare March 12, 2025 12:19
@crasbe crasbe force-pushed the pr/fix_stm32wl_adc branch 2 times, most recently from 35690a0 to e8b083f Compare March 12, 2025 12:25
@crasbe crasbe added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Mar 12, 2025
@crasbe
Copy link
Contributor Author

crasbe commented Mar 12, 2025

After rebasing and a lot of moving things around, this is now in a clean state for Review.

The major change is that I reverted the sampling time for the "normal" channels back to the original value and just changed it for the VBat line. There is no need to slow the other channels down so much if it's not necessary.

The part of the STM32WL code where the sampling time is set still differs from the other two implementations, but I didn't want to change it too. All the ADC implementations are different in one way or another anyway and I just had to find a stopping point and I think it is here 😅

This still has to be tested, but since I didn't change anything functionally, everthing should still work as it should.

@crasbe crasbe changed the title cpu/stm32{f3,l4,wb,wl}: Replace ztimer with busy_wait and {wl only} fix initialization sequence cpu/stm32{f3,l4,wb,wl}: Replace ztimer with busy_wait, fix VBat sampling time and {wl only} fix initialization sequence Mar 12, 2025
@riot-ci
Copy link

riot-ci commented Mar 12, 2025

Murdock results

✔️ PASSED

112e542 cpu/stm32{f3,l4,wb,wl}: increase sampling time for VBat line

Success Failures Total Runtime
10279 0 10280 09m:23s

Artifacts

@crasbe
Copy link
Contributor Author

crasbe commented Mar 12, 2025

This still has to be tested, but since I didn't change anything functionally, everthing should still work as it should.

I just got done testing it and everything still does work as it should.

Copy link
Member

@maribu maribu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one, thx :)

@crasbe crasbe force-pushed the pr/fix_stm32wl_adc branch from e8b083f to 112e542 Compare April 2, 2025 14:53
@crasbe crasbe added the Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) label Apr 2, 2025
@maribu maribu enabled auto-merge April 2, 2025 14:55
@maribu maribu added this pull request to the merge queue Apr 2, 2025
Merged via the queue into RIOT-OS:master with commit 4f676cd Apr 2, 2025
27 checks passed
@crasbe
Copy link
Contributor Author

crasbe commented Apr 2, 2025

Thanks everyone for reviewing and testing :)

@crasbe crasbe deleted the pr/fix_stm32wl_adc branch April 2, 2025 18:54
@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 Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants