8000 nrf: Fix a few issues with UART REPL by dpgeorge · Pull Request #17212 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

nrf: Fix a few issues with UART REPL #17212

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
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ports/nrf/boards/PCA10028/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,8 @@
#define MICROPY_HW_SPI0_MISO (28)

#define HELP_TEXT_BOARD_LED "1,2,3,4"

// The JLink CDC on the PCA10028 cannot accept more than 64 incoming bytes at a time.
// That makes the UART REPL unreliable in general. But it can be improved to some
// extent by setting the raw-paste buffer size to that limit of 64.
#define MICROPY_REPL_STDIN_BUFFER_MAX (64)
5 changes: 5 additions & 0 deletions ports/nrf/boards/PCA10040/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,8 @@
#define MICROPY_HW_PWM2_NAME "PWM2"

#define HELP_TEXT_BOARD_LED "1,2,3,4"

// The JLink CDC on the PCA10040 cannot accept more than 64 incoming bytes at a time.
// That makes the UART REPL unreliable in general. But it can be improved to some
// extent by setting the raw-paste buffer size to that limit of 64.
#define MICROPY_REPL_STDIN_BUFFER_MAX (64)
4 changes: 3 additions & 1 deletion ports/nrf/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "py/gc.h"
#include "py/compile.h"
#include "py/persistentcode.h"
#include "extmod/misc.h"
#include "extmod/modmachine.h"
#include "shared/runtime/pyexec.h"
#include "readline.h"
Expand Down Expand Up @@ -172,7 +173,8 @@ void MP_NORETURN _start(void) {
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL),
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL_BAUD),
};
MP_STATE_VM(dupterm_objs[0]) = MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, make_new)((mp_obj_t)&machine_uart_type, MP_ARRAY_SIZE(args), 0, args);
mp_obj_t uart = MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, make_new)((mp_obj_t)&machine_uart_type, MP_ARRAY_SIZE(args), 0, args);
mp_os_dupterm_obj.fun.var(1, &uart);
}
#endif

Expand Down
57 changes: 42 additions & 15 deletions ports/nrf/modules/machine/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
#include "nrfx_uarte.h"
#endif

#if defined(NRF52832)
// The nRF52832 cannot write more than 255 bytes at a time.
#define UART_MAX_TX_CHUNK (255)
#endif

