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