uart.c 30.1 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
//TODO: Add UART7/8 support for STM32F7

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

76
77
78
#define CHAR_WIDTH_8BIT (0)
#define CHAR_WIDTH_9BIT (1)

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

95
96
97
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);

void uart_init0(void) {
98
99
    for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) {
        MP_STATE_PORT(pyb_uart_obj_all)[i] = NULL;
100
101
102
103
104
    }
}

// unregister all interrupt sources
void uart_deinit(void) {
105
106
    for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) {
        pyb_uart_obj_t *uart_obj = MP_STATE_PORT(pyb_uart_obj_all)[i];
107
108
109
110
111
112
        if (uart_obj != NULL) {
            pyb_uart_deinit(uart_obj);
        }
    }
}

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

Damien George's avatar
Damien George committed
122
    switch (uart_obj->uart_id) {
123
        #if defined(MICROPY_HW_UART1_PORT) && defined(MICROPY_HW_UART1_PINS)
Damien George's avatar
Damien George committed
124
125
126
        // USART1 is on PA9/PA10 (CK on PA8), PB6/PB7
        case PYB_UART_1:
            UARTx = USART1;
127
            irqn = USART1_IRQn;
Damien George's avatar
Damien George committed
128
            GPIO_AF_UARTx = GPIO_AF7_USART1;
129
130
            GPIO_Port = MICROPY_HW_UART1_PORT;
            GPIO_Pin = MICROPY_HW_UART1_PINS;
131
132
            __USART1_CLK_ENABLE();
            break;
133
        #endif
134

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
        #if defined(MICROPY_HW_UART1_TX_PORT) && \
            defined(MICROPY_HW_UART1_TX_PIN) && \
            defined(MICROPY_HW_UART1_RX_PORT) && \
            defined(MICROPY_HW_UART1_RX_PIN)
        case PYB_UART_1:
            UARTx = USART1;
            irqn = USART1_IRQn;
            GPIO_AF_UARTx = GPIO_AF7_USART1;
            GPIO_Port  = MICROPY_HW_UART1_TX_PORT;
            GPIO_Pin   = MICROPY_HW_UART1_TX_PIN;
            GPIO_Port2 = MICROPY_HW_UART1_RX_PORT;
            GPIO_Pin2  = MICROPY_HW_UART1_RX_PIN;
            __USART1_CLK_ENABLE();
            break;
        #endif

151
        #if defined(MICROPY_HW_UART2_PORT) && defined(MICROPY_HW_UART2_PINS)
152
        // USART2 is on PA2/PA3 (CTS,RTS,CK on PA0,PA1,PA4), PD5/PD6 (CK on PD7)
Damien George's avatar
Damien George committed
153
154
        case PYB_UART_2:
            UARTx = USART2;
155
            irqn = USART2_IRQn;
Damien George's avatar
Damien George committed
156
            GPIO_AF_UARTx = GPIO_AF7_USART2;
157
158
159
            GPIO_Port = MICROPY_HW_UART2_PORT;
            GPIO_Pin = MICROPY_HW_UART2_PINS;
            #if defined(MICROPY_HW_UART2_RTS)
160
            if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) {
161
                GPIO_Pin |= MICROPY_HW_UART2_RTS;
162
            }
163
164
            #endif
            #if defined(MICROPY_HW_UART2_CTS)
165
            if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
166
                GPIO_Pin |= MICROPY_HW_UART2_CTS;
167
            }
168
            #endif
169
170
            __USART2_CLK_ENABLE();
            break;
171
        #endif
172

173
        #if defined(USART3) && defined(MICROPY_HW_UART3_PORT) && defined(MICROPY_HW_UART3_PINS)
174
        // 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
175
176
        case PYB_UART_3:
            UARTx = USART3;
177
            irqn = USART3_IRQn;
Damien George's avatar
Damien George committed
178
            GPIO_AF_UARTx = GPIO_AF7_USART3;
