-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
esp32/uart: Correctly init uart driver for repl. #8279
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
Conversation
ports/esp32/uart.c
Outdated
uart_repl_set_pattern_detect(mp_interrupt_char); | ||
|
||
//Create a task to handler UART event from ISR | ||
xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 12, NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A shame that it needs to create a whole new task just to manage ctrl-C interrupts... is there another way to do this? Can we still use uart_isr_register()
? How about uart_set_select_notif_callback()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah the task does seem wasteful. I initially tried to follow the existing isr pattern, but the IDF high level driver itself is using the ISR for much of its behaviour, adding or own would need to replace that.
When I disabled their isr & enabled this one, I had to disable the tx buffer in uart_driver_install() as it's managed by their isr and it mostly worked. However any statement on repl that printed over a certain length ( ~132 characters iirc) it locks up.
Eg (by memory)
>>> [1]*10
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
>>> [1]*100
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
then nothing, couldn't type anything else, couldn't ctrl-c.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't seen uart_set_select_notif_callback()
before though, I'll look into it.
Maybe it would be better to skip their ISR and instead make an extended version of the micropython ringbuffer to support looking for the interrupt character. That code is duplicated a lot, it would probably be good to have a consolidated stdio buffer for both in and out with the interrupt char handling in just that one place? |
b0262bd
to
e1dfe4e
Compare
yep, |
Hey @UnexpectedMaker would it be possible for you to test this branch to see if it fixes the uart repl bootloop issue you were talking about? |
actually... I don't think it can work quite well enough - that callback always appears to be "a character behind" when it comes to interrupt char. In a Looking at the IDF code (https://github.com/espressif/esp-idf/blob/2522277dfe51827575ea4724a1e54d1103aafd6f/components/driver/uart.c#L926) it looks like the interrupt handler reads the internal fifo, fires off this callback if configured, then pushes the data into the rx buffer. Maybe replacing the ISR is the best option, though maybe extending it closer to the "full" version in IDF so it's compatible with the other high level api's I'm wanting to use here. |
What might work is to use |
Yeah I'd kind of thought that, it felt like it was just adding even more layers of abstraction / background tasks to pump chars from one buffer to another - but yeah it's better than a separate freertos task for sure. I can't just replicate their ISR and keep the high level api - far too many static types / variables / functions for that to work. I can't help but think it's better to go mostly back to what's being used currently - a very thin / light driver, just one that's using some of their slightly heigher level init functions to hopefully make it behave properly without any chip-specific coded needed in the micropython interface. There's just so much code in their uart driver, mostly to support all the features / events / callbacks which wer're not using, like the semaphors and queues for their own buffer systems which we basically duplicate anyway with ringbuf. |
Yes that does sound good.... do we know why that approach doesn't work with newer IDF versions? |
no, but the existing driver never runs any of the uart "init" functions, it goes direct to a lower level chips specific |
e1dfe4e
to
debf9d1
Compare
Well that's a much much smaller changeset, will need more info / hardware to test if it resolves the bootloop / newer IDF issue though. |
Ah, but now it's back to an earlier issue I had - if mpy tries to tx too much data back to pc on repl it locks up |
debf9d1
to
ad484ee
Compare
repl stdout now fixed, this should be ready for review @dpgeorge |
ports/esp32/uart.c
Outdated
break; | ||
} | ||
str += ret; | ||
mp_hal_delay_ms(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uart_repl_write
is called by mp_hal_stdout_tx_strn
, which may release and re-acquire the GIL if we are echoing more than 20 characters.
Thus, it is not safe to call mp_hall_delay_ms
here, because that function also releases and re-acquires the GIL, thus causing deadlock when mp_hal_stdout_tx_strn
tries to acquire the GIL.
Fixed the issue locally by replacing this with ulTaskNotifyTake(pdFALSE, 1);
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a great catch thanks, I'll update it tomorrow.
1591b9e
to
4ec8210
Compare
ports/esp32/mphalport.c
Outdated
for (uint32_t i = 0; i < len; ++i) { | ||
uart_tx_one_char(str[i]); | ||
} | ||
uart_repl_write(str, len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd call this function uart_tx_strn()
to match the others here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was actually thinking of renaming the others to be honest, they're named like a generic uart function but in actuality they're hardcoded to repl / uart0 use
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to match usb_tx_strn
and usb_serial_jtag_tx_strn
(which are generic and not tied to the REPL).
Or how about uart_stdout_tx_strn()
? Or uart_tx_strn(MICROPY_HW_UART_REPL, ...)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes I follow now, I've just updated as such
ports/esp32/mphalport.c
Outdated
@@ -54,6 +44,8 @@ | |||
#include "mphalport.h" | |||
#include "usb.h" | |||
#include "usb_serial_jtag.h" | 9E88|||
#include "uart.h" | |||
#include "driver/uart.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it need driver/uart.h
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah probably not anymore, since wrapping the uart write function
ports/esp32/uart.c
Outdated
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, | ||
.rx_flow_ctrl_thresh = 0 | ||
}; | ||
uart_param_config(UART_NUM_0, &uartcfg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth making UART_NUM_0
a #define macro as well, eg MICROPY_HW_UART_REPL
would match stm32.
}; | ||
uart_param_config(UART_NUM_0, &uartcfg); | ||
|
||
const uint32_t rxbuf = 129; // IDF requires > 128 min |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As pert stm32, maybe macro this 129 to MICROPY_HW_UART_REPL_RXBUF
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This rxbuf is not used ( wasted ram :-( ) it needs their high level API ISR to work, but there's an assert to ensure it's defined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
4ec8210
to
3be5b7c
Compare
Thanks for updating, merged in 2cc9232 |
8.2.x backport picopad by @lynt-smitka
Initial attempt to replace the low level "raw" uart driver in uart0 (repl) with the standard high level idf uart driver.
There's some code cleanup (include files) still required, and possibly removal of the ringbuffer still in use for usb / dupterm?
Not sure if any of the other uart event queue types would be useful for anything (example code commented out currently).
Tested with the following test script:
with
mpremote mount .
on master:
With this branch:
Ctrl-C seems to work from repl, eg
For related information see #8255 and #8277