mbed library sources. Supersedes mbed-src.

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

Committer:
AnnaBridge
Date:
Thu Nov 08 11:46:34 2018 +0000
Revision:
188:bcfe06ba3d64
Parent:
184:08ed48f1de7f
Child:
189:f392fc9709a3
mbed-dev library. Release version 164

Who changed what in which revision?

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