179
180
181
            GPIO_Port = MICROPY_HW_UART3_PORT;
            GPIO_Pin = MICROPY_HW_UART3_PINS;
            #if defined(MICROPY_HW_UART3_RTS)
182
            if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) {
183
                GPIO_Pin |= MICROPY_HW_UART3_RTS;
184
            }
185
186
            #endif
            #if defined(MICROPY_HW_UART3_CTS)
187
            if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) {
188
                GPIO_Pin |= MICROPY_HW_UART3_CTS;
189
            }
190
            #endif
191
192
            __USART3_CLK_ENABLE();
            break;
193
        #endif
194

195
        #if defined(UART4) && defined(MICROPY_HW_UART4_PORT) && defined(MICROPY_HW_UART4_PINS)
196
        // UART4 is on PA0/PA1, PC10/PC11
Damien George's avatar
Damien George committed
197
198
        case PYB_UART_4:
            UARTx = UART4;
199
            irqn = UART4_IRQn;
Damien George's avatar
Damien George committed
200
            GPIO_AF_UARTx = GPIO_AF8_UART4;
201
202
            GPIO_Port = MICROPY_HW_UART4_PORT;
            GPIO_Pin = MICROPY_HW_UART4_PINS;
203
204
            __UART4_CLK_ENABLE();
            break;
205
        #endif
206

Dave Hylands's avatar
Dave Hylands committed
207
208
209
210
211
212
213
214
215
216
        #if defined(UART5) && \
            defined(MICROPY_HW_UART5_TX_PORT) && \
            defined(MICROPY_HW_UART5_TX_PIN) && \
            defined(MICROPY_HW_UART5_RX_PORT) && \
            defined(MICROPY_HW_UART5_RX_PIN)
        case PYB_UART_5:
            UARTx = UART5;
            irqn = UART5_IRQn;
            GPIO_AF_UARTx = GPIO_AF8_UART5;
            GPIO_Port = MICROPY_HW_UART5_TX_PORT;
217
            GPIO_Port2 = MICROPY_HW_UART5_RX_PORT;
Dave Hylands's avatar
Dave Hylands committed
218
            GPIO_Pin = MICROPY_HW_UART5_TX_PIN;
219
            GPIO_Pin2 = MICROPY_HW_UART5_RX_PIN;
Dave Hylands's avatar
Dave Hylands committed
220
221
222
223
            __UART5_CLK_ENABLE();
            break;
        #endif

224
        #if defined(MICROPY_HW_UART6_PORT) && defined(MICROPY_HW_UART6_PINS)
Damien George's avatar
Damien George committed
225
226
227
        // USART6 is on PC6/PC7 (CK on PC8)
        case PYB_UART_6:
            UARTx = USART6;
228
            irqn = USART6_IRQn;
Damien George's avatar
Damien George committed
229
            GPIO_AF_UARTx = GPIO_AF8_USART6;
230
231
            GPIO_Port = MICROPY_HW_UART6_PORT;
            GPIO_Pin = MICROPY_HW_UART6_PINS;
232
233
            __USART6_CLK_ENABLE();
            break;
234
        #endif
235
236

        default:
237
            // UART does not exist or is not configured for this board
238
            return false;
239
240
    }

241
242
243
    uart_obj->irqn = irqn;
    uart_obj->uart.Instance = UARTx;

244
    // init GPIO
245
    mp_hal_gpio_clock_enable(GPIO_Port);
246
247
248
249
250
    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
251
    GPIO_InitStructure.Alternate = GPIO_AF_UARTx;
252
253
    HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure);

254
255
256
257
258
259
260
    // init GPIO for second pin if needed
    if (GPIO_Port2 != NULL) {
        mp_hal_gpio_clock_enable(GPIO_Port2);
        GPIO_InitStructure.Pin = GPIO_Pin2;
        HAL_GPIO_Init(GPIO_Port2, &GPIO_InitStructure);
    }

