Robert Hammelrath 2024-04-26 22:11:29 +02:00 zatwierdzone przez GitHub
commit 4dd530949a
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
23 zmienionych plików z 2589 dodań i 56 usunięć

Wyświetl plik

@ -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.

Wyświetl plik

@ -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);

Wyświetl plik

@ -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

Wyświetl plik

@ -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);

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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;

Wyświetl plik

@ -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

Wyświetl plik

@ -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 \

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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;

Wyświetl plik

@ -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"};

Wyświetl plik

@ -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;

Wyświetl plik

@ -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)

Wyświetl plik

@ -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) {

Wyświetl plik

@ -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) //