uart.c 25.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

27
28
#include <stdio.h>
#include <string.h>
29
#include <stdarg.h>
30
#include <errno.h>
31

32
#include "mpconfig.h"
33
#include "nlr.h"
34
35
36
#include "misc.h"
#include "qstr.h"
#include "obj.h"
37
#include "runtime.h"
38
#include "stream.h"
Damien George's avatar
Damien George committed
39
#include "uart.h"
40
#include "pybioctl.h"
41
#include MICROPY_HAL_H
42

43
44
45
46
/// \moduleref pyb
/// \class UART - duplex serial communication bus
///
/// UART implements the standard UART/USART duplex serial communications protocol.  At
47
48
49
/// the physical level it consists of 2 lines: RX and TX.  The unit of communication
/// is a character (not to be confused with a string character) which can be 8 or 9
/// bits wide.
50
///
51
/// UART objects can be created and initialised using:
52
53
54
55
///
///     from pyb import UART
///
///     uart = UART(1, 9600)                         # init with given baudrate
56
///     uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
57
///
58
/// Bits can be 8 or 9.  Parity can be None, 0 (even) or 1 (odd).  Stop can be 1 or 2.
59
///
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/// A UART object acts like a stream object and reading and writing is done
/// using the standard stream methods:
///
///     uart.read(10)       # read 10 characters, returns a bytes object
///     uart.readall()      # read all available characters
///     uart.readline()     # read a line
///     uart.readinto(buf)  # read and store into the given buffer
///     uart.write('abc')   # write the 3 characters
///
/// Individual characters can be read/written using:
///
///     uart.readchar()     # read 1 character and returns it as an integer
///     uart.writechar(42)  # write 1 character
///
/// To check if there is anything to be read, use:
75
76
///
///     uart.any()               # returns True if any characters waiting
77

78
79
80
#define CHAR_WIDTH_8BIT (0)
#define CHAR_WIDTH_9BIT (1)

Damien George's avatar
Damien George committed
81
struct _pyb_uart_obj_t {
Dave Hylands's avatar
Dave Hylands committed
82
    mp_obj_base_t base;
83
    UART_HandleTypeDef uart;            // this is 17 words big
84
    IRQn_Type irqn;
85
86
87
88
    pyb_uart_t uart_id : 8;
    bool is_enabled : 1;
    byte char_width;                    // 0 for 7,8 bit chars, 1 for 9 bit chars
    uint16_t char_mask;                 // 0x7f for 7 bit, 0xff for 8 bit, 0x1ff for 9 bit
89
90
91
92
93
94
    uint16_t timeout;                   // timeout waiting for first char
    uint16_t timeout_char;              // timeout waiting between chars
    uint16_t read_buf_len;              // len in chars; buf can hold len-1 chars
    volatile uint16_t read_buf_head;    // indexes first empty slot
    uint16_t read_buf_tail;             // indexes first full slot (not full if equals head)
    byte *read_buf;                     // byte or uint16_t, depending on char size
Dave Hylands's avatar
Dave Hylands committed
95
};
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// pointers to all UART objects (if they have been created)
STATIC pyb_uart_obj_t *pyb_uart_obj_all[6];

STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);

void uart_init0(void) {
    for (int i = 0; i < MP_ARRAY_SIZE(pyb_uart_obj_all); i++) {
        pyb_uart_obj_all[i] = NULL;
    }
}

// unregister all interrupt sources
void uart_deinit(void) {
    for (int i = 0; i < MP_ARRAY_SIZE(pyb_uart_obj_all); i++) {
        pyb_uart_obj_t *uart_obj = pyb_uart_obj_all[i];
        if (uart_obj != NULL) {
            pyb_uart_deinit(uart_obj);
        }
    }
}

118
// assumes Init parameters have been set up correctly
119
STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
120
121
122
123
    USART_TypeDef *UARTx;
    IRQn_Type irqn;
    uint32_t GPIO_Pin;
    uint8_t GPIO_AF_UARTx = 0;
124
    GPIO_TypeDef* GPIO_Port = NULL;
125