Damien George's avatar
Damien George committed
261
262
    // init UARTx
    HAL_UART_Init(&uart_obj->uart);
263

Damien George's avatar
Damien George committed
264
    uart_obj->is_enabled = true;
265
266
267
268

    return true;
}

269
/* obsolete and unused
Damien George's avatar
Damien George committed
270
271
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
272
273
    memset(uh, 0, sizeof(*uh));
    uh->Init.BaudRate = baudrate;
274
275
276
277
    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
278
279
    uh->Init.HwFlowCtl = UART_HWCONTROL_NONE;
    uh->Init.OverSampling = UART_OVERSAMPLING_16;
Damien George's avatar
Damien George committed
280
    return uart_init2(uart_obj);
281
}
282
*/
283

284
285
286
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;
287
288
}

289
290
291
292
293
294
295
296
297
298
299
300
301
302
// 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();
    }
303
304
}

305
306
307
308
309
310
311
312
313
314
315
316
317
318
// 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
319
320
321
        #if defined(STM32F7)
        return self->uart.Instance->RDR & self->char_mask;
        #else
322
        return self->uart.Instance->DR & self->char_mask;
323
        #endif
324
325
326
    }
}

327
STATIC void uart_tx_char(pyb_uart_obj_t *uart_obj, int c) {
328
    uint8_t ch = c;
329
    HAL_UART_Transmit(&uart_obj->uart, &ch, 1, uart_obj->timeout);
330
331
}

Damien George's avatar
Damien George committed
332
void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
333
    HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, len, uart_obj->timeout);
334
335
}

Damien George's avatar
Damien George committed
336
void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
337
338
    for (const char *top = str + len; str < top; str++) {
        if (*str == '\n') {
Damien George's avatar
Damien George committed
339
            uart_tx_char(uart_obj, '\r');
340
        }
Damien George's avatar
Damien George committed
341
        uart_tx_char(uart_obj, *str);
342
343
344
    }
}

345
346
347
// this IRQ handler is set up to handle RXNE interrupts only
void uart_irq_handler(mp_uint_t uart_id) {
    // get the uart object
348
    pyb_uart_obj_t *self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1];
349
350
351
352
353
354
355
356

    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) {
357
358
359
        #if defined(STM32F7)
        int data = self->uart.Instance->RDR; // clears UART_FLAG_RXNE
        #else
360
        int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE
361
        #endif
362
        data &= self->char_mask;
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
        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
        }
    }
}

380
381
382
/******************************************************************************/
/* Micro Python bindings                                                      */

383
STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
Damien George's avatar
Damien George committed
384
    pyb_uart_obj_t *self = self_in;
385
    if (!self->is_enabled) {
386
        mp_printf(print, "UART(%u)", self->uart_id);
387
    } else {
388
389
390
391
        mp_int_t bits = (self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9);
        if (self->uart.Init.Parity != UART_PARITY_NONE) {
            bits -= 1;
        }
392
        mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=",
393
            self->uart_id, self->uart.Init.BaudRate, bits);
394
        if (self->uart.Init.Parity == UART_PARITY_NONE) {
395
            mp_print_str(print, "None");
396
        } else {
397
            mp_printf(print, "%u", self->uart.Init.Parity == UART_PARITY_EVEN ? 0 : 1);
398
        }
399
        mp_printf(print, ", stop=%u, timeout=%u, timeout_char=%u, read_buf_len=%u)",
400
401
            self->uart.Init.StopBits == UART_STOPBITS_1 ? 1 : 2,
            self->timeout, self->timeout_char, self->read_buf_len);
402
    }
403
404
}

