extmod/machine_uart: Factor ports' UART Python bindings to common code.

This is a code factoring to have the Python bindings in one location, and
all the ports use those same bindings.  For all ports except the two listed
below there is no functional change.

The nrf port has UART.sendbreak() removed, but this method previously did
nothing.

The zephyr port has the following methods added:
- UART.init(): supports setting timeout and timeout_char.
- UART.deinit(): does nothing, just returns None.
- UART.flush(): raises OSError(EINVAL) because it's not implemented.
- UART.any() and UART.txdone(): raise NotImplementedError.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George
2023-10-10 23:46:07 +11:00
parent 95d8b5fd55
commit 5b4a2baff6
65 changed files with 661 additions and 996 deletions

View File

@@ -322,7 +322,6 @@ SRC_C += \
machine_dac.c \
machine_i2c.c \
machine_spi.c \
machine_uart.c \
machine_pin.c \
machine_rtc.c \
machine_sdcard.c \

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2018 Damien P. George
* Copyright (c) 2013-2023 Damien P. George
* Copyright (c) 2021,2022 Renesas Electronics Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -25,12 +25,9 @@
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
// This file is never compiled standalone, it's included directly from
// extmod/machine_uart.c via MICROPY_PY_MACHINE_UART_INCLUDEFILE.
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#include "shared/runtime/interrupt_char.h"
@@ -41,44 +38,13 @@
#define DEFAULT_UART_BAUDRATE (115200)
#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS \
{ MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) }, \
{ MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) }, \
STATIC const char *_parity_name[] = {"None", "ODD", "EVEN"};
/// \moduleref pyb
/// \class UART - duplex serial communication bus
///
/// UART implements the standard UART/USART duplex serial communications protocol. At
/// the physical level it consists of 2 lines: RX and TX. The unit of communication
/// is a character (not to be confused with a string character) which can be 8 or 9
/// bits wide.
///
/// UART objects can be created and initialised using:
///
/// from pyb import UART
///
/// uart = UART(1, 9600) # init with given baudrate
/// uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
///
/// Bits can be 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
///
/// A UART object acts like a stream object and reading and writing is done
/// using the standard stream methods:
///
/// uart.read(10) # read 10 characters, returns a bytes object
/// uart.read() # read all available characters
/// uart.readline() # read a line
/// uart.readinto(buf) # read and store into the given buffer
/// uart.write('abc') # write the 3 characters
///
/// Individual characters can be read/written using:
///
/// uart.readchar() # read 1 character and returns it as an integer
/// uart.writechar(42) # write 1 character
///
/// To check if there is anything to be read, use:
///
/// uart.any() # returns True if any characters waiting
STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (!self->is_enabled) {
mp_printf(print, "UART(%u)", self->uart_id);
@@ -116,7 +82,7 @@ STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_pri
/// - `timeout_char` is the timeout in milliseconds to wait between characters.
/// - `flow` is RTS | CTS where RTS == 256, CTS == 512
/// - `read_buf_len` is the character length of the read buffer (0 to disable).
STATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
STATIC void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_baudrate, MP_ARG_INT | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
@@ -238,7 +204,6 @@ STATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args
#endif
// enable_irq(irq_state);
return mp_const_none;
}
/// \classmethod \constructor(bus, ...)
@@ -256,7 +221,7 @@ STATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args
/// - `UART(6)` is on `YA`: `(TX, RX) = (Y1, Y2) = (PC6, PC7)`
/// - `UART(3)` is on `YB`: `(TX, RX) = (Y9, Y10) = (PB10, PB11)`
/// - `UART(2)` is on: `(TX, RX) = (X3, X4) = (PA2, PA3)`
STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
STATIC mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
@@ -335,43 +300,33 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
// start the peripheral
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
mp_machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
return MP_OBJ_FROM_PTR(self);
}
STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
return machine_uart_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init);
/// \method deinit()
/// Turn off the UART bus.
STATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
// Turn off the UART bus.
STATIC void mp_machine_uart_deinit(machine_uart_obj_t *self) {
uart_deinit(self);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit);
/// \method any()
/// Return `True` if any characters waiting, else `False`.
STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
return MP_OBJ_NEW_SMALL_INT(uart_rx_any(self));
// Return number of characters waiting.
STATIC mp_int_t mp_machine_uart_any(machine_uart_obj_t *self) {
return uart_rx_any(self);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any);
/// \method writechar(char)
/// Write a single character on the bus. `char` is an integer to write.
/// Return value: `None`.
STATIC mp_obj_t machine_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
// Return `true` if all characters have been sent.
STATIC bool mp_machine_uart_txdone(machine_uart_obj_t *self) {
return !uart_tx_busy(self);
}
// get the character to write (might be 9 bits)
uint16_t data = mp_obj_get_int(char_in);
// Send a break condition.
STATIC void mp_machine_uart_sendbreak(machine_uart_obj_t *self) {
ra_sci_tx_break((uint32_t)self->uart_id);
}
// write the character
// Write a single character on the bus. `data` is an integer to write.
STATIC void mp_machine_uart_writechar(machine_uart_obj_t *self, uint16_t data) {
int errcode;
if (uart_tx_wait(self, self->timeout)) {
uart_tx_data(self, &data, 1, &errcode);
@@ -382,53 +337,26 @@ STATIC mp_obj_t machine_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
if (errcode != 0) {
mp_raise_OSError(errcode);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_uart_writechar_obj, machine_uart_writechar);
/// \method readchar()
/// Receive a single character on the bus.
/// Return value: The character read, as an integer. Returns -1 on timeout.
STATIC mp_obj_t machine_uart_readchar(mp_obj_t self_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
// Receive a single character on the bus.
// Return value: The character read, as an integer. Returns -1 on timeout.
STATIC mp_int_t mp_machine_uart_readchar(machine_uart_obj_t *self) {
if (uart_rx_wait(self, self->timeout)) {
return MP_OBJ_NEW_SMALL_INT(uart_rx_char(self));
return uart_rx_char(self);
} else {
// return -1 on timeout
return MP_OBJ_NEW_SMALL_INT(-1);
return -1;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_readchar_obj, machine_uart_readchar);
// uart.sendbreak()
STATIC mp_obj_t machine_uart_sendbreak(mp_obj_t self_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
ra_sci_tx_break((uint32_t)self->uart_id);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_sendbreak_obj, machine_uart_sendbreak);
// \method uart.txdone()
// Return `True` if all characters have been sent.
STATIC mp_obj_t machine_uart_txdone(mp_obj_t self_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
return uart_tx_busy(self) ? mp_const_false : mp_const_true;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_txdone_obj, machine_uart_txdone);
// irq(handler, trigger, hard)
STATIC mp_obj_t machine_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[MP_IRQ_ARG_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_IRQ_ARG_INIT_NUM_ARGS, mp_irq_init_args, args);
machine_uart_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
STATIC mp_irq_obj_t *mp_machine_uart_irq(machine_uart_obj_t *self, bool any_args, mp_arg_val_t *args) {
if (self->mp_irq_obj == NULL) {
self->mp_irq_trigger = 0;
self->mp_irq_obj = mp_irq_new(&uart_irq_methods, MP_OBJ_FROM_PTR(self));
}
if (n_args > 1 || kw_args->used != 0) {
if (any_args) {
// Check the handler
mp_obj_t handler = args[MP_IRQ_ARG_INIT_handler].u_obj;
if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
@@ -450,41 +378,10 @@ STATIC mp_obj_t machine_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map
uart_irq_config(self, true);
}
return MP_OBJ_FROM_PTR(self->mp_irq_obj);
return self->mp_irq_obj;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_irq_obj, 1, machine_uart_irq);
STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = {
// instance methods
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_uart_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) },
{ MP_ROM_QSTR(MP_QSTR_txdone), MP_ROM_PTR(&machine_uart_txdone_obj) },
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
/// \method read([nbytes])
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
/// \method readline()
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},
/// \method readinto(buf[, nbytes])
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
/// \method write(buf)
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_uart_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&machine_uart_writechar_obj) },
{ MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&machine_uart_readchar_obj) },
{ MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_uart_sendbreak_obj) },
// class constants
{ MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) },
{ MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) },
};
STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table);
STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
STATIC mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
byte *buf = buf_in;
@@ -526,7 +423,7 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz
}
}
STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
STATIC mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
const byte *buf = buf_in;
@@ -555,7 +452,7 @@ STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uin
}
}
STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
STATIC mp_uint_t mp_machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_uint_t ret;
if (request == MP_STREAM_POLL) {
@@ -587,21 +484,4 @@ STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr
return ret;
}
STATIC const mp_stream_p_t uart_stream_p = {
.read = machine_uart_read,
.write = machine_uart_write,
.ioctl = machine_uart_ioctl,
.is_text = false,
};
MP_DEFINE_CONST_OBJ_TYPE(
machine_uart_type,
MP_QSTR_UART,
MP_TYPE_FLAG_ITER_IS_STREAM,
make_new, machine_uart_make_new,
locals_dict, &machine_uart_locals_dict,
print, machine_uart_print,
protocol, &uart_stream_p
);
MP_REGISTER_ROOT_POINTER(struct _machine_uart_obj_t *machine_uart_obj_all[MICROPY_HW_MAX_UART + MICROPY_HW_MAX_LPUART]);

