-
Notifications
You must be signed in to change notification settings - Fork 2k
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
pm: provide way to disable uart_stdio rx #7947
Comments
It's usually the UART RX that will block the low power modes. In my opinion, it should be possible to disable UART STDIO RX for low power without messing with the board configurations (periph_conf.h). Also, I'm not sure all drivers have been updated yet to conditionally block low power modes depending on the RX configuration. I have one PR open for the Kinetis CPUs to allow some UART RX functionality even with low power modes #7897 by configuring the RX pin as a wakeup source (there are some limitations to baud rate and module clock sources though), maybe you can do something similar for your platform? |
@gebart ACK. That's the define/flag I mentioned above. We need an easy way to overcome this issue, where you want to deploy a node and don't care about UART anymore. |
@roberthartung I still think it's useful to have the possibility to use the UART for TX only even in low power applications, so the uart_stdio_init should still be run during boot on low power applications, only it should not enable the RX configuration if the low power flag is set. It helps tremendously with debugging to have some sort of output channel. |
What about disabling the UART at runtime just before going to sleep and re-enable it when the device wakes up ? |
@gebart Then we should name it PM_ENABLE_FULL, PM_DISABLE_UART_RX or something like that? @dylad That's what I am doing now and it sucks. I don't want to do this for every application all over again. When deploying I just want to be able to call However we can think about disabling the RX part and enabling tx when ever it is needed. How would we achieve this? This should be transparent to the user. So do we need to have #ifdefs or a special PM_PRINTF()? #define PM_PRINTF(...) uart_enable_tx(); printf(__VA_ARGS); uart_disable_tx(); ? |
Additionally, this would require in separating tx and rx mode of a uart, which is somewhat wishful and we should work on that? EDIT: I've just seen that there already is This would allow us to do uart_disable_rx() in low power mode and uart_enable/disable_tx() is used in PM_PRINFT. Additionally PM_PRINTF could be replaced by printf() or even completely left empty? |
I'm just wondering... Could we just UNDEF both gpio within periph_conf.h file to prevent the stdio driver from enabling UART in your case ? or something like that ? |
Sorry I was not clear in my previous post. What I really mean is the possibility to define both rx & tx pins as GPIO_UNDEF. Then we need to rewrite a bit of uart_stdio in order to check if rx & tx are defined (or defined as GPIO_UNDEF) and so enable or not this UART. This way, user just have to overwrite their periph_conf.h board file to disable this UART. |
I have a protoype somewhere where the shell powers down the uart after an inactivity time, then enable the rx pin as external interrupt for wake up. When a message is received the uart is then powered back on. The first character is the missed... The main drawback of that approach is that some UARTs can still be used in low power and do not need this hack to wake up. We might then decide to add this function (rx wake up) and do the whole process even for low power uarts, but then the |
@dylad I am not sure how that should work by just defining the Pins? Can you Sketch something? Because the uart driver has to be separated for TX and RX, i.e. not enabling both TX and RX mode at the same time. @vincent-d low power uarts have been discussed as Dagstuhl this year already. We really should also think about how to integrate these. Maybe a lpusart interface is required? TBD. In my uart-based tests, I just disable/enable uart if it is not needed, which allows to enter deep sleep modes. |
@dylad Ok. I see what you aim for - that might work. Will have to look into it. What happens if my program still contains printf though? This surely has to be thought through. |
For my application it is very useful to leave the stdio/debug on even in deep sleep mode, that way you can log a suspect node's output. Our current implementation is to put the printf output into a buffer and then wait for the buffer to empty before sleeping. If you implemented a buffer approach, with a minimal printf (which would be a very nice feature), then you could just let the buffer fill if output is off? |
well - I'd use puts() for that, not printf.. probably - not sure. I am looking more into long-term WSN applications where you deploy your network and it does its thing. There's nothing you can log things/errors to - it just has to work! But missing a character is obsiously not acceptable @vincent-d - IMO we should only allow turning on/off the uart if we can make sure we're not missing any data! If we do -> no deep sleep available! |
Well then you can just do uart_off() at the beginning and uart_on()/uart_off() on the specific debug part in your code? |
Good point, but I would prefer if these kind of features (minimal printf/buffered) could be incorporated into RIOT. |
I agree, but all my UARTs can be disabled without losing character (I have a wake up pin from the other side) except the shell, which I use only for debug purpose. But I still need to allow low power. So I tried it in a hacky way. |
I see a number of things that needs improving in this area:
@vincent-d The Kinetis solution is similar to what you describe regarding your (stm32 I guess?) solution, except there are no new functions, everything is handled privately inside the UART driver implementation. I have the same problem with the first character being messed up sometimes because the clock source for the UART does not start up quickly enough, but it depends on which clock source is selected for the module, the worst problems are when using a PLL for the clocking. @photonthunder One level of buffering is already implemented inside newlib, which uses line buffering and a buffer of I think 64 bytes by default, but I assume you want something a little more configurable here? |
@gebart, is there a way to keep the newlib implementation awake until empty (a flag or something)? Typically I just set up a ring buffer in uart.c and then just have a thread that keeps things awake until empty. |
@roberthartung as @gebart said, the easiest way is to put a guard on driver side to ensure tx pin is enable or not (depends of the pin definition within periph_conf.h). Some drivers (not all I think) already check the behaviour of the rx pin before initialize the reception side. |
@dylad that‘s the Point!! The Board is independent of the application! Changing the board‘s periph_conf.h for the applications is wrong! We need a solution on application basis. |
Then we have to do it either at runtime (need to write new function to control it) or use some flags. |
I agree that it should be possible to disable it per application without modifying the board periph_conf.h file. It could be implemented as simply as adding a preprocessor condition to set the RX callback to null during init if some flag is set, that way it will be possible to override from the project Makefile (CFLAGS+=-DUART_STDIN_DISABLE or similar). |
@dylad Runtime always comes with an additional cost (more energy consumption?). Adding a guard has the same problem but that's the trade off you need to take, if you want to be flexible - I guess. The problem is that the board by default uses the uart module, right? so we cannot shift this to the application doing FEATURE_REQUIRED += periph_usart which then compiles the periph module and adds printf() calls, e.g. we have to pay attention to any printfs that might occur, e.g. replacing it with PRINTF? I don't know. Or is this not a problem? Are there any printf calls in the core RIOT code? probably not? And for the runtime I'd vote for a guard, indicating the state of uart tx/tx modes (can we just read the register bit flags here?) and abort uart_writechar if tx is not enabled! |
You don't need to change anything with printf, without enable_debug there are almost no printf calls in the OS (shell does print something always). All printf and puts and other stdout writes will end up in the write syscall, which in turn calls uart_stdio_write, so all you need to do to disable your uart is to make the uart_stdio_write call return without actually writing anything. The printf call overhead for formatting the string will not be noticeable on the overall power consumption unless you are doing something exceptional like printing large arrays of numeric values in decimal, and then you should be able to disable that part of your application if you are building for lowest power consumption. |
Thanks for bringing this up! Apart from always blocking the low-power mode, uart_stdio also uses quite some memory and code.
How about a pseudomodule I'll come up with a PR. |
@kaspar030 How about doing both uart_stdio_rx and uart_stdio_tx which are not selected by default and applications have to choose it explicitely? Or on the other hand, it can be selected by default, but being disabled. |
@kaspar030 Why only RX ? We should be able to disable TX too. |
Is there a use-case for having only RX but not TX? |
We could make it a DEFAULT_MODULE. Then it can be disabled usind DISABLE_MODULE. |
This is not what I mean, I was thinking of disabling both RX and TX at the same time. So user can disable RX only or both RX and TX. |
I agree, I don't see a use-case for only having RX, but not TX for now. See my comments in #7974 . |
Being able to disable rx for stdio is one step forward, but I still think we need a consensus on how to handle low power with uart rx. |
I can't agree on this one. We know that UART has bit errors, but accepting to loose a character in this use cases, when we're in low power modes / waking up, is not acceptable in my opinion and RIOT should not support is. Therefore I suggest, that we don't allow sleeping when UART is still in RX mode. Apart from that I agree to @vincent-d that it is nice to be able to disable rx/tx at compile time, however disabling/enabling it at runtime also is important and this should be able for low-power UARTs and non-low-power UARTs. |
@roberthartung I worked with different microcontrollers for an old project and none of them had low power UART. The wake up was done by sending a dummy character first. Maybe this is a bad design, but sometimes you don't have a choice. |
@vincent-d Not saying that there should be a common API I guess, the API has to be rethinked on how to integrate LPM UARTs. |
Sometimes software design need to be adapted to bad hardware...and changing hardware is harder than changing software ;) |
I agree with @vincent-d, sometimes it is better to lose one char when waking up and still be able to use the UART, than the alternatives (blocking low power, or no UART RX at all). |
I would like to propose a different naming for the pseudomodules: uart_stdin and uart_stdout. Shorter to type and should be fairly obvious to most developers. |
Is this still an issue with #11310 merged? |
No, so let's close this. Feel free to reopen if you disagree. |
The pm_layered module is used to automatically enter power modes if they are not blocked. However, the U(S)ART is usually initialized automatically:
find . -name "board.c" | xargs grep "stdio_init"
./boards/telosb/board.c: uart_stdio_init();
./boards/waspmote-pro/board.c: uart_stdio_init();
./boards/z1/board.c: uart_stdio_init();
./boards/arduino-atmega-common/board.c: uart_stdio_init();
However, this always blocks even first sleep modes, because the uart driver will block the level. Therefore I propose to introduce a simple wrapper e.g.
... or something similar that I can set in my application or pass to make in order to disable the default initialization of the uart. This will surely introduce problems when printf() calls are made,so a custom printf() function (PRINTF?) has to be used.
Are there any other ideas on how to solve this problem?
From what I observed, uart is the only thing that will currently block deep sleep capability.
I look forward to constructive discussions and propoals!
The text was updated successfully, but these errors were encountered: