uart.c 25.6 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
33
34
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/stream.h"
Damien George's avatar
Damien George committed
35
#include "uart.h"
36
#include "pybioctl.h"
37
#include MICROPY_HAL_H
38

39
40
41
42
/// \moduleref pyb
/// \class UART - duplex serial communication bus
///
/// UART implements the standard UART/USART duplex serial communications protocol.  At
43
44
45
/// 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.
46
///
47
/// UART objects can be created and initialised using:
48
49
50
51
///
///     from pyb import UART
///
///     uart = UART(1, 9600)                         # init with given baudrate
52
///     uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
53
///
54
/// Bits can be 8 or 9.  Parity can be None, 0 (even) or 1 (odd).  Stop can be 1 or 2.
55
///
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/// 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:
71
72
///
///     uart.any()               # returns True if any characters waiting
73

74
75
76
#define CHAR_WIDTH_8BIT (0)
#define CHAR_WIDTH_9BIT (1)

Damien George's avatar
Damien George committed
77
struct _pyb_uart_obj_t {
Dave Hylands's avatar
Dave Hylands committed
78
    mp_obj_base_t base;
79
    UART_HandleTypeDef uart;            // this is 17 words big
80
    IRQn_Type irqn;
81
82
83
84
    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
85
86
87
88
89
90
    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
91
};
92

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// 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);
        }
    }
}

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

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

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

            __USART1_CLK_ENABLE();
            break;
139

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

Damien George's avatar
Damien George committed
146
147
            GPIO_Port = GPIOA;
            GPIO_Pin = GPIO_PIN_2 | GPIO_PIN_3;
148

149
150
151
152
153
154
155
            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;
            }

156
157
            __USART2_CLK_ENABLE();
            break;
158

159
        // 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
160
161
        case PYB_UART_3:
            UARTx = USART3;
162
            irqn = USART3_IRQn;
Damien George's avatar
Damien George committed
163
            GPIO_AF_UARTx = GPIO_AF7_USART3;
164

165
#if defined(PYBV3) || defined(PYBV4) | defined(PYBV10)
166
167
            GPIO_Port = GPIOB;
            GPIO_Pin = GPIO_PIN_10 | GPIO_PIN_11;
168
169
170
171
172
173
174

            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;
            }
175
176
177
178
179
180
#else
            GPIO_Port = GPIOD;
            GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9;
#endif
            __USART3_CLK_ENABLE();
            break;
181

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

            GPIO_Port = GPIOA;
            GPIO_Pin = GPIO_PIN_0 | GPIO_PIN_1;

            __UART4_CLK_ENABLE();
            break;

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

            GPIO_Port = GPIOC;
            GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7;

            __USART6_CLK_ENABLE();
            break;
205
206
207

        default:
            return false;
208
209
    }

210
211
212
    uart_obj->irqn = irqn;
    uart_obj->uart.Instance = UARTx;

213
    // init GPIO
214
215
216
217
218
    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
219
    GPIO_InitStructure.Alternate = GPIO_AF_UARTx;
220
221
    HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure);

Damien George's avatar
Damien George committed
222
223
    // init UARTx
    HAL_UART_Init(&uart_obj->uart);
224

Damien George's avatar
Damien George committed
225
    uart_obj->is_enabled = true;
226
227
228
229

    return true;
}

230
/* obsolete and unused
Damien George's avatar
Damien George committed
231
232
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
233
234
    memset(uh, 0, sizeof(*uh));
    uh->Init.BaudRate = baudrate;
235
236
237
238
    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
239
240
    uh->Init.HwFlowCtl = UART_HWCONTROL_NONE;
    uh->Init.OverSampling = UART_OVERSAMPLING_16;
Damien George's avatar
Damien George committed
241
    return uart_init2(uart_obj);
242
}
243
*/
244

245
246
247
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;
248
249
}

250
251
252
253
254
255
256
257
258
259
260
261
262
263
// 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();
    }
264
265
}

266
267
268
269
270
271
272
273
274
275
276
277
278
279
// 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
280
        return self->uart.Instance->DR & self->char_mask;
281
282
283
    }
}

284
STATIC void uart_tx_char(pyb_uart_obj_t *uart_obj, int c) {
285
    uint8_t ch = c;
286
    HAL_UART_Transmit(&uart_obj->uart, &ch, 1, uart_obj->timeout);
287
288
}

Damien George's avatar
Damien George committed
289
void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
290
    HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, len, uart_obj->timeout);
291
292
}

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

302
303
304
305
306
307
308
309
310
311
312
313
314
// 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
315
        data &= self->char_mask;
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
        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
        }
    }
}

333
334
335
/******************************************************************************/
/* Micro Python bindings                                                      */

Damien George's avatar
Damien George committed
336
337
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;
338
    if (!self->is_enabled) {
339
        print(env, "UART(%u)", self->uart_id);
340
    } else {
341
342
343
344
        mp_int_t bits = (self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9);
        if (self->uart.Init.Parity != UART_PARITY_NONE) {
            bits -= 1;
        }
345
        print(env, "UART(%u, baudrate=%u, bits=%u, parity=",
346
            self->uart_id, self->uart.Init.BaudRate, bits);
347
        if (self->uart.Init.Parity == UART_PARITY_NONE) {
348
            print(env, "None");
349
        } else {
350
            print(env, "%u", self->uart.Init.Parity == UART_PARITY_EVEN ? 0 : 1);
351
        }
352
353
354
        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);
355
    }
356
357
}

358
/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, read_buf_len=64)
359
///
360
/// Initialise the UART bus with the given parameters:
361
362
///
///   - `baudrate` is the clock rate.
363
///   - `bits` is the number of bits per byte, 7, 8 or 9.
364
///   - `parity` is the parity, `None`, 0 (even) or 1 (odd).
365
366
367
368
369
370
371
372
373
374
///   - `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} },
375
        { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_HWCONTROL_NONE} },
376
377
378
379
        { 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} },
    };
380
381

    // parse args
382
383
    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);
384

Damien George's avatar
Damien George committed
385
    // set the UART configuration values
386
387
    memset(&self->uart, 0, sizeof(self->uart));
    UART_InitTypeDef *init = &self->uart.Init;
388
389

    // baudrate
390
    init->BaudRate = args[0].u_int;
391
392
393

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

    // 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
412
413
414
415
    switch (args[3].u_int) {
        case 1: init->StopBits = UART_STOPBITS_1; break;
        default: init->StopBits = UART_STOPBITS_2; break;
    }
416
417

    // flow control
418
    init->HwFlowCtl = args[4].u_int;
419
420
421

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

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

    // set timeouts
430
431
    self->timeout = args[5].u_int;
    self->timeout_char = args[6].u_int;
432
433
434
435

    // 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) {
436
        self->char_mask = 0x1ff;
437
438
        self->char_width = CHAR_WIDTH_9BIT;
    } else {
439
440
441
442
443
        if (init->WordLength == UART_WORDLENGTH_9B || init->Parity == UART_PARITY_NONE) {
            self->char_mask = 0xff;
        } else {
            self->char_mask = 0x7f;
        }
444
445
446
447
        self->char_width = CHAR_WIDTH_8BIT;
    }
    self->read_buf_head = 0;
    self->read_buf_tail = 0;
448
    if (args[7].u_int <= 0) {
449
450
451
452
453
454
455
        // 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
456
457
        self->read_buf_len = args[7].u_int;
        self->read_buf = m_new(byte, args[7].u_int << self->char_width);
458
459
460
        __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);
461
462
    }

463
464
465
    return mp_const_none;
}

466
467
468
469
470
471
472
/// \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.
473
474
475
476
477
478
479
480
///
/// 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)`
481
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) {
482
483
484
    // check arguments
    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);

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

522
523
524
525
    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);
526
        pyb_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
527
528
    }

529
    return self;
530
531
}

532
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
533
    return pyb_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
534
}
Damien George's avatar
Damien George committed
535
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);
536

537
538
/// \method deinit()
/// Turn off the UART bus.
Damien George's avatar
Damien George committed
539
540
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
    pyb_uart_obj_t *self = self_in;
541
542
543
544
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
    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();
    }
570
571
    return mp_const_none;
}
Damien George's avatar
Damien George committed
572
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit);
573

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

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

592
593
    // get the character to write (might be 9 bits)
    uint16_t data = mp_obj_get_int(char_in);
594

595
596
    // write the data
    HAL_StatusTypeDef status = HAL_UART_Transmit(&self->uart, (uint8_t*)&data, 1, self->timeout);
597
598

    if (status != HAL_OK) {
599
        mp_hal_raise(status);
600
    }
601

602
603
    return mp_const_none;
}
604
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_uart_writechar_obj, pyb_uart_writechar);
605

606
607
608
609
610
611
612
613
614
615
616
617
618
619
/// \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
620
STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
621
    // instance methods
622

Damien George's avatar
Damien George committed
623
624
625
    { 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 },
626
627
628
629
630
631
632

    /// \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
633
634
    /// \method readinto(buf[, nbytes])
    { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj },
635
636
637
638
639
    /// \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 },
640
641
642
643

    // 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) },
644
645
};

Damien George's avatar
Damien George committed
646
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
647

648
649
650
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
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 {
707
        *errcode = mp_hal_status_to_errno_table[status];
708
709
710
711
        return MP_STREAM_ERROR;
    }
}

712
STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
713
714
715
    pyb_uart_obj_t *self = self_in;
    mp_uint_t ret;
    if (request == MP_IOCTL_POLL) {
716
        mp_uint_t flags = arg;
717
        ret = 0;
718
        if ((flags & MP_IOCTL_POLL_RD) && uart_rx_any(self)) {
719
720
            ret |= MP_IOCTL_POLL_RD;
        }
721
        if ((flags & MP_IOCTL_POLL_WR) && __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_TXE)) {
722
723
724
            ret |= MP_IOCTL_POLL_WR;
        }
    } else {
725
        *errcode = EINVAL;
726
        ret = MP_STREAM_ERROR;
727
728
729
730
731
    }
    return ret;
}

STATIC const mp_stream_p_t uart_stream_p = {
732
733
734
    .read = pyb_uart_read,
    .write = pyb_uart_write,
    .ioctl = pyb_uart_ioctl,
735
736
737
    .is_text = false,
};

Damien George's avatar
Damien George committed
738
const mp_obj_type_t pyb_uart_type = {
739
    { &mp_type_type },
Damien George's avatar
Damien George committed
740
741
742
    .name = MP_QSTR_UART,
    .print = pyb_uart_print,
    .make_new = pyb_uart_make_new,
743
744
    .getiter = mp_identity,
    .iternext = mp_stream_unbuffered_iter,
745
    .stream_p = &uart_stream_p,
Damien George's avatar
Damien George committed
746
    .locals_dict = (mp_obj_t)&pyb_uart_locals_dict,
747
};