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