Color Oled(SSD1331) connect to STMicroelectronics Nucleo-F466

Dependencies:   ssd1331

Committer:
kadonotakashi
Date:
Thu Oct 11 02:27:46 2018 +0000
Revision:
3:f3764f852aa8
Parent:
0:8fdf9a60065b
Nucreo 446 + SSD1331 test version;

Who changed what in which revision?

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