mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Committer:
AnnaBridge
Date:
Wed Feb 20 22:31:08 2019 +0000
Revision:
189:f392fc9709a3
Parent:
188:bcfe06ba3d64
mbed library release version 165

Who changed what in which revision?

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