View File

@@ -296,7 +296,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
#endif
#if MICROPY_PY_MACHINE_UART
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
#endif
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) },
#if MICROPY_PY_MACHINE_PWM
#if MICROPY_HW_ENABLE_HW_PWM

View File

@@ -37,7 +37,6 @@ extern const mp_obj_type_t machine_dac_type;
extern const mp_obj_type_t machine_i2c_type;
extern const mp_obj_type_t machine_spi_type;
extern const mp_obj_type_t machine_i2s_type;
extern const mp_obj_type_t machine_uart_type;
extern const mp_obj_type_t machine_rtc_type;
extern const mp_obj_type_t machine_sdcard_type;

View File

@@ -151,6 +151,11 @@
#define MICROPY_PY_MACHINE_PWM_DUTY (1)
#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/renesas-ra/machine_pwm.c"
#endif
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_UART_INCLUDEFILE "ports/renesas-ra/machine_uart.c"
#define MICROPY_PY_MACHINE_UART_IRQ (1)
#define MICROPY_PY_MACHINE_UART_READCHAR_WRITECHAR (1)
#define MICROPY_PY_MACHINE_UART_SENDBREAK (1)
#if MICROPY_HW_ENABLE_HW_DAC
#define MICROPY_PY_MACHINE_DAC (1)
#endif