|
| 1 | +/* |
| 2 | + * This file is part of the MicroPython project, http://micropython.org/ |
| 3 | + * |
| 4 | + * The MIT License (MIT) |
| 5 | + * |
| 6 | + * Copyright (c) 2016-2023 Damien P. George |
| 7 | + * |
| 8 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 9 | + * of this software and associated documentation files (the "Software"), to deal |
| 10 | + * in the Software without restriction, including without limitation the rights |
| 11 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 12 | + * copies of the Software, and to permit persons to whom the Software is |
| 13 | + * furnished to do so, subject to the following conditions: |
| 14 | + * |
| 15 | + * The above copyright notice and this permission notice shall be included in |
| 16 | + * all copies or substantial portions of the Software. |
| 17 | + * |
| 18 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 19 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 20 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 21 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 22 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 23 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 24 | + * THE SOFTWARE. |
| 25 | + */ |
| 26 | + |
| 27 | +// This file is never compiled standalone, it's included directly from |
| 28 | +// extmod/machine_uart.c via MICROPY_PY_MACHINE_UART_INCLUDEFILE. |
| 29 | + |
| 30 | +#include "driver/uart.h" |
| 31 | +#include "freertos/FreeRTOS.h" |
| 32 | +#include "freertos/task.h" |
| 33 | +#include "freertos/queue.h" |
| 34 | +#include "esp_task.h" |
| 35 | +#include "shared/runtime/mpirq.h" |
| 36 | + |
| 37 | +#include "py/runtime.h" |
| 38 | +#include "py/stream.h" |
| 39 | +#include "py/mperrno.h" |
| 40 | +#include "py/mphal.h" |
| 41 | +#include "uart.h" |
| 42 | +#include "machine_timer.h" |
| 43 | + |
| 44 | +#if SOC_UART_SUPPORT_XTAL_CLK |
| 45 | +// Works independently of APB frequency, on ESP32C3, ESP32S3. |
| 46 | +#define UART_SOURCE_CLK UART_SCLK_XTAL |
| 47 | +#else |
| 48 | +#define UART_SOURCE_CLK UART_SCLK_DEFAULT |
| 49 | +#endif |
| 50 | + |
| 51 | +#define UART_INV_TX UART_SIGNAL_TXD_INV |
| 52 | +#define UART_INV_RX UART_SIGNAL_RXD_INV |
| 53 | +#define UART_INV_RTS UART_SIGNAL_RTS_INV |
| 54 | +#define UART_INV_CTS UART_SIGNAL_CTS_INV |
| 55 | + |
| 56 | +#define UART_INV_MASK (UART_INV_TX | UART_INV_RX | UART_INV_RTS | UART_INV_CTS) |
| 57 | +#define UART_IRQ_RX (1 << UART_DATA) |
| 58 | +#define UART_IRQ_RXIDLE (0x1000) |
| 59 | +#define UART_IRQ_BREAK (1 << UART_BREAK) |
| 60 | +#define MP_UART_ALLOWED_FLAGS (UART_IRQ_RX | UART_IRQ_RXIDLE | UART_IRQ_BREAK) |
| 61 | +#define RXIDLE_TIMER_MIN (5000) // 500 us |
| 62 | + |
| 63 | +#define TIMER_DIVIDER 8 |
| 64 | +#define TIMER_SCALE (APB_CLK_FREQ / TIMER_DIVIDER) |
| 65 | + |
| 66 | +enum { |
| 67 | + RXIDLE_INACTIVE, |
| 68 | + RXIDLE_STANDBY, |
| 69 | + RXIDLE_ARMED, |
| 70 | + RXIDLE_ALERT, |
| 71 | +}; |
| 72 | + |
| 73 | +typedef struct _machine_uart_obj_t { |
| 74 | + mp_obj_base_t base; |
| 75 | + uart_port_t uart_num; |
| 76 | + uart_hw_flowcontrol_t flowcontrol; |
| 77 | + uint8_t bits; |
| 78 | + uint8_t parity; |
| 79 | + uint8_t stop; |
| 80 | + gpio_num_t tx; |
| 81 | + gpio_num_t rx; |
| 82 | + gpio_num_t rts; |
| 83 | + gpio_num_t cts; |
| 84 | + uint16_t txbuf; |
| 85 | + uint16_t rxbuf; |
| 86 | + uint16_t timeout; // timeout waiting for first char (in ms) |
| 87 | + uint16_t timeout_char; // timeout waiting between chars (in ms) |
| 88 | + uint32_t invert; // lines to invert |
| 89 | + TaskHandle_t uart_event_task; |
| 90 | + QueueHandle_t uart_queue; |
| 91 | + uint16_t mp_irq_trigger; // user IRQ trigger mask |
| 92 | + uint16_t mp_irq_flags; // user IRQ active IRQ flags |
| 93 | + mp_irq_obj_t *mp_irq_obj; // user IRQ object |
| 94 | + machine_timer_obj_t *rxidle_timer; |
| 95 | + uint8_t rxidle_state; |
| 96 | + uint16_t rxidle_period; |
| 97 | +} machine_uart_obj_t; |
| 98 | + |
| 99 | +static const char *_parity_name[] = {"None", "1", "0"}; |
| 100 | + |
| 101 | +/******************************************************************************/ |
| 102 | +// MicroPython bindings for UART |
| 103 | + |
| 104 | +#define MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS \ |
| 105 | + { MP_ROM_QSTR(MP_QSTR_INV_TX), MP_ROM_INT(UART_INV_TX) }, \ |
| 106 | + { MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INV_RX) }, \ |
| 107 | + { MP_ROM_QSTR(MP_QSTR_INV_RTS), MP_ROM_INT(UART_INV_RTS) }, \ |
| 108 | + { MP_ROM_QSTR(MP_QSTR_INV_CTS), MP_ROM_INT(UART_INV_CTS) }, \ |
| 109 | + { MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HW_FLOWCTRL_RTS) }, \ |
| 110 | + { MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HW_FLOWCTRL_CTS) }, \ |
| 111 | + { MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(UART_IRQ_RX) }, \ |
| 112 | + { MP_ROM_QSTR(MP_QSTR_IRQ_RXIDLE), MP_ROM_INT(UART_IRQ_RXIDLE) }, \ |
| 113 | + { MP_ROM_QSTR(MP_QSTR_IRQ_BREAK), MP_ROM_INT(UART_IRQ_BREAK) }, \ |
| 114 | + |
| 115 | +static void uart_timer_callback(void *self_in) { |
| 116 | + machine_timer_obj_t *self = self_in; |
| 117 | + |
| 118 | + // The UART object is referred here by the callback field. |
| 119 | + machine_uart_obj_t *uart = (machine_uart_obj_t *)self->callback; |
| 120 | + if (uart->rxidle_state == RXIDLE_ALERT) { |
| 121 | + // At the first call, just switch the state |
| 122 | + uart->rxidle_state = RXIDLE_ARMED; |
| 123 | + } else if (uart->rxidle_state == RXIDLE_ARMED) { |
| 124 | + // At the second call, run the irq callback and stop the timer |
| 125 | + uart->rxidle_state = RXIDLE_STANDBY; |
| 126 | + uart->mp_irq_flags = UART_IRQ_RXIDLE; |
| 127 | + mp_irq_handler(uart->mp_irq_obj); |
| 128 | + mp_hal_wake_main_task_from_isr(); |
| 129 | + machine_timer_disable(uart->rxidle_timer); |
| 130 | + } |
| 131 | +} |
| 132 | + |
| 133 | +static void uart_event_task(void *self_in) { |
| 134 | + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 135 | + uart_event_t event; |
| 136 | + for (;;) { |
| 137 | + // Waiting for an UART event. |
| 138 | + if (xQueueReceive(self->uart_queue, (void *)&event, (TickType_t)portMAX_DELAY)) { |
| 139 | + uint16_t mp_irq_flags = 0; |
| 140 | + switch (event.type) { |
| 141 | + // Event of UART receiving data |
| 142 | + case UART_DATA: |
| 143 | + if (self->mp_irq_trigger & UART_IRQ_RXIDLE) { |
| 144 | + if (self->rxidle_state != RXIDLE_INACTIVE) { |
| 145 | + if (self->rxidle_state == RXIDLE_STANDBY) { |
| 146 | + self->rxidle_timer->repeat = true; |
| 147 | + self->rxidle_timer->handle = NULL; |
| 148 | + machine_timer_enable(self->rxidle_timer, uart_timer_callback); |
| 149 | + } |
| 150 | + } |
| 151 | + self->rxidle_state = RXIDLE_ALERT; |
| 152 | + } |
| 153 | + mp_irq_flags |= UART_IRQ_RX; |
| 154 | + break; |
| 155 | + case UART_BREAK: |
| 156 | + mp_irq_flags |= UART_IRQ_BREAK; |
| 157 | + break; |
| 158 | + default: |
| 159 | + break; |
| 160 | + } |
| 161 | + // Check the flags to see if the user handler should be called |
| 162 | + if (self->mp_irq_trigger & mp_irq_flags) { |
| 163 | + self->mp_irq_flags = mp_irq_flags; |
| 164 | + mp_irq_handler(self->mp_irq_obj); |
| 165 | + mp_hal_wake_main_task_from_isr(); |
| 166 | + } |
| 167 | + } |
| 168 | + } |
| 169 | +} |
| 170 | + |
| 171 | +static void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { |
| 172 | + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 173 | + uint32_t baudrate; |
| 174 | + check_esp_err(uart_get_baudrate(self->uart_num, &baudrate)); |
| 175 | + 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", |
| 176 | + self->uart_num, baudrate, self->bits, _parity_name[self->parity], |
| 177 | + self->stop, self->tx, self->rx, self->rts, self->cts, self->txbuf, self->rxbuf, self->timeout, self->timeout_char, self->mp_irq_trigger); |
| 178 | + if (self->invert) { |
| 179 | + mp_printf(print, ", invert="); |
| 180 | + uint32_t invert_mask = self->invert; |
| 181 | + if (invert_mask & UART_INV_TX) { |
| 182 | + mp_printf(print, "INV_TX"); |
| 183 | + invert_mask &= ~UART_INV_TX; |
| 184 | + if (invert_mask) { |
| 185 | + mp_printf(print, "|"); |
| 186 | + } |
| 187 | + } |
| 188 | + if (invert_mask & UART_INV_RX) { |
| 189 | + mp_printf(print, "INV_RX"); |
| 190 | + invert_mask &= ~UART_INV_RX; |
| 191 | + if (invert_mask) { |
| 192 | + mp_printf(print, "|"); |
| 193 | + } |
| 194 | + } |
| 195 | + if (invert_mask & UART_INV_RTS) { |
| 196 | + mp_printf(print, "INV_RTS"); |
| 197 | + invert_mask &= ~UART_INV_RTS; |
| 198 | + if (invert_mask) { |
| 199 | + mp_printf(print, "|"); |
| 200 | + } |
| 201 | + } |
| 202 | + if (invert_mask & UART_INV_CTS) { |
| 203 | + mp_printf(print, "INV_CTS"); |
| 204 | + } |
| 205 | + } |
| 206 | + if (self->flowcontrol) { |
| 207 | + mp_printf(print, ", flow="); |
| 208 | + uint32_t flow_mask = self->flowcontrol; |
| 209 | + if (flow_mask & UART_HW_FLOWCTRL_RTS) { |
| 210 | + mp_printf(print, "RTS"); |
| 211 | + flow_mask &= ~UART_HW_FLOWCTRL_RTS; |
| 212 | + if (flow_mask) { |
| 213 | + mp_printf(print, "|"); |
| 214 | + } |
| 215 | + } |
| 216 | + if (flow_mask & UART_HW_FLOWCTRL_CTS) { |
| 217 | + mp_printf(print, "CTS"); |
| 218 | + } |
| 219 | + } |
| 220 | + mp_printf(print, ")"); |
| 221 | +} |
| 222 | + |
| 223 | +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) { |
| 224 | + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_txbuf, ARG_rxbuf, ARG_timeout, ARG_timeout_char, ARG_invert, ARG_flow }; |
| 225 | + static const mp_arg_t allowed_args[] = { |
| 226 | + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} }, |
| 227 | + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} }, |
| 228 | + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, |
| 229 | + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} }, |
| 230 | + { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, |
| 231 | + { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, |
| 232 | + { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, |
| 233 | + { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, |
| 234 | + { MP_QSTR_txbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, |
| 235 | + { MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, |
| 236 | + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, |
| 237 | + { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, |
| 238 | + { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, |
| 239 | + { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, |
| 240 | + }; |
| 241 | + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
| 242 | + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
| 243 | + |
| 244 | + // wait for all data to be transmitted before changing settings |
| 245 | + uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000)); |
| 246 | + |
| 247 | + if (args[ARG_txbuf].u_int >= 0 || args[ARG_rxbuf].u_int >= 0) { |
| 248 | + // must reinitialise driver to change the tx/rx buffer size |
| 249 | + #if MICROPY_HW_ENABLE_UART_REPL |
| 250 | + if (self->uart_num == MICROPY_HW_UART_REPL) { |
| 251 | + mp_raise_ValueError(MP_ERROR_TEXT("UART buffer size is fixed")); |
| 252 | + } |
| 253 | + #endif |
| 254 | + |
| 255 | + if (args[ARG_txbuf].u_int >= 0) { |
| 256 | + self->txbuf = args[ARG_txbuf].u_int; |
| 257 | + } |
| 258 | + if (args[ARG_rxbuf].u_int >= 0) { |
| 259 | + self->rxbuf = args[ARG_rxbuf].u_int; |
| 260 | + } |
| 261 | + uart_config_t uartcfg = { |
| 262 | + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, |
| 263 | + .rx_flow_ctrl_thresh = 0, |
| 264 | + .source_clk = UART_SOURCE_CLK, |
| 265 | + }; |
| 266 | + uint32_t baudrate; |
| 267 | + check_esp_err(uart_get_baudrate(self->uart_num, &baudrate)); |
| 268 | + uartcfg.baud_rate = baudrate; |
| 269 | + check_esp_err(uart_get_word_length(self->uart_num, &uartcfg.data_bits)); |
| 270 | + check_esp_err(uart_get_parity(self->uart_num, &uartcfg.parity)); |
| 271 | + check_esp_err(uart_get_stop_bits(self->uart_num, &uartcfg.stop_bits)); |
| 272 | + check_esp_err(uart_driver_delete(self->uart_num)); |
| 273 | + check_esp_err(uart_param_config(self->uart_num, &uartcfg)); |
| 274 | + check_esp_err(uart_driver_install(self->uart_num, self->rxbuf, self->txbuf, 0, NULL, 0)); |
| 275 | + } |
| 276 | + |
| 277 | + // set baudrate |
| 278 | + uint32_t baudrate = 115200; |
| 279 | + if (args[ARG_baudrate].u_int > 0) { |
| 280 | + check_esp_err(uart_set_baudrate(self->uart_num, args[ARG_baudrate].u_int)); |
| 281 | + } |
| 282 | + check_esp_err(uart_get_baudrate(self->uart_num, &baudrate)); |
| 283 | + |
| 284 | + if (args[ARG_tx].u_obj != MP_OBJ_NULL) { |
| 285 | + self->tx = machine_pin_get_id(args[ARG_tx].u_obj); |
| 286 | + } |
| 287 | + |
| 288 | + if (args[ARG_rx].u_obj != MP_OBJ_NULL) { |
| 289 | + self->rx = machine_pin_get_id(args[ARG_rx].u_obj); |
| 290 | + } |
| 291 | + |
| 292 | + if (args[ARG_rts].u_obj != MP_OBJ_NULL) { |
| 293 | + self->rts = machine_pin_get_id(args[ARG_rts].u_obj); |
| 294 | + } |
| 295 | + |
| 296 | + if (args[ARG_cts].u_obj != MP_OBJ_NULL) { |
| 297 | + self->cts = machine_pin_get_id(args[ARG_cts].u_obj); |
| 298 | + } |
| 299 | + check_esp_err(uart_set_pin(self->uart_num, self->tx, self->rx, self->rts, self->cts)); |
| 300 | + |
| 301 | + // set data bits |
| 302 | + switch (args[ARG_bits].u_int) { |
| 303 | + case 0: |
| 304 | + break; |
| 305 | + case 5: |
| 306 | + check_esp_err(uart_set_word_length(self->uart_num, UART_DATA_5_BITS)); |
| 307 | + self->bits = 5; |
| 308 | + break; |
| 309 | + case 6: |
| 310 | + check_esp_err(uart_set_word_length(self->uart_num, UART_DATA_6_BITS)); |
| 311 | + self->bits = 6; |
| 312 | + break; |
| 313 | + case 7: |
| 314 | + check_esp_err(uart_set_word_length(self->uart_num, UART_DATA_7_BITS)); |
| 315 | + self->bits = 7; |
| 316 | + break; |
| 317 | + case 8: |
| 318 | + check_esp_err(uart_set_word_length(self->uart_num, UART_DATA_8_BITS)); |
| 319 | + self->bits = 8; |
| 320 | + break; |
| 321 | + default: |
| 322 | + mp_raise_ValueError(MP_ERROR_TEXT("invalid data bits")); |
| 323 | + break; |
| 324 | + } |
| 325 | + |
| 326 | + // set parity |
| 327 | + if (args[ARG_parity].u_obj != MP_OBJ_NULL) { |
| 328 | + if (args[ARG_parity].u_obj == mp_const_none) { |
| 329 | + check_esp_err(uart_set_parity(self->uart_num, UART_PARITY_DISABLE)); |
| 330 | + self->parity = 0; |
| 331 | + } else { |
| 332 | + mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj); |
| 333 | + if (parity & 1) { |
| 334 | + check_esp_err(uart_set_parity(self->uart_num, UART_PARITY_ODD)); |
| 335 | + self->parity = 1; |
| 336 | + } else { |
| 337 | + check_esp_err(uart_set_parity(self->uart_num, UART_PARITY_EVEN)); |
| 338 | + self->parity = 2; |
| 339 | + } |
| 340 | + } |
| 341 | + } |
| 342 | + |
| 343 | + // set stop bits |
| 344 | + switch (args[ARG_stop].u_int) { |
| 345 | + // FIXME: ESP32 also supports 1.5 stop bits |
| 346 | + case 0: |
| 347 | + break; |
| 348 | + case 1: |
| 349 | + check_esp_err(uart_set_stop_bits(self->uart_num, UART_STOP_BITS_1)); |
| 350 | + self->stop = 1; |
| 351 | + break; |
| 352 | + case 2: |
| 353 | + check_esp_err(uart_set_stop_bits(self->uart_num, UART_STOP_BITS_2)); |
| 354 | + self->stop = 2; |
| 355 | + break; |
| 356 | + default: |
| 357 | + mp_raise_ValueError(MP_ERROR_TEXT("invalid stop bits")); |
| 358 | + break; |
| 359 | + } |
| 360 | + |
| 361 | + // set timeout |
| 362 | + if (args[ARG_timeout].u_int != -1) { |
| 363 | + self->timeout = args[ARG_timeout].u_int; |
| 364 | + } |
| 365 | + |
| 366 | + // set timeout_char |
| 367 | + if (args[ARG_timeout_char].u_int != -1) { |
| 368 | + self->timeout_char = args[ARG_timeout_char].u_int; |
| 369 | + } |
| 370 | + // make sure it is at least as long as a whole character (12 bits here) |
| 371 | + uint32_t char_time_ms = 12000 / baudrate + 1; |
| 372 | + uint32_t rx_timeout = self->timeout_char / char_time_ms; |
| 373 | + if (rx_timeout < 1) { |
| 374 | + check_esp_err(uart_set_rx_full_threshold(self->uart_num, 1)); |
| 375 | + check_esp_err(uart_set_rx_timeout(self->uart_num, 1)); |
| 376 | + } else { |
| 377 | + check_esp_err(uart_set_rx_timeout(self->uart_num, rx_timeout)); |
| 378 | + } |
| 379 | + |
| 380 | + // set line inversion |
| 381 | + if (args[ARG_invert].u_int != -1) { |
| 382 | + if (args[ARG_invert].u_int & ~UART_INV_MASK) { |
| 383 | + mp_raise_ValueError(MP_ERROR_TEXT("invalid inversion mask")); |
| 384 | + } |
| 385 | + self->invert = args[ARG_invert].u_int; |
| 386 | + } |
| 387 | + check_esp_err(uart_set_line_inverse(self->uart_num, self->invert)); |
| 388 | + |
| 389 | + // set hardware flow control |
| 390 | + if (args[ARG_flow].u_int != -1) { |
| 391 | + if (args[ARG_flow].u_int & ~UART_HW_FLOWCTRL_CTS_RTS) { |
| 392 | + mp_raise_ValueError(MP_ERROR_TEXT("invalid flow control mask")); |
| 393 | + } |
| 394 | + self->flowcontrol = args[ARG_flow].u_int; |
| 395 | + } |
| 396 | + uint8_t uart_fifo_len = UART_HW_FIFO_LEN(self->uart_num); |
| 397 | + check_esp_err(uart_set_hw_flow_ctrl(self->uart_num, self->flowcontrol, uart_fifo_len - uart_fifo_len / 4)); |
| 398 | +} |
| 399 | + |
| 400 | +static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { |
| 401 | + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); |
| 402 | + |
| 403 | + // get uart id |
| 404 | + mp_int_t uart_num = mp_obj_get_int(args[0]); |
| 405 | + if (uart_num < 0 || uart_num >= UART_NUM_MAX) { |
| 406 | + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) does not exist"), uart_num); |
| 407 | + } |
| 408 | + |
| 409 | + // Defaults |
| 410 | + uart_config_t uartcfg = { |
| 411 | + .baud_rate = 115200, |
| 412 | + .data_bits = UART_DATA_8_BITS, |
| 413 | + .parity = UART_PARITY_DISABLE, |
| 414 | + .stop_bits = UART_STOP_BITS_1, |
| 415 | + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, |
| 416 | + .rx_flow_ctrl_thresh = 0, |
| 417 | + .source_clk = UART_SOURCE_CLK, |
| 418 | + }; |
| 419 | + |
| 420 | + // create instance |
| 421 | + machine_uart_obj_t *self = mp_obj_malloc(machine_uart_obj_t, &machine_uart_type); |
| 422 | + self->uart_num = uart_num; |
| 423 | + self->bits = 8; |
| 424 | + self->parity = 0; |
| 425 | + self->stop = 1; |
| 426 | + self->rts = UART_PIN_NO_CHANGE; |
| 427 | + self->cts = UART_PIN_NO_CHANGE; |
| 428 | + self->txbuf = 256; |
| 429 | + self->rxbuf = 256; // IDF minimum |
| 430 | + self->timeout = 0; |
| 431 | + self->timeout_char = 0; |
| 432 | + self->invert = 0; |
| 433 | + self->flowcontrol = 0; |
| 434 | + self->uart_event_task = 0; |
| 435 | + self->rxidle_state = RXIDLE_INACTIVE; |
| 436 | + |
| 437 | + switch (uart_num) { |
| 438 | + case UART_NUM_0: |
| 439 | + self->rx = UART_PIN_NO_CHANGE; // GPIO 3 |
| 440 | + self->tx = UART_PIN_NO_CHANGE; // GPIO 1 |
| 441 | + break; |
| 442 | + case UART_NUM_1: |
| 443 | + self->rx = 9; |
| 444 | + self->tx = 10; |
| 445 | + break; |
| 446 | + #if SOC_UART_HP_NUM > 2 |
| 447 | + case UART_NUM_2: |
| 448 | + self->rx = 16; |
| 449 | + self->tx = 17; |
| 450 | + break; |
| 451 | + #endif |
| 452 | + #if SOC_UART_LP_NUM >= 1 |
| 453 | + case LP_UART_NUM_0: |
| 454 | + self->rx = 4; |
| 455 | + self->tx = 5; |
| 456 | + #endif |
| 457 | + |
| 458 | + } |
| 459 | + |
| 460 | + #if MICROPY_HW_ENABLE_UART_REPL |
| 461 | + // Only reset the driver if it's not the REPL UART. |
| 462 | + if (uart_num != MICROPY_HW_UART_REPL) |
| 463 | + #endif |
| 464 | + { |
| 465 | + // Remove any existing configuration |
| 466 | + check_esp_err(uart_driver_delete(self->uart_num)); |
| 467 | + |
| 468 | + // init the peripheral |
| 469 | + // Setup |
| 470 | + check_esp_err(uart_param_config(self->uart_num, &uartcfg)); |
| 471 | + |
| 472 | + check_esp_err(uart_driver_install(uart_num, self->rxbuf, self->txbuf, 3, &self->uart_queue, 0)); |
| 473 | + } |
| 474 | + |
| 475 | + mp_map_t kw_args; |
| 476 | + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); |
| 477 | + mp_machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args); |
| 478 | + |
| 479 | + // Make sure pins are connected. |
| 480 | + check_esp_err(uart_set_pin(self->uart_num, self->tx, self->rx, self->rts, self->cts)); |
| 481 | + |
| 482 | + return MP_OBJ_FROM_PTR(self); |
| 483 | +} |
| 484 | + |
| 485 | +static void mp_machine_uart_deinit(machine_uart_obj_t *self) { |
| 486 | + check_esp_err(uart_driver_delete(self->uart_num)); |
| 487 | +} |
| 488 | + |
| 489 | +static mp_int_t mp_machine_uart_any(machine_uart_obj_t *self) { |
| 490 | + size_t rxbufsize; |
| 491 | + check_esp_err(uart_get_buffered_data_len(self->uart_num, &rxbufsize)); |
| 492 | + return rxbufsize; |
| 493 | +} |
| 494 | + |
| 495 | +static bool mp_machine_uart_txdone(machine_uart_obj_t *self) { |
| 496 | + return uart_wait_tx_done(self->uart_num, 0) == ESP_OK; |
| 497 | +} |
| 498 | + |
| 499 | +static void mp_machine_uart_sendbreak(machine_uart_obj_t *self) { |
| 500 | + // Save settings |
| 501 | + uint32_t baudrate; |
| 502 | + check_esp_err(uart_get_baudrate(self->uart_num, &baudrate)); |
| 503 | + |
| 504 | + // Synthesise the break condition by reducing the baud rate, |
| 505 | + // and cater for the worst case of 5 data bits, no parity. |
| 506 | + check_esp_err(uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000))); |
| 507 | + check_esp_err(uart_set_baudrate(self->uart_num, baudrate * 6 / 15)); |
| 508 | + char buf[1] = {0}; |
| 509 | + uart_write_bytes(self->uart_num, buf, 1); |
| 510 | + check_esp_err(uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000))); |
| 511 | + |
| 512 | + // Restore original setting |
| 513 | + check_esp_err(uart_set_baudrate(self->uart_num, baudrate)); |
| 514 | +} |
| 515 | + |
| 516 | +// Configure the timer used for IRQ_RXIDLE |
| 517 | +static void uart_irq_configure_timer(machine_uart_obj_t *self, mp_uint_t trigger) { |
| 518 | + |
| 519 | + self->rxidle_state = RXIDLE_INACTIVE; |
| 520 | + |
| 521 | + if (trigger & UART_IRQ_RXIDLE) { |
| 522 | + // The RXIDLE event is always a soft IRQ. |
| 523 | + self->mp_irq_obj->ishard = false; |
| 524 | + uint32_t baudrate; |
| 525 | + uart_get_baudrate(self->uart_num, &baudrate); |
| 526 | + mp_int_t period = TIMER_SCALE * 20 / baudrate + 1; |
| 527 | + if (period < RXIDLE_TIMER_MIN) { |
| 528 | + period = RXIDLE_TIMER_MIN; |
| 529 | + } |
| 530 | + self->rxidle_period = period; |
| 531 | + self->rxidle_timer->period = period; |
| 532 | + // The Python callback is not used. So use this |
| 533 | + // data field to hold a reference to the UART object. |
| 534 | + self->rxidle_timer->callback = self; |
| 535 | + self->rxidle_timer->repeat = true; |
| 536 | + self->rxidle_timer->handle = NULL; |
| 537 | + self->rxidle_state = RXIDLE_STANDBY; |
| 538 | + } |
| 539 | +} |
| 540 | + |
| 541 | +static mp_uint_t uart_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) { |
| 542 | + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 543 | + |
| 544 | + uart_irq_configure_timer(self, new_trigger); |
| 545 | + self->mp_irq_trigger = new_trigger; |
| 546 | + return 0; |
| 547 | +} |
| 548 | + |
| 549 | +static mp_uint_t uart_irq_info(mp_obj_t self_in, mp_uint_t info_type) { |
| 550 | + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 551 | + if (info_type == MP_IRQ_INFO_FLAGS) { |
| 552 | + return self->mp_irq_flags; |
| 553 | + } else if (info_type == MP_IRQ_INFO_TRIGGERS) { |
| 554 | + return self->mp_irq_trigger; |
| 555 | + } |
| 556 | + return 0; |
| 557 | +} |
| 558 | + |
| 559 | +static const mp_irq_methods_t uart_irq_methods = { |
| 560 | + .trigger = uart_irq_trigger, |
| 561 | + .info = uart_irq_info, |
| 562 | +}; |
| 563 | + |
| 564 | +static mp_irq_obj_t *mp_machine_uart_irq(machine_uart_obj_t *self, bool any_args, mp_arg_val_t *args) { |
| 565 | + if (self->mp_irq_obj == NULL) { |
| 566 | + self->mp_irq_trigger = 0; |
| 567 | + self->mp_irq_obj = mp_irq_new(&uart_irq_methods, MP_OBJ_FROM_PTR(self)); |
| 568 | + } |
| 569 | + |
| 570 | + if (any_args) { |
| 571 | + // Check the handler |
| 572 | + mp_obj_t handler = args[MP_IRQ_ARG_INIT_handler].u_obj; |
| 573 | + if (handler != mp_const_none && !mp_obj_is_callable(handler)) { |
| 574 | + mp_raise_ValueError(MP_ERROR_TEXT("handler must be None or callable")); |
| 575 | + } |
| 576 | + |
| 577 | + // Check the trigger |
| 578 | + mp_uint_t trigger = args[MP_IRQ_ARG_INIT_trigger].u_int; |
| 579 | + mp_uint_t not_supported = trigger & ~MP_UART_ALLOWED_FLAGS; |
| 580 | + if (trigger != 0 && not_supported) { |
| 581 | + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("trigger 0x%04x unsupported"), not_supported); |
| 582 | + } |
| 583 | + |
| 584 | + self->mp_irq_obj->handler = handler; |
| 585 | + if (args[MP_IRQ_ARG_INIT_hard].u_bool) { |
| 586 | + mp_raise_ValueError(MP_ERROR_TEXT("hard IRQ is not supported")); |
| 587 | + } |
| 588 | + self->mp_irq_obj->ishard = false; |
| 589 | + self->mp_irq_trigger = trigger; |
| 590 | + self->rxidle_timer = machine_timer_create(0); |
| 591 | + uart_irq_configure_timer(self, trigger); |
| 592 | + |
| 593 | + // Start a task for handling events |
| 594 | + if (handler != mp_const_none && self->uart_event_task == NULL) { |
| 595 | + xTaskCreatePinnedToCore(uart_event_task, "uart_event_task", 2048, self, |
| 596 | + ESP_TASKD_EVENT_PRIO, (TaskHandle_t *)&self->uart_event_task, MP_TASK_COREID); |
| 597 | + } else if (handler == mp_const_none && self->uart_event_task != NULL) { |
| 598 | + vTaskDelete(self->uart_event_task); |
| 599 | + self->uart_event_task = NULL; |
| 600 | + } |
| 601 | + } |
| 602 | + |
| 603 | + return self->mp_irq_obj; |
| 604 | +} |
| 605 | + |
| 606 | +static mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { |
| 607 | + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 608 | + |
| 609 | + // make sure we want at least 1 char |
| 610 | + if (size == 0) { |
| 611 | + return 0; |
| 612 | + } |
| 613 | + |
| 614 | + TickType_t time_to_wait; |
| 615 | + if (self->timeout == 0) { |
| 616 | + time_to_wait = 0; |
| 617 | + } else { |
| 618 | + time_to_wait = pdMS_TO_TICKS(self->timeout); |
| 619 | + } |
| 620 | + |
| 621 | + bool release_gil = time_to_wait > 0; |
| 622 | + if (release_gil) { |
| 623 | + MP_THREAD_GIL_EXIT(); |
| 624 | + } |
| 625 | + |
| 626 | + int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait); |
| 627 | + |
| 628 | + if (release_gil) { |
| 629 | + MP_THREAD_GIL_ENTER(); |
| 630 | + } |
| 631 | + |
| 632 | + if (bytes_read <= 0) { |
| 633 | + *errcode = MP_EAGAIN; |
| 634 | + return MP_STREAM_ERROR; |
| 635 | + } |
| 636 | + |
| 637 | + return bytes_read; |
| 638 | +} |
| 639 | + |
| 640 | +static mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { |
| 641 | + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 642 | + |
| 643 | + int bytes_written = uart_write_bytes(self->uart_num, buf_in, size); |
| 644 | + |
| 645 | + if (bytes_written < 0) { |
| 646 | + *errcode = MP_EAGAIN; |
| 647 | + return MP_STREAM_ERROR; |
| 648 | + } |
| 649 | + |
| 650 | + // return number of bytes written |
| 651 | + return bytes_written; |
| 652 | +} |
| 653 | + |
| 654 | +static mp_uint_t mp_machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { |
| 655 | + machine_uart_obj_t *self = self_in; |
| 656 | + mp_uint_t ret; |
| 657 | + if (request == MP_STREAM_POLL) { |
| 658 | + mp_uint_t flags = arg; |
| 659 | + ret = 0; |
| 660 | + size_t rxbufsize; |
| 661 | + check_esp_err(uart_get_buffered_data_len(self->uart_num, &rxbufsize)); |
| 662 | + if ((flags & MP_STREAM_POLL_RD) && rxbufsize > 0) { |
| 663 | + ret |= MP_STREAM_POLL_RD; |
| 664 | + } |
| 665 | + if ((flags & MP_STREAM_POLL_WR) && 1) { // FIXME: uart_tx_any_room(self->uart_num) |
| 666 | + ret |= MP_STREAM_POLL_WR; |
| 667 | + } |
| 668 | + } else if (request == MP_STREAM_FLUSH) { |
| 669 | + // The timeout is estimated using the buffer size and the baudrate. |
| 670 | + // Take the worst case assumptions at 13 bit symbol size times 2. |
| 671 | + uint32_t baudrate; |
| 672 | + check_esp_err(uart_get_baudrate(self->uart_num, &baudrate)); |
| 673 | + uint32_t timeout = (3 + self->txbuf) * 13000 * 2 / baudrate; |
| 674 | + if (uart_wait_tx_done(self->uart_num, timeout) == ESP_OK) { |
| 675 | + ret = 0; |
| 676 | + } else { |
| 677 | + *errcode = MP_ETIMEDOUT; |
| 678 | + ret = MP_STREAM_ERROR; |
| 679 | + } |
| 680 | + } else { |
| 681 | + *errcode = MP_EINVAL; |
| 682 | + ret = MP_STREAM_ERROR; |
| 683 | + } |
| 684 | + return ret; |
| 685 | +} |
0 commit comments