Damien George's avatar
Damien George committed
126
127
128
129
    switch (uart_obj->uart_id) {
        // USART1 is on PA9/PA10 (CK on PA8), PB6/PB7
        case PYB_UART_1:
            UARTx = USART1;
130
            irqn = USART1_IRQn;
Damien George's avatar
Damien George committed
131
            GPIO_AF_UARTx = GPIO_AF7_USART1;
132

Damien George's avatar
Damien George committed
133
#if defined (PYBV4) || defined(PYBV10)
134
135
136
            GPIO_Port = GPIOB;
            GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7;
#else
137
138
            GPIO_Port = GPIOA;
            GPIO_Pin = GPIO_PIN_9 | GPIO_PIN_10;
139
#endif
140
141
142

            __USART1_CLK_ENABLE();
            break;
143

144
        // USART2 is on PA2/PA3 (CTS,RTS,CK on PA0,PA1,PA4), PD5/PD6 (CK on PD7)
Damien George's avatar
Damien George committed
145
146
        case PYB_UART_2:
            UARTx = USART2;
147
            irqn = USART2_IRQn;
Damien George's avatar
Damien George committed
148
            GPIO_AF_UARTx = GPIO_AF7_USART2;
149

Damien George's avatar
Damien George committed
150
151
            GPIO_Port = GPIOA;
            GPIO_Pin = GPIO_PIN_2 | GPIO_PIN_3;
152

153
154
155
156
157
158
159
            if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) {
                GPIO_Pin |= GPIO_PIN_1;
            }
            if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
                GPIO_Pin |= GPIO_PIN_0;
            }

160
161
            __USART2_CLK_ENABLE();
            break;
162

163
        // USART3 is on PB10/PB11 (CK,CTS,RTS on PB12,PB13,PB14), PC10/PC11 (CK on PC12), PD8/PD9 (CK on PD10)
Damien George's avatar
Damien George committed
164
165
        case PYB_UART_3:
            UARTx = USART3;
166
            irqn = USART3_IRQn;
Damien George's avatar
Damien George committed
167
            GPIO_AF_UARTx = GPIO_AF7_USART3;
168

169
#if defined(PYBV3) || defined(PYBV4) | defined(PYBV10)
170
171
            GPIO_Port = GPIOB;
            GPIO_Pin = GPIO_PIN_10 | GPIO_PIN_11;
172
173
174
175
176
177
178

            if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) {
                GPIO_Pin |= GPIO_PIN_14;
            }
            if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
                GPIO_Pin |= GPIO_PIN_13;
            }
179
180
181
182
183
184
#else
            GPIO_Port = GPIOD;
            GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9;
#endif
            __USART3_CLK_ENABLE();
            break;
185

186
        // UART4 is on PA0/PA1, PC10/PC11
Damien George's avatar
Damien George committed
187
188
        case PYB_UART_4:
            UARTx = UART4;
189
            irqn = UART4_IRQn;
Damien George's avatar
Damien George committed
190
            GPIO_AF_UARTx = GPIO_AF8_UART4;
191
192
193
194
195
196
197

            GPIO_Port = GPIOA;
            GPIO_Pin = GPIO_PIN_0 | GPIO_PIN_1;

            __UART4_CLK_ENABLE();
            break;

Damien George's avatar
Damien George committed
198
199
200
        // USART6 is on PC6/PC7 (CK on PC8)
        case PYB_UART_6:
            UARTx = USART6;
201
            irqn = USART6_IRQn;
Damien George's avatar
Damien George committed
202
            GPIO_AF_UARTx = GPIO_AF8_USART6;
203
204
205
206
207
208

            GPIO_Port = GPIOC;
            GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7;

            __USART6_CLK_ENABLE();
            break;
209
210
211

        default:
            return false;
212
213
    }

214
215
216
    uart_obj->irqn = irqn;
    uart_obj->uart.Instance = UARTx;

217
    // init GPIO
218
219
220
221
222
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = GPIO_Pin;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
Damien George's avatar
Damien George committed
223
    GPIO_InitStructure.Alternate = GPIO_AF_UARTx;
224
225
    HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure);

Damien George's avatar
Damien George committed
226
227
    // init UARTx
    HAL_UART_Init(&uart_obj->uart);
