kopia lustrzana https://github.com/micropython/micropython
Merge 2754f5095f
into e60e8079a7
commit
4dd530949a
|
@ -152,31 +152,6 @@ Methods
|
|||
Send a break condition on the bus. This drives the bus low for a duration
|
||||
longer than required for a normal transmission of a character.
|
||||
|
||||
.. method:: UART.irq(trigger, priority=1, handler=None, wake=machine.IDLE)
|
||||
|
||||
Create a callback to be triggered when data is received on the UART.
|
||||
|
||||
- *trigger* can only be ``UART.RX_ANY``
|
||||
- *priority* level of the interrupt. Can take values in the range 1-7.
|
||||
Higher values represent higher priorities.
|
||||
- *handler* an optional function to be called when new characters arrive.
|
||||
- *wake* can only be ``machine.IDLE``.
|
||||
|
||||
.. note::
|
||||
|
||||
The handler will be called whenever any of the following two conditions are met:
|
||||
|
||||
- 8 new characters have been received.
|
||||
- At least 1 new character is waiting in the Rx buffer and the Rx line has been
|
||||
silent for the duration of 1 complete frame.
|
||||
|
||||
This means that when the handler function is called there will be between 1 to 8
|
||||
characters waiting.
|
||||
|
||||
Returns an irq object.
|
||||
|
||||
Availability: WiPy.
|
||||
|
||||
.. method:: UART.flush()
|
||||
|
||||
Waits until all data has been sent. In case of a timeout, an exception is raised. The timeout
|
||||
|
@ -203,11 +178,81 @@ Methods
|
|||
|
||||
Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra
|
||||
|
||||
.. method:: UART.irq(handler=None, trigger=0, hard=False)
|
||||
|
||||
Configure an interrupt handler to be called when a UART event occurs.
|
||||
|
||||
The arguments are:
|
||||
|
||||
- *handler* is an optional function to be called when the interrupt event
|
||||
triggers. The handler must take exactly one argument which is the
|
||||
``UART`` instance.
|
||||
|
||||
- *trigger* configures the event which can generate an interrupt.
|
||||
Possible values are:
|
||||
|
||||
- ``UART.IRQ_RXIDLE`` interrupt after receiving at least one character
|
||||
and then the RX line goes idle.
|
||||
- ``UART.IRQ_RX`` interrupt after each received character.
|
||||
- ``UART.TX_IDLE`` interrupt after or while the last character(s) of
|
||||
a message are of have been sent.
|
||||
- ``UART.BREAK`` interrupt when a break state is detected at RX
|
||||
|
||||
- *hard* if true a hardware interrupt is used. This reduces the delay
|
||||
between the pin change and the handler being called. Hard interrupt
|
||||
handlers may not allocate memory; see :ref:`isr_rules`.
|
||||
|
||||
Returns an irq object.
|
||||
|
||||
Due to limitations of the hardware not all trigger events are available at all ports.
|
||||
|
||||
.. table:: Availability of triggers
|
||||
:align: center
|
||||
|
||||
============== ======= === ====== =====
|
||||
Port / Trigger RX_IDLE RX TXIDLE BREAK
|
||||
============== ======= === ====== =====
|
||||
STM32 yes
|
||||
ESP32 yes yes
|
||||
RP2040 yes yes yes
|
||||
MIMXRT yes yes
|
||||
SAMD yes yes
|
||||
RENESAS-RA yes
|
||||
NRF yes yes
|
||||
CC3200 yes
|
||||
============== ======= === ====== =====
|
||||
|
||||
|
||||
.. note::
|
||||
- At the RP2040 port UART.TXIDLE is only triggered when the message
|
||||
is longer than 5 characters and the trigger happens when still 5 characters
|
||||
are to be sent.
|
||||
|
||||
- At the SAMD port UART.TXIDLE is triggered while the last character is sent.
|
||||
|
||||
- At the RP2040 port UART.BREAK needs receiving valid characters for triggering
|
||||
again.
|
||||
|
||||
- The ESP32 port does not support the option hard=True.
|
||||
|
||||
|
||||
Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, nrf, cc3200.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: UART.RX_ANY
|
||||
.. data:: UART.RTS
|
||||
UART.CTS
|
||||
|
||||
IRQ trigger sources
|
||||
Flow control options.
|
||||
|
||||
Availability: WiPy.
|
||||
Availability: esp32, mimxrt, renesas-ra, rp2, stm32.
|
||||
|
||||
.. data:: UART.IRQ_RXIDLE
|
||||
UART.IRQ_RX
|
||||
UART.IRQ_TXIDLE
|
||||
UART.IRQ_BREAK
|
||||
|
||||
IRQ trigger sources.
|
||||
|
||||
Availability: renesas-ra, stm32, esp32, rp2040, mimxrt, samd, cc3200.
|
||||
|
|
|
@ -590,6 +590,7 @@ static const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = {
|
|||
|
||||
// class constants
|
||||
{ MP_ROM_QSTR(MP_QSTR_RX_ANY), MP_ROM_INT(UART_TRIGGER_RX_ANY) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(UART_TRIGGER_RX_ANY) },
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
|
||||
|
|
|
@ -32,6 +32,7 @@ list(APPEND MICROPY_SOURCE_SHARED
|
|||
${MICROPY_DIR}/shared/netutils/netutils.c
|
||||
${MICROPY_DIR}/shared/timeutils/timeutils.c
|
||||
${MICROPY_DIR}/shared/runtime/interrupt_char.c
|
||||
${MICROPY_DIR}/shared/runtime/mpirq.c
|
||||
${MICROPY_DIR}/shared/runtime/stdout_helpers.c
|
||||
${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c
|
||||
${MICROPY_DIR}/shared/runtime/pyexec.c
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
|
||||
#include "driver/uart.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_task.h"
|
||||
#include "shared/runtime/mpirq.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
|
@ -49,6 +53,9 @@
|
|||
#define UART_INV_CTS UART_SIGNAL_CTS_INV
|
||||
|
||||
#define UART_INV_MASK (UART_INV_TX | UART_INV_RX | UART_INV_RTS | UART_INV_CTS)
|
||||
#define UART_IRQ_RX (1 << UART_DATA)
|
||||
#define UART_IRQ_BREAK (1 << UART_BREAK)
|
||||
#define MP_UART_ALLOWED_FLAGS (UART_IRQ_RX | UART_IRQ_BREAK)
|
||||
|
||||
typedef struct _machine_uart_obj_t {
|
||||
mp_obj_base_t base;
|
||||
|
@ -66,6 +73,11 @@ typedef struct _machine_uart_obj_t {
|
|||
uint16_t timeout; // timeout waiting for first char (in ms)
|
||||
uint16_t timeout_char; // timeout waiting between chars (in ms)
|
||||
uint32_t invert; // lines to invert
|
||||
TaskHandle_t uart_event_task;
|
||||
QueueHandle_t uart_queue;
|
||||
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
|
||||
} machine_uart_obj_t;
|
||||
|
||||
static const char *_parity_name[] = {"None", "1", "0"};
|
||||
|
@ -80,14 +92,43 @@ static const char *_parity_name[] = {"None", "1", "0"};
|
|||
{ MP_ROM_QSTR(MP_QSTR_INV_CTS), MP_ROM_INT(UART_INV_CTS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HW_FLOWCTRL_RTS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HW_FLOWCTRL_CTS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(UART_IRQ_RX) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_BREAK), MP_ROM_INT(UART_IRQ_BREAK) }, \
|
||||
|
||||
static void uart_event_task(void *self_in) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uart_event_t event;
|
||||
for (;;) {
|
||||
// Waiting for an UART event.
|
||||
if (xQueueReceive(self->uart_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
|
||||
self->mp_irq_flags = 0;
|
||||
switch (event.type) {
|
||||
// Event of UART receiving data
|
||||
case UART_DATA:
|
||||
self->mp_irq_flags |= UART_IRQ_RX;
|
||||
break;
|
||||
case UART_BREAK:
|
||||
self->mp_irq_flags |= UART_IRQ_BREAK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 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);
|
||||
mp_hal_wake_main_task_from_isr();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t baudrate;
|
||||
check_esp_err(uart_get_baudrate(self->uart_num, &baudrate));
|
||||
mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, rts=%d, cts=%d, txbuf=%u, rxbuf=%u, timeout=%u, timeout_char=%u",
|
||||
mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, rts=%d, cts=%d, txbuf=%u, rxbuf=%u, timeout=%u, timeout_char=%u, irq=%d",
|
||||
self->uart_num, baudrate, self->bits, _parity_name[self->parity],
|
||||
self->stop, self->tx, self->rx, self->rts, self->cts, self->txbuf, self->rxbuf, self->timeout, self->timeout_char);
|
||||
self->stop, self->tx, self->rx, self->rts, self->cts, self->txbuf, self->rxbuf, self->timeout, self->timeout_char, self->mp_irq_trigger);
|
||||
if (self->invert) {
|
||||
mp_printf(print, ", invert=");
|
||||
uint32_t invert_mask = self->invert;
|
||||
|
@ -348,6 +389,7 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||
self->timeout_char = 0;
|
||||
self->invert = 0;
|
||||
self->flowcontrol = 0;
|
||||
self->uart_event_task = 0;
|
||||
|
||||
switch (uart_num) {
|
||||
case UART_NUM_0:
|
||||
|
@ -378,7 +420,7 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||
// Setup
|
||||
check_esp_err(uart_param_config(self->uart_num, &uartcfg));
|
||||
|
||||
check_esp_err(uart_driver_install(uart_num, self->rxbuf, self->txbuf, 0, NULL, 0));
|
||||
check_esp_err(uart_driver_install(uart_num, self->rxbuf, self->txbuf, 3, &self->uart_queue, 0));
|
||||
}
|
||||
|
||||
mp_map_t kw_args;
|
||||
|
@ -422,6 +464,66 @@ static void mp_machine_uart_sendbreak(machine_uart_obj_t *self) {
|
|||
check_esp_err(uart_set_baudrate(self->uart_num, baudrate));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
if (args[MP_IRQ_ARG_INIT_hard].u_bool) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("hard IRQ is not supported"));
|
||||
}
|
||||
self->mp_irq_obj->ishard = false;
|
||||
self->mp_irq_trigger = trigger;
|
||||
// Start a task for handling events
|
||||
if (handler != mp_const_none && self->uart_event_task == NULL) {
|
||||
xTaskCreatePinnedToCore(uart_event_task, "uart_event_task", 2048, self,
|
||||
ESP_TASKD_EVENT_PRIO, (TaskHandle_t *)&self->uart_event_task, MP_TASK_COREID);
|
||||
} else if (handler == mp_const_none && self->uart_event_task != NULL) {
|
||||
vTaskDelete(self->uart_event_task);
|
||||
self->uart_event_task = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return self->mp_irq_obj;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -152,6 +152,7 @@
|
|||
#define MICROPY_PY_MACHINE_UART (1)
|
||||
#define MICROPY_PY_MACHINE_UART_INCLUDEFILE "ports/esp32/machine_uart.c"
|
||||
#define MICROPY_PY_MACHINE_UART_SENDBREAK (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
#define MICROPY_PY_MACHINE_WDT (1)
|
||||
#define MICROPY_PY_MACHINE_WDT_INCLUDEFILE "ports/esp32/machine_wdt.c"
|
||||
#define MICROPY_PY_NETWORK (1)
|
||||
|
|
|
@ -132,7 +132,6 @@ SRC_HAL_IMX_C += \
|
|||
$(MCU_DIR)/drivers/fsl_lpi2c.c \
|
||||
$(MCU_DIR)/drivers/fsl_lpspi.c \
|
||||
$(MCU_DIR)/drivers/fsl_lpspi_edma.c \
|
||||
$(MCU_DIR)/drivers/fsl_lpuart.c \
|
||||
$(MCU_DIR)/drivers/fsl_pit.c \
|
||||
$(MCU_DIR)/drivers/fsl_pwm.c \
|
||||
$(MCU_DIR)/drivers/fsl_sai.c \
|
||||
|
@ -191,6 +190,7 @@ SRC_C += \
|
|||
eth.c \
|
||||
fatfs_port.c \
|
||||
flash.c \
|
||||
hal/fsl_lpuart.c \
|
||||
hal/pwm_backport.c \
|
||||
help.c \
|
||||
led.c \
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -50,6 +50,10 @@
|
|||
#define UART_INVERT_RX (2)
|
||||
#define UART_INVERT_MASK (UART_INVERT_TX | UART_INVERT_RX)
|
||||
|
||||
#define UART_IRQ_RXIDLE (1)
|
||||
#define UART_IRQ_TXIDLE (2)
|
||||
#define MP_UART_ALLOWED_FLAGS (UART_IRQ_RXIDLE | UART_IRQ_TXIDLE)
|
||||
|
||||
typedef struct _machine_uart_obj_t {
|
||||
mp_obj_base_t base;
|
||||
struct _lpuart_handle handle;
|
||||
|
@ -63,6 +67,9 @@ typedef struct _machine_uart_obj_t {
|
|||
uint8_t *txbuf;
|
||||
uint16_t txbuf_len;
|
||||
bool new;
|
||||
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
|
||||
} machine_uart_obj_t;
|
||||
|
||||
typedef struct _iomux_table_t {
|
||||
|
@ -137,11 +144,21 @@ bool lpuart_set_iomux_cts(int8_t uart) {
|
|||
|
||||
void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, status_t status, void *userData) {
|
||||
machine_uart_obj_t *self = userData;
|
||||
if (kStatus_LPUART_TxIdle == status) {
|
||||
|
||||
if (status == kStatus_LPUART_TxIdle) {
|
||||
self->tx_status = kStatus_LPUART_TxIdle;
|
||||
self->mp_irq_flags = UART_IRQ_TXIDLE;
|
||||
} else if (status == kStatus_LPUART_IdleLineDetected) {
|
||||
self->mp_irq_flags = UART_IRQ_RXIDLE;
|
||||
} else {
|
||||
self->mp_irq_flags = 0;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (kStatus_LPUART_RxRingBufferOverrun == status) {
|
||||
if (status == kStatus_LPUART_RxRingBufferOverrun) {
|
||||
; // Ringbuffer full, deassert RTS if flow control is enabled
|
||||
}
|
||||
}
|
||||
|
@ -170,16 +187,18 @@ void machine_uart_set_baudrate(mp_obj_t uart_in, uint32_t baudrate) {
|
|||
{ MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INVERT_RX) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RXIDLE), MP_ROM_INT(UART_IRQ_RXIDLE) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_TXIDLE), MP_ROM_INT(UART_IRQ_TXIDLE) }, \
|
||||
|
||||
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);
|
||||
mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, flow=%s, "
|
||||
"rxbuf=%d, txbuf=%d, timeout=%u, timeout_char=%u, invert=%s)",
|
||||
"rxbuf=%d, txbuf=%d, timeout=%u, timeout_char=%u, invert=%s, irq=%d)",
|
||||
self->id, self->config.baudRate_Bps, 8 - self->config.dataBitsCount,
|
||||
_parity_name[self->config.parityMode], self->config.stopBitCount + 1,
|
||||
_flow_name[(self->config.enableTxCTS << 1) | self->config.enableRxRTS],
|
||||
self->handle.rxRingBufferSize, self->txbuf_len, self->timeout, self->timeout_char,
|
||||
_invert_name[self->invert]);
|
||||
_invert_name[self->invert], self->mp_irq_trigger);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -313,12 +332,17 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args,
|
|||
#else
|
||||
LPUART_Init(self->lpuart, &self->config, CLOCK_GetClockRootFreq(kCLOCK_UartClkRoot));
|
||||
#endif
|
||||
self->config.rxIdleType = kLPUART_IdleTypeStartBit;
|
||||
self->config.rxIdleConfig = kLPUART_IdleCharacter4;
|
||||
LPUART_Init(self->lpuart, &self->config, BOARD_BOOTCLOCKRUN_UART_CLK_ROOT);
|
||||
LPUART_TransferCreateHandle(self->lpuart, &self->handle, LPUART_UserCallback, self);
|
||||
uint8_t *buffer = m_new(uint8_t, rxbuf_len + 1);
|
||||
LPUART_TransferStartRingBuffer(self->lpuart, &self->handle, buffer, rxbuf_len);
|
||||
self->txbuf = m_new(uint8_t, txbuf_len); // Allocate the TX buffer.
|
||||
self->txbuf_len = txbuf_len;
|
||||
|
||||
LPUART_EnableInterrupts(self->lpuart, kLPUART_IdleLineInterruptEnable);
|
||||
|
||||
// The Uart supports inverting, but not the fsl API, so it has to coded directly
|
||||
// And it has to be done after LPUART_Init.
|
||||
if (self->invert & UART_INVERT_RX) {
|
||||
|
@ -356,6 +380,8 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||
self->timeout = 1;
|
||||
self->timeout_char = 1;
|
||||
self->new = true;
|
||||
self->mp_irq_obj = NULL;
|
||||
|
||||
LPUART_GetDefaultConfig(&self->config);
|
||||
|
||||
// Configure board-specific pin MUX based on the hardware device number.
|
||||
|
@ -401,6 +427,55 @@ void machine_uart_deinit_all(void) {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
uint64_t t = ticks_us64() + (uint64_t)self->timeout * 1000;
|
||||
|
|
|
@ -114,6 +114,7 @@ uint32_t trng_random_u32(void);
|
|||
#define MICROPY_PY_MACHINE_UART (1)
|
||||
#define MICROPY_PY_MACHINE_UART_INCLUDEFILE "ports/mimxrt/machine_uart.c"
|
||||
#define MICROPY_PY_MACHINE_UART_SENDBREAK (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
#define MICROPY_PY_ONEWIRE (1)
|
||||
|
||||
// fatfs configuration used in ffconf.h
|
||||
|
|
|
@ -182,6 +182,7 @@ endif
|
|||
SRC_SHARED_C += $(addprefix shared/,\
|
||||
libc/string0.c \
|
||||
readline/readline.c \
|
||||
runtime/mpirq.c \
|
||||
runtime/pyexec.c \
|
||||
runtime/sys_stdio_mphal.c \
|
||||
runtime/interrupt_char.c \
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_ADC (1)
|
||||
#define MICROPY_PY_MACHINE_TEMP (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
|
||||
#define MICROPY_HW_USB_CDC (1)
|
||||
#define MICROPY_HW_HAS_LED (1)
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_ADC (1)
|
||||
#define MICROPY_PY_MACHINE_TEMP (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
|
||||
// Configure LEDS
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_ADC (1)
|
||||
#define MICROPY_PY_MACHINE_TEMP (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_ADC (1)
|
||||
#define MICROPY_PY_MACHINE_TEMP (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_ADC (1)
|
||||
#define MICROPY_PY_MACHINE_TEMP (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_ADC (1)
|
||||
#define MICROPY_PY_MACHINE_TEMP (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_ADC (1)
|
||||
#define MICROPY_PY_MACHINE_TEMP (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
#define MICROPY_HW_HAS_FLASH (1)
|
||||
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
|
|
|
@ -68,6 +68,7 @@ typedef struct _machine_uart_buf_t {
|
|||
#define NRF_UART_HWFC_DISABLED NRF_UARTE_HWFC_DISABLED
|
||||
#define NRF_UART_PARITY_EXCLUDED NRF_UARTE_PARITY_EXCLUDED
|
||||
#define NRFX_UART_EVT_RX_DONE NRFX_UARTE_EVT_RX_DONE
|
||||
#define NRFX_UART_EVT_TX_DONE NRFX_UARTE_EVT_TX_DONE
|
||||
#define NRFX_UART_EVT_ERROR NRFX_UARTE_EVT_ERROR
|
||||
|
||||
#define NRF_UART_BAUDRATE_1200 NRF_UARTE_BAUDRATE_1200
|
||||
|
@ -87,12 +88,24 @@ typedef struct _machine_uart_buf_t {
|
|||
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||
#define NRFX_UART_IRQ_RX (1 << NRFX_UART_EVT_RX_DONE)
|
||||
#define NRFX_UART_IRQ_TXIDLE (1 << NRFX_UART_EVT_TX_DONE)
|
||||
#define MP_UART_ALLOWED_FLAGS (NRFX_UART_IRQ_RX | NRFX_UART_IRQ_TXIDLE)
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct _machine_uart_obj_t {
|
||||
mp_obj_base_t base;
|
||||
const nrfx_uart_t *p_uart; // Driver instance
|
||||
machine_uart_buf_t buf;
|
||||
uint16_t timeout; // timeout waiting for first char (in ms)
|
||||
uint16_t timeout_char; // timeout waiting between chars (in ms)
|
||||
#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 nrfx_uart_t instance0 = NRFX_UART_INSTANCE(0);
|
||||
|
@ -115,6 +128,9 @@ static int uart_find(mp_obj_t id) {
|
|||
|
||||
static void uart_event_handler(nrfx_uart_event_t const *p_event, void *p_context) {
|
||||
machine_uart_obj_t *self = p_context;
|
||||
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||
self->mp_irq_flags = 0;
|
||||
#endif
|
||||
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];
|
||||
|
@ -128,10 +144,23 @@ static void uart_event_handler(nrfx_uart_event_t const *p_event, void *p_context
|
|||
{
|
||||
ringbuf_put((ringbuf_t *)&self->buf.rx_ringbuf, chr);
|
||||
}
|
||||
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||
self->mp_irq_flags |= NRFX_UART_IRQ_RX;
|
||||
#endif
|
||||
} else if (p_event->type == NRFX_UART_EVT_ERROR) {
|
||||
// Perform a read to unlock UART in case of an error
|
||||
nrfx_uart_rx(self->p_uart, &self->buf.rx_buf[0], 1);
|
||||
} else if (p_event->type == NRFX_UART_EVT_TX_DONE) {
|
||||
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||
self->mp_irq_flags |= NRFX_UART_IRQ_TXIDLE;
|
||||
#endif
|
||||
}
|
||||
#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
|
||||
}
|
||||
|
||||
bool uart_rx_any(machine_uart_obj_t *self) {
|
||||
|
@ -170,7 +199,14 @@ void uart_tx_strn_cooked(machine_uart_obj_t *uart_obj, const char *str, uint len
|
|||
/* MicroPython bindings */
|
||||
|
||||
// The UART class doesn't have any constants for this port.
|
||||
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||
#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(NRFX_UART_IRQ_RX) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_TXIDLE), MP_ROM_INT(NRFX_UART_IRQ_TXIDLE) }, \
|
||||
|
||||
#else
|
||||
#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS
|
||||
#endif
|
||||
|
||||
static void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_printf(print, "UART(0)");
|
||||
|
@ -292,6 +328,57 @@ static bool mp_machine_uart_txdone(machine_uart_obj_t *self) {
|
|||
return !nrfx_uart_tx_in_progress(self->p_uart);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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 = self_in;
|
||||
byte *buf = buf_in;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#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) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(0x10) }, \
|
||||
|
||||
static const char *_parity_name[] = {"None", "ODD", "EVEN"};
|
||||
|
||||
|
|
|
@ -80,6 +80,11 @@
|
|||
|
||||
#define UART_HWCONTROL_CTS (1)
|
||||
#define UART_HWCONTROL_RTS (2)
|
||||
// OR-ed IRQ flags which are allowed to be used by the user
|
||||
#define MP_UART_ALLOWED_FLAGS (UART_UARTMIS_RTMIS_BITS | UART_UARTMIS_TXMIS_BITS | UART_UARTMIS_BEMIS_BITS)
|
||||
#define UART_FIFO_SIZE_RX (32)
|
||||
#define UART_FIFO_TRIGGER_LEVEL_RX (24)
|
||||
|
||||
|
||||
static mutex_t write_mutex_0;
|
||||
static mutex_t write_mutex_1;
|
||||
|
@ -111,12 +116,15 @@ typedef struct _machine_uart_obj_t {
|
|||
mutex_t *read_mutex;
|
||||
ringbuf_t write_buffer;
|
||||
mutex_t *write_mutex;
|
||||
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
|
||||
} machine_uart_obj_t;
|
||||
|
||||
static machine_uart_obj_t machine_uart_obj[] = {
|
||||
{{&machine_uart_type}, uart0, 0, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP,
|
||||
MICROPY_HW_UART0_TX, MICROPY_HW_UART0_RX, MICROPY_HW_UART0_CTS, MICROPY_HW_UART0_RTS,
|
||||
0, 0, 0, 0, {NULL, 1, 0, 0}, &read_mutex_0, {NULL, 1, 0, 0}, &write_mutex_0},
|
||||
0, 0, 0, 0, {NULL, 1, 0, 0}, &read_mutex_0, {NULL, 1, 0, 0}, &write_mutex_0, 0, 0, NULL},
|
||||
{{&machine_uart_type}, uart1, 1, 0, DEFAULT_UART_BITS, UART_PARITY_NONE, DEFAULT_UART_STOP,
|
||||
MICROPY_HW_UART1_TX, MICROPY_HW_UART1_RX, MICROPY_HW_UART1_CTS, MICROPY_HW_UART1_RTS,
|
||||
0, 0, 0, 0, {NULL, 1, 0, 0}, &read_mutex_1, {NULL, 1, 0, 0}, &write_mutex_1},
|
||||
|
@ -144,14 +152,15 @@ static inline void read_mutex_unlock(machine_uart_obj_t *u) {
|
|||
mutex_exit(u->read_mutex);
|
||||
}
|
||||
|
||||
// take all bytes from the fifo and store them in the buffer
|
||||
static void uart_drain_rx_fifo(machine_uart_obj_t *self) {
|
||||
// take at most max_items bytes from the fifo and store them in the buffer
|
||||
static void uart_drain_rx_fifo(machine_uart_obj_t *self, uint32_t max_items) {
|
||||
if (read_mutex_try_lock(self)) {
|
||||
while (uart_is_readable(self->uart) && ringbuf_free(&self->read_buffer) > 0) {
|
||||
while (uart_is_readable(self->uart) && ringbuf_free(&self->read_buffer) > 0 && max_items > 0) {
|
||||
// Get a byte from uart and put into the buffer. Every entry from
|
||||
// the FIFO is accompanied by 4 error bits, that may be used for
|
||||
// error handling.
|
||||
uint16_t c = uart_get_hw(self->uart)->dr;
|
||||
max_items -= 1;
|
||||
if (c & UART_UARTDR_OE_BITS) {
|
||||
// Overrun Error: We missed at least one byte. Not much we can do here.
|
||||
}
|
||||
|
@ -187,15 +196,29 @@ static void uart_fill_tx_fifo(machine_uart_obj_t *self) {
|
|||
}
|
||||
|
||||
static inline void uart_service_interrupt(machine_uart_obj_t *self) {
|
||||
if (uart_get_hw(self->uart)->mis & (UART_UARTMIS_RXMIS_BITS | UART_UARTMIS_RTMIS_BITS)) { // rx interrupt?
|
||||
// clear all interrupt bits but tx
|
||||
uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & (~UART_UARTICR_TXIC_BITS);
|
||||
uart_drain_rx_fifo(self);
|
||||
self->mp_irq_flags = uart_get_hw(self->uart)->mis & (UART_UARTMIS_RXMIS_BITS | UART_UARTMIS_RTMIS_BITS);
|
||||
if (self->mp_irq_flags) { // rx interrupt?
|
||||
// clear all interrupt bits but tx and break
|
||||
uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & ~(UART_UARTICR_TXIC_BITS | UART_UARTICR_BEIC_BITS);
|
||||
uart_drain_rx_fifo(self, UART_FIFO_TRIGGER_LEVEL_RX - 1);
|
||||
}
|
||||
if (uart_get_hw(self->uart)->mis & UART_UARTMIS_TXMIS_BITS) { // tx interrupt?
|
||||
// clear all interrupt bits but rx
|
||||
uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & ~(UART_UARTICR_RXIC_BITS | UART_UARTICR_RTIC_BITS);
|
||||
uart_fill_tx_fifo(self);
|
||||
// clear all interrupt bits but rx and break
|
||||
uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & ~(UART_UARTICR_RXIC_BITS | UART_UARTICR_RTIC_BITS | UART_UARTICR_BEIC_BITS);
|
||||
if (ringbuf_avail(&self->write_buffer) == 0) {
|
||||
self->mp_irq_flags |= UART_UARTMIS_TXMIS_BITS;
|
||||
} else {
|
||||
uart_fill_tx_fifo(self);
|
||||
}
|
||||
}
|
||||
if (uart_get_hw(self->uart)->mis & UART_UARTMIS_BEMIS_BITS) { // break interrupt?
|
||||
// CLear the event
|
||||
hw_set_bits(&uart_get_hw(self->uart)->icr, UART_UARTICR_BEIC_BITS);
|
||||
self->mp_irq_flags |= UART_UARTMIS_BEMIS_BITS;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,14 +238,17 @@ static void uart1_irq_handler(void) {
|
|||
{ MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INVERT_RX) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HWCONTROL_CTS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HWCONTROL_RTS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RXIDLE), MP_ROM_INT(UART_UARTMIS_RTMIS_BITS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_TXIDLE), MP_ROM_INT(UART_UARTMIS_TXMIS_BITS) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_BREAK), MP_ROM_INT(UART_UARTMIS_BEMIS_BITS) }, \
|
||||
|
||||
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);
|
||||
mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, "
|
||||
"txbuf=%d, rxbuf=%d, timeout=%u, timeout_char=%u, invert=%s)",
|
||||
"txbuf=%d, rxbuf=%d, timeout=%u, timeout_char=%u, invert=%s, irq=%d)",
|
||||
self->uart_id, self->baudrate, self->bits, _parity_name[self->parity],
|
||||
self->stop, self->tx, self->rx, self->write_buffer.size - 1, self->read_buffer.size - 1,
|
||||
self->timeout, self->timeout_char, _invert_name[self->invert]);
|
||||
self->timeout, self->timeout_char, _invert_name[self->invert], self->mp_irq_trigger);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -422,6 +448,7 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||
|
||||
// Get static peripheral object.
|
||||
machine_uart_obj_t *self = (machine_uart_obj_t *)&machine_uart_obj[uart_id];
|
||||
self->mp_irq_obj = NULL;
|
||||
|
||||
// Initialise the UART peripheral.
|
||||
mp_map_t kw_args;
|
||||
|
@ -445,7 +472,7 @@ static void mp_machine_uart_deinit(machine_uart_obj_t *self) {
|
|||
|
||||
static mp_int_t mp_machine_uart_any(machine_uart_obj_t *self) {
|
||||
// get all bytes from the fifo first
|
||||
uart_drain_rx_fifo(self);
|
||||
uart_drain_rx_fifo(self, UART_FIFO_SIZE_RX + 1);
|
||||
return ringbuf_avail(&self->read_buffer);
|
||||
}
|
||||
|
||||
|
@ -460,6 +487,76 @@ static void mp_machine_uart_sendbreak(machine_uart_obj_t *self) {
|
|||
uart_set_break(self->uart, false);
|
||||
}
|
||||
|
||||
static void uart_set_irq_level(machine_uart_obj_t *self, uint16_t trigger) {
|
||||
if (trigger & UART_UARTMIS_BEMIS_BITS) {
|
||||
// Enable the break Interrupt
|
||||
hw_set_bits(&uart_get_hw(self->uart)->imsc, UART_UARTIMSC_BEIM_BITS);
|
||||
} else {
|
||||
// Disable the break Interrupt
|
||||
hw_clear_bits(&uart_get_hw(self->uart)->imsc, UART_UARTIMSC_BEIM_BITS);
|
||||
}
|
||||
if (trigger & UART_UARTMIS_RTMIS_BITS) {
|
||||
// Set the RX trigger level to 3/4 FIFO_size
|
||||
hw_write_masked(&uart_get_hw(self->uart)->ifls, 0b011 << UART_UARTIFLS_RXIFLSEL_LSB,
|
||||
UART_UARTIFLS_RXIFLSEL_BITS);
|
||||
} else {
|
||||
// Set the RX trigger level to 1/8 FIFO_size
|
||||
hw_write_masked(&uart_get_hw(self->uart)->ifls, 0 << UART_UARTIFLS_RXIFLSEL_LSB,
|
||||
UART_UARTIFLS_RXIFLSEL_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
uart_set_irq_level(self, 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;
|
||||
}
|
||||
|
||||
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;
|
||||
uart_set_irq_level(self, trigger);
|
||||
}
|
||||
|
||||
return self->mp_irq_obj;
|
||||
}
|
||||
|
||||
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);
|
||||
mp_uint_t start = mp_hal_ticks_ms();
|
||||
|
@ -471,7 +568,7 @@ static mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t
|
|||
while (ringbuf_avail(&self->read_buffer) == 0) {
|
||||
if (uart_is_readable(self->uart)) {
|
||||
// Force a few incoming bytes to the buffer
|
||||
uart_drain_rx_fifo(self);
|
||||
uart_drain_rx_fifo(self, UART_FIFO_SIZE_RX + 1);
|
||||
break;
|
||||
}
|
||||
mp_uint_t elapsed = mp_hal_ticks_ms() - start;
|
||||
|
|
|
@ -145,6 +145,7 @@
|
|||
#define MICROPY_PY_MACHINE_UART (1)
|
||||
#define MICROPY_PY_MACHINE_UART_INCLUDEFILE "ports/rp2/machine_uart.c"
|
||||
#define MICROPY_PY_MACHINE_UART_SENDBREAK (1)
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (1)
|
||||
#define MICROPY_PY_MACHINE_WDT (1)
|
||||
#define MICROPY_PY_MACHINE_WDT_INCLUDEFILE "ports/rp2/machine_wdt.c"
|
||||
#define MICROPY_PY_ONEWIRE (1)
|
||||
|
|
|
@ -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,16 +107,28 @@ 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
|
||||
|
@ -110,6 +136,13 @@ void common_uart_irq_handler(int uart_id) {
|
|||
// 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 +235,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 +248,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
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -386,6 +425,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 +487,57 @@ 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;
|
||||
}
|
||||
|
||||
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];
|
||||
|
@ -484,6 +577,12 @@ static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_
|
|||
#if MICROPY_HW_UART_TXBUF
|
||||
uint64_t t = mp_hal_ticks_ms_64() + self->timeout;
|
||||
|
||||
// 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
|
||||
while (i < size) {
|
||||
// Wait for the first/next character to be sent.
|
||||
while (ringbuf_free(&(self->write_buffer)) == 0) {
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
#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)
|
||||
#define MICROPY_FATFS_RPATH (2)
|
||||
#define MICROPY_FATFS_MAX_SS (4096)
|
||||
#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
|
||||
#define MICROPY_FATFS_ENABLE_LFN (1)
|
||||
#define MICROPY_FATFS_RPATH (2)
|
||||
#define MICROPY_FATFS_MAX_SS (4096)
|
||||
#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
|
||||
|
||||
#define VFS_BLOCK_SIZE_BYTES (1536) //
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue