5.2.1 - Updated I2C files

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Committer:
group-onsemi
Date:
Wed Jan 25 20:34:15 2017 +0000
Revision:
0:098463de4c5d
Initial commit

Who changed what in which revision?

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