summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/samd/machine_uart.c123
-rw-r--r--ports/samd/mcu/samd21/mpconfigmcu.h1
-rw-r--r--ports/samd/mcu/samd51/mpconfigmcu.h1
3 files changed, 118 insertions, 7 deletions
diff --git a/ports/samd/machine_uart.c b/ports/samd/machine_uart.c
index b560e0e8e..aa781a170 100644
--- a/ports/samd/machine_uart.c
+++ b/ports/samd/machine_uart.c
@@ -40,7 +40,16 @@
#define FLOW_CONTROL_RTS (1)
#define FLOW_CONTROL_CTS (2)
+#define MP_UART_ALLOWED_FLAGS (SERCOM_USART_INTFLAG_RXC | SERCOM_USART_INTFLAG_TXC)
+
+#if MICROPY_PY_MACHINE_UART_IRQ
+#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS \
+ { MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(SERCOM_USART_INTFLAG_RXC) }, \
+ { MP_ROM_QSTR(MP_QSTR_IRQ_TXIDLE), MP_ROM_INT(SERCOM_USART_INTFLAG_TXC) }, \
+
+#else
#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS
+#endif
typedef struct _machine_uart_obj_t {
mp_obj_base_t base;
@@ -67,6 +76,11 @@ typedef struct _machine_uart_obj_t {
#if MICROPY_HW_UART_TXBUF
ringbuf_t write_buffer;
#endif
+ #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
+ mp_irq_obj_t *mp_irq_obj; // user IRQ object
+ #endif
} machine_uart_obj_t;
static const char *_parity_name[] = {"None", "", "0", "1"}; // Is defined as 0, 2, 3
@@ -93,23 +107,41 @@ void common_uart_irq_handler(int uart_id) {
// Handle IRQ
if (self != NULL) {
Sercom *uart = sercom_instance[self->id];
+ #if MICROPY_PY_MACHINE_UART_IRQ
+ self->mp_irq_flags = 0;
+ #endif
if (uart->USART.INTFLAG.bit.RXC != 0) {
// Now handler the incoming data
uart_drain_rx_fifo(self, uart);
+ #if MICROPY_PY_MACHINE_UART_IRQ
+ if (ringbuf_avail(&self->read_buffer) > 0) {
+ self->mp_irq_flags = SERCOM_USART_INTFLAG_RXC;
+ }
+ #endif
} else if (uart->USART.INTFLAG.bit.DRE != 0) {
#if MICROPY_HW_UART_TXBUF
// handle the outgoing data
if (ringbuf_avail(&self->write_buffer) > 0) {
uart->USART.DATA.bit.DATA = ringbuf_get(&self->write_buffer);
} else {
- // Stop the interrupt if there is no more data
+ #if MICROPY_PY_MACHINE_UART_IRQ
+ // Set the TXIDLE flag
+ self->mp_irq_flags |= SERCOM_USART_INTFLAG_TXC;
+ #endif
+ // Stop the DRE interrupt if there is no more data
uart->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE;
}
#endif
- } else {
- // Disable the other interrupts, if set by error
- uart->USART.INTENCLR.reg = (uint8_t) ~(SERCOM_USART_INTENCLR_DRE | SERCOM_USART_INTENCLR_RXC);
}
+ // Disable the other interrupts, if set by error
+ uart->USART.INTENCLR.reg = (uint8_t) ~(SERCOM_USART_INTENCLR_DRE | SERCOM_USART_INTENCLR_RXC);
+
+ #if MICROPY_PY_MACHINE_UART_IRQ
+ // Check the flags to see if the user handler should be called
+ if (self->mp_irq_trigger & self->mp_irq_flags) {
+ mp_irq_handler(self->mp_irq_obj);
+ }
+ #endif
}
}
@@ -202,6 +234,9 @@ static void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_
#if MICROPY_HW_UART_RTSCTS
", rts=%q, cts=%q"
#endif
+ #if MICROPY_PY_MACHINE_UART_IRQ
+ ", irq=%d"
+ #endif
")",
self->id, self->baudrate, self->bits, _parity_name[self->parity],
self->stop + 1, self->timeout, self->timeout_char, self->read_buffer.size - 1
@@ -212,6 +247,9 @@ static void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_
, self->rts != 0xff ? pin_find_by_id(self->rts)->name : MP_QSTR_None
, self->cts != 0xff ? pin_find_by_id(self->cts)->name : MP_QSTR_None
#endif
+ #if MICROPY_PY_MACHINE_UART_IRQ
+ , self->mp_irq_trigger
+ #endif
);
}
@@ -228,9 +266,7 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args,
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- #if MICROPY_HW_UART_TXBUF
{ MP_QSTR_txbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- #endif
#if MICROPY_HW_UART_RTSCTS
{ MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
@@ -386,6 +422,9 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
self->rts = 0xff;
self->cts = 0xff;
#endif
+ #if MICROPY_PY_MACHINE_UART_IRQ
+ self->mp_irq_obj = NULL;
+ #endif
self->new = true;
MP_STATE_PORT(sercom_table[uart_id]) = self;
@@ -445,6 +484,59 @@ static void mp_machine_uart_sendbreak(machine_uart_obj_t *self) {
mp_hal_set_pin_mux(self->tx, self->tx_pad_config.alt_fct);
}
+#if MICROPY_PY_MACHINE_UART_IRQ
+
+static mp_uint_t uart_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
+ machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ self->mp_irq_trigger = new_trigger;
+ return 0;
+}
+
+static mp_uint_t uart_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
+ machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (info_type == MP_IRQ_INFO_FLAGS) {
+ return self->mp_irq_flags;
+ } else if (info_type == MP_IRQ_INFO_TRIGGERS) {
+ return self->mp_irq_trigger;
+ }
+ return 0;
+}
+
+static const mp_irq_methods_t uart_irq_methods = {
+ .trigger = uart_irq_trigger,
+ .info = uart_irq_info,
+};
+
+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 (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)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("handler must be None or callable"));
+ }
+
+ // Check the trigger
+ mp_uint_t trigger = args[MP_IRQ_ARG_INIT_trigger].u_int;
+ mp_uint_t not_supported = trigger & ~MP_UART_ALLOWED_FLAGS;
+ if (trigger != 0 && not_supported) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("trigger 0x%04x unsupported"), not_supported);
+ }
+
+ self->mp_irq_obj->handler = handler;
+ self->mp_irq_obj->ishard = args[MP_IRQ_ARG_INIT_hard].u_bool;
+ self->mp_irq_trigger = trigger;
+ }
+
+ return self->mp_irq_obj;
+}
+
+#endif
+
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);
Sercom *uart = sercom_instance[self->id];
@@ -481,9 +573,17 @@ static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_
const uint8_t *src = buf_in;
Sercom *uart = sercom_instance[self->id];
- #if MICROPY_HW_UART_TXBUF
uint64_t t = mp_hal_ticks_ms_64() + self->timeout;
+ #if MICROPY_HW_UART_TXBUF
+ #if MICROPY_PY_MACHINE_UART_IRQ
+ // Prefill the FIFO to get rid of the initial IRQ_TXIDLE event
+ while (i < size && ringbuf_free(&(self->write_buffer)) > 0) {
+ ringbuf_put(&(self->write_buffer), *src++);
+ i++;
+ }
+ uart->USART.INTENSET.reg = SERCOM_USART_INTENSET_DRE; // kick off the IRQ
+ #endif
while (i < size) {
// Wait for the first/next character to be sent.
while (ringbuf_free(&(self->write_buffer)) == 0) {
@@ -506,6 +606,15 @@ static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_
while (i < size) {
while (!(uart->USART.INTFLAG.bit.DRE)) {
+ if (mp_hal_ticks_ms_64() > t) { // timed out
+ if (i <= 0) {
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ } else {
+ return i;
+ }
+ }
+ MICROPY_EVENT_POLL_HOOK
}
uart->USART.DATA.bit.DATA = *src++;
i++;
diff --git a/ports/samd/mcu/samd21/mpconfigmcu.h b/ports/samd/mcu/samd21/mpconfigmcu.h
index fbb5b28e2..29965f50f 100644
--- a/ports/samd/mcu/samd21/mpconfigmcu.h
+++ b/ports/samd/mcu/samd21/mpconfigmcu.h
@@ -51,6 +51,7 @@ unsigned long trng_random_u32(int delay);
#ifndef MICROPY_HW_UART_RTSCTS
#define MICROPY_HW_UART_RTSCTS (SAMD21_EXTRA_FEATURES)
#endif
+#define MICROPY_PY_MACHINE_UART_IRQ (SAMD21_EXTRA_FEATURES)
// selected extensions of the extra features set
#define MICROPY_PY_OS_URANDOM (1)
diff --git a/ports/samd/mcu/samd51/mpconfigmcu.h b/ports/samd/mcu/samd51/mpconfigmcu.h
index d567f28eb..9a7b8528f 100644
--- a/ports/samd/mcu/samd51/mpconfigmcu.h
+++ b/ports/samd/mcu/samd51/mpconfigmcu.h
@@ -15,6 +15,7 @@
#define MICROPY_PY_ONEWIRE (1)
#define MICROPY_PY_RANDOM_SEED_INIT_FUNC (trng_random_u32())
unsigned long trng_random_u32(void);
+#define MICROPY_PY_MACHINE_UART_IRQ (1)
// fatfs configuration used in ffconf.h
#define MICROPY_FATFS_ENABLE_LFN (1)