228

Damien George's avatar
Damien George committed
229
    uart_obj->is_enabled = true;
230
231
232
233

    return true;
}

234
/* obsolete and unused
Damien George's avatar
Damien George committed
235
236
bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate) {
    UART_HandleTypeDef *uh = &uart_obj->uart;
Dave Hylands's avatar
Dave Hylands committed
237
238
    memset(uh, 0, sizeof(*uh));
    uh->Init.BaudRate = baudrate;
239
240
241
242
    uh->Init.WordLength = UART_WORDLENGTH_8B;
    uh->Init.StopBits = UART_STOPBITS_1;
    uh->Init.Parity = UART_PARITY_NONE;
    uh->Init.Mode = UART_MODE_TX_RX;
Dave Hylands's avatar
Dave Hylands committed
243
244
    uh->Init.HwFlowCtl = UART_HWCONTROL_NONE;
    uh->Init.OverSampling = UART_OVERSAMPLING_16;
Damien George's avatar
Damien George committed
245
    return uart_init2(uart_obj);
246
}
247
*/
248

249
250
251
bool uart_rx_any(pyb_uart_obj_t *self) {
    return self->read_buf_tail != self->read_buf_head
        || __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET;
252
253
}

254
255
256
257
258
259
260
261
262
263
264
265
266
267
// Waits at most timeout milliseconds for at least 1 char to become ready for
// reading (from buf or for direct reading).
// Returns true if something available, false if not.
STATIC bool uart_rx_wait(pyb_uart_obj_t *self, uint32_t timeout) {
    uint32_t start = HAL_GetTick();
    for (;;) {
        if (self->read_buf_tail != self->read_buf_head || __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) {
            return true; // have at least 1 char ready for reading
        }
        if (HAL_GetTick() - start >= timeout) {
            return false; // timeout
        }
        __WFI();
    }
268
269
}

270
271
272
273
274
275
276
277
278
279
280
281
282
283
// assumes there is a character available
int uart_rx_char(pyb_uart_obj_t *self) {
    if (self->read_buf_tail != self->read_buf_head) {
        // buffering via IRQ
        int data;
        if (self->char_width == CHAR_WIDTH_9BIT) {
            data = ((uint16_t*)self->read_buf)[self->read_buf_tail];
        } else {
            data = self->read_buf[self->read_buf_tail];
        }
        self->read_buf_tail = (self->read_buf_tail + 1) % self->read_buf_len;
        return data;
    } else {
        // no buffering
284
        return self->uart.Instance->DR & self->char_mask;
285
286
287
    }
}

288
STATIC void uart_tx_char(pyb_uart_obj_t *uart_obj, int c) {
289
    uint8_t ch = c;
290
    HAL_UART_Transmit(&uart_obj->uart, &ch, 1, uart_obj->timeout);
291
292
}

Damien George's avatar
Damien George committed
293
void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
294
    HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, len, uart_obj->timeout);
295
296
}

Damien George's avatar
Damien George committed
297
void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
298
299
    for (const char *top = str + len; str < top; str++) {
        if (*str == '\n') {
Damien George's avatar
Damien George committed
300
            uart_tx_char(uart_obj, '\r');
301
        }
Damien George's avatar
Damien George committed
302
        uart_tx_char(uart_obj, *str);
303
304
305
    }
}

306
307
308
309
310
311
312
313
314
315
316
317
318
// this IRQ handler is set up to handle RXNE interrupts only
void uart_irq_handler(mp_uint_t uart_id) {
    // get the uart object
    pyb_uart_obj_t *self = pyb_uart_obj_all[uart_id - 1];

    if (self == NULL) {
        // UART object has not been set, so we can't do anything, not
        // even disable the IRQ.  This should never happen.
        return;
    }

    if (__HAL_UART_GET_FLAG(&self->uart, UART_FLAG_RXNE) != RESET) {
        int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE
319
        data &= self->char_mask;
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
        if (self->read_buf_len != 0) {
            uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len;
            if (next_head != self->read_buf_tail) {
                // only store data if room in buf
                if (self->char_width == CHAR_WIDTH_9BIT) {
                    ((uint16_t*)self->read_buf)[self->read_buf_head] = data;
                } else {
                    self->read_buf[self->read_buf_head] = data;
                }
                self->read_buf_head = next_head;
            }
        } else {
            // TODO set flag for buffer overflow
        }
    }
}