405
/// \method init(baudrate, bits=8, parity=None, stop=1, *, timeout=1000, timeout_char=0, read_buf_len=64)
406
///
407
/// Initialise the UART bus with the given parameters:
408
409
///
///   - `baudrate` is the clock rate.
410
///   - `bits` is the number of bits per byte, 7, 8 or 9.
411
///   - `parity` is the parity, `None`, 0 (even) or 1 (odd).
412
413
414
415
416
417
418
419
420
421
///   - `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} },
422
        { MP_QSTR_flow, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_HWCONTROL_NONE} },
423
424
425
426
        { 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} },
    };
427
428

    // parse args
429
430
    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);
431

Damien George's avatar
Damien George committed
432
    // set the UART configuration values
433
434
    memset(&self->uart, 0, sizeof(self->uart));
    UART_InitTypeDef *init = &self->uart.Init;
435
436

    // baudrate
437
    init->BaudRate = args[0].u_int;
438
439
440

    // parity
    mp_int_t bits = args[1].u_int;
441
    if (args[2].u_obj == mp_const_none) {
442
443
        init->Parity = UART_PARITY_NONE;
    } else {
444
        mp_int_t parity = mp_obj_get_int(args[2].u_obj);
445
        init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN;
446
        bits += 1; // STs convention has bits including parity
447
    }
448
449
450
451
452
453
454
455
456
457
458

    // 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
459
460
461
462
    switch (args[3].u_int) {
        case 1: init->StopBits = UART_STOPBITS_1; break;
        default: init->StopBits = UART_STOPBITS_2; break;
    }
463
464

    // flow control
465
    init->HwFlowCtl = args[4].u_int;
466
467
468

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

Damien George's avatar
Damien George committed
471
472
    // init UART (if it fails, it's because the port doesn't exist)
    if (!uart_init2(self)) {
473
474
475
476
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", self->uart_id));
    }

    // set timeouts
477
478
    self->timeout = args[5].u_int;
    self->timeout_char = args[6].u_int;
479
480
481
482

    // 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) {
483
        self->char_mask = 0x1ff;
484
485
        self->char_width = CHAR_WIDTH_9BIT;
    } else {
486
487
488
489
490
        if (init->WordLength == UART_WORDLENGTH_9B || init->Parity == UART_PARITY_NONE) {
            self->char_mask = 0xff;
        } else {
            self->char_mask = 0x7f;
        }
491
492
493
494
        self->char_width = CHAR_WIDTH_8BIT;
    }
    self->read_buf_head = 0;
    self->read_buf_tail = 0;
495
    if (args[7].u_int <= 0) {
496
497
498
499
500
501
502
        // 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
503
504
        self->read_buf_len = args[7].u_int;
        self->read_buf = m_new(byte, args[7].u_int << self->char_width);
505
506
507
        __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);
508
509
    }

510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
    // compute actual baudrate that was configured
    // (this formula assumes UART_OVERSAMPLING_16)
    uint32_t actual_baudrate;
    if (self->uart.Instance == USART1 || self->uart.Instance == USART6) {
        actual_baudrate = HAL_RCC_GetPCLK2Freq();
    } else {
        actual_baudrate = HAL_RCC_GetPCLK1Freq();
    }
    actual_baudrate /= self->uart.Instance->BRR;

    // check we could set the baudrate within 5%
    uint32_t baudrate_diff;
    if (actual_baudrate > init->BaudRate) {
        baudrate_diff = actual_baudrate - init->BaudRate;
    } else {
        baudrate_diff = init->BaudRate - actual_baudrate;
    }
    init->BaudRate = actual_baudrate; // remember actual baudrate for printing
    if (20 * baudrate_diff > init->BaudRate) {
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "set baudrate %d is not within 5%% of desired value", actual_baudrate));
    }

532
533
534
    return mp_const_none;
}

535
536
537
538
539
540
541
/// \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.
542
543
544
545
546
547
548
549
///
/// 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)`
550
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) {
551
552
553
    // check arguments
    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);

554
    // work out port
555
    int uart_id = 0;
556
557
    if (MP_OBJ_IS_STR(args[0])) {
        const char *port = mp_obj_str_get_str(args[0]);
558
        if (0) {
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
        #ifdef MICROPY_HW_UART1_NAME
        } else if (strcmp(port, MICROPY_HW_UART1_NAME) == 0) {
            uart_id = PYB_UART_1;
        #endif
        #ifdef MICROPY_HW_UART2_NAME
        } else if (strcmp(port, MICROPY_HW_UART2_NAME) == 0) {
            uart_id = PYB_UART_2;
        #endif
        #ifdef MICROPY_HW_UART3_NAME
        } else if (strcmp(port, MICROPY_HW_UART3_NAME) == 0) {
            uart_id = PYB_UART_3;
        #endif
        #ifdef MICROPY_HW_UART4_NAME
        } else if (strcmp(port, MICROPY_HW_UART4_NAME) == 0) {
            uart_id = PYB_UART_4;
        #endif
        #ifdef MICROPY_HW_UART5_NAME
        } else if (strcmp(port, MICROPY_HW_UART5_NAME) == 0) {
            uart_id = PYB_UART_5;
        #endif
        #ifdef MICROPY_HW_UART6_NAME
        } else if (strcmp(port, MICROPY_HW_UART6_NAME) == 0) {
            uart_id = PYB_UART_6;
        #endif
583
        } else {
584
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%s) does not exist", port));
585
        }
586
    } else {
587
        uart_id = mp_obj_get_int(args[0]);
588
        if (uart_id < 1 || uart_id > MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all))) {
589
590
591
592
593
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_id));
        }
    }

    pyb_uart_obj_t *self;
594
    if (MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1] == NULL) {
595
596
597
598
        // create new UART object
        self = m_new0(pyb_uart_obj_t, 1);
        self->base.type = &pyb_uart_type;
        self->uart_id = uart_id;
599
        MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1] = self;
600
601
    } else {
        // reference existing UART object
602
        self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1];
603
604
    }

605
606
607
608
    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);
609
        pyb_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
610
611
    }

612
    return self;
613
614
}

615
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
616
    return pyb_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
617
}
Damien George's avatar
Damien George committed
618
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);
619

620
621
/// \method deinit()
/// Turn off the UART bus.
Damien George's avatar
Damien George committed
622
623
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
    pyb_uart_obj_t *self = self_in;
624
625
626
627
628
629
630
631
632
633
634
635
636
    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();
637
    #if defined(USART3)
638
639
640
641
642
    } else if (uart->Instance == USART3) {
        HAL_NVIC_DisableIRQ(USART3_IRQn);
        __USART3_FORCE_RESET();
        __USART3_RELEASE_RESET();
        __USART3_CLK_DISABLE();
643
644
    #endif
    #if defined(UART4)
645
646
647
648
649
    } else if (uart->Instance == UART4) {
        HAL_NVIC_DisableIRQ(UART4_IRQn);
        __UART4_FORCE_RESET();
        __UART4_RELEASE_RESET();
        __UART4_CLK_DISABLE();
650
    #endif
Dave Hylands's avatar
Dave Hylands committed
651
652
653
654
655
656
657
    #if defined(UART5)
    } else if (uart->Instance == UART5) {
        HAL_NVIC_DisableIRQ(UART5_IRQn);
        __UART5_FORCE_RESET();
        __UART5_RELEASE_RESET();
        __UART5_CLK_DISABLE();
    #endif
658
659
660
661
662
663
    } else if (uart->Instance == USART6) {
        HAL_NVIC_DisableIRQ(USART6_IRQn);
        __USART6_FORCE_RESET();
        __USART6_RELEASE_RESET();
        __USART6_CLK_DISABLE();
    }
664
665
    return mp_const_none;
}
Damien George's avatar
Damien George committed
666
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit);
667

