helpfor studient

Dependents:   STM32_F103-C8T6basecanblink_led

Fork of mbed-dev by mbed official

Committer:
AnnaBridge
Date:
Thu Apr 19 17:12:19 2018 +0100
Revision:
185:08ed48f1de7f
Parent:
177:447f873cad2f
mbed-dev library. Release version 161

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