337
338
339
/******************************************************************************/
/* Micro Python bindings                                                      */

Damien George's avatar
Damien George committed
340
341
STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
    pyb_uart_obj_t *self = self_in;
342
    if (!self->is_enabled) {
343
        print(env, "UART(%u)", self->uart_id);
344
    } else {
345
346
347
348
        mp_int_t bits = (self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9);
        if (self->uart.Init.Parity != UART_PARITY_NONE) {
            bits -= 1;
        }
349
        print(env, "UART(%u, baudrate=%u, bits=%u, parity=",
350
            self->uart_id, self->uart.Init.BaudRate, bits);
351
        if (self->uart.Init.Parity == UART_PARITY_NONE) {
352
            print(env, "None");
353
        } else {
354
            print(env, "%u", self->uart.Init.Parity == UART_PARITY_EVEN ? 0 : 1);
355
        }
356
357
358
        print(env, ", stop=%u, timeout=%u, timeout_char=%u, read_buf_len=%u)",
            self->uart.Init.StopBits == UART_STOPBITS_1 ? 1 : 2,
            self->timeout, self->timeout_char, self->read_buf_len);
359
    }
360
361
}

362
/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, read_buf_len=64)
363
///
364
/// Initialise the UART bus with the given parameters:
365
366
///
///   - `baudrate` is the clock rate.
367
///   - `bits` is the number of bits per byte, 7, 8 or 9.
368
///   - `parity` is the parity, `None`, 0 (even) or 1 (odd).
369
370
371
372
373
374
375
376
377
378
///   - `stop` is the number of stop bits, 1 or 2.
///   - `timeout` is the timeout in milliseconds to wait for the first character.
///   - `timeout_char` is the timeout in milliseconds to wait between characters.
///   - `read_buf_len` is the character length of the read buffer (0 to disable).
STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
    static const mp_arg_t allowed_args[] = {
        { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} },
        { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
        { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} },
        { MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} },
379
        { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_HWCONTROL_NONE} },
380
381
382
383
        { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} },
        { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
        { MP_QSTR_read_buf_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
    };
384
385

    // parse args
386
387
    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
388

Damien George's avatar
Damien George committed
389
    // set the UART configuration values
390
391
    memset(&self->uart, 0, sizeof(self->uart));
    UART_InitTypeDef *init = &self->uart.Init;
392
393

    // baudrate
394
    init->BaudRate = args[0].u_int;
395
396
397

    // parity
    mp_int_t bits = args[1].u_int;
398
    if (args[2].u_obj == mp_const_none) {
399
400
        init->Parity = UART_PARITY_NONE;
    } else {
401
        mp_int_t parity = mp_obj_get_int(args[2].u_obj);
402
        init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN;
403
        bits += 1; // STs convention has bits including parity
404
    }
405
406
407
408
409
410
411
412
413
414
415

    // number of bits
    if (bits == 8) {
        init->WordLength = UART_WORDLENGTH_8B;
    } else if (bits == 9) {
        init->WordLength = UART_WORDLENGTH_9B;
    } else {
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unsupported combination of bits and parity"));
    }

    // stop bits
416
417
418
419
    switch (args[3].u_int) {
        case 1: init->StopBits = UART_STOPBITS_1; break;
        default: init->StopBits = UART_STOPBITS_2; break;
    }
420
421

    // flow control
422
    init->HwFlowCtl = args[4].u_int;
423
424
425

    // extra config (not yet configurable)
    init->Mode = UART_MODE_TX_RX;
426
427
    init->OverSampling = UART_OVERSAMPLING_16;

Damien George's avatar
Damien George committed
428
429
    // init UART (if it fails, it's because the port doesn't exist)
    if (!uart_init2(self)) {
430
431
432
433
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", self->uart_id));
    }

    // set timeouts
434
435
    self->timeout = args[5].u_int;
    self->timeout_char = args[6].u_int;
436
437
438
439

    // setup the read buffer
    m_del(byte, self->read_buf, self->read_buf_len << self->char_width);
    if (init->WordLength == UART_WORDLENGTH_9B && init->Parity == UART_PARITY_NONE) {
440
        self->char_mask = 0x1ff;
441
442
        self->char_width = CHAR_WIDTH_9BIT;
    } else {
443
444
445
446
447
        if (init->WordLength == UART_WORDLENGTH_9B || init->Parity == UART_PARITY_NONE) {
            self->char_mask = 0xff;
        } else {
            self->char_mask = 0x7f;
        }
448
449
450
451
        self->char_width = CHAR_WIDTH_8BIT;
    }
    self->read_buf_head = 0;
    self->read_buf_tail = 0;
452
    if (args[7].u_int <= 0) {
453
454
455
456
457
458
459
        // no read buffer
        self->read_buf_len = 0;
        self->read_buf = NULL;
        HAL_NVIC_DisableIRQ(self->irqn);
        __HAL_UART_DISABLE_IT(&self->uart, UART_IT_RXNE);
    } else {
        // read buffer using interrupts
460
461
        self->read_buf_len = args[7].u_int;
        self->read_buf = m_new(byte, args[7].u_int << self->char_width);
462
463
464
        __HAL_UART_ENABLE_IT(&self->uart, UART_IT_RXNE);
        HAL_NVIC_SetPriority(self->irqn, 0xd, 0xd); // next-to-next-to lowest priority
        HAL_NVIC_EnableIRQ(self->irqn);
465
466
    }

467
468
469
    return mp_const_none;
}

