boot: Moved stdio_init() into periph_init()#10806
boot: Moved stdio_init() into periph_init()#10806maribu wants to merge 7 commits intoRIOT-OS:masterfrom
Conversation
|
WARNING: This PR can easily break stuff... So the more testing the better. But testing is easy and fast :-) |
|
@kenrabold: Mind to test this on the |
|
Oh, the msp430 family also needs testing, of course... |
|
Being honest, the impact is actually minor, but the chance to break stuff is major. So I still felt to better set the "Impact: major" label in order to ring some alarm bells :-) |
|
I suggest to start with the testing once I managed to fix all compilation issues Murdock uncovers. I would also kindly ask to delay reviewing the code until that, so that I can squash/force-push right away. I'll leave a comment once I'm done and will stop un-authorized squashing/force pushing then. |
|
Can do! |
|
Done! Compilation errors fixed and squashed. Reviewing & testing can start now :-) |
|
I ran all tests (release specs compile_and_test_for_board.py) on the nucleo-f103rb/f401re/f303re. The only tests that failed are likely not due to this PR |
|
@gschorcht @MrKevinWeiss: Thanks for the testing! :-) |
|
The PR as is breaks the HiFive1 board. The code for the board was never setup to call periph_init(), so the modifications stop all stdio output. Easy fix however. Similar to the msba2 mods, you can add the periph_init() call in board.c for HiFive1: (and the #include "periph/init.h" ) You will also need to update the Makefile.include in boards\hifive1 to include the periph modules: |
|
Oh, you noticed that ugly hack in the MSB-A2. If I remember correctly, `periph_init()` is to be called by `cpu_init()`. The lack of `cpu_init()` for MSB-A2 lead to the quick and dirty fix for the MSB-A2 which hopefully gets replaced be a proper fix...
Maybe we can try a proper fix for the HiFive1 from the beginning, as it is not a legacy board.
|
|
I will just interpret the absence of rejections as an implicit agreement that I may rebase to solve the conflicts :-) |
Prior to this commit stdio is initialized at different stages during boot depending on the board used. This commit moves the initialization of stdio to the beginning of periph_init(). This commit makes stdio available at a predictable and hardware independent stage during boot, which makes the use of stdio (e.g. via DEBUG(...)) during boot more robust.
|
I did the rebase. Please test again. (Hopefully now the HiFive1 will also work :-)) |
The failing tests on the nucleo-f103rb, still don't think any problems caused by this PR. |
Seems OK for the nucleo-f303re |
|
@francois-berder: Thanks for pointing that out. Looks like a failed assertion. Maybe you can recompile with |
|
So I finally found why it was not working on the WiFire board (and Clicker as well). By default, Here are the patches for pic32-wifire and pic32-clicker boards (I have tested this PR on both boards): mips-patches.zip |
Signed-off-by: Marian Buschsieweke <[email protected]>
* STDIO_UART_DEV was not set in board.h
* Remove call to uart_init in board_init. UART is initialized
in stdio_init.
Signed-off-by: Marian Buschsieweke <[email protected]>
* STDIO_UART_DEV was not set in board.h
* Remove call to uart_init in board_init. UART is initialized
in stdio_init.
Signed-off-by: Marian Buschsieweke <[email protected]>
|
@francois-berder: Thanks for identifying and fixing the problem. I added your patches to this PR |
|
@kenrabold or @pyropeter: Could one of you test again with the HiFive1 and confirm that it is now working? @OlegHahm: I heard you have some msp430 laying around? Would you mind to give this PR a test? Would someone mind to confirm that it works still on AVR? (I tested successfully on the Arduino Uno and Arduino Mega2560, but I'm afraid of the "Works on My Machine Syndrome".) |
|
Btw: @haukepetersen noticed that |
|
@maribu For this PR to work on HiFive1, this change is needed in the HiFive1 board_init() function: The board_init_clock() call must happen before the cpu_init(). Because periph_init() is now called by cpu_init(), and that periph_init() will call down into stdio_init() which then calls uart_init(), the UART on the HiFive1 is configured based on the power on clock, and then that gets changed by board_init_clock(). That results in the divisor for the UART not being correct and the text going to serial output is all messed up. So, just update the board.c for the HiFive1 to be like the code above and this PR will work. |
|
@kenrabold: Thanks for pointing that out. Can you test again to confirm it now works? |
|
@maribu - Yes, that works |
|
OK, I tested on the MSP430 platform myself using the wonderful FIT/IoT-Lab. It seems to work on every supported platform. May I squash? |
haukepetersen
left a comment
There was a problem hiding this comment.
Sorry for only jumping in so late, but I have to object on the concept this PR solves the problem at hand. See me inline comment for a IMHO better solution to this.
drivers/periph_common/init.c
Outdated
| void periph_init(void) | ||
| { | ||
| /* initialize stdio first to allow DEBUG() during later stages */ | ||
| #ifdef CPU_NATIVE |
There was a problem hiding this comment.
This 'ifdef' hell should not be here. After all, periph_common is a platform independent module and adding all this platform dependencies here does destroy this whole concept!
The better way I see is to move these calls to the common platform modules, calling these functions from right before periph_init is called (or not in e.g. case of native). This way there is no need for any hard to read ifdefs anywhere, just a #ifdef MODULE_STDIO in for each supported architecture...
There was a problem hiding this comment.
One general remark: It is very rarely seen that someone jumps in at the very end of a process and after a lot of work has been done and asks for dropping core concepts of this process. For good reason. Also a lot of people tend to get very upset about such things.
That said, the idea of this PR is to assure that stdio is available when the periphs are initialized, so that using DEBUG() there is a save thing to do. This solves a real issue, as people starting to ENABLE_DEBUG in periph initialization would like to debug that periph code and don't want to think about why the debug output does not appear in the console or even crashes the board.
By having the stdio initialization here centralized, it is enforced that DEBUG() is safe to do in periph initialization. If it is up to the board/cpu, inconsistent behavior can easily sneak back it. So this idea about making RIOT less hardware dependent.
How about this instead:
#ifndef HAVE_ARCH_STDIO_INIT
static inline void arch_stdio_init(void)
{
stdio_init();
}
#endif
void periph_init(void)
{
#if defined(MODULE_STDIO_UART) || defined(MODULE_STDIO_RTT)
arch_stdio_init();
#endif
....
}This would allow to provide a architecture specific void arch_stdio_init() if needed and handle the hardware specific stuff there.
There was a problem hiding this comment.
One general remark: It is very rarely seen that someone jumps in at the very end of a process
I am aware I and I honestly don't feel good about my behavior. I simply havn't seen this PR before (as I am not spending too much time on tracking PRs lately), and I stumbled upon this today - but when I see something like this I would simply feel bad about staying quit. So please accept my apologies.
On the topic at hand: I still disagree with putting this initialization into periph_common. periph_common is about peripheral, and STDIO is clearly not part of this. So just using periph_common/init.c as init trigger for some (critical, yes)) system module breaks with a global concept and is ergo always a bad idea!
So what would be needed is some generic 'pre-init' function reliably called by all platforms before periph_common/init, that can be used to bootstrap this kind of system modules. I don't see a large issue with doing such a thing, right?
Process wise I would be ok with merging this PR first (as it is already nicely tested), if someone promises to address this issue right afterwards.
There was a problem hiding this comment.
Maybe it is best to split off the mips32 changes, as any PR trying to reduce the hardware specific differences will depend on that. Maybe @francois-berder could open an PR for that, as he authored those commits anyway?
And maybe it would be a good idea to add get a general picture how the boot up process in an ideal RIOT board look like. Maybe a sequence diagram like this one in the doc of the Network Device Driver API could help. In that diagram the hardware specific part could be color coded, as those will likely still differ in various ways due to specific hardware dependent requirements.
Here is the sequence diagram I linked above (sadly with broken style):
Such a diagram might help to at least have new added boards/architectures behave in a similar way and might be a good starting point to refactor and work out the differences of the existing boards.
Update: Fixed language/grammar
|
@haukepetersen: This latest commit implements what I suggested as alternative to your feedback |
|
I see, but it does not solve the issue for abusing the |
Maybe one could view stdio as an peripheral device in a broader sense, as it is an upper layer for interacting with peripheral devices such as keyboard/terminal/serial port on a PC and UART/RTT in the context of RIOT. Those devices are definitely peripheral devices and stdio is RIOT's default interface to UART when there is a human on the other side of the UART port. Looking into the code of |
IMO that proves only that stdio_uart has periph/uart as a dependency. Thus initializing stdio_uart before the uart periph subsystem got a chance to be initialized (through periph_init()) is at least dangerous (or well, will lead to crashes). I'd assume that stdio_rtt would have a similar issue. It depends on xtimer, which depends on periph_timer, which is also not initialized at this point. |
|
I agree with @kaspar030, that just because But one important point: the So again, we all agree, that Side note (revisiting the discussion above): the |
|
@kaspar030, @haukepetersen: How about in addition to that we add a test to |
yes from my side.
Personally, I think this is overkill. Of course we need to make sure, that What we might want to think about in parallel, is to add some specific, general documentation on the boot order and the 'special cases' like |
|
Honestly, I'm not fully sure if a panic on But more generally: @MrKevinWeiss already implemented a safeguard in #10615 that drops UART output when used prior to initialization. But that change affects
Let me point out again that the test I suggested to add to #ifdef TEST_STDIO_OUTPUT_ON_PERIPH_INIT
puts("Initializing peripheral devices...");
#endif |
|
I remembered #10615 incorrectly. It will only drop output with |
|
I'd like to take a step back and focus on the core problem at hand: a clear definition of the point in time in the boot sequence, from which it is safe to use STDIO. We all agree, that this should as soon as possible, to allow for using STDIO early on during boot. If this is 'standardized', IMO there is no need for additional checking code if STDIO is available or not. So what are the challenges:
(b) is easy to solve by moving the init code into the platform specific init before |
|
I'm closing this PR now in favor of creating individual PRs per platform that move @francois-berder: Would you mind to create such a PR for the mips platform? This PR would greatly depend on the code you contributed anyway. |
Contribution description
Prior to this commit
stdiois initialized at different stages during boot depending on the board used. This commit moves the initialization ofstdioto the beginning ofperiph_init(). This commit makesstdioavailable at a predictable and hardware independent stage during boot, which makes the use ofstdio(e.g. viaDEBUG(...)) during boot more robust.Testing procedure
If
examples/hello_worldstill compiles and prints, this would be a good indicator thatstdiois still initialized properly.Issues/PRs references
Addresses issue #10645
Related to PR #10615
Testing state
ARM familiy
ESP familiy
RISC-V family
Native Family
ATmega Family
MSP430 Family
MIPS Familiy
Update 1: Beatified markdown output
Update 2: Added tracker for testing
Update 3: Added testing results for Nulceo-F{103RB,303RE,401RE}
Update 4: Un-checked all tests because of force push
Update 5: Added new testing results for MSB-A2, Blue Pill, Arduino Due, Arduino Mega 2560
Update 6: Added test case for
stdio_rttto todo listUpdate 7: Added test results for WiFire and Clicker board
Update 8: Removed
stdio_rtttesting (which is not working in master anyway). Testing for ARM should be enough now.Update 9: Added RISC-V test result
Update 10: Added MSP430 test result
Update 11: Added Arduino Uno test result