mbed

Fork of mbed-dev by mbed official

Committer:
AnnaBridge
Date:
Thu Aug 31 17:27:04 2017 +0100
Revision:
173:7d866c31b3c5
Child:
177:447f873cad2f
This updates the lib to the mbed lib v 150

Who changed what in which revision?

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