470
471
472
473
474
475
476
/// \classmethod \constructor(bus, ...)
///
/// Construct a UART object on the given bus.  `bus` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'.
/// With no additional parameters, the UART object is created but not
/// initialised (it has the settings from the last initialisation of
/// the bus, if any).  If extra arguments are given, the bus is initialised.
/// See `init` for parameters of initialisation.
477
478
479
480
481
482
483
484
///
/// The physical pins of the UART busses are:
///
///   - `UART(4)` is on `XA`: `(TX, RX) = (X1, X2) = (PA0, PA1)`
///   - `UART(1)` is on `XB`: `(TX, RX) = (X9, X10) = (PB6, PB7)`
///   - `UART(6)` is on `YA`: `(TX, RX) = (Y1, Y2) = (PC6, PC7)`
///   - `UART(3)` is on `YB`: `(TX, RX) = (Y9, Y10) = (PB10, PB11)`
///   - `UART(2)` is on: `(TX, RX) = (X3, X4) = (PA2, PA3)`
485
STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
486
487
488
    // check arguments
    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);

489
    // work out port
490
    int uart_id = 0;
491
492
    if (MP_OBJ_IS_STR(args[0])) {
        const char *port = mp_obj_str_get_str(args[0]);
493
494
495
        if (0) {
#if defined(PYBV10)
        } else if (strcmp(port, "XA") == 0) {
496
            uart_id = PYB_UART_XA;
497
        } else if (strcmp(port, "XB") == 0) {
498
            uart_id = PYB_UART_XB;
499
        } else if (strcmp(port, "YA") == 0) {
500
            uart_id = PYB_UART_YA;
501
        } else if (strcmp(port, "YB") == 0) {
502
            uart_id = PYB_UART_YB;
503
#endif
504
        } else {
505
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%s) does not exist", port));
506
        }
507
    } else {
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
        uart_id = mp_obj_get_int(args[0]);
        if (uart_id < 1 || uart_id > MP_ARRAY_SIZE(pyb_uart_obj_all)) {
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_id));
        }
    }

    pyb_uart_obj_t *self;
    if (pyb_uart_obj_all[uart_id - 1] == NULL) {
        // create new UART object
        self = m_new0(pyb_uart_obj_t, 1);
        self->base.type = &pyb_uart_type;
        self->uart_id = uart_id;
        pyb_uart_obj_all[uart_id - 1] = self;
    } else {
        // reference existing UART object
        self = pyb_uart_obj_all[uart_id - 1];
524
525
    }

526
527
528
529
    if (n_args > 1 || n_kw > 0) {
        // start the peripheral
        mp_map_t kw_args;
        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
530
        pyb_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
531
532
    }

533
    return self;
534
535
}

536
STATIC mp_obj_t pyb_uart_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
Damien George's avatar
Damien George committed
537
    return pyb_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
538
}
Damien George's avatar
Damien George committed
539
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);
540

541
542
/// \method deinit()
/// Turn off the UART bus.
Damien George's avatar
Damien George committed
543
544
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
    pyb_uart_obj_t *self = self_in;
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
    self->is_enabled = false;
    UART_HandleTypeDef *uart = &self->uart;
    HAL_UART_DeInit(uart);
    if (uart->Instance == USART1) {
        HAL_NVIC_DisableIRQ(USART1_IRQn);
        __USART1_FORCE_RESET();
        __USART1_RELEASE_RESET();
        __USART1_CLK_DISABLE();
    } else if (uart->Instance == USART2) {
        HAL_NVIC_DisableIRQ(USART2_IRQn);
        __USART2_FORCE_RESET();
        __USART2_RELEASE_RESET();
        __USART2_CLK_DISABLE();
    } else if (uart->Instance == USART3) {
        HAL_NVIC_DisableIRQ(USART3_IRQn);
        __USART3_FORCE_RESET();
        __USART3_RELEASE_RESET();
        __USART3_CLK_DISABLE();
    } else if (uart->Instance == UART4) {
        HAL_NVIC_DisableIRQ(UART4_IRQn);
        __UART4_FORCE_RESET();
        __UART4_RELEASE_RESET();
        __UART4_CLK_DISABLE();
    } else if (uart->Instance == USART6) {
        HAL_NVIC_DisableIRQ(USART6_IRQn);
        __USART6_FORCE_RESET();
        __USART6_RELEASE_RESET();
        __USART6_CLK_DISABLE();
    }
574
575
    return mp_const_none;
}
Damien George's avatar
Damien George committed
576
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit);
577

578
579
/// \method any()
/// Return `True` if any characters waiting, else `False`.
Damien George's avatar
Damien George committed
580
581
582
STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) {
    pyb_uart_obj_t *self = self_in;
    if (uart_rx_any(self)) {
583
584
585
586
587
        return mp_const_true;
    } else {
        return mp_const_false;
    }
}
Damien George's avatar
Damien George committed
588
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any);
589

590
591
/// \method writechar(char)
/// Write a single character on the bus.  `char` is an integer to write.
592
/// Return value: `None`.
593
594
STATIC mp_obj_t pyb_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
    pyb_uart_obj_t *self = self_in;
595

596
597
    // get the character to write (might be 9 bits)
    uint16_t data = mp_obj_get_int(char_in);
598

599
600
    // write the data
    HAL_StatusTypeDef status = HAL_UART_Transmit(&self->uart, (uint8_t*)&data, 1, self->timeout);
601
602

    if (status != HAL_OK) {
603
        mp_hal_raise(status);
604
    }
605

606
607
    return mp_const_none;
}
608
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_uart_writechar_obj, pyb_uart_writechar);
609

610
611
612
613
614
615
616
617
618
619
620
621
622
623
/// \method readchar()
/// Receive a single character on the bus.
/// Return value: The character read, as an integer.  Returns -1 on timeout.
STATIC mp_obj_t pyb_uart_readchar(mp_obj_t self_in) {
    pyb_uart_obj_t *self = self_in;
    if (uart_rx_wait(self, self->timeout)) {
        return MP_OBJ_NEW_SMALL_INT(uart_rx_char(self));
    } else {
        // return -1 on timeout
        return MP_OBJ_NEW_SMALL_INT(-1);
    }
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar);

Damien George's avatar
Damien George committed
624
STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
625
    // instance methods
626

Damien George's avatar
Damien George committed
627
628
629
    { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_uart_init_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_uart_deinit_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_uart_any_obj },
