Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-dev by
targets/TARGET_NUVOTON/TARGET_M480/serial_api.c@180:d79f997829d6, 2017-12-18 (annotated)
- Committer:
- Anythingconnected
- Date:
- Mon Dec 18 10:14:27 2017 +0000
- Revision:
- 180:d79f997829d6
- Parent:
- 176:447f873cad2f
Getting byte by byte read to work
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AnnaBridge | 172:7d866c31b3c5 | 1 | /* mbed Microcontroller Library |
AnnaBridge | 172:7d866c31b3c5 | 2 | * Copyright (c) 2015-2016 Nuvoton |
AnnaBridge | 172:7d866c31b3c5 | 3 | * |
AnnaBridge | 172:7d866c31b3c5 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
AnnaBridge | 172:7d866c31b3c5 | 5 | * you may not use this file except in compliance with the License. |
AnnaBridge | 172:7d866c31b3c5 | 6 | * You may obtain a copy of the License at |
AnnaBridge | 172:7d866c31b3c5 | 7 | * |
AnnaBridge | 172:7d866c31b3c5 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
AnnaBridge | 172:7d866c31b3c5 | 9 | * |
AnnaBridge | 172:7d866c31b3c5 | 10 | * Unless required by applicable law or agreed to in writing, software |
AnnaBridge | 172:7d866c31b3c5 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
AnnaBridge | 172:7d866c31b3c5 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
AnnaBridge | 172:7d866c31b3c5 | 13 | * See the License for the specific language governing permissions and |
AnnaBridge | 172:7d866c31b3c5 | 14 | * limitations under the License. |
AnnaBridge | 172:7d866c31b3c5 | 15 | */ |
AnnaBridge | 172:7d866c31b3c5 | 16 | |
AnnaBridge | 172:7d866c31b3c5 | 17 | #include "serial_api.h" |
AnnaBridge | 172:7d866c31b3c5 | 18 | |
AnnaBridge | 172:7d866c31b3c5 | 19 | #if DEVICE_SERIAL |
AnnaBridge | 172:7d866c31b3c5 | 20 | |
AnnaBridge | 172:7d866c31b3c5 | 21 | #include "cmsis.h" |
AnnaBridge | 172:7d866c31b3c5 | 22 | #include "mbed_error.h" |
AnnaBridge | 172:7d866c31b3c5 | 23 | #include "mbed_assert.h" |
AnnaBridge | 172:7d866c31b3c5 | 24 | #include "PeripheralPins.h" |
AnnaBridge | 172:7d866c31b3c5 | 25 | #include "nu_modutil.h" |
AnnaBridge | 172:7d866c31b3c5 | 26 | #include "nu_bitutil.h" |
AnnaBridge | 172:7d866c31b3c5 | 27 | #include <string.h> |
AnnaBridge | 172:7d866c31b3c5 | 28 | |
AnnaBridge | 172:7d866c31b3c5 | 29 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 30 | #include "dma_api.h" |
AnnaBridge | 172:7d866c31b3c5 | 31 | #include "dma.h" |
AnnaBridge | 172:7d866c31b3c5 | 32 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 33 | |
AnnaBridge | 172:7d866c31b3c5 | 34 | struct nu_uart_var { |
AnnaBridge | 172:7d866c31b3c5 | 35 | uint32_t ref_cnt; // Reference count of the H/W module |
AnnaBridge | 172:7d866c31b3c5 | 36 | serial_t * obj; |
AnnaBridge | 172:7d866c31b3c5 | 37 | uint32_t fifo_size_tx; |
AnnaBridge | 172:7d866c31b3c5 | 38 | uint32_t fifo_size_rx; |
AnnaBridge | 172:7d866c31b3c5 | 39 | void (*vec)(void); |
AnnaBridge | 172:7d866c31b3c5 | 40 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 41 | void (*vec_async)(void); |
AnnaBridge | 172:7d866c31b3c5 | 42 | uint8_t pdma_perp_tx; |
AnnaBridge | 172:7d866c31b3c5 | 43 | uint8_t pdma_perp_rx; |
AnnaBridge | 172:7d866c31b3c5 | 44 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 45 | }; |
AnnaBridge | 172:7d866c31b3c5 | 46 | |
AnnaBridge | 172:7d866c31b3c5 | 47 | static void uart0_vec(void); |
AnnaBridge | 172:7d866c31b3c5 | 48 | static void uart1_vec(void); |
AnnaBridge | 172:7d866c31b3c5 | 49 | static void uart2_vec(void); |
AnnaBridge | 172:7d866c31b3c5 | 50 | static void uart3_vec(void); |
AnnaBridge | 172:7d866c31b3c5 | 51 | static void uart4_vec(void); |
AnnaBridge | 172:7d866c31b3c5 | 52 | static void uart5_vec(void); |
AnnaBridge | 172:7d866c31b3c5 | 53 | static void uart_irq(serial_t *obj); |
AnnaBridge | 172:7d866c31b3c5 | 54 | |
AnnaBridge | 172:7d866c31b3c5 | 55 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 56 | static void uart0_vec_async(void); |
AnnaBridge | 172:7d866c31b3c5 | 57 | static void uart1_vec_async(void); |
AnnaBridge | 172:7d866c31b3c5 | 58 | static void uart2_vec_async(void); |
AnnaBridge | 172:7d866c31b3c5 | 59 | static void uart3_vec_async(void); |
AnnaBridge | 172:7d866c31b3c5 | 60 | static void uart4_vec_async(void); |
AnnaBridge | 172:7d866c31b3c5 | 61 | static void uart5_vec_async(void); |
AnnaBridge | 172:7d866c31b3c5 | 62 | static void uart_irq_async(serial_t *obj); |
AnnaBridge | 172:7d866c31b3c5 | 63 | |
AnnaBridge | 172:7d866c31b3c5 | 64 | static void uart_dma_handler_tx(uint32_t id, uint32_t event); |
AnnaBridge | 172:7d866c31b3c5 | 65 | static void uart_dma_handler_rx(uint32_t id, uint32_t event); |
AnnaBridge | 172:7d866c31b3c5 | 66 | |
AnnaBridge | 172:7d866c31b3c5 | 67 | static void serial_tx_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable); |
AnnaBridge | 172:7d866c31b3c5 | 68 | static void serial_rx_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable); |
AnnaBridge | 172:7d866c31b3c5 | 69 | static void serial_enable_interrupt(serial_t *obj, SerialIrq irq, uint32_t enable); |
AnnaBridge | 172:7d866c31b3c5 | 70 | static void serial_rollback_interrupt(serial_t *obj, SerialIrq irq); |
AnnaBridge | 172:7d866c31b3c5 | 71 | static int serial_write_async(serial_t *obj); |
AnnaBridge | 172:7d866c31b3c5 | 72 | static int serial_read_async(serial_t *obj); |
AnnaBridge | 172:7d866c31b3c5 | 73 | |
AnnaBridge | 172:7d866c31b3c5 | 74 | static uint32_t serial_rx_event_check(serial_t *obj); |
AnnaBridge | 172:7d866c31b3c5 | 75 | static uint32_t serial_tx_event_check(serial_t *obj); |
AnnaBridge | 172:7d866c31b3c5 | 76 | |
AnnaBridge | 172:7d866c31b3c5 | 77 | static int serial_is_tx_complete(serial_t *obj); |
AnnaBridge | 172:7d866c31b3c5 | 78 | static void serial_tx_enable_event(serial_t *obj, int event, uint8_t enable); |
AnnaBridge | 172:7d866c31b3c5 | 79 | |
AnnaBridge | 172:7d866c31b3c5 | 80 | static void serial_tx_buffer_set(serial_t *obj, const void *tx, size_t length, uint8_t width); |
AnnaBridge | 172:7d866c31b3c5 | 81 | static void serial_rx_buffer_set(serial_t *obj, void *rx, size_t length, uint8_t width); |
AnnaBridge | 172:7d866c31b3c5 | 82 | static void serial_rx_set_char_match(serial_t *obj, uint8_t char_match); |
AnnaBridge | 172:7d866c31b3c5 | 83 | static void serial_rx_enable_event(serial_t *obj, int event, uint8_t enable); |
AnnaBridge | 172:7d866c31b3c5 | 84 | static int serial_is_rx_complete(serial_t *obj); |
AnnaBridge | 172:7d866c31b3c5 | 85 | |
AnnaBridge | 172:7d866c31b3c5 | 86 | static void serial_check_dma_usage(DMAUsage *dma_usage, int *dma_ch); |
AnnaBridge | 172:7d866c31b3c5 | 87 | static int serial_is_irq_en(serial_t *obj, SerialIrq irq); |
AnnaBridge | 172:7d866c31b3c5 | 88 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 89 | |
AnnaBridge | 172:7d866c31b3c5 | 90 | static struct nu_uart_var uart0_var = { |
AnnaBridge | 172:7d866c31b3c5 | 91 | .ref_cnt = 0, |
AnnaBridge | 172:7d866c31b3c5 | 92 | .obj = NULL, |
AnnaBridge | 172:7d866c31b3c5 | 93 | .fifo_size_tx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 94 | .fifo_size_rx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 95 | .vec = uart0_vec, |
AnnaBridge | 172:7d866c31b3c5 | 96 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 97 | .vec_async = uart0_vec_async, |
AnnaBridge | 172:7d866c31b3c5 | 98 | .pdma_perp_tx = PDMA_UART0_TX, |
AnnaBridge | 172:7d866c31b3c5 | 99 | .pdma_perp_rx = PDMA_UART0_RX |
AnnaBridge | 172:7d866c31b3c5 | 100 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 101 | }; |
AnnaBridge | 172:7d866c31b3c5 | 102 | static struct nu_uart_var uart1_var = { |
AnnaBridge | 172:7d866c31b3c5 | 103 | .ref_cnt = 0, |
AnnaBridge | 172:7d866c31b3c5 | 104 | .obj = NULL, |
AnnaBridge | 172:7d866c31b3c5 | 105 | .fifo_size_tx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 106 | .fifo_size_rx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 107 | .vec = uart1_vec, |
AnnaBridge | 172:7d866c31b3c5 | 108 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 109 | .vec_async = uart1_vec_async, |
AnnaBridge | 172:7d866c31b3c5 | 110 | .pdma_perp_tx = PDMA_UART1_TX, |
AnnaBridge | 172:7d866c31b3c5 | 111 | .pdma_perp_rx = PDMA_UART1_RX |
AnnaBridge | 172:7d866c31b3c5 | 112 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 113 | }; |
AnnaBridge | 172:7d866c31b3c5 | 114 | static struct nu_uart_var uart2_var = { |
AnnaBridge | 172:7d866c31b3c5 | 115 | .ref_cnt = 0, |
AnnaBridge | 172:7d866c31b3c5 | 116 | .obj = NULL, |
AnnaBridge | 172:7d866c31b3c5 | 117 | .fifo_size_tx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 118 | .fifo_size_rx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 119 | .vec = uart2_vec, |
AnnaBridge | 172:7d866c31b3c5 | 120 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 121 | .vec_async = uart2_vec_async, |
AnnaBridge | 172:7d866c31b3c5 | 122 | .pdma_perp_tx = PDMA_UART2_TX, |
AnnaBridge | 172:7d866c31b3c5 | 123 | .pdma_perp_rx = PDMA_UART2_RX |
AnnaBridge | 172:7d866c31b3c5 | 124 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 125 | }; |
AnnaBridge | 172:7d866c31b3c5 | 126 | static struct nu_uart_var uart3_var = { |
AnnaBridge | 172:7d866c31b3c5 | 127 | .ref_cnt = 0, |
AnnaBridge | 172:7d866c31b3c5 | 128 | .obj = NULL, |
AnnaBridge | 172:7d866c31b3c5 | 129 | .fifo_size_tx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 130 | .fifo_size_rx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 131 | .vec = uart3_vec, |
AnnaBridge | 172:7d866c31b3c5 | 132 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 133 | .vec_async = uart3_vec_async, |
AnnaBridge | 172:7d866c31b3c5 | 134 | .pdma_perp_tx = PDMA_UART3_TX, |
AnnaBridge | 172:7d866c31b3c5 | 135 | .pdma_perp_rx = PDMA_UART3_RX |
AnnaBridge | 172:7d866c31b3c5 | 136 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 137 | }; |
AnnaBridge | 172:7d866c31b3c5 | 138 | static struct nu_uart_var uart4_var = { |
AnnaBridge | 172:7d866c31b3c5 | 139 | .ref_cnt = 0, |
AnnaBridge | 172:7d866c31b3c5 | 140 | .obj = NULL, |
AnnaBridge | 172:7d866c31b3c5 | 141 | .fifo_size_tx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 142 | .fifo_size_rx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 143 | .vec = uart4_vec, |
AnnaBridge | 172:7d866c31b3c5 | 144 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 145 | .vec_async = uart4_vec_async, |
AnnaBridge | 172:7d866c31b3c5 | 146 | .pdma_perp_tx = PDMA_UART4_TX, |
AnnaBridge | 172:7d866c31b3c5 | 147 | .pdma_perp_rx = PDMA_UART4_RX |
AnnaBridge | 172:7d866c31b3c5 | 148 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 149 | }; |
AnnaBridge | 172:7d866c31b3c5 | 150 | static struct nu_uart_var uart5_var = { |
AnnaBridge | 172:7d866c31b3c5 | 151 | .ref_cnt = 0, |
AnnaBridge | 172:7d866c31b3c5 | 152 | .obj = NULL, |
AnnaBridge | 172:7d866c31b3c5 | 153 | .fifo_size_tx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 154 | .fifo_size_rx = 16, |
AnnaBridge | 172:7d866c31b3c5 | 155 | .vec = uart5_vec, |
AnnaBridge | 172:7d866c31b3c5 | 156 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 157 | .vec_async = uart5_vec_async, |
AnnaBridge | 172:7d866c31b3c5 | 158 | .pdma_perp_tx = PDMA_UART5_TX, |
AnnaBridge | 172:7d866c31b3c5 | 159 | .pdma_perp_rx = PDMA_UART5_RX |
AnnaBridge | 172:7d866c31b3c5 | 160 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 161 | }; |
AnnaBridge | 172:7d866c31b3c5 | 162 | |
AnnaBridge | 172:7d866c31b3c5 | 163 | |
AnnaBridge | 172:7d866c31b3c5 | 164 | int stdio_uart_inited = 0; |
AnnaBridge | 172:7d866c31b3c5 | 165 | serial_t stdio_uart; |
AnnaBridge | 172:7d866c31b3c5 | 166 | static uint32_t uart_modinit_mask = 0; |
AnnaBridge | 172:7d866c31b3c5 | 167 | |
AnnaBridge | 172:7d866c31b3c5 | 168 | static const struct nu_modinit_s uart_modinit_tab[] = { |
AnnaBridge | 172:7d866c31b3c5 | 169 | {UART_0, UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1), UART0_RST, UART0_IRQn, &uart0_var}, |
AnnaBridge | 172:7d866c31b3c5 | 170 | {UART_1, UART1_MODULE, CLK_CLKSEL1_UART1SEL_HIRC, CLK_CLKDIV0_UART1(1), UART1_RST, UART1_IRQn, &uart1_var}, |
AnnaBridge | 172:7d866c31b3c5 | 171 | {UART_2, UART2_MODULE, CLK_CLKSEL3_UART2SEL_HIRC, CLK_CLKDIV4_UART2(1), UART2_RST, UART2_IRQn, &uart2_var}, |
AnnaBridge | 172:7d866c31b3c5 | 172 | {UART_3, UART3_MODULE, CLK_CLKSEL3_UART3SEL_HIRC, CLK_CLKDIV4_UART3(1), UART3_RST, UART3_IRQn, &uart3_var}, |
AnnaBridge | 172:7d866c31b3c5 | 173 | {UART_4, UART4_MODULE, CLK_CLKSEL3_UART4SEL_HIRC, CLK_CLKDIV4_UART4(1), UART4_RST, UART4_IRQn, &uart4_var}, |
AnnaBridge | 172:7d866c31b3c5 | 174 | {UART_5, UART5_MODULE, CLK_CLKSEL3_UART5SEL_HIRC, CLK_CLKDIV4_UART5(1), UART5_RST, UART5_IRQn, &uart5_var}, |
AnnaBridge | 172:7d866c31b3c5 | 175 | |
AnnaBridge | 172:7d866c31b3c5 | 176 | {NC, 0, 0, 0, 0, (IRQn_Type) 0, NULL} |
AnnaBridge | 172:7d866c31b3c5 | 177 | }; |
AnnaBridge | 172:7d866c31b3c5 | 178 | |
AnnaBridge | 172:7d866c31b3c5 | 179 | extern void mbed_sdk_init(void); |
AnnaBridge | 172:7d866c31b3c5 | 180 | |
AnnaBridge | 172:7d866c31b3c5 | 181 | void serial_init(serial_t *obj, PinName tx, PinName rx) |
AnnaBridge | 172:7d866c31b3c5 | 182 | { |
AnnaBridge | 172:7d866c31b3c5 | 183 | // NOTE: With armcc, serial_init() gets called from _sys_open() timing of which is before main()/mbed_sdk_init(). |
AnnaBridge | 172:7d866c31b3c5 | 184 | mbed_sdk_init(); |
AnnaBridge | 172:7d866c31b3c5 | 185 | |
AnnaBridge | 172:7d866c31b3c5 | 186 | // Determine which UART_x the pins are used for |
AnnaBridge | 172:7d866c31b3c5 | 187 | uint32_t uart_tx = pinmap_peripheral(tx, PinMap_UART_TX); |
AnnaBridge | 172:7d866c31b3c5 | 188 | uint32_t uart_rx = pinmap_peripheral(rx, PinMap_UART_RX); |
AnnaBridge | 172:7d866c31b3c5 | 189 | // Get the peripheral name (UART_x) from the pins and assign it to the object |
AnnaBridge | 172:7d866c31b3c5 | 190 | obj->serial.uart = (UARTName) pinmap_merge(uart_tx, uart_rx); |
AnnaBridge | 172:7d866c31b3c5 | 191 | MBED_ASSERT((int)obj->serial.uart != NC); |
AnnaBridge | 172:7d866c31b3c5 | 192 | |
AnnaBridge | 172:7d866c31b3c5 | 193 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 194 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 195 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 196 | |
AnnaBridge | 172:7d866c31b3c5 | 197 | struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; |
AnnaBridge | 172:7d866c31b3c5 | 198 | |
AnnaBridge | 172:7d866c31b3c5 | 199 | if (! var->ref_cnt) { |
AnnaBridge | 172:7d866c31b3c5 | 200 | do { |
AnnaBridge | 172:7d866c31b3c5 | 201 | // Reset this module |
AnnaBridge | 172:7d866c31b3c5 | 202 | SYS_ResetModule(modinit->rsetidx); |
AnnaBridge | 172:7d866c31b3c5 | 203 | |
AnnaBridge | 172:7d866c31b3c5 | 204 | // Select IP clock source |
AnnaBridge | 172:7d866c31b3c5 | 205 | CLK_SetModuleClock(modinit->clkidx, modinit->clksrc, modinit->clkdiv); |
AnnaBridge | 172:7d866c31b3c5 | 206 | // Enable IP clock |
AnnaBridge | 172:7d866c31b3c5 | 207 | CLK_EnableModuleClock(modinit->clkidx); |
AnnaBridge | 172:7d866c31b3c5 | 208 | |
AnnaBridge | 172:7d866c31b3c5 | 209 | pinmap_pinout(tx, PinMap_UART_TX); |
AnnaBridge | 172:7d866c31b3c5 | 210 | pinmap_pinout(rx, PinMap_UART_RX); |
AnnaBridge | 172:7d866c31b3c5 | 211 | } while (0); |
AnnaBridge | 172:7d866c31b3c5 | 212 | |
AnnaBridge | 172:7d866c31b3c5 | 213 | obj->serial.pin_tx = tx; |
AnnaBridge | 172:7d866c31b3c5 | 214 | obj->serial.pin_rx = rx; |
AnnaBridge | 172:7d866c31b3c5 | 215 | } |
AnnaBridge | 172:7d866c31b3c5 | 216 | var->ref_cnt ++; |
AnnaBridge | 172:7d866c31b3c5 | 217 | |
AnnaBridge | 172:7d866c31b3c5 | 218 | // Configure the UART module and set its baudrate |
AnnaBridge | 172:7d866c31b3c5 | 219 | serial_baud(obj, 9600); |
AnnaBridge | 172:7d866c31b3c5 | 220 | // Configure data bits, parity, and stop bits |
AnnaBridge | 172:7d866c31b3c5 | 221 | serial_format(obj, 8, ParityNone, 1); |
AnnaBridge | 172:7d866c31b3c5 | 222 | |
AnnaBridge | 172:7d866c31b3c5 | 223 | obj->serial.vec = var->vec; |
AnnaBridge | 172:7d866c31b3c5 | 224 | obj->serial.irq_en = 0; |
AnnaBridge | 172:7d866c31b3c5 | 225 | |
AnnaBridge | 172:7d866c31b3c5 | 226 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 227 | obj->serial.dma_usage_tx = DMA_USAGE_NEVER; |
AnnaBridge | 172:7d866c31b3c5 | 228 | obj->serial.dma_usage_rx = DMA_USAGE_NEVER; |
AnnaBridge | 172:7d866c31b3c5 | 229 | obj->serial.event = 0; |
AnnaBridge | 172:7d866c31b3c5 | 230 | obj->serial.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS; |
AnnaBridge | 172:7d866c31b3c5 | 231 | obj->serial.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS; |
AnnaBridge | 172:7d866c31b3c5 | 232 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 233 | |
AnnaBridge | 172:7d866c31b3c5 | 234 | // For stdio management |
AnnaBridge | 172:7d866c31b3c5 | 235 | if (obj->serial.uart == STDIO_UART) { |
AnnaBridge | 172:7d866c31b3c5 | 236 | stdio_uart_inited = 1; |
AnnaBridge | 172:7d866c31b3c5 | 237 | memcpy(&stdio_uart, obj, sizeof(serial_t)); |
AnnaBridge | 172:7d866c31b3c5 | 238 | } |
AnnaBridge | 172:7d866c31b3c5 | 239 | |
AnnaBridge | 172:7d866c31b3c5 | 240 | if (var->ref_cnt) { |
AnnaBridge | 172:7d866c31b3c5 | 241 | // Mark this module to be inited. |
AnnaBridge | 172:7d866c31b3c5 | 242 | int i = modinit - uart_modinit_tab; |
AnnaBridge | 172:7d866c31b3c5 | 243 | uart_modinit_mask |= 1 << i; |
AnnaBridge | 172:7d866c31b3c5 | 244 | } |
AnnaBridge | 172:7d866c31b3c5 | 245 | } |
AnnaBridge | 172:7d866c31b3c5 | 246 | |
AnnaBridge | 172:7d866c31b3c5 | 247 | void serial_free(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 248 | { |
AnnaBridge | 172:7d866c31b3c5 | 249 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 250 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 251 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 252 | |
AnnaBridge | 172:7d866c31b3c5 | 253 | struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; |
AnnaBridge | 172:7d866c31b3c5 | 254 | |
AnnaBridge | 172:7d866c31b3c5 | 255 | var->ref_cnt --; |
AnnaBridge | 172:7d866c31b3c5 | 256 | if (! var->ref_cnt) { |
AnnaBridge | 172:7d866c31b3c5 | 257 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 258 | if (obj->serial.dma_chn_id_tx != DMA_ERROR_OUT_OF_CHANNELS) { |
AnnaBridge | 172:7d866c31b3c5 | 259 | dma_channel_free(obj->serial.dma_chn_id_tx); |
AnnaBridge | 172:7d866c31b3c5 | 260 | obj->serial.dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS; |
AnnaBridge | 172:7d866c31b3c5 | 261 | } |
AnnaBridge | 172:7d866c31b3c5 | 262 | if (obj->serial.dma_chn_id_rx != DMA_ERROR_OUT_OF_CHANNELS) { |
AnnaBridge | 172:7d866c31b3c5 | 263 | dma_channel_free(obj->serial.dma_chn_id_rx); |
AnnaBridge | 172:7d866c31b3c5 | 264 | obj->serial.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS; |
AnnaBridge | 172:7d866c31b3c5 | 265 | } |
AnnaBridge | 172:7d866c31b3c5 | 266 | #endif |
AnnaBridge | 172:7d866c31b3c5 | 267 | |
AnnaBridge | 172:7d866c31b3c5 | 268 | do { |
AnnaBridge | 172:7d866c31b3c5 | 269 | UART_Close((UART_T *) NU_MODBASE(obj->serial.uart)); |
AnnaBridge | 172:7d866c31b3c5 | 270 | |
AnnaBridge | 172:7d866c31b3c5 | 271 | UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_THREIEN_Msk | UART_INTEN_RXTOIEN_Msk)); |
AnnaBridge | 172:7d866c31b3c5 | 272 | NVIC_DisableIRQ(modinit->irq_n); |
AnnaBridge | 172:7d866c31b3c5 | 273 | |
AnnaBridge | 172:7d866c31b3c5 | 274 | // Disable IP clock |
AnnaBridge | 172:7d866c31b3c5 | 275 | CLK_DisableModuleClock(modinit->clkidx); |
AnnaBridge | 172:7d866c31b3c5 | 276 | } while (0); |
AnnaBridge | 172:7d866c31b3c5 | 277 | } |
AnnaBridge | 172:7d866c31b3c5 | 278 | |
AnnaBridge | 172:7d866c31b3c5 | 279 | if (var->obj == obj) { |
AnnaBridge | 172:7d866c31b3c5 | 280 | var->obj = NULL; |
AnnaBridge | 172:7d866c31b3c5 | 281 | } |
AnnaBridge | 172:7d866c31b3c5 | 282 | |
AnnaBridge | 172:7d866c31b3c5 | 283 | if (obj->serial.uart == STDIO_UART) { |
AnnaBridge | 172:7d866c31b3c5 | 284 | stdio_uart_inited = 0; |
AnnaBridge | 172:7d866c31b3c5 | 285 | } |
AnnaBridge | 172:7d866c31b3c5 | 286 | |
AnnaBridge | 172:7d866c31b3c5 | 287 | if (! var->ref_cnt) { |
AnnaBridge | 172:7d866c31b3c5 | 288 | // Mark this module to be deinited. |
AnnaBridge | 172:7d866c31b3c5 | 289 | int i = modinit - uart_modinit_tab; |
AnnaBridge | 172:7d866c31b3c5 | 290 | uart_modinit_mask &= ~(1 << i); |
AnnaBridge | 172:7d866c31b3c5 | 291 | } |
AnnaBridge | 172:7d866c31b3c5 | 292 | } |
AnnaBridge | 172:7d866c31b3c5 | 293 | |
AnnaBridge | 172:7d866c31b3c5 | 294 | void serial_baud(serial_t *obj, int baudrate) |
AnnaBridge | 172:7d866c31b3c5 | 295 | { |
AnnaBridge | 172:7d866c31b3c5 | 296 | // Flush Tx FIFO. Otherwise, output data may get lost on this change. |
AnnaBridge | 172:7d866c31b3c5 | 297 | while (! UART_IS_TX_EMPTY((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 298 | |
AnnaBridge | 172:7d866c31b3c5 | 299 | obj->serial.baudrate = baudrate; |
AnnaBridge | 172:7d866c31b3c5 | 300 | UART_Open((UART_T *) NU_MODBASE(obj->serial.uart), baudrate); |
AnnaBridge | 172:7d866c31b3c5 | 301 | } |
AnnaBridge | 172:7d866c31b3c5 | 302 | |
AnnaBridge | 172:7d866c31b3c5 | 303 | void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) |
AnnaBridge | 172:7d866c31b3c5 | 304 | { |
AnnaBridge | 172:7d866c31b3c5 | 305 | // Flush Tx FIFO. Otherwise, output data may get lost on this change. |
AnnaBridge | 172:7d866c31b3c5 | 306 | while (! UART_IS_TX_EMPTY((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 307 | |
AnnaBridge | 172:7d866c31b3c5 | 308 | // Sanity check arguments |
AnnaBridge | 172:7d866c31b3c5 | 309 | MBED_ASSERT((data_bits == 5) || (data_bits == 6) || (data_bits == 7) || (data_bits == 8)); |
AnnaBridge | 172:7d866c31b3c5 | 310 | MBED_ASSERT((parity == ParityNone) || (parity == ParityOdd) || (parity == ParityEven) || (parity == ParityForced1) || (parity == ParityForced0)); |
AnnaBridge | 172:7d866c31b3c5 | 311 | MBED_ASSERT((stop_bits == 1) || (stop_bits == 2)); |
AnnaBridge | 172:7d866c31b3c5 | 312 | |
AnnaBridge | 172:7d866c31b3c5 | 313 | obj->serial.databits = data_bits; |
AnnaBridge | 172:7d866c31b3c5 | 314 | obj->serial.parity = parity; |
AnnaBridge | 172:7d866c31b3c5 | 315 | obj->serial.stopbits = stop_bits; |
AnnaBridge | 172:7d866c31b3c5 | 316 | |
AnnaBridge | 172:7d866c31b3c5 | 317 | uint32_t databits_intern = (data_bits == 5) ? UART_WORD_LEN_5 : |
AnnaBridge | 172:7d866c31b3c5 | 318 | (data_bits == 6) ? UART_WORD_LEN_6 : |
AnnaBridge | 172:7d866c31b3c5 | 319 | (data_bits == 7) ? UART_WORD_LEN_7 : |
AnnaBridge | 172:7d866c31b3c5 | 320 | UART_WORD_LEN_8; |
AnnaBridge | 172:7d866c31b3c5 | 321 | uint32_t parity_intern = (parity == ParityOdd || parity == ParityForced1) ? UART_PARITY_ODD : |
AnnaBridge | 172:7d866c31b3c5 | 322 | (parity == ParityEven || parity == ParityForced0) ? UART_PARITY_EVEN : |
AnnaBridge | 172:7d866c31b3c5 | 323 | UART_PARITY_NONE; |
AnnaBridge | 172:7d866c31b3c5 | 324 | uint32_t stopbits_intern = (stop_bits == 2) ? UART_STOP_BIT_2 : UART_STOP_BIT_1; |
AnnaBridge | 172:7d866c31b3c5 | 325 | UART_SetLine_Config((UART_T *) NU_MODBASE(obj->serial.uart), |
AnnaBridge | 172:7d866c31b3c5 | 326 | 0, // Don't change baudrate |
AnnaBridge | 172:7d866c31b3c5 | 327 | databits_intern, |
AnnaBridge | 172:7d866c31b3c5 | 328 | parity_intern, |
AnnaBridge | 172:7d866c31b3c5 | 329 | stopbits_intern); |
AnnaBridge | 172:7d866c31b3c5 | 330 | } |
AnnaBridge | 172:7d866c31b3c5 | 331 | |
AnnaBridge | 172:7d866c31b3c5 | 332 | #if DEVICE_SERIAL_FC |
AnnaBridge | 172:7d866c31b3c5 | 333 | |
AnnaBridge | 172:7d866c31b3c5 | 334 | void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) |
AnnaBridge | 172:7d866c31b3c5 | 335 | { |
AnnaBridge | 172:7d866c31b3c5 | 336 | UART_T *uart_base = (UART_T *) NU_MODBASE(obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 337 | |
AnnaBridge | 172:7d866c31b3c5 | 338 | // First, disable flow control completely. |
AnnaBridge | 172:7d866c31b3c5 | 339 | uart_base->INTEN &= ~(UART_INTEN_ATORTSEN_Msk | UART_INTEN_ATOCTSEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 340 | |
AnnaBridge | 172:7d866c31b3c5 | 341 | if ((type == FlowControlRTS || type == FlowControlRTSCTS) && rxflow != NC) { |
AnnaBridge | 172:7d866c31b3c5 | 342 | // Check if RTS pin matches. |
AnnaBridge | 172:7d866c31b3c5 | 343 | uint32_t uart_rts = pinmap_peripheral(rxflow, PinMap_UART_RTS); |
AnnaBridge | 172:7d866c31b3c5 | 344 | MBED_ASSERT(uart_rts == obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 345 | // Enable the pin for RTS function |
AnnaBridge | 172:7d866c31b3c5 | 346 | pinmap_pinout(rxflow, PinMap_UART_RTS); |
AnnaBridge | 172:7d866c31b3c5 | 347 | |
AnnaBridge | 172:7d866c31b3c5 | 348 | // NOTE: Added in M480. Before configuring RTSACTLV, disable TX/RX. |
AnnaBridge | 172:7d866c31b3c5 | 349 | uart_base->FUNCSEL |= UART_FUNCSEL_TXRXDIS_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 350 | while (uart_base->FIFOSTS & UART_FIFOSTS_TXRXACT_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 351 | // nRTS pin output is low level active |
AnnaBridge | 172:7d866c31b3c5 | 352 | uart_base->MODEM |= UART_MODEM_RTSACTLV_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 353 | // NOTE: Added in M480. After configuring RTSACTLV, re-enable TX/RX. |
AnnaBridge | 172:7d866c31b3c5 | 354 | uart_base->FUNCSEL &= ~UART_FUNCSEL_TXRXDIS_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 355 | |
AnnaBridge | 172:7d866c31b3c5 | 356 | uart_base->FIFO = (uart_base->FIFO & ~UART_FIFO_RTSTRGLV_Msk) | UART_FIFO_RTSTRGLV_8BYTES; |
AnnaBridge | 172:7d866c31b3c5 | 357 | |
AnnaBridge | 172:7d866c31b3c5 | 358 | // Enable RTS |
AnnaBridge | 172:7d866c31b3c5 | 359 | uart_base->INTEN |= UART_INTEN_ATORTSEN_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 360 | } |
AnnaBridge | 172:7d866c31b3c5 | 361 | |
AnnaBridge | 172:7d866c31b3c5 | 362 | if ((type == FlowControlCTS || type == FlowControlRTSCTS) && txflow != NC) { |
AnnaBridge | 172:7d866c31b3c5 | 363 | // Check if CTS pin matches. |
AnnaBridge | 172:7d866c31b3c5 | 364 | uint32_t uart_cts = pinmap_peripheral(txflow, PinMap_UART_CTS); |
AnnaBridge | 172:7d866c31b3c5 | 365 | MBED_ASSERT(uart_cts == obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 366 | // Enable the pin for CTS function |
AnnaBridge | 172:7d866c31b3c5 | 367 | pinmap_pinout(txflow, PinMap_UART_CTS); |
AnnaBridge | 172:7d866c31b3c5 | 368 | |
AnnaBridge | 172:7d866c31b3c5 | 369 | // NOTE: Added in M480. Before configuring CTSACTLV, disable TX/RX. |
AnnaBridge | 172:7d866c31b3c5 | 370 | uart_base->FUNCSEL |= UART_FUNCSEL_TXRXDIS_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 371 | while (uart_base->FIFOSTS & UART_FIFOSTS_TXRXACT_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 372 | // nCTS pin input is low level active |
AnnaBridge | 172:7d866c31b3c5 | 373 | uart_base->MODEMSTS |= UART_MODEMSTS_CTSACTLV_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 374 | // NOTE: Added in M480. After configuring CTSACTLV, re-enable TX/RX. |
AnnaBridge | 172:7d866c31b3c5 | 375 | uart_base->FUNCSEL &= ~UART_FUNCSEL_TXRXDIS_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 376 | |
AnnaBridge | 172:7d866c31b3c5 | 377 | // Enable CTS |
AnnaBridge | 172:7d866c31b3c5 | 378 | uart_base->INTEN |= UART_INTEN_ATOCTSEN_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 379 | } |
AnnaBridge | 172:7d866c31b3c5 | 380 | } |
AnnaBridge | 172:7d866c31b3c5 | 381 | |
AnnaBridge | 172:7d866c31b3c5 | 382 | #endif //DEVICE_SERIAL_FC |
AnnaBridge | 172:7d866c31b3c5 | 383 | |
AnnaBridge | 172:7d866c31b3c5 | 384 | void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) |
AnnaBridge | 172:7d866c31b3c5 | 385 | { |
AnnaBridge | 172:7d866c31b3c5 | 386 | // Flush Tx FIFO. Otherwise, output data may get lost on this change. |
AnnaBridge | 172:7d866c31b3c5 | 387 | while (! UART_IS_TX_EMPTY((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 388 | |
AnnaBridge | 172:7d866c31b3c5 | 389 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 390 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 391 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 392 | |
AnnaBridge | 172:7d866c31b3c5 | 393 | obj->serial.irq_handler = (uint32_t) handler; |
AnnaBridge | 172:7d866c31b3c5 | 394 | obj->serial.irq_id = id; |
AnnaBridge | 172:7d866c31b3c5 | 395 | |
AnnaBridge | 172:7d866c31b3c5 | 396 | // Restore sync-mode vector |
AnnaBridge | 172:7d866c31b3c5 | 397 | obj->serial.vec = ((struct nu_uart_var *) modinit->var)->vec; |
AnnaBridge | 172:7d866c31b3c5 | 398 | } |
AnnaBridge | 172:7d866c31b3c5 | 399 | |
AnnaBridge | 172:7d866c31b3c5 | 400 | void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) |
AnnaBridge | 172:7d866c31b3c5 | 401 | { |
AnnaBridge | 172:7d866c31b3c5 | 402 | obj->serial.irq_en = enable; |
AnnaBridge | 172:7d866c31b3c5 | 403 | serial_enable_interrupt(obj, irq, enable); |
AnnaBridge | 172:7d866c31b3c5 | 404 | } |
AnnaBridge | 172:7d866c31b3c5 | 405 | |
AnnaBridge | 172:7d866c31b3c5 | 406 | int serial_getc(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 407 | { |
AnnaBridge | 172:7d866c31b3c5 | 408 | // NOTE: Every byte access requires accompaniment of one interrupt. This has side effect of performance degradation. |
AnnaBridge | 172:7d866c31b3c5 | 409 | while (! serial_readable(obj)); |
AnnaBridge | 172:7d866c31b3c5 | 410 | int c = UART_READ(((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 411 | |
AnnaBridge | 172:7d866c31b3c5 | 412 | // NOTE: On Nuvoton targets, no H/W IRQ to match TxIrq/RxIrq. |
AnnaBridge | 172:7d866c31b3c5 | 413 | // Simulation of TxIrq/RxIrq requires the call to Serial::putc()/Serial::getc() respectively. |
AnnaBridge | 172:7d866c31b3c5 | 414 | if (obj->serial.inten_msk & (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)) { |
AnnaBridge | 172:7d866c31b3c5 | 415 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); |
AnnaBridge | 172:7d866c31b3c5 | 416 | } |
AnnaBridge | 172:7d866c31b3c5 | 417 | |
AnnaBridge | 172:7d866c31b3c5 | 418 | return c; |
AnnaBridge | 172:7d866c31b3c5 | 419 | } |
AnnaBridge | 172:7d866c31b3c5 | 420 | |
AnnaBridge | 172:7d866c31b3c5 | 421 | void serial_putc(serial_t *obj, int c) |
AnnaBridge | 172:7d866c31b3c5 | 422 | { |
AnnaBridge | 172:7d866c31b3c5 | 423 | // NOTE: Every byte access requires accompaniment of one interrupt. This has side effect of performance degradation. |
AnnaBridge | 172:7d866c31b3c5 | 424 | while (! serial_writable(obj)); |
AnnaBridge | 172:7d866c31b3c5 | 425 | UART_WRITE(((UART_T *) NU_MODBASE(obj->serial.uart)), c); |
AnnaBridge | 172:7d866c31b3c5 | 426 | |
AnnaBridge | 172:7d866c31b3c5 | 427 | // NOTE: On Nuvoton targets, no H/W IRQ to match TxIrq/RxIrq. |
AnnaBridge | 172:7d866c31b3c5 | 428 | // Simulation of TxIrq/RxIrq requires the call to Serial::putc()/Serial::getc() respectively. |
AnnaBridge | 172:7d866c31b3c5 | 429 | if (obj->serial.inten_msk & UART_INTEN_THREIEN_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 430 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 431 | } |
AnnaBridge | 172:7d866c31b3c5 | 432 | } |
AnnaBridge | 172:7d866c31b3c5 | 433 | |
AnnaBridge | 172:7d866c31b3c5 | 434 | int serial_readable(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 435 | { |
AnnaBridge | 172:7d866c31b3c5 | 436 | return ! UART_GET_RX_EMPTY(((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 437 | } |
AnnaBridge | 172:7d866c31b3c5 | 438 | |
AnnaBridge | 172:7d866c31b3c5 | 439 | int serial_writable(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 440 | { |
AnnaBridge | 172:7d866c31b3c5 | 441 | return ! UART_IS_TX_FULL(((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 442 | } |
AnnaBridge | 172:7d866c31b3c5 | 443 | |
AnnaBridge | 172:7d866c31b3c5 | 444 | void serial_pinout_tx(PinName tx) |
AnnaBridge | 172:7d866c31b3c5 | 445 | { |
AnnaBridge | 172:7d866c31b3c5 | 446 | pinmap_pinout(tx, PinMap_UART_TX); |
AnnaBridge | 172:7d866c31b3c5 | 447 | } |
AnnaBridge | 172:7d866c31b3c5 | 448 | |
AnnaBridge | 172:7d866c31b3c5 | 449 | void serial_break_set(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 450 | { |
AnnaBridge | 172:7d866c31b3c5 | 451 | ((UART_T *) NU_MODBASE(obj->serial.uart))->LINE |= UART_LINE_BCB_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 452 | } |
AnnaBridge | 172:7d866c31b3c5 | 453 | |
AnnaBridge | 172:7d866c31b3c5 | 454 | void serial_break_clear(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 455 | { |
AnnaBridge | 172:7d866c31b3c5 | 456 | ((UART_T *) NU_MODBASE(obj->serial.uart))->LINE &= ~UART_LINE_BCB_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 457 | } |
AnnaBridge | 172:7d866c31b3c5 | 458 | |
AnnaBridge | 172:7d866c31b3c5 | 459 | static void uart0_vec(void) |
AnnaBridge | 172:7d866c31b3c5 | 460 | { |
AnnaBridge | 172:7d866c31b3c5 | 461 | uart_irq(uart0_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 462 | } |
AnnaBridge | 172:7d866c31b3c5 | 463 | |
AnnaBridge | 172:7d866c31b3c5 | 464 | static void uart1_vec(void) |
AnnaBridge | 172:7d866c31b3c5 | 465 | { |
AnnaBridge | 172:7d866c31b3c5 | 466 | uart_irq(uart1_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 467 | } |
AnnaBridge | 172:7d866c31b3c5 | 468 | |
AnnaBridge | 172:7d866c31b3c5 | 469 | static void uart2_vec(void) |
AnnaBridge | 172:7d866c31b3c5 | 470 | { |
AnnaBridge | 172:7d866c31b3c5 | 471 | uart_irq(uart2_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 472 | } |
AnnaBridge | 172:7d866c31b3c5 | 473 | |
AnnaBridge | 172:7d866c31b3c5 | 474 | static void uart3_vec(void) |
AnnaBridge | 172:7d866c31b3c5 | 475 | { |
AnnaBridge | 172:7d866c31b3c5 | 476 | uart_irq(uart3_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 477 | } |
AnnaBridge | 172:7d866c31b3c5 | 478 | |
AnnaBridge | 172:7d866c31b3c5 | 479 | static void uart4_vec(void) |
AnnaBridge | 172:7d866c31b3c5 | 480 | { |
AnnaBridge | 172:7d866c31b3c5 | 481 | uart_irq(uart4_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 482 | } |
AnnaBridge | 172:7d866c31b3c5 | 483 | |
AnnaBridge | 172:7d866c31b3c5 | 484 | static void uart5_vec(void) |
AnnaBridge | 172:7d866c31b3c5 | 485 | { |
AnnaBridge | 172:7d866c31b3c5 | 486 | uart_irq(uart5_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 487 | } |
AnnaBridge | 172:7d866c31b3c5 | 488 | |
AnnaBridge | 172:7d866c31b3c5 | 489 | static void uart_irq(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 490 | { |
AnnaBridge | 172:7d866c31b3c5 | 491 | UART_T *uart_base = (UART_T *) NU_MODBASE(obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 492 | |
AnnaBridge | 172:7d866c31b3c5 | 493 | if (uart_base->INTSTS & (UART_INTSTS_RDAINT_Msk | UART_INTSTS_RXTOINT_Msk)) { |
AnnaBridge | 172:7d866c31b3c5 | 494 | // Simulate clear of the interrupt flag. Temporarily disable the interrupt here and to be recovered on next read. |
AnnaBridge | 172:7d866c31b3c5 | 495 | UART_DISABLE_INT(uart_base, (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); |
AnnaBridge | 172:7d866c31b3c5 | 496 | if (obj->serial.irq_handler) { |
AnnaBridge | 172:7d866c31b3c5 | 497 | ((uart_irq_handler) obj->serial.irq_handler)(obj->serial.irq_id, RxIrq); |
AnnaBridge | 172:7d866c31b3c5 | 498 | } |
AnnaBridge | 172:7d866c31b3c5 | 499 | } |
AnnaBridge | 172:7d866c31b3c5 | 500 | |
AnnaBridge | 172:7d866c31b3c5 | 501 | if (uart_base->INTSTS & UART_INTSTS_THREINT_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 502 | // Simulate clear of the interrupt flag. Temporarily disable the interrupt here and to be recovered on next write. |
AnnaBridge | 172:7d866c31b3c5 | 503 | UART_DISABLE_INT(uart_base, UART_INTEN_THREIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 504 | if (obj->serial.irq_handler) { |
AnnaBridge | 172:7d866c31b3c5 | 505 | ((uart_irq_handler) obj->serial.irq_handler)(obj->serial.irq_id, TxIrq); |
AnnaBridge | 172:7d866c31b3c5 | 506 | } |
AnnaBridge | 172:7d866c31b3c5 | 507 | } |
AnnaBridge | 172:7d866c31b3c5 | 508 | |
AnnaBridge | 172:7d866c31b3c5 | 509 | // FIXME: Ignore all other interrupt flags. Clear them. Otherwise, program will get stuck in interrupt. |
AnnaBridge | 172:7d866c31b3c5 | 510 | uart_base->INTSTS = uart_base->INTSTS; |
AnnaBridge | 172:7d866c31b3c5 | 511 | uart_base->FIFOSTS = uart_base->FIFOSTS; |
AnnaBridge | 172:7d866c31b3c5 | 512 | } |
AnnaBridge | 172:7d866c31b3c5 | 513 | |
AnnaBridge | 172:7d866c31b3c5 | 514 | |
AnnaBridge | 172:7d866c31b3c5 | 515 | #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 516 | int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint) |
AnnaBridge | 172:7d866c31b3c5 | 517 | { |
AnnaBridge | 172:7d866c31b3c5 | 518 | MBED_ASSERT(tx_width == 8 || tx_width == 16 || tx_width == 32); |
AnnaBridge | 172:7d866c31b3c5 | 519 | |
AnnaBridge | 172:7d866c31b3c5 | 520 | obj->serial.dma_usage_tx = hint; |
AnnaBridge | 172:7d866c31b3c5 | 521 | serial_check_dma_usage(&obj->serial.dma_usage_tx, &obj->serial.dma_chn_id_tx); |
AnnaBridge | 172:7d866c31b3c5 | 522 | |
AnnaBridge | 172:7d866c31b3c5 | 523 | // UART IRQ is necessary for both interrupt way and DMA way |
AnnaBridge | 172:7d866c31b3c5 | 524 | serial_tx_enable_event(obj, event, 1); |
AnnaBridge | 172:7d866c31b3c5 | 525 | serial_tx_buffer_set(obj, tx, tx_length, tx_width); |
AnnaBridge | 172:7d866c31b3c5 | 526 | |
AnnaBridge | 172:7d866c31b3c5 | 527 | int n_word = 0; |
AnnaBridge | 172:7d866c31b3c5 | 528 | if (obj->serial.dma_usage_tx == DMA_USAGE_NEVER) { |
AnnaBridge | 172:7d866c31b3c5 | 529 | // Interrupt way |
AnnaBridge | 172:7d866c31b3c5 | 530 | n_word = serial_write_async(obj); |
AnnaBridge | 172:7d866c31b3c5 | 531 | serial_tx_enable_interrupt(obj, handler, 1); |
AnnaBridge | 172:7d866c31b3c5 | 532 | } else { |
AnnaBridge | 172:7d866c31b3c5 | 533 | // DMA way |
AnnaBridge | 172:7d866c31b3c5 | 534 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 535 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 536 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 537 | |
AnnaBridge | 172:7d866c31b3c5 | 538 | PDMA_T *pdma_base = dma_modbase(); |
AnnaBridge | 172:7d866c31b3c5 | 539 | |
AnnaBridge | 172:7d866c31b3c5 | 540 | pdma_base->CHCTL |= 1 << obj->serial.dma_chn_id_tx; // Enable this DMA channel |
AnnaBridge | 172:7d866c31b3c5 | 541 | PDMA_SetTransferMode(obj->serial.dma_chn_id_tx, |
AnnaBridge | 172:7d866c31b3c5 | 542 | ((struct nu_uart_var *) modinit->var)->pdma_perp_tx, // Peripheral connected to this PDMA |
AnnaBridge | 172:7d866c31b3c5 | 543 | 0, // Scatter-gather disabled |
AnnaBridge | 172:7d866c31b3c5 | 544 | 0); // Scatter-gather descriptor address |
AnnaBridge | 172:7d866c31b3c5 | 545 | PDMA_SetTransferCnt(obj->serial.dma_chn_id_tx, |
AnnaBridge | 172:7d866c31b3c5 | 546 | (tx_width == 8) ? PDMA_WIDTH_8 : (tx_width == 16) ? PDMA_WIDTH_16 : PDMA_WIDTH_32, |
AnnaBridge | 172:7d866c31b3c5 | 547 | tx_length); |
AnnaBridge | 172:7d866c31b3c5 | 548 | PDMA_SetTransferAddr(obj->serial.dma_chn_id_tx, |
AnnaBridge | 172:7d866c31b3c5 | 549 | (uint32_t) tx, // NOTE: |
AnnaBridge | 172:7d866c31b3c5 | 550 | // NUC472: End of source address |
AnnaBridge | 172:7d866c31b3c5 | 551 | // M451: Start of source address |
AnnaBridge | 172:7d866c31b3c5 | 552 | // M480: Start of source address |
AnnaBridge | 172:7d866c31b3c5 | 553 | PDMA_SAR_INC, // Source address incremental |
AnnaBridge | 172:7d866c31b3c5 | 554 | (uint32_t) NU_MODBASE(obj->serial.uart), // Destination address |
AnnaBridge | 172:7d866c31b3c5 | 555 | PDMA_DAR_FIX); // Destination address fixed |
AnnaBridge | 172:7d866c31b3c5 | 556 | PDMA_SetBurstType(obj->serial.dma_chn_id_tx, |
AnnaBridge | 172:7d866c31b3c5 | 557 | PDMA_REQ_SINGLE, // Single mode |
AnnaBridge | 172:7d866c31b3c5 | 558 | 0); // Burst size |
AnnaBridge | 172:7d866c31b3c5 | 559 | PDMA_EnableInt(obj->serial.dma_chn_id_tx, |
AnnaBridge | 172:7d866c31b3c5 | 560 | PDMA_INT_TRANS_DONE); // Interrupt type |
AnnaBridge | 172:7d866c31b3c5 | 561 | // Register DMA event handler |
AnnaBridge | 172:7d866c31b3c5 | 562 | dma_set_handler(obj->serial.dma_chn_id_tx, (uint32_t) uart_dma_handler_tx, (uint32_t) obj, DMA_EVENT_ALL); |
AnnaBridge | 172:7d866c31b3c5 | 563 | serial_tx_enable_interrupt(obj, handler, 1); |
AnnaBridge | 172:7d866c31b3c5 | 564 | ((UART_T *) NU_MODBASE(obj->serial.uart))->INTEN |= UART_INTEN_TXPDMAEN_Msk; // Start DMA transfer |
AnnaBridge | 172:7d866c31b3c5 | 565 | } |
AnnaBridge | 172:7d866c31b3c5 | 566 | |
AnnaBridge | 172:7d866c31b3c5 | 567 | return n_word; |
AnnaBridge | 172:7d866c31b3c5 | 568 | } |
AnnaBridge | 172:7d866c31b3c5 | 569 | |
AnnaBridge | 172:7d866c31b3c5 | 570 | void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint) |
AnnaBridge | 172:7d866c31b3c5 | 571 | { |
AnnaBridge | 172:7d866c31b3c5 | 572 | MBED_ASSERT(rx_width == 8 || rx_width == 16 || rx_width == 32); |
AnnaBridge | 172:7d866c31b3c5 | 573 | |
AnnaBridge | 172:7d866c31b3c5 | 574 | obj->serial.dma_usage_rx = hint; |
AnnaBridge | 172:7d866c31b3c5 | 575 | serial_check_dma_usage(&obj->serial.dma_usage_rx, &obj->serial.dma_chn_id_rx); |
AnnaBridge | 172:7d866c31b3c5 | 576 | // DMA doesn't support char match, so fall back to IRQ if it is requested. |
AnnaBridge | 172:7d866c31b3c5 | 577 | if (obj->serial.dma_usage_rx != DMA_USAGE_NEVER && |
AnnaBridge | 172:7d866c31b3c5 | 578 | (event & SERIAL_EVENT_RX_CHARACTER_MATCH) && |
AnnaBridge | 172:7d866c31b3c5 | 579 | char_match != SERIAL_RESERVED_CHAR_MATCH) { |
AnnaBridge | 172:7d866c31b3c5 | 580 | obj->serial.dma_usage_rx = DMA_USAGE_NEVER; |
AnnaBridge | 172:7d866c31b3c5 | 581 | dma_channel_free(obj->serial.dma_chn_id_rx); |
AnnaBridge | 172:7d866c31b3c5 | 582 | obj->serial.dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS; |
AnnaBridge | 172:7d866c31b3c5 | 583 | } |
AnnaBridge | 172:7d866c31b3c5 | 584 | |
AnnaBridge | 172:7d866c31b3c5 | 585 | // UART IRQ is necessary for both interrupt way and DMA way |
AnnaBridge | 172:7d866c31b3c5 | 586 | serial_rx_enable_event(obj, event, 1); |
AnnaBridge | 172:7d866c31b3c5 | 587 | serial_rx_buffer_set(obj, rx, rx_length, rx_width); |
AnnaBridge | 172:7d866c31b3c5 | 588 | serial_rx_set_char_match(obj, char_match); |
AnnaBridge | 172:7d866c31b3c5 | 589 | |
AnnaBridge | 172:7d866c31b3c5 | 590 | if (obj->serial.dma_usage_rx == DMA_USAGE_NEVER) { |
AnnaBridge | 172:7d866c31b3c5 | 591 | // Interrupt way |
AnnaBridge | 172:7d866c31b3c5 | 592 | serial_rx_enable_interrupt(obj, handler, 1); |
AnnaBridge | 172:7d866c31b3c5 | 593 | } else { |
AnnaBridge | 172:7d866c31b3c5 | 594 | // DMA way |
AnnaBridge | 172:7d866c31b3c5 | 595 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 596 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 597 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 598 | |
AnnaBridge | 172:7d866c31b3c5 | 599 | PDMA_T *pdma_base = dma_modbase(); |
AnnaBridge | 172:7d866c31b3c5 | 600 | |
AnnaBridge | 172:7d866c31b3c5 | 601 | pdma_base->CHCTL |= 1 << obj->serial.dma_chn_id_rx; // Enable this DMA channel |
AnnaBridge | 172:7d866c31b3c5 | 602 | PDMA_SetTransferMode(obj->serial.dma_chn_id_rx, |
AnnaBridge | 172:7d866c31b3c5 | 603 | ((struct nu_uart_var *) modinit->var)->pdma_perp_rx, // Peripheral connected to this PDMA |
AnnaBridge | 172:7d866c31b3c5 | 604 | 0, // Scatter-gather disabled |
AnnaBridge | 172:7d866c31b3c5 | 605 | 0); // Scatter-gather descriptor address |
AnnaBridge | 172:7d866c31b3c5 | 606 | PDMA_SetTransferCnt(obj->serial.dma_chn_id_rx, |
AnnaBridge | 172:7d866c31b3c5 | 607 | (rx_width == 8) ? PDMA_WIDTH_8 : (rx_width == 16) ? PDMA_WIDTH_16 : PDMA_WIDTH_32, |
AnnaBridge | 172:7d866c31b3c5 | 608 | rx_length); |
AnnaBridge | 172:7d866c31b3c5 | 609 | PDMA_SetTransferAddr(obj->serial.dma_chn_id_rx, |
AnnaBridge | 172:7d866c31b3c5 | 610 | (uint32_t) NU_MODBASE(obj->serial.uart), // Source address |
AnnaBridge | 172:7d866c31b3c5 | 611 | PDMA_SAR_FIX, // Source address fixed |
AnnaBridge | 172:7d866c31b3c5 | 612 | (uint32_t) rx, // NOTE: |
AnnaBridge | 172:7d866c31b3c5 | 613 | // NUC472: End of destination address |
AnnaBridge | 172:7d866c31b3c5 | 614 | // M451: Start of destination address |
AnnaBridge | 172:7d866c31b3c5 | 615 | // M480: Start of destination address |
AnnaBridge | 172:7d866c31b3c5 | 616 | PDMA_DAR_INC); // Destination address incremental |
AnnaBridge | 172:7d866c31b3c5 | 617 | PDMA_SetBurstType(obj->serial.dma_chn_id_rx, |
AnnaBridge | 172:7d866c31b3c5 | 618 | PDMA_REQ_SINGLE, // Single mode |
AnnaBridge | 172:7d866c31b3c5 | 619 | 0); // Burst size |
AnnaBridge | 172:7d866c31b3c5 | 620 | PDMA_EnableInt(obj->serial.dma_chn_id_rx, |
AnnaBridge | 172:7d866c31b3c5 | 621 | PDMA_INT_TRANS_DONE); // Interrupt type |
AnnaBridge | 172:7d866c31b3c5 | 622 | // Register DMA event handler |
AnnaBridge | 172:7d866c31b3c5 | 623 | dma_set_handler(obj->serial.dma_chn_id_rx, (uint32_t) uart_dma_handler_rx, (uint32_t) obj, DMA_EVENT_ALL); |
AnnaBridge | 172:7d866c31b3c5 | 624 | serial_rx_enable_interrupt(obj, handler, 1); |
AnnaBridge | 172:7d866c31b3c5 | 625 | ((UART_T *) NU_MODBASE(obj->serial.uart))->INTEN |= UART_INTEN_RXPDMAEN_Msk; // Start DMA transfer |
AnnaBridge | 172:7d866c31b3c5 | 626 | } |
AnnaBridge | 172:7d866c31b3c5 | 627 | } |
AnnaBridge | 172:7d866c31b3c5 | 628 | |
AnnaBridge | 172:7d866c31b3c5 | 629 | void serial_tx_abort_asynch(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 630 | { |
AnnaBridge | 172:7d866c31b3c5 | 631 | // Flush Tx FIFO. Otherwise, output data may get lost on this change. |
AnnaBridge | 172:7d866c31b3c5 | 632 | while (! UART_IS_TX_EMPTY((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 633 | |
AnnaBridge | 172:7d866c31b3c5 | 634 | if (obj->serial.dma_usage_tx != DMA_USAGE_NEVER) { |
AnnaBridge | 172:7d866c31b3c5 | 635 | PDMA_T *pdma_base = dma_modbase(); |
AnnaBridge | 172:7d866c31b3c5 | 636 | |
AnnaBridge | 172:7d866c31b3c5 | 637 | if (obj->serial.dma_chn_id_tx != DMA_ERROR_OUT_OF_CHANNELS) { |
AnnaBridge | 172:7d866c31b3c5 | 638 | PDMA_DisableInt(obj->serial.dma_chn_id_tx, PDMA_INT_TRANS_DONE); |
AnnaBridge | 172:7d866c31b3c5 | 639 | // NOTE: On NUC472, next PDMA transfer will fail with PDMA_STOP() called. Cause is unknown. |
AnnaBridge | 172:7d866c31b3c5 | 640 | pdma_base->CHCTL &= ~(1 << obj->serial.dma_chn_id_tx); |
AnnaBridge | 172:7d866c31b3c5 | 641 | } |
AnnaBridge | 172:7d866c31b3c5 | 642 | UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_TXPDMAEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 643 | } |
AnnaBridge | 172:7d866c31b3c5 | 644 | |
AnnaBridge | 172:7d866c31b3c5 | 645 | // Necessary for both interrupt way and DMA way |
AnnaBridge | 172:7d866c31b3c5 | 646 | serial_enable_interrupt(obj, TxIrq, 0); |
AnnaBridge | 172:7d866c31b3c5 | 647 | serial_rollback_interrupt(obj, TxIrq); |
AnnaBridge | 172:7d866c31b3c5 | 648 | } |
AnnaBridge | 172:7d866c31b3c5 | 649 | |
AnnaBridge | 172:7d866c31b3c5 | 650 | void serial_rx_abort_asynch(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 651 | { |
AnnaBridge | 172:7d866c31b3c5 | 652 | if (obj->serial.dma_usage_rx != DMA_USAGE_NEVER) { |
AnnaBridge | 172:7d866c31b3c5 | 653 | PDMA_T *pdma_base = dma_modbase(); |
AnnaBridge | 172:7d866c31b3c5 | 654 | |
AnnaBridge | 172:7d866c31b3c5 | 655 | if (obj->serial.dma_chn_id_rx != DMA_ERROR_OUT_OF_CHANNELS) { |
AnnaBridge | 172:7d866c31b3c5 | 656 | PDMA_DisableInt(obj->serial.dma_chn_id_rx, PDMA_INT_TRANS_DONE); |
AnnaBridge | 172:7d866c31b3c5 | 657 | // NOTE: On NUC472, next PDMA transfer will fail with PDMA_STOP() called. Cause is unknown. |
AnnaBridge | 172:7d866c31b3c5 | 658 | pdma_base->CHCTL &= ~(1 << obj->serial.dma_chn_id_rx); |
AnnaBridge | 172:7d866c31b3c5 | 659 | } |
AnnaBridge | 172:7d866c31b3c5 | 660 | UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_RXPDMAEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 661 | } |
AnnaBridge | 172:7d866c31b3c5 | 662 | |
AnnaBridge | 172:7d866c31b3c5 | 663 | // Necessary for both interrupt way and DMA way |
AnnaBridge | 172:7d866c31b3c5 | 664 | serial_enable_interrupt(obj, RxIrq, 0); |
AnnaBridge | 172:7d866c31b3c5 | 665 | serial_rollback_interrupt(obj, RxIrq); |
AnnaBridge | 172:7d866c31b3c5 | 666 | } |
AnnaBridge | 172:7d866c31b3c5 | 667 | |
AnnaBridge | 172:7d866c31b3c5 | 668 | uint8_t serial_tx_active(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 669 | { |
AnnaBridge | 172:7d866c31b3c5 | 670 | // NOTE: Judge by serial_is_irq_en(obj, TxIrq) doesn't work with sync/async modes interleaved. Change with TX FIFO empty flag. |
AnnaBridge | 172:7d866c31b3c5 | 671 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 672 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 673 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 674 | |
AnnaBridge | 172:7d866c31b3c5 | 675 | struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; |
AnnaBridge | 172:7d866c31b3c5 | 676 | return (obj->serial.vec == var->vec_async); |
AnnaBridge | 172:7d866c31b3c5 | 677 | } |
AnnaBridge | 172:7d866c31b3c5 | 678 | |
AnnaBridge | 172:7d866c31b3c5 | 679 | uint8_t serial_rx_active(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 680 | { |
AnnaBridge | 172:7d866c31b3c5 | 681 | // NOTE: Judge by serial_is_irq_en(obj, RxIrq) doesn't work with sync/async modes interleaved. Change with RX FIFO empty flag. |
AnnaBridge | 172:7d866c31b3c5 | 682 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 683 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 684 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 685 | |
AnnaBridge | 172:7d866c31b3c5 | 686 | struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; |
AnnaBridge | 172:7d866c31b3c5 | 687 | return (obj->serial.vec == var->vec_async); |
AnnaBridge | 172:7d866c31b3c5 | 688 | } |
AnnaBridge | 172:7d866c31b3c5 | 689 | |
AnnaBridge | 172:7d866c31b3c5 | 690 | int serial_irq_handler_asynch(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 691 | { |
AnnaBridge | 172:7d866c31b3c5 | 692 | int event_rx = 0; |
AnnaBridge | 172:7d866c31b3c5 | 693 | int event_tx = 0; |
AnnaBridge | 172:7d866c31b3c5 | 694 | |
AnnaBridge | 172:7d866c31b3c5 | 695 | // Necessary for both interrupt way and DMA way |
AnnaBridge | 172:7d866c31b3c5 | 696 | if (serial_is_irq_en(obj, RxIrq)) { |
AnnaBridge | 172:7d866c31b3c5 | 697 | event_rx = serial_rx_event_check(obj); |
AnnaBridge | 172:7d866c31b3c5 | 698 | if (event_rx) { |
AnnaBridge | 172:7d866c31b3c5 | 699 | serial_rx_abort_asynch(obj); |
AnnaBridge | 172:7d866c31b3c5 | 700 | } |
AnnaBridge | 172:7d866c31b3c5 | 701 | } |
AnnaBridge | 172:7d866c31b3c5 | 702 | |
AnnaBridge | 172:7d866c31b3c5 | 703 | if (serial_is_irq_en(obj, TxIrq)) { |
AnnaBridge | 172:7d866c31b3c5 | 704 | event_tx = serial_tx_event_check(obj); |
AnnaBridge | 172:7d866c31b3c5 | 705 | if (event_tx) { |
AnnaBridge | 172:7d866c31b3c5 | 706 | serial_tx_abort_asynch(obj); |
AnnaBridge | 172:7d866c31b3c5 | 707 | } |
AnnaBridge | 172:7d866c31b3c5 | 708 | } |
AnnaBridge | 172:7d866c31b3c5 | 709 | |
AnnaBridge | 172:7d866c31b3c5 | 710 | return (obj->serial.event & (event_rx | event_tx)); |
AnnaBridge | 172:7d866c31b3c5 | 711 | } |
AnnaBridge | 172:7d866c31b3c5 | 712 | |
AnnaBridge | 172:7d866c31b3c5 | 713 | static void uart0_vec_async(void) |
AnnaBridge | 172:7d866c31b3c5 | 714 | { |
AnnaBridge | 172:7d866c31b3c5 | 715 | uart_irq_async(uart0_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 716 | } |
AnnaBridge | 172:7d866c31b3c5 | 717 | |
AnnaBridge | 172:7d866c31b3c5 | 718 | static void uart1_vec_async(void) |
AnnaBridge | 172:7d866c31b3c5 | 719 | { |
AnnaBridge | 172:7d866c31b3c5 | 720 | uart_irq_async(uart1_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 721 | } |
AnnaBridge | 172:7d866c31b3c5 | 722 | |
AnnaBridge | 172:7d866c31b3c5 | 723 | static void uart2_vec_async(void) |
AnnaBridge | 172:7d866c31b3c5 | 724 | { |
AnnaBridge | 172:7d866c31b3c5 | 725 | uart_irq_async(uart2_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 726 | } |
AnnaBridge | 172:7d866c31b3c5 | 727 | |
AnnaBridge | 172:7d866c31b3c5 | 728 | static void uart3_vec_async(void) |
AnnaBridge | 172:7d866c31b3c5 | 729 | { |
AnnaBridge | 172:7d866c31b3c5 | 730 | uart_irq_async(uart3_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 731 | } |
AnnaBridge | 172:7d866c31b3c5 | 732 | |
AnnaBridge | 172:7d866c31b3c5 | 733 | static void uart4_vec_async(void) |
AnnaBridge | 172:7d866c31b3c5 | 734 | { |
AnnaBridge | 172:7d866c31b3c5 | 735 | uart_irq_async(uart4_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 736 | } |
AnnaBridge | 172:7d866c31b3c5 | 737 | |
AnnaBridge | 172:7d866c31b3c5 | 738 | static void uart5_vec_async(void) |
AnnaBridge | 172:7d866c31b3c5 | 739 | { |
AnnaBridge | 172:7d866c31b3c5 | 740 | uart_irq_async(uart5_var.obj); |
AnnaBridge | 172:7d866c31b3c5 | 741 | } |
AnnaBridge | 172:7d866c31b3c5 | 742 | |
AnnaBridge | 172:7d866c31b3c5 | 743 | static void uart_irq_async(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 744 | { |
AnnaBridge | 172:7d866c31b3c5 | 745 | if (serial_is_irq_en(obj, RxIrq)) { |
AnnaBridge | 172:7d866c31b3c5 | 746 | (*obj->serial.irq_handler_rx_async)(); |
AnnaBridge | 172:7d866c31b3c5 | 747 | } |
AnnaBridge | 172:7d866c31b3c5 | 748 | if (serial_is_irq_en(obj, TxIrq)) { |
AnnaBridge | 172:7d866c31b3c5 | 749 | (*obj->serial.irq_handler_tx_async)(); |
AnnaBridge | 172:7d866c31b3c5 | 750 | } |
AnnaBridge | 172:7d866c31b3c5 | 751 | } |
AnnaBridge | 172:7d866c31b3c5 | 752 | |
AnnaBridge | 172:7d866c31b3c5 | 753 | static void serial_rx_set_char_match(serial_t *obj, uint8_t char_match) |
AnnaBridge | 172:7d866c31b3c5 | 754 | { |
AnnaBridge | 172:7d866c31b3c5 | 755 | obj->char_match = char_match; |
AnnaBridge | 172:7d866c31b3c5 | 756 | obj->char_found = 0; |
AnnaBridge | 172:7d866c31b3c5 | 757 | } |
AnnaBridge | 172:7d866c31b3c5 | 758 | |
AnnaBridge | 172:7d866c31b3c5 | 759 | static void serial_tx_enable_event(serial_t *obj, int event, uint8_t enable) |
AnnaBridge | 172:7d866c31b3c5 | 760 | { |
AnnaBridge | 172:7d866c31b3c5 | 761 | obj->serial.event &= ~SERIAL_EVENT_TX_MASK; |
AnnaBridge | 172:7d866c31b3c5 | 762 | obj->serial.event |= (event & SERIAL_EVENT_TX_MASK); |
AnnaBridge | 172:7d866c31b3c5 | 763 | |
AnnaBridge | 172:7d866c31b3c5 | 764 | if (event & SERIAL_EVENT_TX_COMPLETE) { |
AnnaBridge | 172:7d866c31b3c5 | 765 | // N/A |
AnnaBridge | 172:7d866c31b3c5 | 766 | } |
AnnaBridge | 172:7d866c31b3c5 | 767 | } |
AnnaBridge | 172:7d866c31b3c5 | 768 | |
AnnaBridge | 172:7d866c31b3c5 | 769 | static void serial_rx_enable_event(serial_t *obj, int event, uint8_t enable) |
AnnaBridge | 172:7d866c31b3c5 | 770 | { |
AnnaBridge | 172:7d866c31b3c5 | 771 | obj->serial.event &= ~SERIAL_EVENT_RX_MASK; |
AnnaBridge | 172:7d866c31b3c5 | 772 | obj->serial.event |= (event & SERIAL_EVENT_RX_MASK); |
AnnaBridge | 172:7d866c31b3c5 | 773 | |
AnnaBridge | 172:7d866c31b3c5 | 774 | if (event & SERIAL_EVENT_RX_COMPLETE) { |
AnnaBridge | 172:7d866c31b3c5 | 775 | // N/A |
AnnaBridge | 172:7d866c31b3c5 | 776 | } |
AnnaBridge | 172:7d866c31b3c5 | 777 | if (event & SERIAL_EVENT_RX_OVERRUN_ERROR) { |
AnnaBridge | 172:7d866c31b3c5 | 778 | // N/A |
AnnaBridge | 172:7d866c31b3c5 | 779 | } |
AnnaBridge | 172:7d866c31b3c5 | 780 | if (event & SERIAL_EVENT_RX_FRAMING_ERROR) { |
AnnaBridge | 172:7d866c31b3c5 | 781 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_RLSIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 782 | } |
AnnaBridge | 172:7d866c31b3c5 | 783 | if (event & SERIAL_EVENT_RX_PARITY_ERROR) { |
AnnaBridge | 172:7d866c31b3c5 | 784 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_RLSIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 785 | } |
AnnaBridge | 172:7d866c31b3c5 | 786 | if (event & SERIAL_EVENT_RX_OVERFLOW) { |
AnnaBridge | 172:7d866c31b3c5 | 787 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_BUFERRIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 788 | } |
AnnaBridge | 172:7d866c31b3c5 | 789 | if (event & SERIAL_EVENT_RX_CHARACTER_MATCH) { |
AnnaBridge | 172:7d866c31b3c5 | 790 | // N/A |
AnnaBridge | 172:7d866c31b3c5 | 791 | } |
AnnaBridge | 172:7d866c31b3c5 | 792 | } |
AnnaBridge | 172:7d866c31b3c5 | 793 | |
AnnaBridge | 172:7d866c31b3c5 | 794 | static int serial_is_tx_complete(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 795 | { |
AnnaBridge | 172:7d866c31b3c5 | 796 | // NOTE: Exclude tx fifo empty check due to no such interrupt on DMA way |
AnnaBridge | 172:7d866c31b3c5 | 797 | return (obj->tx_buff.pos == obj->tx_buff.length); |
AnnaBridge | 172:7d866c31b3c5 | 798 | } |
AnnaBridge | 172:7d866c31b3c5 | 799 | |
AnnaBridge | 172:7d866c31b3c5 | 800 | static int serial_is_rx_complete(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 801 | { |
AnnaBridge | 172:7d866c31b3c5 | 802 | return (obj->rx_buff.pos == obj->rx_buff.length); |
AnnaBridge | 172:7d866c31b3c5 | 803 | } |
AnnaBridge | 172:7d866c31b3c5 | 804 | |
AnnaBridge | 172:7d866c31b3c5 | 805 | static uint32_t serial_tx_event_check(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 806 | { |
AnnaBridge | 172:7d866c31b3c5 | 807 | UART_T *uart_base = (UART_T *) NU_MODBASE(obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 808 | |
AnnaBridge | 172:7d866c31b3c5 | 809 | if (uart_base->INTSTS & UART_INTSTS_THREINT_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 810 | // Simulate clear of the interrupt flag. Temporarily disable the interrupt here and to be recovered on next write. |
AnnaBridge | 172:7d866c31b3c5 | 811 | UART_DISABLE_INT(uart_base, UART_INTEN_THREIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 812 | } |
AnnaBridge | 172:7d866c31b3c5 | 813 | |
AnnaBridge | 172:7d866c31b3c5 | 814 | uint32_t event = 0; |
AnnaBridge | 172:7d866c31b3c5 | 815 | |
AnnaBridge | 172:7d866c31b3c5 | 816 | if (obj->serial.dma_usage_tx == DMA_USAGE_NEVER) { |
AnnaBridge | 172:7d866c31b3c5 | 817 | serial_write_async(obj); |
AnnaBridge | 172:7d866c31b3c5 | 818 | } |
AnnaBridge | 172:7d866c31b3c5 | 819 | |
AnnaBridge | 172:7d866c31b3c5 | 820 | if (serial_is_tx_complete(obj)) { |
AnnaBridge | 172:7d866c31b3c5 | 821 | event |= SERIAL_EVENT_TX_COMPLETE; |
AnnaBridge | 172:7d866c31b3c5 | 822 | } |
AnnaBridge | 172:7d866c31b3c5 | 823 | |
AnnaBridge | 172:7d866c31b3c5 | 824 | return event; |
AnnaBridge | 172:7d866c31b3c5 | 825 | } |
AnnaBridge | 172:7d866c31b3c5 | 826 | |
AnnaBridge | 172:7d866c31b3c5 | 827 | static uint32_t serial_rx_event_check(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 828 | { |
AnnaBridge | 172:7d866c31b3c5 | 829 | UART_T *uart_base = (UART_T *) NU_MODBASE(obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 830 | |
AnnaBridge | 172:7d866c31b3c5 | 831 | if (uart_base->INTSTS & (UART_INTSTS_RDAINT_Msk | UART_INTSTS_RXTOINT_Msk)) { |
AnnaBridge | 172:7d866c31b3c5 | 832 | // Simulate clear of the interrupt flag. Temporarily disable the interrupt here and to be recovered on next read. |
AnnaBridge | 172:7d866c31b3c5 | 833 | UART_DISABLE_INT(uart_base, (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); |
AnnaBridge | 172:7d866c31b3c5 | 834 | } |
AnnaBridge | 172:7d866c31b3c5 | 835 | |
AnnaBridge | 172:7d866c31b3c5 | 836 | uint32_t event = 0; |
AnnaBridge | 172:7d866c31b3c5 | 837 | |
AnnaBridge | 172:7d866c31b3c5 | 838 | if (uart_base->FIFOSTS & UART_FIFOSTS_BIF_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 839 | uart_base->FIFOSTS = UART_FIFOSTS_BIF_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 840 | } |
AnnaBridge | 172:7d866c31b3c5 | 841 | if (uart_base->FIFOSTS & UART_FIFOSTS_FEF_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 842 | uart_base->FIFOSTS = UART_FIFOSTS_FEF_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 843 | event |= SERIAL_EVENT_RX_FRAMING_ERROR; |
AnnaBridge | 172:7d866c31b3c5 | 844 | } |
AnnaBridge | 172:7d866c31b3c5 | 845 | if (uart_base->FIFOSTS & UART_FIFOSTS_PEF_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 846 | uart_base->FIFOSTS = UART_FIFOSTS_PEF_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 847 | event |= SERIAL_EVENT_RX_PARITY_ERROR; |
AnnaBridge | 172:7d866c31b3c5 | 848 | } |
AnnaBridge | 172:7d866c31b3c5 | 849 | |
AnnaBridge | 172:7d866c31b3c5 | 850 | if (uart_base->FIFOSTS & UART_FIFOSTS_RXOVIF_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 851 | uart_base->FIFOSTS = UART_FIFOSTS_RXOVIF_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 852 | event |= SERIAL_EVENT_RX_OVERFLOW; |
AnnaBridge | 172:7d866c31b3c5 | 853 | } |
AnnaBridge | 172:7d866c31b3c5 | 854 | |
AnnaBridge | 172:7d866c31b3c5 | 855 | if (obj->serial.dma_usage_rx == DMA_USAGE_NEVER) { |
AnnaBridge | 172:7d866c31b3c5 | 856 | serial_read_async(obj); |
AnnaBridge | 172:7d866c31b3c5 | 857 | } |
AnnaBridge | 172:7d866c31b3c5 | 858 | |
AnnaBridge | 172:7d866c31b3c5 | 859 | if (serial_is_rx_complete(obj)) { |
AnnaBridge | 172:7d866c31b3c5 | 860 | event |= SERIAL_EVENT_RX_COMPLETE; |
AnnaBridge | 172:7d866c31b3c5 | 861 | } |
AnnaBridge | 172:7d866c31b3c5 | 862 | if ((obj->char_match != SERIAL_RESERVED_CHAR_MATCH) && obj->char_found) { |
AnnaBridge | 172:7d866c31b3c5 | 863 | event |= SERIAL_EVENT_RX_CHARACTER_MATCH; |
AnnaBridge | 172:7d866c31b3c5 | 864 | } |
AnnaBridge | 172:7d866c31b3c5 | 865 | |
AnnaBridge | 172:7d866c31b3c5 | 866 | return event; |
AnnaBridge | 172:7d866c31b3c5 | 867 | } |
AnnaBridge | 172:7d866c31b3c5 | 868 | |
AnnaBridge | 172:7d866c31b3c5 | 869 | static void uart_dma_handler_tx(uint32_t id, uint32_t event_dma) |
AnnaBridge | 172:7d866c31b3c5 | 870 | { |
AnnaBridge | 172:7d866c31b3c5 | 871 | serial_t *obj = (serial_t *) id; |
AnnaBridge | 172:7d866c31b3c5 | 872 | |
AnnaBridge | 172:7d866c31b3c5 | 873 | // FIXME: Pass this error to caller |
AnnaBridge | 172:7d866c31b3c5 | 874 | if (event_dma & DMA_EVENT_ABORT) { |
AnnaBridge | 172:7d866c31b3c5 | 875 | } |
AnnaBridge | 172:7d866c31b3c5 | 876 | // Expect UART IRQ will catch this transfer done event |
AnnaBridge | 172:7d866c31b3c5 | 877 | if (event_dma & DMA_EVENT_TRANSFER_DONE) { |
AnnaBridge | 172:7d866c31b3c5 | 878 | obj->tx_buff.pos = obj->tx_buff.length; |
AnnaBridge | 172:7d866c31b3c5 | 879 | } |
AnnaBridge | 172:7d866c31b3c5 | 880 | // FIXME: Pass this error to caller |
AnnaBridge | 172:7d866c31b3c5 | 881 | if (event_dma & DMA_EVENT_TIMEOUT) { |
AnnaBridge | 172:7d866c31b3c5 | 882 | } |
AnnaBridge | 172:7d866c31b3c5 | 883 | |
AnnaBridge | 172:7d866c31b3c5 | 884 | uart_irq_async(obj); |
AnnaBridge | 172:7d866c31b3c5 | 885 | } |
AnnaBridge | 172:7d866c31b3c5 | 886 | |
AnnaBridge | 172:7d866c31b3c5 | 887 | static void uart_dma_handler_rx(uint32_t id, uint32_t event_dma) |
AnnaBridge | 172:7d866c31b3c5 | 888 | { |
AnnaBridge | 172:7d866c31b3c5 | 889 | serial_t *obj = (serial_t *) id; |
AnnaBridge | 172:7d866c31b3c5 | 890 | |
AnnaBridge | 172:7d866c31b3c5 | 891 | // FIXME: Pass this error to caller |
AnnaBridge | 172:7d866c31b3c5 | 892 | if (event_dma & DMA_EVENT_ABORT) { |
AnnaBridge | 172:7d866c31b3c5 | 893 | } |
AnnaBridge | 172:7d866c31b3c5 | 894 | // Expect UART IRQ will catch this transfer done event |
AnnaBridge | 172:7d866c31b3c5 | 895 | if (event_dma & DMA_EVENT_TRANSFER_DONE) { |
AnnaBridge | 172:7d866c31b3c5 | 896 | obj->rx_buff.pos = obj->rx_buff.length; |
AnnaBridge | 172:7d866c31b3c5 | 897 | } |
AnnaBridge | 172:7d866c31b3c5 | 898 | // FIXME: Pass this error to caller |
AnnaBridge | 172:7d866c31b3c5 | 899 | if (event_dma & DMA_EVENT_TIMEOUT) { |
AnnaBridge | 172:7d866c31b3c5 | 900 | } |
AnnaBridge | 172:7d866c31b3c5 | 901 | |
AnnaBridge | 172:7d866c31b3c5 | 902 | uart_irq_async(obj); |
AnnaBridge | 172:7d866c31b3c5 | 903 | } |
AnnaBridge | 172:7d866c31b3c5 | 904 | |
AnnaBridge | 172:7d866c31b3c5 | 905 | static int serial_write_async(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 906 | { |
AnnaBridge | 172:7d866c31b3c5 | 907 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 908 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 909 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 910 | |
AnnaBridge | 172:7d866c31b3c5 | 911 | UART_T *uart_base = (UART_T *) NU_MODBASE(obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 912 | |
AnnaBridge | 172:7d866c31b3c5 | 913 | uint32_t tx_fifo_max = ((struct nu_uart_var *) modinit->var)->fifo_size_tx; |
AnnaBridge | 172:7d866c31b3c5 | 914 | uint32_t tx_fifo_busy = (uart_base->FIFOSTS & UART_FIFOSTS_TXPTR_Msk) >> UART_FIFOSTS_TXPTR_Pos; |
AnnaBridge | 172:7d866c31b3c5 | 915 | if (uart_base->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 916 | tx_fifo_busy = tx_fifo_max; |
AnnaBridge | 172:7d866c31b3c5 | 917 | } |
AnnaBridge | 172:7d866c31b3c5 | 918 | uint32_t tx_fifo_free = tx_fifo_max - tx_fifo_busy; |
AnnaBridge | 172:7d866c31b3c5 | 919 | if (tx_fifo_free == 0) { |
AnnaBridge | 172:7d866c31b3c5 | 920 | // Simulate clear of the interrupt flag |
AnnaBridge | 172:7d866c31b3c5 | 921 | if (obj->serial.inten_msk & UART_INTEN_THREIEN_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 922 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 923 | } |
AnnaBridge | 172:7d866c31b3c5 | 924 | return 0; |
AnnaBridge | 172:7d866c31b3c5 | 925 | } |
AnnaBridge | 172:7d866c31b3c5 | 926 | |
AnnaBridge | 172:7d866c31b3c5 | 927 | uint32_t bytes_per_word = obj->tx_buff.width / 8; |
AnnaBridge | 172:7d866c31b3c5 | 928 | |
AnnaBridge | 172:7d866c31b3c5 | 929 | uint8_t *tx = (uint8_t *)(obj->tx_buff.buffer) + bytes_per_word * obj->tx_buff.pos; |
AnnaBridge | 172:7d866c31b3c5 | 930 | int n_words = 0; |
AnnaBridge | 172:7d866c31b3c5 | 931 | while (obj->tx_buff.pos < obj->tx_buff.length && tx_fifo_free >= bytes_per_word) { |
AnnaBridge | 172:7d866c31b3c5 | 932 | switch (bytes_per_word) { |
AnnaBridge | 172:7d866c31b3c5 | 933 | case 4: |
AnnaBridge | 172:7d866c31b3c5 | 934 | UART_WRITE(((UART_T *) NU_MODBASE(obj->serial.uart)), *tx ++); |
AnnaBridge | 172:7d866c31b3c5 | 935 | UART_WRITE(((UART_T *) NU_MODBASE(obj->serial.uart)), *tx ++); |
AnnaBridge | 172:7d866c31b3c5 | 936 | case 2: |
AnnaBridge | 172:7d866c31b3c5 | 937 | UART_WRITE(((UART_T *) NU_MODBASE(obj->serial.uart)), *tx ++); |
AnnaBridge | 172:7d866c31b3c5 | 938 | case 1: |
AnnaBridge | 172:7d866c31b3c5 | 939 | UART_WRITE(((UART_T *) NU_MODBASE(obj->serial.uart)), *tx ++); |
AnnaBridge | 172:7d866c31b3c5 | 940 | } |
AnnaBridge | 172:7d866c31b3c5 | 941 | |
AnnaBridge | 172:7d866c31b3c5 | 942 | n_words ++; |
AnnaBridge | 172:7d866c31b3c5 | 943 | tx_fifo_free -= bytes_per_word; |
AnnaBridge | 172:7d866c31b3c5 | 944 | obj->tx_buff.pos ++; |
AnnaBridge | 172:7d866c31b3c5 | 945 | } |
AnnaBridge | 172:7d866c31b3c5 | 946 | |
AnnaBridge | 172:7d866c31b3c5 | 947 | if (n_words) { |
AnnaBridge | 172:7d866c31b3c5 | 948 | // Simulate clear of the interrupt flag |
AnnaBridge | 172:7d866c31b3c5 | 949 | if (obj->serial.inten_msk & UART_INTEN_THREIEN_Msk) { |
AnnaBridge | 172:7d866c31b3c5 | 950 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 951 | } |
AnnaBridge | 172:7d866c31b3c5 | 952 | } |
AnnaBridge | 172:7d866c31b3c5 | 953 | |
AnnaBridge | 172:7d866c31b3c5 | 954 | return n_words; |
AnnaBridge | 172:7d866c31b3c5 | 955 | } |
AnnaBridge | 172:7d866c31b3c5 | 956 | |
AnnaBridge | 172:7d866c31b3c5 | 957 | static int serial_read_async(serial_t *obj) |
AnnaBridge | 172:7d866c31b3c5 | 958 | { |
AnnaBridge | 172:7d866c31b3c5 | 959 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 960 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 961 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 962 | |
AnnaBridge | 172:7d866c31b3c5 | 963 | uint32_t rx_fifo_busy = (((UART_T *) NU_MODBASE(obj->serial.uart))->FIFOSTS & UART_FIFOSTS_RXPTR_Msk) >> UART_FIFOSTS_RXPTR_Pos; |
AnnaBridge | 172:7d866c31b3c5 | 964 | |
AnnaBridge | 172:7d866c31b3c5 | 965 | uint32_t bytes_per_word = obj->rx_buff.width / 8; |
AnnaBridge | 172:7d866c31b3c5 | 966 | |
AnnaBridge | 172:7d866c31b3c5 | 967 | uint8_t *rx = (uint8_t *)(obj->rx_buff.buffer) + bytes_per_word * obj->rx_buff.pos; |
AnnaBridge | 172:7d866c31b3c5 | 968 | int n_words = 0; |
AnnaBridge | 172:7d866c31b3c5 | 969 | while (obj->rx_buff.pos < obj->rx_buff.length && rx_fifo_busy >= bytes_per_word) { |
AnnaBridge | 172:7d866c31b3c5 | 970 | switch (bytes_per_word) { |
AnnaBridge | 172:7d866c31b3c5 | 971 | case 4: |
AnnaBridge | 172:7d866c31b3c5 | 972 | *rx ++ = UART_READ(((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 973 | *rx ++ = UART_READ(((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 974 | case 2: |
AnnaBridge | 172:7d866c31b3c5 | 975 | *rx ++ = UART_READ(((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 976 | case 1: |
AnnaBridge | 172:7d866c31b3c5 | 977 | *rx ++ = UART_READ(((UART_T *) NU_MODBASE(obj->serial.uart))); |
AnnaBridge | 172:7d866c31b3c5 | 978 | } |
AnnaBridge | 172:7d866c31b3c5 | 979 | |
AnnaBridge | 172:7d866c31b3c5 | 980 | n_words ++; |
AnnaBridge | 172:7d866c31b3c5 | 981 | rx_fifo_busy -= bytes_per_word; |
AnnaBridge | 172:7d866c31b3c5 | 982 | obj->rx_buff.pos ++; |
AnnaBridge | 172:7d866c31b3c5 | 983 | |
AnnaBridge | 172:7d866c31b3c5 | 984 | if ((obj->serial.event & SERIAL_EVENT_RX_CHARACTER_MATCH) && |
AnnaBridge | 172:7d866c31b3c5 | 985 | obj->char_match != SERIAL_RESERVED_CHAR_MATCH) { |
AnnaBridge | 172:7d866c31b3c5 | 986 | uint8_t *rx_cmp = rx; |
AnnaBridge | 172:7d866c31b3c5 | 987 | switch (bytes_per_word) { |
AnnaBridge | 172:7d866c31b3c5 | 988 | case 4: |
AnnaBridge | 172:7d866c31b3c5 | 989 | rx_cmp -= 2; |
AnnaBridge | 172:7d866c31b3c5 | 990 | case 2: |
AnnaBridge | 172:7d866c31b3c5 | 991 | rx_cmp --; |
AnnaBridge | 172:7d866c31b3c5 | 992 | case 1: |
AnnaBridge | 172:7d866c31b3c5 | 993 | rx_cmp --; |
AnnaBridge | 172:7d866c31b3c5 | 994 | } |
AnnaBridge | 172:7d866c31b3c5 | 995 | if (*rx_cmp == obj->char_match) { |
AnnaBridge | 172:7d866c31b3c5 | 996 | obj->char_found = 1; |
AnnaBridge | 172:7d866c31b3c5 | 997 | break; |
AnnaBridge | 172:7d866c31b3c5 | 998 | } |
AnnaBridge | 172:7d866c31b3c5 | 999 | } |
AnnaBridge | 172:7d866c31b3c5 | 1000 | } |
AnnaBridge | 172:7d866c31b3c5 | 1001 | |
AnnaBridge | 172:7d866c31b3c5 | 1002 | if (n_words) { |
AnnaBridge | 172:7d866c31b3c5 | 1003 | // Simulate clear of the interrupt flag |
AnnaBridge | 172:7d866c31b3c5 | 1004 | if (obj->serial.inten_msk & (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)) { |
AnnaBridge | 172:7d866c31b3c5 | 1005 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); |
AnnaBridge | 172:7d866c31b3c5 | 1006 | } |
AnnaBridge | 172:7d866c31b3c5 | 1007 | } |
AnnaBridge | 172:7d866c31b3c5 | 1008 | |
AnnaBridge | 172:7d866c31b3c5 | 1009 | return n_words; |
AnnaBridge | 172:7d866c31b3c5 | 1010 | } |
AnnaBridge | 172:7d866c31b3c5 | 1011 | |
AnnaBridge | 172:7d866c31b3c5 | 1012 | static void serial_tx_buffer_set(serial_t *obj, const void *tx, size_t length, uint8_t width) |
AnnaBridge | 172:7d866c31b3c5 | 1013 | { |
AnnaBridge | 172:7d866c31b3c5 | 1014 | obj->tx_buff.buffer = (void *) tx; |
AnnaBridge | 172:7d866c31b3c5 | 1015 | obj->tx_buff.length = length; |
AnnaBridge | 172:7d866c31b3c5 | 1016 | obj->tx_buff.pos = 0; |
AnnaBridge | 172:7d866c31b3c5 | 1017 | obj->tx_buff.width = width; |
AnnaBridge | 172:7d866c31b3c5 | 1018 | } |
AnnaBridge | 172:7d866c31b3c5 | 1019 | |
AnnaBridge | 172:7d866c31b3c5 | 1020 | static void serial_rx_buffer_set(serial_t *obj, void *rx, size_t length, uint8_t width) |
AnnaBridge | 172:7d866c31b3c5 | 1021 | { |
AnnaBridge | 172:7d866c31b3c5 | 1022 | obj->rx_buff.buffer = rx; |
AnnaBridge | 172:7d866c31b3c5 | 1023 | obj->rx_buff.length = length; |
AnnaBridge | 172:7d866c31b3c5 | 1024 | obj->rx_buff.pos = 0; |
AnnaBridge | 172:7d866c31b3c5 | 1025 | obj->rx_buff.width = width; |
AnnaBridge | 172:7d866c31b3c5 | 1026 | } |
AnnaBridge | 172:7d866c31b3c5 | 1027 | |
AnnaBridge | 172:7d866c31b3c5 | 1028 | static void serial_tx_enable_interrupt(serial_t *obj, uint32_t handler, uint8_t enable) |
AnnaBridge | 172:7d866c31b3c5 | 1029 | { |
AnnaBridge | 172:7d866c31b3c5 | 1030 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 1031 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 1032 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 1033 | |
AnnaBridge | 172:7d866c31b3c5 | 1034 | // Necessary for both interrupt way and DMA way |
AnnaBridge | 172:7d866c31b3c5 | 1035 | struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; |
AnnaBridge | 172:7d866c31b3c5 | 1036 | // With our own async vector, tx/rx handlers can be different. |
AnnaBridge | 172:7d866c31b3c5 | 1037 | obj->serial.vec = var->vec_async; |
AnnaBridge | 172:7d866c31b3c5 | 1038 | obj->serial.irq_handler_tx_async = (void (*)(void)) handler; |
AnnaBridge | 172:7d866c31b3c5 | 1039 | serial_enable_interrupt(obj, TxIrq, enable); |
AnnaBridge | 172:7d866c31b3c5 | 1040 | } |
AnnaBridge | 172:7d866c31b3c5 | 1041 | |
AnnaBridge | 172:7d866c31b3c5 | 1042 | static void serial_rx_enable_interrupt(serial_t *obj, uint32_t handler, uint8_t enable) |
AnnaBridge | 172:7d866c31b3c5 | 1043 | { |
AnnaBridge | 172:7d866c31b3c5 | 1044 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 1045 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 1046 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 1047 | |
AnnaBridge | 172:7d866c31b3c5 | 1048 | // Necessary for both interrupt way and DMA way |
AnnaBridge | 172:7d866c31b3c5 | 1049 | struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; |
AnnaBridge | 172:7d866c31b3c5 | 1050 | // With our own async vector, tx/rx handlers can be different. |
AnnaBridge | 172:7d866c31b3c5 | 1051 | obj->serial.vec = var->vec_async; |
AnnaBridge | 172:7d866c31b3c5 | 1052 | obj->serial.irq_handler_rx_async = (void (*) (void)) handler; |
AnnaBridge | 172:7d866c31b3c5 | 1053 | serial_enable_interrupt(obj, RxIrq, enable); |
AnnaBridge | 172:7d866c31b3c5 | 1054 | } |
AnnaBridge | 172:7d866c31b3c5 | 1055 | |
AnnaBridge | 172:7d866c31b3c5 | 1056 | static void serial_enable_interrupt(serial_t *obj, SerialIrq irq, uint32_t enable) |
AnnaBridge | 172:7d866c31b3c5 | 1057 | { |
AnnaBridge | 172:7d866c31b3c5 | 1058 | if (enable) { |
AnnaBridge | 172:7d866c31b3c5 | 1059 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 1060 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 1061 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 1062 | |
AnnaBridge | 172:7d866c31b3c5 | 1063 | NVIC_SetVector(modinit->irq_n, (uint32_t) obj->serial.vec); |
AnnaBridge | 172:7d866c31b3c5 | 1064 | NVIC_EnableIRQ(modinit->irq_n); |
AnnaBridge | 172:7d866c31b3c5 | 1065 | |
AnnaBridge | 172:7d866c31b3c5 | 1066 | struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; |
AnnaBridge | 172:7d866c31b3c5 | 1067 | // Multiple serial S/W objects for single UART H/W module possibly. |
AnnaBridge | 172:7d866c31b3c5 | 1068 | // Bind serial S/W object to UART H/W module as interrupt is enabled. |
AnnaBridge | 172:7d866c31b3c5 | 1069 | var->obj = obj; |
AnnaBridge | 172:7d866c31b3c5 | 1070 | |
AnnaBridge | 172:7d866c31b3c5 | 1071 | switch (irq) { |
AnnaBridge | 172:7d866c31b3c5 | 1072 | // NOTE: Setting inten_msk first to avoid race condition |
AnnaBridge | 172:7d866c31b3c5 | 1073 | case RxIrq: |
AnnaBridge | 172:7d866c31b3c5 | 1074 | obj->serial.inten_msk = obj->serial.inten_msk | (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 1075 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); |
AnnaBridge | 172:7d866c31b3c5 | 1076 | break; |
AnnaBridge | 172:7d866c31b3c5 | 1077 | case TxIrq: |
AnnaBridge | 172:7d866c31b3c5 | 1078 | obj->serial.inten_msk = obj->serial.inten_msk | UART_INTEN_THREIEN_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 1079 | UART_ENABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 1080 | break; |
AnnaBridge | 172:7d866c31b3c5 | 1081 | } |
AnnaBridge | 172:7d866c31b3c5 | 1082 | } else { // disable |
AnnaBridge | 172:7d866c31b3c5 | 1083 | switch (irq) { |
AnnaBridge | 172:7d866c31b3c5 | 1084 | case RxIrq: |
AnnaBridge | 172:7d866c31b3c5 | 1085 | UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk)); |
AnnaBridge | 172:7d866c31b3c5 | 1086 | obj->serial.inten_msk = obj->serial.inten_msk & ~(UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 1087 | break; |
AnnaBridge | 172:7d866c31b3c5 | 1088 | case TxIrq: |
AnnaBridge | 172:7d866c31b3c5 | 1089 | UART_DISABLE_INT(((UART_T *) NU_MODBASE(obj->serial.uart)), UART_INTEN_THREIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 1090 | obj->serial.inten_msk = obj->serial.inten_msk & ~UART_INTEN_THREIEN_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 1091 | break; |
AnnaBridge | 172:7d866c31b3c5 | 1092 | } |
AnnaBridge | 172:7d866c31b3c5 | 1093 | } |
AnnaBridge | 172:7d866c31b3c5 | 1094 | } |
AnnaBridge | 172:7d866c31b3c5 | 1095 | |
AnnaBridge | 172:7d866c31b3c5 | 1096 | static void serial_rollback_interrupt(serial_t *obj, SerialIrq irq) |
AnnaBridge | 172:7d866c31b3c5 | 1097 | { |
AnnaBridge | 172:7d866c31b3c5 | 1098 | const struct nu_modinit_s *modinit = get_modinit(obj->serial.uart, uart_modinit_tab); |
AnnaBridge | 172:7d866c31b3c5 | 1099 | MBED_ASSERT(modinit != NULL); |
AnnaBridge | 172:7d866c31b3c5 | 1100 | MBED_ASSERT(modinit->modname == (int) obj->serial.uart); |
AnnaBridge | 172:7d866c31b3c5 | 1101 | |
AnnaBridge | 172:7d866c31b3c5 | 1102 | struct nu_uart_var *var = (struct nu_uart_var *) modinit->var; |
AnnaBridge | 172:7d866c31b3c5 | 1103 | |
AnnaBridge | 172:7d866c31b3c5 | 1104 | obj->serial.vec = var->vec; |
AnnaBridge | 172:7d866c31b3c5 | 1105 | serial_enable_interrupt(obj, irq, obj->serial.irq_en); |
AnnaBridge | 172:7d866c31b3c5 | 1106 | } |
AnnaBridge | 172:7d866c31b3c5 | 1107 | |
AnnaBridge | 172:7d866c31b3c5 | 1108 | static void serial_check_dma_usage(DMAUsage *dma_usage, int *dma_ch) |
AnnaBridge | 172:7d866c31b3c5 | 1109 | { |
AnnaBridge | 172:7d866c31b3c5 | 1110 | if (*dma_usage != DMA_USAGE_NEVER) { |
AnnaBridge | 172:7d866c31b3c5 | 1111 | if (*dma_ch == DMA_ERROR_OUT_OF_CHANNELS) { |
AnnaBridge | 172:7d866c31b3c5 | 1112 | *dma_ch = dma_channel_allocate(DMA_CAP_NONE); |
AnnaBridge | 172:7d866c31b3c5 | 1113 | } |
AnnaBridge | 172:7d866c31b3c5 | 1114 | if (*dma_ch == DMA_ERROR_OUT_OF_CHANNELS) { |
AnnaBridge | 172:7d866c31b3c5 | 1115 | *dma_usage = DMA_USAGE_NEVER; |
AnnaBridge | 172:7d866c31b3c5 | 1116 | } |
AnnaBridge | 172:7d866c31b3c5 | 1117 | } else { |
AnnaBridge | 172:7d866c31b3c5 | 1118 | dma_channel_free(*dma_ch); |
AnnaBridge | 172:7d866c31b3c5 | 1119 | *dma_ch = DMA_ERROR_OUT_OF_CHANNELS; |
AnnaBridge | 172:7d866c31b3c5 | 1120 | } |
AnnaBridge | 172:7d866c31b3c5 | 1121 | } |
AnnaBridge | 172:7d866c31b3c5 | 1122 | |
AnnaBridge | 172:7d866c31b3c5 | 1123 | static int serial_is_irq_en(serial_t *obj, SerialIrq irq) |
AnnaBridge | 172:7d866c31b3c5 | 1124 | { |
AnnaBridge | 172:7d866c31b3c5 | 1125 | int inten_msk = 0; |
AnnaBridge | 172:7d866c31b3c5 | 1126 | |
AnnaBridge | 172:7d866c31b3c5 | 1127 | switch (irq) { |
AnnaBridge | 172:7d866c31b3c5 | 1128 | case RxIrq: |
AnnaBridge | 172:7d866c31b3c5 | 1129 | inten_msk = obj->serial.inten_msk & (UART_INTEN_RDAIEN_Msk | UART_INTEN_RXTOIEN_Msk); |
AnnaBridge | 172:7d866c31b3c5 | 1130 | break; |
AnnaBridge | 172:7d866c31b3c5 | 1131 | case TxIrq: |
AnnaBridge | 172:7d866c31b3c5 | 1132 | inten_msk = obj->serial.inten_msk & UART_INTEN_THREIEN_Msk; |
AnnaBridge | 172:7d866c31b3c5 | 1133 | break; |
AnnaBridge | 172:7d866c31b3c5 | 1134 | } |
AnnaBridge | 172:7d866c31b3c5 | 1135 | |
AnnaBridge | 172:7d866c31b3c5 | 1136 | return !! inten_msk; |
AnnaBridge | 172:7d866c31b3c5 | 1137 | } |
AnnaBridge | 172:7d866c31b3c5 | 1138 | |
AnnaBridge | 172:7d866c31b3c5 | 1139 | #endif // #if DEVICE_SERIAL_ASYNCH |
AnnaBridge | 172:7d866c31b3c5 | 1140 | #endif // #if DEVICE_SERIAL |