668
669
/// \method any()
/// Return `True` if any characters waiting, else `False`.
Damien George's avatar
Damien George committed
670
671
672
STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) {
    pyb_uart_obj_t *self = self_in;
    if (uart_rx_any(self)) {
673
674
675
676
677
        return mp_const_true;
    } else {
        return mp_const_false;
    }
}
Damien George's avatar
Damien George committed
678
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any);
679

680
681
/// \method writechar(char)
/// Write a single character on the bus.  `char` is an integer to write.
682
/// Return value: `None`.
683
684
STATIC mp_obj_t pyb_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
    pyb_uart_obj_t *self = self_in;
685

686
687
    // get the character to write (might be 9 bits)
    uint16_t data = mp_obj_get_int(char_in);
688

689
690
    // write the data
    HAL_StatusTypeDef status = HAL_UART_Transmit(&self->uart, (uint8_t*)&data, 1, self->timeout);
691
692

    if (status != HAL_OK) {
693
        mp_hal_raise(status);
694
    }
695

696
697
    return mp_const_none;
}
698
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_uart_writechar_obj, pyb_uart_writechar);
699

700
701
702
703
704
705
706
707
708
709
710
711
712
713
/// \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);

714
715
716
// uart.sendbreak()
STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
    pyb_uart_obj_t *self = self_in;
717
718
719
    #if defined(STM32F7)
    self->uart.Instance->RQR = USART_RQR_SBKRQ; // write-only register
    #else
720
    self->uart.Instance->CR1 |= USART_CR1_SBK;
721
    #endif
722
723
724
725
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak);

Damien George's avatar
Damien George committed
726
STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
727
    // instance methods
728

Damien George's avatar
Damien George committed
729
730
731
    { 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 },
732
733
734
735
736
737
738

    /// \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
739
740
    /// \method readinto(buf[, nbytes])
    { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj },
741
742
743
744
745
    /// \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 },
746
    { MP_OBJ_NEW_QSTR(MP_QSTR_sendbreak), (mp_obj_t)&pyb_uart_sendbreak_obj },
747
748
749
750

    // 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) },
751
752
};

Damien George's avatar
Damien George committed
753
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
754

755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
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 {
814
        *errcode = mp_hal_status_to_errno_table[status];
815
816
817
818
        return MP_STREAM_ERROR;
    }
}

819
STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
820
821
822
    pyb_uart_obj_t *self = self_in;
    mp_uint_t ret;
    if (request == MP_IOCTL_POLL) {
823
        mp_uint_t flags = arg;
824
        ret = 0;
825
        if ((flags & MP_IOCTL_POLL_RD) && uart_rx_any(self)) {
826
827
            ret |= MP_IOCTL_POLL_RD;
        }
828
        if ((flags & MP_IOCTL_POLL_WR) && __HAL_UART_GET_FLAG(&self->uart, UART_FLAG_TXE)) {
829
830
831
            ret |= MP_IOCTL_POLL_WR;
        }
    } else {
832
        *errcode = EINVAL;
833
        ret = MP_STREAM_ERROR;
834
835
836
837
838
    }
    return ret;
}

STATIC const mp_stream_p_t uart_stream_p = {
839
840
841
    .read = pyb_uart_read,
    .write = pyb_uart_write,
    .ioctl = pyb_uart_ioctl,
842
843
844
    .is_text = false,
};

Damien George's avatar
Damien George committed
845
const mp_obj_type_t pyb_uart_type = {
846
    { &mp_type_type },
Damien George's avatar
Damien George committed
847
848
849
    .name = MP_QSTR_UART,
    .print = pyb_uart_print,
    .make_new = pyb_uart_make_new,
850
851
    .getiter = mp_identity,
    .iternext = mp_stream_unbuffered_iter,
852
    .stream_p = &uart_stream_p,
Damien George's avatar
Damien George committed
853
    .locals_dict = (mp_obj_t)&pyb_uart_locals_dict,
854
};