diff --git a/ports/nrf/boards/PCA10028/mpconfigboard.h b/ports/nrf/boards/PCA10028/mpconfigboard.h index 3dc8ed3459b53..df2e4e85d931f 100644 --- a/ports/nrf/boards/PCA10028/mpconfigboard.h +++ b/ports/nrf/boards/PCA10028/mpconfigboard.h @@ -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) diff --git a/ports/nrf/boards/PCA10040/mpconfigboard.h b/ports/nrf/boards/PCA10040/mpconfigboard.h index b965bf319d082..2b1c4c7ef5cfb 100644 --- a/ports/nrf/boards/PCA10040/mpconfigboard.h +++ b/ports/nrf/boards/PCA10040/mpconfigboard.h @@ -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) diff --git a/ports/nrf/main.c b/ports/nrf/main.c index 784a031ce29bb..21a71c7c9e48c 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -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" @@ -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 diff --git a/ports/nrf/modules/machine/uart.c b/ports/nrf/modules/machine/uart.c index 8d5a73e095f5e..4c75bf8209830 100644 --- a/ports/nrf/modules/machine/uart.c +++ b/ports/nrf/modules/machine/uart.c @@ -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]; @@ -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 @@ -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) { @@ -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 @@ -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 + 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) { diff --git a/ports/nrf/modules/machine/uart.h b/ports/nrf/modules/machine/uart.h index 741473ab7a4e3..85c2092458541 100644 --- a/ports/nrf/modules/machine/uart.h +++ b/ports/nrf/modules/machine/uart.h @@ -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); diff --git a/ports/nrf/modules/os/modos.c b/ports/nrf/modules/os/modos.c index f000e1eeb6457..97ed1e1badbbc 100644 --- a/ports/nrf/modules/os/modos.c +++ b/ports/nrf/modules/os/modos.c @@ -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. @@ -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