typedef struct _machine_uart_buf_t {
uint8_t tx_buf[1];
uint8_t rx_buf[1];
Expand Down Expand Up @@ -104,6 +109,7 @@ typedef struct _machine_uart_obj_t {
uint16_t timeout_char; // timeout waiting between chars (in ms)
uint8_t uart_id;
bool initialized; // static flag. Initialized to False
bool attached_to_repl;
#if MICROPY_PY_MACHINE_UART_IRQ
uint16_t mp_irq_trigger; // user IRQ trigger mask
uint16_t mp_irq_flags; // user IRQ active IRQ flags
Expand All @@ -118,6 +124,13 @@ static machine_uart_obj_t machine_uart_obj[] = {
};

void uart_init0(void) {
for (int i = 0; i < MP_ARRAY_SIZE(machine_uart_obj); i++) {
machine_uart_obj[i].attached_to_repl = false;
}
}

void uart_attach_to_repl(machine_uart_obj_t *self, bool attached) {
self->attached_to_repl = attached;
}

static int uart_find(mp_obj_t id) {
Expand All @@ -137,14 +150,16 @@ static void uart_event_handler(nrfx_uart_event_t const *p_event, void *p_context
if (p_event->type == NRFX_UART_EVT_RX_DONE) {
nrfx_uart_rx(self->p_uart, &self->buf.rx_buf[0], 1);
int chr = self->buf.rx_buf[0];
#if !MICROPY_PY_BLE_NUS && MICROPY_KBD_EXCEPTION
if (chr == mp_interrupt_char) {
self->buf.rx_ringbuf.iget = 0;
self->buf.rx_ringbuf.iput = 0;
mp_sched_keyboard_interrupt();
} else
#endif
{
if (self->attached_to_repl) {
#if MICROPY_KBD_EXCEPTION
if (chr == mp_interrupt_char) {
mp_sched_keyboard_interrupt();
} else
#endif
{
ringbuf_put((ringbuf_t *)&stdin_ringbuf, chr);
}
} else {
ringbuf_put((ringbuf_t *)&self->buf.rx_ringbuf, chr);
}
#if MICROPY_PY_MACHINE_UART_IRQ
Expand Down Expand Up @@ -446,17 +461,29 @@ static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf, mp_uin
#endif

machine_uart_obj_t *self = self_in;
nrfx_err_t err = nrfx_uart_tx(self->p_uart, buf, size);
if (err == NRFX_SUCCESS) {

// Send data out, in chunks if needed.
mp_uint_t remaining = size;
while (remaining) {
#ifdef UART_MAX_TX_CHUNK
mp_uint_t chunk = MIN(UART_MAX_TX_CHUNK, remaining);
#else
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to have this 255 number configurable?

Copy link
Member Author

Choose a reason for hiding this comment

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

I've now made this a macro.

mp_uint_t chunk = remaining;
#endif
nrfx_err_t err = nrfx_uart_tx(self->p_uart, buf, chunk);
if (err != NRFX_SUCCESS) {
*errcode = mp_hal_status_to_errno_table[err];
return MP_STREAM_ERROR;
}
while (nrfx_uart_tx_in_progress(self->p_uart)) {
MICROPY_EVENT_POLL_HOOK;
}
// return number of bytes written
return size;
} else {
*errcode = mp_hal_status_to_errno_table[err];
return MP_STREAM_ERROR;
buf += chunk;
remaining -= chunk;
}

// return number of bytes written
return size;
}

static mp_uint_t mp_machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
Expand Down
3 changes: 1 addition & 2 deletions ports/nrf/modules/machine/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@
typedef struct _machine_uart_obj_t machine_uart_obj_t;

void uart_init0(void);
void uart_deinit(void);
void uart_irq_handler(mp_uint_t uart_id);
void uart_attach_to_repl(machine_uart_obj_t *self, bool attached);

bool uart_rx_any(machine_uart_obj_t *uart_obj);
int uart_rx_char(machine_uart_obj_t *uart_obj);
Expand Down
14 changes: 11 additions & 3 deletions ports/nrf/modules/os/modos.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "py/runtime.h"
#include "extmod/modmachine.h"
#include "drivers/rng.h"
#include "modules/machine/uart.h"

#if MICROPY_PY_OS_URANDOM
// Return a bytes object with n random bytes, generated by the hardware random number generator.
Expand All @@ -46,10 +47,17 @@ static MP_DEFINE_CONST_FUN_OBJ_1(mp_os_urandom_obj, mp_os_urandom);
#endif

#if MICROPY_PY_OS_DUPTERM
// TODO should accept any object with read/write methods.
void mp_os_dupterm_stream_detached_attached(mp_obj_t stream_detached, mp_obj_t stream_attached) {
if (!(stream_attached == mp_const_none || mp_obj_get_type(stream_attached) == &machine_uart_type)) {
mp_raise_ValueError(MP_ERROR_TEXT("need a UART object"));
#if MICROPY_PY_MACHINE_UART
if (mp_obj_get_type(stream_detached) == &machine_uart_type) {
uart_attach_to_repl(MP_OBJ_TO_PTR(stream_detached), false);
}
#endif

#if MICROPY_PY_MACHINE_UART
if (mp_obj_get_type(stream_attached) == &machine_uart_type) {
uart_attach_to_repl(MP_OBJ_TO_PTR(stream_attached), true);
}
#endif
}
#endif // MICROPY_PY_OS_DUPTERM
Loading
0