630
631
632
633
634
635
636

    /// \method read([nbytes])
    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
    /// \method readall()
    { MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj },
    /// \method readline()
    { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
Damien George's avatar
Damien George committed
637
638
    /// \method readinto(buf[, nbytes])
    { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj },
639
640
641
642
643
    /// \method write(buf)
    { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },

    { MP_OBJ_NEW_QSTR(MP_QSTR_writechar), (mp_obj_t)&pyb_uart_writechar_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_readchar), (mp_obj_t)&pyb_uart_readchar_obj },
644
645
646
647

    // class constants
    { MP_OBJ_NEW_QSTR(MP_QSTR_RTS), MP_OBJ_NEW_SMALL_INT(UART_HWCONTROL_RTS) },
    { MP_OBJ_NEW_QSTR(MP_QSTR_CTS), MP_OBJ_NEW_SMALL_INT(UART_HWCONTROL_CTS) },
648
649
};

Damien George's avatar
Damien George committed
650
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
651

652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
    pyb_uart_obj_t *self = self_in;
    byte *buf = buf_in;

    // check that size is a multiple of character width
    if (size & self->char_width) {
        *errcode = EIO;
        return MP_STREAM_ERROR;
    }

    // convert byte size to char size
    size >>= self->char_width;

    // make sure we want at least 1 char
    if (size == 0) {
        return 0;
    }

    // wait for first char to become available
    if (!uart_rx_wait(self, self->timeout)) {
        // we can either return 0 to indicate EOF (then read() method returns b'')
        // or return EAGAIN error to indicate non-blocking (then read() method returns None)
        return 0;
    }

    // read the data
    byte *orig_buf = buf;
    for (;;) {
        int data = uart_rx_char(self);
        if (self->char_width == CHAR_WIDTH_9BIT) {
            *(uint16_t*)buf = data;
            buf += 2;
        } else {
            *buf++ = data;
        }
        if (--size == 0 || !uart_rx_wait(self, self->timeout_char)) {
            // return number of bytes read
            return buf - orig_buf;
        }
    }
}

STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
    pyb_uart_obj_t *self = self_in;
    const byte *buf = buf_in;

    // check that size is a multiple of character width
    if (size & self->char_width) {
        *errcode = EIO;
        return MP_STREAM_ERROR;
    }

    // write the data
    HAL_StatusTypeDef status = HAL_UART_Transmit(&self->uart, (uint8_t*)buf, size >> self->char_width, self->timeout);

    if (status == HAL_OK) {
        // return number of bytes written
        return size;
    } else {
711
        *errcode = mp_hal_status_to_errno_table[status];
712
713
714
715
716
        return MP_STREAM_ERROR;
    }
}

STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, int *errcode, ...) {
717
718
719
720
721
722
723
    pyb_uart_obj_t *self = self_in;
    va_list vargs;
    va_start(vargs, errcode);
    mp_uint_t ret;
    if (request == MP_IOCTL_POLL) {
        mp_uint_t flags = va_arg(vargs, mp_uint_t);
        ret = 0;
724
        if ((flags & MP_IOCTL_POLL_RD) && uart_rx_any(self)) {
725
726
            ret |= MP_IOCTL_POLL_RD;
        }
727
        if ((flags & MP_IOCTL_POLL_WR) && __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_TXE)) {
728
729
730
            ret |= MP_IOCTL_POLL_WR;
        }
    } else {
731
        *errcode = EINVAL;
732
        ret = MP_STREAM_ERROR;
733
734
735
736
737
738
    }
    va_end(vargs);
    return ret;
}

STATIC const mp_stream_p_t uart_stream_p = {
739
740
741
    .read = pyb_uart_read,
    .write = pyb_uart_write,
    .ioctl = pyb_uart_ioctl,
742
743
744
    .is_text = false,
};

Damien George's avatar
Damien George committed
745
const mp_obj_type_t pyb_uart_type = {
746
    { &mp_type_type },
Damien George's avatar
Damien George committed
747
748
749
    .name = MP_QSTR_UART,
    .print = pyb_uart_print,
    .make_new = pyb_uart_make_new,
750
751
    .getiter = mp_identity,
    .iternext = mp_stream_unbuffered_iter,
752
    .stream_p = &uart_stream_p,
Damien George's avatar
Damien George committed
753
    .locals_dict = (mp_obj_t)&pyb_uart_locals_dict,
754
};