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/hal/TARGET_Silicon_Labs/TARGET_EFM32/serial_api.c@144:ef7eb2e8f9f7, 2016-09-02 (annotated)
- Committer:
- <>
- Date:
- Fri Sep 02 15:07:44 2016 +0100
- Revision:
- 144:ef7eb2e8f9f7
- Parent:
- 52:4ce9155acc4d
This updates the lib to the mbed lib v125
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
<> | 144:ef7eb2e8f9f7 | 1 | /***************************************************************************//** |
<> | 144:ef7eb2e8f9f7 | 2 | * @file serial_api.c |
<> | 144:ef7eb2e8f9f7 | 3 | ******************************************************************************* |
<> | 144:ef7eb2e8f9f7 | 4 | * @section License |
<> | 144:ef7eb2e8f9f7 | 5 | * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b> |
<> | 144:ef7eb2e8f9f7 | 6 | ******************************************************************************* |
<> | 144:ef7eb2e8f9f7 | 7 | * |
<> | 144:ef7eb2e8f9f7 | 8 | * SPDX-License-Identifier: Apache-2.0 |
<> | 144:ef7eb2e8f9f7 | 9 | * |
<> | 144:ef7eb2e8f9f7 | 10 | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
<> | 144:ef7eb2e8f9f7 | 11 | * not use this file except in compliance with the License. |
<> | 144:ef7eb2e8f9f7 | 12 | * You may obtain a copy of the License at |
<> | 144:ef7eb2e8f9f7 | 13 | * |
<> | 144:ef7eb2e8f9f7 | 14 | * http://www.apache.org/licenses/LICENSE-2.0 |
<> | 144:ef7eb2e8f9f7 | 15 | * |
<> | 144:ef7eb2e8f9f7 | 16 | * Unless required by applicable law or agreed to in writing, software |
<> | 144:ef7eb2e8f9f7 | 17 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
<> | 144:ef7eb2e8f9f7 | 18 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
<> | 144:ef7eb2e8f9f7 | 19 | * See the License for the specific language governing permissions and |
<> | 144:ef7eb2e8f9f7 | 20 | * limitations under the License. |
<> | 144:ef7eb2e8f9f7 | 21 | * |
<> | 144:ef7eb2e8f9f7 | 22 | ******************************************************************************/ |
<> | 144:ef7eb2e8f9f7 | 23 | |
<> | 144:ef7eb2e8f9f7 | 24 | #include "device.h" |
<> | 144:ef7eb2e8f9f7 | 25 | #include "clocking.h" |
<> | 144:ef7eb2e8f9f7 | 26 | #if DEVICE_SERIAL |
<> | 144:ef7eb2e8f9f7 | 27 | |
<> | 144:ef7eb2e8f9f7 | 28 | #include "mbed_assert.h" |
<> | 144:ef7eb2e8f9f7 | 29 | #include "serial_api.h" |
<> | 144:ef7eb2e8f9f7 | 30 | #include "serial_api_HAL.h" |
<> | 144:ef7eb2e8f9f7 | 31 | #include <string.h> |
<> | 144:ef7eb2e8f9f7 | 32 | #include <stdbool.h> |
<> | 144:ef7eb2e8f9f7 | 33 | |
<> | 144:ef7eb2e8f9f7 | 34 | #include "pinmap.h" |
<> | 144:ef7eb2e8f9f7 | 35 | #include "pinmap_function.h" |
<> | 144:ef7eb2e8f9f7 | 36 | #include "PeripheralPins.h" |
<> | 144:ef7eb2e8f9f7 | 37 | #include "PeripheralNames.h" |
<> | 144:ef7eb2e8f9f7 | 38 | |
<> | 144:ef7eb2e8f9f7 | 39 | #include "em_usart.h" |
<> | 144:ef7eb2e8f9f7 | 40 | #include "em_leuart.h" |
<> | 144:ef7eb2e8f9f7 | 41 | #include "em_cmu.h" |
<> | 144:ef7eb2e8f9f7 | 42 | #include "em_dma.h" |
<> | 144:ef7eb2e8f9f7 | 43 | #include "dma_api_HAL.h" |
<> | 144:ef7eb2e8f9f7 | 44 | #include "dma_api.h" |
<> | 144:ef7eb2e8f9f7 | 45 | #include "sleep_api.h" |
<> | 144:ef7eb2e8f9f7 | 46 | #include "buffer.h" |
<> | 144:ef7eb2e8f9f7 | 47 | #include "sleepmodes.h" |
<> | 144:ef7eb2e8f9f7 | 48 | |
<> | 144:ef7eb2e8f9f7 | 49 | #define SERIAL_LEAST_ACTIVE_SLEEPMODE EM1 |
<> | 144:ef7eb2e8f9f7 | 50 | #define SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART EM2 |
<> | 144:ef7eb2e8f9f7 | 51 | |
<> | 144:ef7eb2e8f9f7 | 52 | /** Validation of LEUART register block pointer reference |
<> | 144:ef7eb2e8f9f7 | 53 | * for assert statements. */ |
<> | 144:ef7eb2e8f9f7 | 54 | #if !defined(LEUART_COUNT) |
<> | 144:ef7eb2e8f9f7 | 55 | #define LEUART_REF_VALID(ref) (0) |
<> | 144:ef7eb2e8f9f7 | 56 | #elif (LEUART_COUNT == 1) |
<> | 144:ef7eb2e8f9f7 | 57 | #define LEUART_REF_VALID(ref) ((ref) == LEUART0) |
<> | 144:ef7eb2e8f9f7 | 58 | #elif (LEUART_COUNT == 2) |
<> | 144:ef7eb2e8f9f7 | 59 | #define LEUART_REF_VALID(ref) (((ref) == LEUART0) || ((ref) == LEUART1)) |
<> | 144:ef7eb2e8f9f7 | 60 | #else |
<> | 144:ef7eb2e8f9f7 | 61 | #error Undefined number of low energy UARTs (LEUART). |
<> | 144:ef7eb2e8f9f7 | 62 | #endif |
<> | 144:ef7eb2e8f9f7 | 63 | |
<> | 144:ef7eb2e8f9f7 | 64 | /* Store IRQ id for each UART */ |
<> | 144:ef7eb2e8f9f7 | 65 | static uint32_t serial_irq_ids[MODULES_SIZE_SERIAL] = { 0 }; |
<> | 144:ef7eb2e8f9f7 | 66 | /* Interrupt handler from mbed common */ |
<> | 144:ef7eb2e8f9f7 | 67 | static uart_irq_handler irq_handler; |
<> | 144:ef7eb2e8f9f7 | 68 | /* Keep track of incoming DMA IRQ's */ |
<> | 144:ef7eb2e8f9f7 | 69 | static bool serial_dma_irq_fired[DMACTRL_CH_CNT] = { false }; |
<> | 144:ef7eb2e8f9f7 | 70 | |
<> | 144:ef7eb2e8f9f7 | 71 | /* Serial interface on USBTX/USBRX retargets stdio */ |
<> | 144:ef7eb2e8f9f7 | 72 | int stdio_uart_inited = 0; |
<> | 144:ef7eb2e8f9f7 | 73 | serial_t stdio_uart; |
<> | 144:ef7eb2e8f9f7 | 74 | |
<> | 144:ef7eb2e8f9f7 | 75 | static void uart_irq(UARTName, SerialIrq); |
<> | 144:ef7eb2e8f9f7 | 76 | static uint8_t serial_get_index(serial_t *obj); |
<> | 144:ef7eb2e8f9f7 | 77 | static void serial_enable(serial_t *obj, uint8_t enable); |
<> | 144:ef7eb2e8f9f7 | 78 | static void serial_enable_pins(serial_t *obj, uint8_t enable); |
<> | 144:ef7eb2e8f9f7 | 79 | static void serial_set_route(serial_t *obj); |
<> | 144:ef7eb2e8f9f7 | 80 | static IRQn_Type serial_get_rx_irq_index(serial_t *obj); |
<> | 144:ef7eb2e8f9f7 | 81 | static IRQn_Type serial_get_tx_irq_index(serial_t *obj); |
<> | 144:ef7eb2e8f9f7 | 82 | static CMU_Clock_TypeDef serial_get_clock(serial_t *obj); |
<> | 144:ef7eb2e8f9f7 | 83 | static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx); |
<> | 144:ef7eb2e8f9f7 | 84 | static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep); |
<> | 144:ef7eb2e8f9f7 | 85 | static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep); |
<> | 144:ef7eb2e8f9f7 | 86 | static void serial_block_sleep(serial_t *obj); |
<> | 144:ef7eb2e8f9f7 | 87 | static void serial_unblock_sleep(serial_t *obj); |
<> | 144:ef7eb2e8f9f7 | 88 | static void serial_leuart_baud(serial_t *obj, int baudrate); |
<> | 144:ef7eb2e8f9f7 | 89 | |
<> | 144:ef7eb2e8f9f7 | 90 | /* ISRs for RX and TX events */ |
<> | 144:ef7eb2e8f9f7 | 91 | #ifdef UART0 |
<> | 144:ef7eb2e8f9f7 | 92 | static void uart0_rx_irq() { uart_irq(UART_0, RxIrq); } |
<> | 144:ef7eb2e8f9f7 | 93 | static void uart0_tx_irq() { uart_irq(UART_0, TxIrq); USART_IntClear((USART_TypeDef*)UART_0, USART_IFC_TXC);} |
<> | 144:ef7eb2e8f9f7 | 94 | #endif |
<> | 144:ef7eb2e8f9f7 | 95 | #ifdef UART1 |
<> | 144:ef7eb2e8f9f7 | 96 | static void uart1_rx_irq() { uart_irq(UART_1, RxIrq); } |
<> | 144:ef7eb2e8f9f7 | 97 | static void uart1_tx_irq() { uart_irq(UART_1, TxIrq); USART_IntClear((USART_TypeDef*)UART_1, USART_IFC_TXC);} |
<> | 144:ef7eb2e8f9f7 | 98 | #endif |
<> | 144:ef7eb2e8f9f7 | 99 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 100 | static void usart0_rx_irq() { uart_irq(USART_0, RxIrq); } |
<> | 144:ef7eb2e8f9f7 | 101 | static void usart0_tx_irq() { uart_irq(USART_0, TxIrq); USART_IntClear((USART_TypeDef*)USART_0, USART_IFC_TXC);} |
<> | 144:ef7eb2e8f9f7 | 102 | #endif |
<> | 144:ef7eb2e8f9f7 | 103 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 104 | static void usart1_rx_irq() { uart_irq(USART_1, RxIrq); } |
<> | 144:ef7eb2e8f9f7 | 105 | static void usart1_tx_irq() { uart_irq(USART_1, TxIrq); USART_IntClear((USART_TypeDef*)USART_1, USART_IFC_TXC);} |
<> | 144:ef7eb2e8f9f7 | 106 | #endif |
<> | 144:ef7eb2e8f9f7 | 107 | #ifdef USART2 |
<> | 144:ef7eb2e8f9f7 | 108 | static void usart2_rx_irq() { uart_irq(USART_2, RxIrq); } |
<> | 144:ef7eb2e8f9f7 | 109 | static void usart2_tx_irq() { uart_irq(USART_2, TxIrq); USART_IntClear((USART_TypeDef*)USART_2, USART_IFC_TXC);} |
<> | 144:ef7eb2e8f9f7 | 110 | #endif |
<> | 144:ef7eb2e8f9f7 | 111 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 112 | static void leuart0_irq() |
<> | 144:ef7eb2e8f9f7 | 113 | { |
<> | 144:ef7eb2e8f9f7 | 114 | if(LEUART_IntGetEnabled(LEUART0) & (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IF_PERR | LEUART_IF_RXOF)) { |
<> | 144:ef7eb2e8f9f7 | 115 | uart_irq(LEUART_0, RxIrq); |
<> | 144:ef7eb2e8f9f7 | 116 | } |
<> | 144:ef7eb2e8f9f7 | 117 | |
<> | 144:ef7eb2e8f9f7 | 118 | if(LEUART_IntGetEnabled(LEUART0) & (LEUART_IF_TXC | LEUART_IF_TXBL | LEUART_IF_TXOF)) { |
<> | 144:ef7eb2e8f9f7 | 119 | uart_irq(LEUART_0, TxIrq); |
<> | 144:ef7eb2e8f9f7 | 120 | LEUART_IntClear(LEUART0, LEUART_IFC_TXC); |
<> | 144:ef7eb2e8f9f7 | 121 | } |
<> | 144:ef7eb2e8f9f7 | 122 | } |
<> | 144:ef7eb2e8f9f7 | 123 | #endif |
<> | 144:ef7eb2e8f9f7 | 124 | #ifdef LEUART1 |
<> | 144:ef7eb2e8f9f7 | 125 | static void leuart1_irq() |
<> | 144:ef7eb2e8f9f7 | 126 | { |
<> | 144:ef7eb2e8f9f7 | 127 | if(LEUART_IntGetEnabled(LEUART1) & (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IF_PERR | LEUART_IF_RXOF)) { |
<> | 144:ef7eb2e8f9f7 | 128 | uart_irq(LEUART_1, RxIrq); |
<> | 144:ef7eb2e8f9f7 | 129 | } |
<> | 144:ef7eb2e8f9f7 | 130 | |
<> | 144:ef7eb2e8f9f7 | 131 | if(LEUART_IntGetEnabled(LEUART1) & (LEUART_IF_TXC | LEUART_IF_TXBL | LEUART_IF_TXOF)) { |
<> | 144:ef7eb2e8f9f7 | 132 | uart_irq(LEUART_1, TxIrq); |
<> | 144:ef7eb2e8f9f7 | 133 | LEUART_IntClear(LEUART1, LEUART_IFC_TXC); |
<> | 144:ef7eb2e8f9f7 | 134 | } |
<> | 144:ef7eb2e8f9f7 | 135 | } |
<> | 144:ef7eb2e8f9f7 | 136 | #endif |
<> | 144:ef7eb2e8f9f7 | 137 | |
<> | 144:ef7eb2e8f9f7 | 138 | /** |
<> | 144:ef7eb2e8f9f7 | 139 | * Initialize the UART using default settings, overridden by settings from serial object |
<> | 144:ef7eb2e8f9f7 | 140 | * |
<> | 144:ef7eb2e8f9f7 | 141 | * @param obj pointer to serial object |
<> | 144:ef7eb2e8f9f7 | 142 | */ |
<> | 144:ef7eb2e8f9f7 | 143 | static void uart_init(serial_t *obj, uint32_t baudrate, SerialParity parity, int stop_bits) |
<> | 144:ef7eb2e8f9f7 | 144 | { |
<> | 144:ef7eb2e8f9f7 | 145 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 146 | LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT; |
<> | 144:ef7eb2e8f9f7 | 147 | |
<> | 144:ef7eb2e8f9f7 | 148 | if (stop_bits == 2) { |
<> | 144:ef7eb2e8f9f7 | 149 | init.stopbits = leuartStopbits2; |
<> | 144:ef7eb2e8f9f7 | 150 | } else { |
<> | 144:ef7eb2e8f9f7 | 151 | init.stopbits = leuartStopbits1; |
<> | 144:ef7eb2e8f9f7 | 152 | } |
<> | 144:ef7eb2e8f9f7 | 153 | |
<> | 144:ef7eb2e8f9f7 | 154 | switch (parity) { |
<> | 144:ef7eb2e8f9f7 | 155 | case ParityOdd: |
<> | 144:ef7eb2e8f9f7 | 156 | case ParityForced0: |
<> | 144:ef7eb2e8f9f7 | 157 | init.parity = leuartOddParity; |
<> | 144:ef7eb2e8f9f7 | 158 | break; |
<> | 144:ef7eb2e8f9f7 | 159 | case ParityEven: |
<> | 144:ef7eb2e8f9f7 | 160 | case ParityForced1: |
<> | 144:ef7eb2e8f9f7 | 161 | init.parity = leuartEvenParity; |
<> | 144:ef7eb2e8f9f7 | 162 | break; |
<> | 144:ef7eb2e8f9f7 | 163 | default: /* ParityNone */ |
<> | 144:ef7eb2e8f9f7 | 164 | init.parity = leuartNoParity; |
<> | 144:ef7eb2e8f9f7 | 165 | break; |
<> | 144:ef7eb2e8f9f7 | 166 | } |
<> | 144:ef7eb2e8f9f7 | 167 | |
<> | 144:ef7eb2e8f9f7 | 168 | init.enable = leuartDisable; |
<> | 144:ef7eb2e8f9f7 | 169 | init.baudrate = 9600; |
<> | 144:ef7eb2e8f9f7 | 170 | init.databits = leuartDatabits8; |
<> | 144:ef7eb2e8f9f7 | 171 | #ifdef LEUART_USING_LFXO |
<> | 144:ef7eb2e8f9f7 | 172 | init.refFreq = LEUART_LF_REF_FREQ; |
<> | 144:ef7eb2e8f9f7 | 173 | #else |
<> | 144:ef7eb2e8f9f7 | 174 | init.refFreq = LEUART_REF_FREQ; |
<> | 144:ef7eb2e8f9f7 | 175 | #endif |
<> | 144:ef7eb2e8f9f7 | 176 | LEUART_Init(obj->serial.periph.leuart, &init); |
<> | 144:ef7eb2e8f9f7 | 177 | |
<> | 144:ef7eb2e8f9f7 | 178 | if (baudrate != 9600) { |
<> | 144:ef7eb2e8f9f7 | 179 | serial_baud(obj, baudrate); |
<> | 144:ef7eb2e8f9f7 | 180 | } |
<> | 144:ef7eb2e8f9f7 | 181 | } else { |
<> | 144:ef7eb2e8f9f7 | 182 | USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT; |
<> | 144:ef7eb2e8f9f7 | 183 | |
<> | 144:ef7eb2e8f9f7 | 184 | if (stop_bits == 2) { |
<> | 144:ef7eb2e8f9f7 | 185 | init.stopbits = usartStopbits2; |
<> | 144:ef7eb2e8f9f7 | 186 | } else { |
<> | 144:ef7eb2e8f9f7 | 187 | init.stopbits = usartStopbits1; |
<> | 144:ef7eb2e8f9f7 | 188 | } |
<> | 144:ef7eb2e8f9f7 | 189 | switch (parity) { |
<> | 144:ef7eb2e8f9f7 | 190 | case ParityOdd: |
<> | 144:ef7eb2e8f9f7 | 191 | case ParityForced0: |
<> | 144:ef7eb2e8f9f7 | 192 | init.parity = usartOddParity; |
<> | 144:ef7eb2e8f9f7 | 193 | break; |
<> | 144:ef7eb2e8f9f7 | 194 | case ParityEven: |
<> | 144:ef7eb2e8f9f7 | 195 | case ParityForced1: |
<> | 144:ef7eb2e8f9f7 | 196 | init.parity = usartEvenParity; |
<> | 144:ef7eb2e8f9f7 | 197 | break; |
<> | 144:ef7eb2e8f9f7 | 198 | default: /* ParityNone */ |
<> | 144:ef7eb2e8f9f7 | 199 | init.parity = usartNoParity; |
<> | 144:ef7eb2e8f9f7 | 200 | break; |
<> | 144:ef7eb2e8f9f7 | 201 | } |
<> | 144:ef7eb2e8f9f7 | 202 | |
<> | 144:ef7eb2e8f9f7 | 203 | init.enable = usartDisable; |
<> | 144:ef7eb2e8f9f7 | 204 | init.baudrate = baudrate; |
<> | 144:ef7eb2e8f9f7 | 205 | init.oversampling = usartOVS16; |
<> | 144:ef7eb2e8f9f7 | 206 | init.databits = usartDatabits8; |
<> | 144:ef7eb2e8f9f7 | 207 | init.refFreq = REFERENCE_FREQUENCY; |
<> | 144:ef7eb2e8f9f7 | 208 | |
<> | 144:ef7eb2e8f9f7 | 209 | USART_InitAsync(obj->serial.periph.uart, &init); |
<> | 144:ef7eb2e8f9f7 | 210 | } |
<> | 144:ef7eb2e8f9f7 | 211 | } |
<> | 144:ef7eb2e8f9f7 | 212 | /** |
<> | 144:ef7eb2e8f9f7 | 213 | * Get index of serial object, relating it to the physical peripheral. |
<> | 144:ef7eb2e8f9f7 | 214 | * |
<> | 144:ef7eb2e8f9f7 | 215 | * @param obj pointer to serial peripheral (= base address of periph) |
<> | 144:ef7eb2e8f9f7 | 216 | * @return internal index of U(S)ART peripheral |
<> | 144:ef7eb2e8f9f7 | 217 | */ |
<> | 144:ef7eb2e8f9f7 | 218 | static inline uint8_t serial_pointer_get_index(uint32_t serial_ptr) |
<> | 144:ef7eb2e8f9f7 | 219 | { |
<> | 144:ef7eb2e8f9f7 | 220 | uint8_t index = 0; |
<> | 144:ef7eb2e8f9f7 | 221 | #ifdef UART0 |
<> | 144:ef7eb2e8f9f7 | 222 | if (serial_ptr == UART_0) return index; |
<> | 144:ef7eb2e8f9f7 | 223 | index++; |
<> | 144:ef7eb2e8f9f7 | 224 | #endif |
<> | 144:ef7eb2e8f9f7 | 225 | #ifdef UART1 |
<> | 144:ef7eb2e8f9f7 | 226 | if (serial_ptr == UART_1) return index; |
<> | 144:ef7eb2e8f9f7 | 227 | index++; |
<> | 144:ef7eb2e8f9f7 | 228 | #endif |
<> | 144:ef7eb2e8f9f7 | 229 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 230 | if (serial_ptr == USART_0) return index; |
<> | 144:ef7eb2e8f9f7 | 231 | index++; |
<> | 144:ef7eb2e8f9f7 | 232 | #endif |
<> | 144:ef7eb2e8f9f7 | 233 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 234 | if (serial_ptr == USART_1) return index; |
<> | 144:ef7eb2e8f9f7 | 235 | index++; |
<> | 144:ef7eb2e8f9f7 | 236 | #endif |
<> | 144:ef7eb2e8f9f7 | 237 | #ifdef USART2 |
<> | 144:ef7eb2e8f9f7 | 238 | if (serial_ptr == USART_2) return index; |
<> | 144:ef7eb2e8f9f7 | 239 | index++; |
<> | 144:ef7eb2e8f9f7 | 240 | #endif |
<> | 144:ef7eb2e8f9f7 | 241 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 242 | if (serial_ptr == LEUART_0) return index; |
<> | 144:ef7eb2e8f9f7 | 243 | index++; |
<> | 144:ef7eb2e8f9f7 | 244 | #endif |
<> | 144:ef7eb2e8f9f7 | 245 | #ifdef LEUART1 |
<> | 144:ef7eb2e8f9f7 | 246 | if (serial_ptr == LEUART_1) return index; |
<> | 144:ef7eb2e8f9f7 | 247 | index++; |
<> | 144:ef7eb2e8f9f7 | 248 | #endif |
<> | 144:ef7eb2e8f9f7 | 249 | return 0; |
<> | 144:ef7eb2e8f9f7 | 250 | } |
<> | 144:ef7eb2e8f9f7 | 251 | |
<> | 144:ef7eb2e8f9f7 | 252 | /** |
<> | 144:ef7eb2e8f9f7 | 253 | * Get index of serial object, relating it to the physical peripheral. |
<> | 144:ef7eb2e8f9f7 | 254 | * |
<> | 144:ef7eb2e8f9f7 | 255 | * @param obj pointer to serial object (mbed object) |
<> | 144:ef7eb2e8f9f7 | 256 | * @return internal index of U(S)ART peripheral |
<> | 144:ef7eb2e8f9f7 | 257 | */ |
<> | 144:ef7eb2e8f9f7 | 258 | static inline uint8_t serial_get_index(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 259 | { |
<> | 144:ef7eb2e8f9f7 | 260 | return serial_pointer_get_index((uint32_t)obj->serial.periph.uart); |
<> | 144:ef7eb2e8f9f7 | 261 | } |
<> | 144:ef7eb2e8f9f7 | 262 | |
<> | 144:ef7eb2e8f9f7 | 263 | /** |
<> | 144:ef7eb2e8f9f7 | 264 | * Get index of serial object RX IRQ, relating it to the physical peripheral. |
<> | 144:ef7eb2e8f9f7 | 265 | * |
<> | 144:ef7eb2e8f9f7 | 266 | * @param obj pointer to serial object |
<> | 144:ef7eb2e8f9f7 | 267 | * @return internal NVIC RX IRQ index of U(S)ART peripheral |
<> | 144:ef7eb2e8f9f7 | 268 | */ |
<> | 144:ef7eb2e8f9f7 | 269 | static inline IRQn_Type serial_get_rx_irq_index(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 270 | { |
<> | 144:ef7eb2e8f9f7 | 271 | switch ((uint32_t)obj->serial.periph.uart) { |
<> | 144:ef7eb2e8f9f7 | 272 | #ifdef UART0 |
<> | 144:ef7eb2e8f9f7 | 273 | case UART_0: |
<> | 144:ef7eb2e8f9f7 | 274 | return UART0_RX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 275 | #endif |
<> | 144:ef7eb2e8f9f7 | 276 | #ifdef UART1 |
<> | 144:ef7eb2e8f9f7 | 277 | case UART_1: |
<> | 144:ef7eb2e8f9f7 | 278 | return UART1_RX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 279 | #endif |
<> | 144:ef7eb2e8f9f7 | 280 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 281 | case USART_0: |
<> | 144:ef7eb2e8f9f7 | 282 | return USART0_RX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 283 | #endif |
<> | 144:ef7eb2e8f9f7 | 284 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 285 | case USART_1: |
<> | 144:ef7eb2e8f9f7 | 286 | return USART1_RX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 287 | #endif |
<> | 144:ef7eb2e8f9f7 | 288 | #ifdef USART2 |
<> | 144:ef7eb2e8f9f7 | 289 | case USART_2: |
<> | 144:ef7eb2e8f9f7 | 290 | return USART2_RX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 291 | #endif |
<> | 144:ef7eb2e8f9f7 | 292 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 293 | case LEUART_0: |
<> | 144:ef7eb2e8f9f7 | 294 | return LEUART0_IRQn; |
<> | 144:ef7eb2e8f9f7 | 295 | #endif |
<> | 144:ef7eb2e8f9f7 | 296 | #ifdef LEUART1 |
<> | 144:ef7eb2e8f9f7 | 297 | case LEUART_1: |
<> | 144:ef7eb2e8f9f7 | 298 | return LEUART1_IRQn; |
<> | 144:ef7eb2e8f9f7 | 299 | #endif |
<> | 144:ef7eb2e8f9f7 | 300 | default: |
<> | 144:ef7eb2e8f9f7 | 301 | MBED_ASSERT(0); |
<> | 144:ef7eb2e8f9f7 | 302 | } |
<> | 144:ef7eb2e8f9f7 | 303 | return (IRQn_Type)0; |
<> | 144:ef7eb2e8f9f7 | 304 | } |
<> | 144:ef7eb2e8f9f7 | 305 | |
<> | 144:ef7eb2e8f9f7 | 306 | /** |
<> | 144:ef7eb2e8f9f7 | 307 | * Get index of serial object TX IRQ, relating it to the physical peripheral. |
<> | 144:ef7eb2e8f9f7 | 308 | * |
<> | 144:ef7eb2e8f9f7 | 309 | * @param obj pointer to serial object |
<> | 144:ef7eb2e8f9f7 | 310 | * @return internal NVIC TX IRQ index of U(S)ART peripheral |
<> | 144:ef7eb2e8f9f7 | 311 | */ |
<> | 144:ef7eb2e8f9f7 | 312 | static inline IRQn_Type serial_get_tx_irq_index(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 313 | { |
<> | 144:ef7eb2e8f9f7 | 314 | switch ((uint32_t)obj->serial.periph.uart) { |
<> | 144:ef7eb2e8f9f7 | 315 | #ifdef UART0 |
<> | 144:ef7eb2e8f9f7 | 316 | case UART_0: |
<> | 144:ef7eb2e8f9f7 | 317 | return UART0_TX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 318 | #endif |
<> | 144:ef7eb2e8f9f7 | 319 | #ifdef UART1 |
<> | 144:ef7eb2e8f9f7 | 320 | case UART_1: |
<> | 144:ef7eb2e8f9f7 | 321 | return UART1_TX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 322 | #endif |
<> | 144:ef7eb2e8f9f7 | 323 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 324 | case USART_0: |
<> | 144:ef7eb2e8f9f7 | 325 | return USART0_TX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 326 | #endif |
<> | 144:ef7eb2e8f9f7 | 327 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 328 | case USART_1: |
<> | 144:ef7eb2e8f9f7 | 329 | return USART1_TX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 330 | #endif |
<> | 144:ef7eb2e8f9f7 | 331 | #ifdef USART2 |
<> | 144:ef7eb2e8f9f7 | 332 | case USART_2: |
<> | 144:ef7eb2e8f9f7 | 333 | return USART2_TX_IRQn; |
<> | 144:ef7eb2e8f9f7 | 334 | #endif |
<> | 144:ef7eb2e8f9f7 | 335 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 336 | case LEUART_0: |
<> | 144:ef7eb2e8f9f7 | 337 | return LEUART0_IRQn; |
<> | 144:ef7eb2e8f9f7 | 338 | #endif |
<> | 144:ef7eb2e8f9f7 | 339 | #ifdef LEUART1 |
<> | 144:ef7eb2e8f9f7 | 340 | case LEUART_1: |
<> | 144:ef7eb2e8f9f7 | 341 | return LEUART1_IRQn; |
<> | 144:ef7eb2e8f9f7 | 342 | #endif |
<> | 144:ef7eb2e8f9f7 | 343 | default: |
<> | 144:ef7eb2e8f9f7 | 344 | MBED_ASSERT(0); |
<> | 144:ef7eb2e8f9f7 | 345 | } |
<> | 144:ef7eb2e8f9f7 | 346 | return (IRQn_Type)0; |
<> | 144:ef7eb2e8f9f7 | 347 | } |
<> | 144:ef7eb2e8f9f7 | 348 | |
<> | 144:ef7eb2e8f9f7 | 349 | /** |
<> | 144:ef7eb2e8f9f7 | 350 | * Get clock tree for serial peripheral pointed to by obj. |
<> | 144:ef7eb2e8f9f7 | 351 | * |
<> | 144:ef7eb2e8f9f7 | 352 | * @param obj pointer to serial object |
<> | 144:ef7eb2e8f9f7 | 353 | * @return CMU_Clock_TypeDef for U(S)ART |
<> | 144:ef7eb2e8f9f7 | 354 | */ |
<> | 144:ef7eb2e8f9f7 | 355 | inline CMU_Clock_TypeDef serial_get_clock(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 356 | { |
<> | 144:ef7eb2e8f9f7 | 357 | switch ((uint32_t)obj->serial.periph.uart) { |
<> | 144:ef7eb2e8f9f7 | 358 | #ifdef UART0 |
<> | 144:ef7eb2e8f9f7 | 359 | case UART_0: |
<> | 144:ef7eb2e8f9f7 | 360 | return cmuClock_UART0; |
<> | 144:ef7eb2e8f9f7 | 361 | #endif |
<> | 144:ef7eb2e8f9f7 | 362 | #ifdef UART1 |
<> | 144:ef7eb2e8f9f7 | 363 | case UART_1: |
<> | 144:ef7eb2e8f9f7 | 364 | return cmuClock_UART1; |
<> | 144:ef7eb2e8f9f7 | 365 | #endif |
<> | 144:ef7eb2e8f9f7 | 366 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 367 | case USART_0: |
<> | 144:ef7eb2e8f9f7 | 368 | return cmuClock_USART0; |
<> | 144:ef7eb2e8f9f7 | 369 | #endif |
<> | 144:ef7eb2e8f9f7 | 370 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 371 | case USART_1: |
<> | 144:ef7eb2e8f9f7 | 372 | return cmuClock_USART1; |
<> | 144:ef7eb2e8f9f7 | 373 | #endif |
<> | 144:ef7eb2e8f9f7 | 374 | #ifdef USART2 |
<> | 144:ef7eb2e8f9f7 | 375 | case USART_2: |
<> | 144:ef7eb2e8f9f7 | 376 | return cmuClock_USART2; |
<> | 144:ef7eb2e8f9f7 | 377 | #endif |
<> | 144:ef7eb2e8f9f7 | 378 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 379 | case LEUART_0: |
<> | 144:ef7eb2e8f9f7 | 380 | return cmuClock_LEUART0; |
<> | 144:ef7eb2e8f9f7 | 381 | #endif |
<> | 144:ef7eb2e8f9f7 | 382 | #ifdef LEUART1 |
<> | 144:ef7eb2e8f9f7 | 383 | case LEUART_1: |
<> | 144:ef7eb2e8f9f7 | 384 | return cmuClock_LEUART1; |
<> | 144:ef7eb2e8f9f7 | 385 | #endif |
<> | 144:ef7eb2e8f9f7 | 386 | default: |
<> | 144:ef7eb2e8f9f7 | 387 | return cmuClock_HFPER; |
<> | 144:ef7eb2e8f9f7 | 388 | } |
<> | 144:ef7eb2e8f9f7 | 389 | } |
<> | 144:ef7eb2e8f9f7 | 390 | |
<> | 144:ef7eb2e8f9f7 | 391 | void serial_preinit(serial_t *obj, PinName tx, PinName rx) |
<> | 144:ef7eb2e8f9f7 | 392 | { |
<> | 144:ef7eb2e8f9f7 | 393 | /* Get UART object connected to the given pins */ |
<> | 144:ef7eb2e8f9f7 | 394 | UARTName uart_tx = (UARTName) pinmap_peripheral(tx, PinMap_UART_TX); |
<> | 144:ef7eb2e8f9f7 | 395 | UARTName uart_rx = (UARTName) pinmap_peripheral(rx, PinMap_UART_RX); |
<> | 144:ef7eb2e8f9f7 | 396 | /* Check that pins are connected to same UART */ |
<> | 144:ef7eb2e8f9f7 | 397 | UARTName uart = (UARTName) pinmap_merge(uart_tx, uart_rx); |
<> | 144:ef7eb2e8f9f7 | 398 | MBED_ASSERT((int) uart != NC); |
<> | 144:ef7eb2e8f9f7 | 399 | |
<> | 144:ef7eb2e8f9f7 | 400 | obj->serial.periph.uart = (USART_TypeDef *) uart; |
<> | 144:ef7eb2e8f9f7 | 401 | |
<> | 144:ef7eb2e8f9f7 | 402 | /* Get location */ |
<> | 144:ef7eb2e8f9f7 | 403 | uint32_t uart_tx_loc = pin_location(tx, PinMap_UART_TX); |
<> | 144:ef7eb2e8f9f7 | 404 | uint32_t uart_rx_loc = pin_location(rx, PinMap_UART_RX); |
<> | 144:ef7eb2e8f9f7 | 405 | |
<> | 144:ef7eb2e8f9f7 | 406 | #if defined(_SILICON_LABS_32B_PLATFORM_1) |
<> | 144:ef7eb2e8f9f7 | 407 | /* Check that pins are used by same location for the given UART */ |
<> | 144:ef7eb2e8f9f7 | 408 | obj->serial.location = pinmap_merge(uart_tx_loc, uart_rx_loc); |
<> | 144:ef7eb2e8f9f7 | 409 | MBED_ASSERT(obj->serial.location != (uint32_t)NC); |
<> | 144:ef7eb2e8f9f7 | 410 | #else |
<> | 144:ef7eb2e8f9f7 | 411 | obj->serial.location_tx = uart_tx_loc; |
<> | 144:ef7eb2e8f9f7 | 412 | obj->serial.location_rx = uart_rx_loc; |
<> | 144:ef7eb2e8f9f7 | 413 | #endif |
<> | 144:ef7eb2e8f9f7 | 414 | |
<> | 144:ef7eb2e8f9f7 | 415 | /* Store pins in object for easy disabling in serial_free() */ |
<> | 144:ef7eb2e8f9f7 | 416 | //TODO: replace all usages with AF_USARTx_TX_PORT(location) macro to save 8 bytes from struct |
<> | 144:ef7eb2e8f9f7 | 417 | obj->serial.rx_pin = rx; |
<> | 144:ef7eb2e8f9f7 | 418 | obj->serial.tx_pin = tx; |
<> | 144:ef7eb2e8f9f7 | 419 | |
<> | 144:ef7eb2e8f9f7 | 420 | /* Select interrupt */ |
<> | 144:ef7eb2e8f9f7 | 421 | switch ((uint32_t)obj->serial.periph.uart) { |
<> | 144:ef7eb2e8f9f7 | 422 | #ifdef UART0 |
<> | 144:ef7eb2e8f9f7 | 423 | case UART_0: |
<> | 144:ef7eb2e8f9f7 | 424 | NVIC_SetVector(UART0_RX_IRQn, (uint32_t) &uart0_rx_irq); |
<> | 144:ef7eb2e8f9f7 | 425 | NVIC_SetVector(UART0_TX_IRQn, (uint32_t) &uart0_tx_irq); |
<> | 144:ef7eb2e8f9f7 | 426 | NVIC_SetPriority(UART0_TX_IRQn, 1); |
<> | 144:ef7eb2e8f9f7 | 427 | break; |
<> | 144:ef7eb2e8f9f7 | 428 | #endif |
<> | 144:ef7eb2e8f9f7 | 429 | #ifdef UART1 |
<> | 144:ef7eb2e8f9f7 | 430 | case UART_1: |
<> | 144:ef7eb2e8f9f7 | 431 | NVIC_SetVector(UART1_RX_IRQn, (uint32_t) &uart1_rx_irq); |
<> | 144:ef7eb2e8f9f7 | 432 | NVIC_SetVector(UART1_TX_IRQn, (uint32_t) &uart1_tx_irq); |
<> | 144:ef7eb2e8f9f7 | 433 | NVIC_SetPriority(UART1_TX_IRQn, 1); |
<> | 144:ef7eb2e8f9f7 | 434 | break; |
<> | 144:ef7eb2e8f9f7 | 435 | #endif |
<> | 144:ef7eb2e8f9f7 | 436 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 437 | case USART_0: |
<> | 144:ef7eb2e8f9f7 | 438 | NVIC_SetVector(USART0_RX_IRQn, (uint32_t) &usart0_rx_irq); |
<> | 144:ef7eb2e8f9f7 | 439 | NVIC_SetVector(USART0_TX_IRQn, (uint32_t) &usart0_tx_irq); |
<> | 144:ef7eb2e8f9f7 | 440 | NVIC_SetPriority(USART0_TX_IRQn, 1); |
<> | 144:ef7eb2e8f9f7 | 441 | break; |
<> | 144:ef7eb2e8f9f7 | 442 | #endif |
<> | 144:ef7eb2e8f9f7 | 443 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 444 | case USART_1: |
<> | 144:ef7eb2e8f9f7 | 445 | NVIC_SetVector(USART1_RX_IRQn, (uint32_t) &usart1_rx_irq); |
<> | 144:ef7eb2e8f9f7 | 446 | NVIC_SetVector(USART1_TX_IRQn, (uint32_t) &usart1_tx_irq); |
<> | 144:ef7eb2e8f9f7 | 447 | NVIC_SetPriority(USART1_TX_IRQn, 1); |
<> | 144:ef7eb2e8f9f7 | 448 | break; |
<> | 144:ef7eb2e8f9f7 | 449 | #endif |
<> | 144:ef7eb2e8f9f7 | 450 | #ifdef USART2 |
<> | 144:ef7eb2e8f9f7 | 451 | case USART_2: |
<> | 144:ef7eb2e8f9f7 | 452 | NVIC_SetVector(USART2_RX_IRQn, (uint32_t) &usart2_rx_irq); |
<> | 144:ef7eb2e8f9f7 | 453 | NVIC_SetVector(USART2_TX_IRQn, (uint32_t) &usart2_tx_irq); |
<> | 144:ef7eb2e8f9f7 | 454 | NVIC_SetPriority(USART2_TX_IRQn, 1); |
<> | 144:ef7eb2e8f9f7 | 455 | break; |
<> | 144:ef7eb2e8f9f7 | 456 | #endif |
<> | 144:ef7eb2e8f9f7 | 457 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 458 | case LEUART_0: |
<> | 144:ef7eb2e8f9f7 | 459 | NVIC_SetVector(LEUART0_IRQn, (uint32_t) &leuart0_irq); |
<> | 144:ef7eb2e8f9f7 | 460 | break; |
<> | 144:ef7eb2e8f9f7 | 461 | #endif |
<> | 144:ef7eb2e8f9f7 | 462 | #ifdef LEUART1 |
<> | 144:ef7eb2e8f9f7 | 463 | case LEUART_1: |
<> | 144:ef7eb2e8f9f7 | 464 | NVIC_SetVector(LEUART1_IRQn, (uint32_t) &leuart1_irq); |
<> | 144:ef7eb2e8f9f7 | 465 | break; |
<> | 144:ef7eb2e8f9f7 | 466 | #endif |
<> | 144:ef7eb2e8f9f7 | 467 | } |
<> | 144:ef7eb2e8f9f7 | 468 | } |
<> | 144:ef7eb2e8f9f7 | 469 | |
<> | 144:ef7eb2e8f9f7 | 470 | static void serial_enable_pins(serial_t *obj, uint8_t enable) |
<> | 144:ef7eb2e8f9f7 | 471 | { |
<> | 144:ef7eb2e8f9f7 | 472 | if (enable) { |
<> | 144:ef7eb2e8f9f7 | 473 | /* Configure GPIO pins*/ |
<> | 144:ef7eb2e8f9f7 | 474 | if(obj->serial.rx_pin != NC) { |
<> | 144:ef7eb2e8f9f7 | 475 | pin_mode(obj->serial.rx_pin, Input); |
<> | 144:ef7eb2e8f9f7 | 476 | } |
<> | 144:ef7eb2e8f9f7 | 477 | /* Set DOUT first to prevent glitches */ |
<> | 144:ef7eb2e8f9f7 | 478 | if(obj->serial.tx_pin != NC) { |
<> | 144:ef7eb2e8f9f7 | 479 | GPIO_PinOutSet((GPIO_Port_TypeDef)(obj->serial.tx_pin >> 4 & 0xF), obj->serial.tx_pin & 0xF); |
<> | 144:ef7eb2e8f9f7 | 480 | pin_mode(obj->serial.tx_pin, PushPull); |
<> | 144:ef7eb2e8f9f7 | 481 | } |
<> | 144:ef7eb2e8f9f7 | 482 | } else { |
<> | 144:ef7eb2e8f9f7 | 483 | if(obj->serial.rx_pin != NC) { |
<> | 144:ef7eb2e8f9f7 | 484 | pin_mode(obj->serial.rx_pin, Disabled); |
<> | 144:ef7eb2e8f9f7 | 485 | } |
<> | 144:ef7eb2e8f9f7 | 486 | if(obj->serial.tx_pin != NC) { |
<> | 144:ef7eb2e8f9f7 | 487 | pin_mode(obj->serial.tx_pin, Disabled); |
<> | 144:ef7eb2e8f9f7 | 488 | } |
<> | 144:ef7eb2e8f9f7 | 489 | } |
<> | 144:ef7eb2e8f9f7 | 490 | } |
<> | 144:ef7eb2e8f9f7 | 491 | |
<> | 144:ef7eb2e8f9f7 | 492 | static void serial_set_route(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 493 | { |
<> | 144:ef7eb2e8f9f7 | 494 | /* Enable pins for UART at correct location */ |
<> | 144:ef7eb2e8f9f7 | 495 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 496 | #ifdef _LEUART_ROUTE_LOCATION_SHIFT |
<> | 144:ef7eb2e8f9f7 | 497 | obj->serial.periph.leuart->ROUTE = (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT); |
<> | 144:ef7eb2e8f9f7 | 498 | if(obj->serial.tx_pin != (uint32_t)NC) { |
<> | 144:ef7eb2e8f9f7 | 499 | obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_TXPEN; |
<> | 144:ef7eb2e8f9f7 | 500 | } else { |
<> | 144:ef7eb2e8f9f7 | 501 | obj->serial.periph.leuart->ROUTE &= ~LEUART_ROUTE_TXPEN; |
<> | 144:ef7eb2e8f9f7 | 502 | } |
<> | 144:ef7eb2e8f9f7 | 503 | if(obj->serial.rx_pin != (uint32_t)NC) { |
<> | 144:ef7eb2e8f9f7 | 504 | obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_RXPEN; |
<> | 144:ef7eb2e8f9f7 | 505 | } else { |
<> | 144:ef7eb2e8f9f7 | 506 | obj->serial.periph.leuart->CMD = LEUART_CMD_RXBLOCKEN; |
<> | 144:ef7eb2e8f9f7 | 507 | obj->serial.periph.leuart->ROUTE &= ~LEUART_ROUTE_RXPEN; |
<> | 144:ef7eb2e8f9f7 | 508 | } |
<> | 144:ef7eb2e8f9f7 | 509 | #else |
<> | 144:ef7eb2e8f9f7 | 510 | if(obj->serial.location_tx != NC) { |
<> | 144:ef7eb2e8f9f7 | 511 | obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _LEUART_ROUTELOC0_TXLOC_SHIFT); |
<> | 144:ef7eb2e8f9f7 | 512 | obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK)) | LEUART_ROUTEPEN_TXPEN; |
<> | 144:ef7eb2e8f9f7 | 513 | } else { |
<> | 144:ef7eb2e8f9f7 | 514 | obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK)); |
<> | 144:ef7eb2e8f9f7 | 515 | } |
<> | 144:ef7eb2e8f9f7 | 516 | if(obj->serial.location_rx != NC) { |
<> | 144:ef7eb2e8f9f7 | 517 | obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _LEUART_ROUTELOC0_RXLOC_SHIFT); |
<> | 144:ef7eb2e8f9f7 | 518 | obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK)) | LEUART_ROUTEPEN_RXPEN; |
<> | 144:ef7eb2e8f9f7 | 519 | } else { |
<> | 144:ef7eb2e8f9f7 | 520 | obj->serial.periph.leuart->CMD = LEUART_CMD_RXBLOCKEN; |
<> | 144:ef7eb2e8f9f7 | 521 | obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK)); |
<> | 144:ef7eb2e8f9f7 | 522 | } |
<> | 144:ef7eb2e8f9f7 | 523 | #endif |
<> | 144:ef7eb2e8f9f7 | 524 | } else { |
<> | 144:ef7eb2e8f9f7 | 525 | #ifdef _USART_ROUTE_LOCATION_SHIFT |
<> | 144:ef7eb2e8f9f7 | 526 | obj->serial.periph.uart->ROUTE = (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT); |
<> | 144:ef7eb2e8f9f7 | 527 | if(obj->serial.tx_pin != (uint32_t)NC) { |
<> | 144:ef7eb2e8f9f7 | 528 | obj->serial.periph.uart->ROUTE |= USART_ROUTE_TXPEN; |
<> | 144:ef7eb2e8f9f7 | 529 | } else { |
<> | 144:ef7eb2e8f9f7 | 530 | obj->serial.periph.uart->ROUTE &= ~USART_ROUTE_TXPEN; |
<> | 144:ef7eb2e8f9f7 | 531 | } |
<> | 144:ef7eb2e8f9f7 | 532 | if(obj->serial.rx_pin != (uint32_t)NC) { |
<> | 144:ef7eb2e8f9f7 | 533 | obj->serial.periph.uart->ROUTE |= USART_ROUTE_RXPEN; |
<> | 144:ef7eb2e8f9f7 | 534 | } else { |
<> | 144:ef7eb2e8f9f7 | 535 | obj->serial.periph.uart->CMD = USART_CMD_RXBLOCKEN; |
<> | 144:ef7eb2e8f9f7 | 536 | obj->serial.periph.uart->ROUTE &= ~USART_ROUTE_RXPEN; |
<> | 144:ef7eb2e8f9f7 | 537 | } |
<> | 144:ef7eb2e8f9f7 | 538 | #else |
<> | 144:ef7eb2e8f9f7 | 539 | if(obj->serial.location_tx != NC) { |
<> | 144:ef7eb2e8f9f7 | 540 | obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT); |
<> | 144:ef7eb2e8f9f7 | 541 | obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK)) | USART_ROUTEPEN_TXPEN; |
<> | 144:ef7eb2e8f9f7 | 542 | } else { |
<> | 144:ef7eb2e8f9f7 | 543 | obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK)); |
<> | 144:ef7eb2e8f9f7 | 544 | } |
<> | 144:ef7eb2e8f9f7 | 545 | if(obj->serial.location_rx != NC) { |
<> | 144:ef7eb2e8f9f7 | 546 | obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT); |
<> | 144:ef7eb2e8f9f7 | 547 | obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK)) | USART_ROUTEPEN_RXPEN; |
<> | 144:ef7eb2e8f9f7 | 548 | } else { |
<> | 144:ef7eb2e8f9f7 | 549 | obj->serial.periph.uart->CMD = USART_CMD_RXBLOCKEN; |
<> | 144:ef7eb2e8f9f7 | 550 | obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK)); |
<> | 144:ef7eb2e8f9f7 | 551 | } |
<> | 144:ef7eb2e8f9f7 | 552 | #endif |
<> | 144:ef7eb2e8f9f7 | 553 | } |
<> | 144:ef7eb2e8f9f7 | 554 | } |
<> | 144:ef7eb2e8f9f7 | 555 | |
<> | 144:ef7eb2e8f9f7 | 556 | void serial_init(serial_t *obj, PinName tx, PinName rx) |
<> | 144:ef7eb2e8f9f7 | 557 | { |
<> | 144:ef7eb2e8f9f7 | 558 | uint32_t baudrate; |
<> | 144:ef7eb2e8f9f7 | 559 | uint32_t uart_for_stdio = false; |
<> | 144:ef7eb2e8f9f7 | 560 | |
<> | 144:ef7eb2e8f9f7 | 561 | serial_preinit(obj, tx, rx); |
<> | 144:ef7eb2e8f9f7 | 562 | |
<> | 144:ef7eb2e8f9f7 | 563 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 564 | // Set up LEUART clock tree |
<> | 144:ef7eb2e8f9f7 | 565 | #ifdef LEUART_USING_LFXO |
<> | 144:ef7eb2e8f9f7 | 566 | //set to use LFXO |
<> | 144:ef7eb2e8f9f7 | 567 | CMU_ClockEnable(cmuClock_CORELE, true); |
<> | 144:ef7eb2e8f9f7 | 568 | CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO); |
<> | 144:ef7eb2e8f9f7 | 569 | #else |
<> | 144:ef7eb2e8f9f7 | 570 | //set to use high-speed clock |
<> | 144:ef7eb2e8f9f7 | 571 | #ifdef _SILICON_LABS_32B_PLATFORM_2 |
<> | 144:ef7eb2e8f9f7 | 572 | CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_HFCLKLE); |
<> | 144:ef7eb2e8f9f7 | 573 | #else |
<> | 144:ef7eb2e8f9f7 | 574 | CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2); |
<> | 144:ef7eb2e8f9f7 | 575 | #endif |
<> | 144:ef7eb2e8f9f7 | 576 | #endif |
<> | 144:ef7eb2e8f9f7 | 577 | } |
<> | 144:ef7eb2e8f9f7 | 578 | |
<> | 144:ef7eb2e8f9f7 | 579 | CMU_ClockEnable(serial_get_clock(obj), true); |
<> | 144:ef7eb2e8f9f7 | 580 | |
<> | 144:ef7eb2e8f9f7 | 581 | /* Limitations of board controller: CDC port only supports 115kbaud */ |
<> | 144:ef7eb2e8f9f7 | 582 | if(((tx == STDIO_UART_TX) || (rx == STDIO_UART_RX)) |
<> | 144:ef7eb2e8f9f7 | 583 | && (obj->serial.periph.uart == (USART_TypeDef*)STDIO_UART ) |
<> | 144:ef7eb2e8f9f7 | 584 | ) { |
<> | 144:ef7eb2e8f9f7 | 585 | baudrate = 115200; |
<> | 144:ef7eb2e8f9f7 | 586 | uart_for_stdio = true; |
<> | 144:ef7eb2e8f9f7 | 587 | } else { |
<> | 144:ef7eb2e8f9f7 | 588 | baudrate = 9600; |
<> | 144:ef7eb2e8f9f7 | 589 | } |
<> | 144:ef7eb2e8f9f7 | 590 | |
<> | 144:ef7eb2e8f9f7 | 591 | /* Configure UART for async operation */ |
<> | 144:ef7eb2e8f9f7 | 592 | uart_init(obj, baudrate, ParityNone, 1); |
<> | 144:ef7eb2e8f9f7 | 593 | |
<> | 144:ef7eb2e8f9f7 | 594 | /* Enable pins for UART at correct location */ |
<> | 144:ef7eb2e8f9f7 | 595 | serial_set_route(obj); |
<> | 144:ef7eb2e8f9f7 | 596 | |
<> | 144:ef7eb2e8f9f7 | 597 | /* Reset interrupts */ |
<> | 144:ef7eb2e8f9f7 | 598 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 599 | obj->serial.periph.leuart->IFC = LEUART_IFC_TXC; |
<> | 144:ef7eb2e8f9f7 | 600 | obj->serial.periph.leuart->CTRL |= LEUART_CTRL_RXDMAWU | LEUART_CTRL_TXDMAWU; |
<> | 144:ef7eb2e8f9f7 | 601 | } else { |
<> | 144:ef7eb2e8f9f7 | 602 | obj->serial.periph.uart->IFC = USART_IFC_TXC; |
<> | 144:ef7eb2e8f9f7 | 603 | } |
<> | 144:ef7eb2e8f9f7 | 604 | |
<> | 144:ef7eb2e8f9f7 | 605 | /* If this is the UART to be used for stdio, copy it to the stdio_uart struct */ |
<> | 144:ef7eb2e8f9f7 | 606 | if(uart_for_stdio) { |
<> | 144:ef7eb2e8f9f7 | 607 | stdio_uart_inited = 1; |
<> | 144:ef7eb2e8f9f7 | 608 | memcpy(&stdio_uart, obj, sizeof(serial_t)); |
<> | 144:ef7eb2e8f9f7 | 609 | } |
<> | 144:ef7eb2e8f9f7 | 610 | |
<> | 144:ef7eb2e8f9f7 | 611 | serial_enable_pins(obj, true); |
<> | 144:ef7eb2e8f9f7 | 612 | serial_enable(obj, true); |
<> | 144:ef7eb2e8f9f7 | 613 | |
<> | 144:ef7eb2e8f9f7 | 614 | obj->serial.dmaOptionsTX.dmaChannel = -1; |
<> | 144:ef7eb2e8f9f7 | 615 | obj->serial.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC; |
<> | 144:ef7eb2e8f9f7 | 616 | |
<> | 144:ef7eb2e8f9f7 | 617 | obj->serial.dmaOptionsRX.dmaChannel = -1; |
<> | 144:ef7eb2e8f9f7 | 618 | obj->serial.dmaOptionsRX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC; |
<> | 144:ef7eb2e8f9f7 | 619 | |
<> | 144:ef7eb2e8f9f7 | 620 | } |
<> | 144:ef7eb2e8f9f7 | 621 | |
<> | 144:ef7eb2e8f9f7 | 622 | void serial_free(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 623 | { |
<> | 144:ef7eb2e8f9f7 | 624 | if( LEUART_REF_VALID(obj->serial.periph.leuart) ) { |
<> | 144:ef7eb2e8f9f7 | 625 | LEUART_Enable(obj->serial.periph.leuart, leuartDisable); |
<> | 144:ef7eb2e8f9f7 | 626 | } else { |
<> | 144:ef7eb2e8f9f7 | 627 | USART_Enable(obj->serial.periph.uart, usartDisable); |
<> | 144:ef7eb2e8f9f7 | 628 | } |
<> | 144:ef7eb2e8f9f7 | 629 | serial_enable_pins(obj, false); |
<> | 144:ef7eb2e8f9f7 | 630 | } |
<> | 144:ef7eb2e8f9f7 | 631 | |
<> | 144:ef7eb2e8f9f7 | 632 | static void serial_enable(serial_t *obj, uint8_t enable) |
<> | 144:ef7eb2e8f9f7 | 633 | { |
<> | 144:ef7eb2e8f9f7 | 634 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 635 | if (enable) { |
<> | 144:ef7eb2e8f9f7 | 636 | LEUART_Enable(obj->serial.periph.leuart, leuartEnable); |
<> | 144:ef7eb2e8f9f7 | 637 | } else { |
<> | 144:ef7eb2e8f9f7 | 638 | LEUART_Enable(obj->serial.periph.leuart, leuartDisable); |
<> | 144:ef7eb2e8f9f7 | 639 | } |
<> | 144:ef7eb2e8f9f7 | 640 | } else { |
<> | 144:ef7eb2e8f9f7 | 641 | if (enable) { |
<> | 144:ef7eb2e8f9f7 | 642 | USART_Enable(obj->serial.periph.uart, usartEnable); |
<> | 144:ef7eb2e8f9f7 | 643 | } else { |
<> | 144:ef7eb2e8f9f7 | 644 | USART_Enable(obj->serial.periph.uart, usartDisable); |
<> | 144:ef7eb2e8f9f7 | 645 | } |
<> | 144:ef7eb2e8f9f7 | 646 | } |
<> | 144:ef7eb2e8f9f7 | 647 | serial_irq_ids[serial_get_index(obj)] = 0; |
<> | 144:ef7eb2e8f9f7 | 648 | } |
<> | 144:ef7eb2e8f9f7 | 649 | |
<> | 144:ef7eb2e8f9f7 | 650 | /** |
<> | 144:ef7eb2e8f9f7 | 651 | * Set UART baud rate |
<> | 144:ef7eb2e8f9f7 | 652 | */ |
<> | 144:ef7eb2e8f9f7 | 653 | void serial_baud(serial_t *obj, int baudrate) |
<> | 144:ef7eb2e8f9f7 | 654 | { |
<> | 144:ef7eb2e8f9f7 | 655 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 656 | serial_leuart_baud(obj, baudrate); |
<> | 144:ef7eb2e8f9f7 | 657 | } else { |
<> | 144:ef7eb2e8f9f7 | 658 | USART_BaudrateAsyncSet(obj->serial.periph.uart, REFERENCE_FREQUENCY, (uint32_t)baudrate, usartOVS16); |
<> | 144:ef7eb2e8f9f7 | 659 | } |
<> | 144:ef7eb2e8f9f7 | 660 | } |
<> | 144:ef7eb2e8f9f7 | 661 | |
<> | 144:ef7eb2e8f9f7 | 662 | /** |
<> | 144:ef7eb2e8f9f7 | 663 | * Set LEUART baud rate |
<> | 144:ef7eb2e8f9f7 | 664 | * Calculate whether LF or HF clock should be used. |
<> | 144:ef7eb2e8f9f7 | 665 | */ |
<> | 144:ef7eb2e8f9f7 | 666 | static void serial_leuart_baud(serial_t *obj, int baudrate) |
<> | 144:ef7eb2e8f9f7 | 667 | { |
<> | 144:ef7eb2e8f9f7 | 668 | #ifdef LEUART_USING_LFXO |
<> | 144:ef7eb2e8f9f7 | 669 | /* check if baudrate is within allowed range */ |
<> | 144:ef7eb2e8f9f7 | 670 | #if defined(_SILICON_LABS_32B_PLATFORM_2) |
<> | 144:ef7eb2e8f9f7 | 671 | // P2 has 9 bits + 5 fractional bits in LEUART CLKDIV register |
<> | 144:ef7eb2e8f9f7 | 672 | MBED_ASSERT(baudrate >= (LEUART_LF_REF_FREQ >> 9)); |
<> | 144:ef7eb2e8f9f7 | 673 | #else |
<> | 144:ef7eb2e8f9f7 | 674 | // P1 has 7 bits + 5 fractional bits in LEUART CLKDIV register |
<> | 144:ef7eb2e8f9f7 | 675 | MBED_ASSERT(baudrate >= (LEUART_LF_REF_FREQ >> 7)); |
<> | 144:ef7eb2e8f9f7 | 676 | #endif |
<> | 144:ef7eb2e8f9f7 | 677 | |
<> | 144:ef7eb2e8f9f7 | 678 | if(baudrate > (LEUART_LF_REF_FREQ >> 1)){ |
<> | 144:ef7eb2e8f9f7 | 679 | // Baudrate is bigger than LFCLK/2 - we need to use the HF clock |
<> | 144:ef7eb2e8f9f7 | 680 | uint8_t divisor = 1; |
<> | 144:ef7eb2e8f9f7 | 681 | |
<> | 144:ef7eb2e8f9f7 | 682 | #if defined(_SILICON_LABS_32B_PLATFORM_2) |
<> | 144:ef7eb2e8f9f7 | 683 | /* Check if baudrate is within allowed range: (HFCLK/4096, HFCLK/2] */ |
<> | 144:ef7eb2e8f9f7 | 684 | MBED_ASSERT((baudrate <= (LEUART_HF_REF_FREQ >> 1)) && (baudrate > (LEUART_HF_REF_FREQ >> 12))); |
<> | 144:ef7eb2e8f9f7 | 685 | |
<> | 144:ef7eb2e8f9f7 | 686 | CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_HFCLKLE); |
<> | 144:ef7eb2e8f9f7 | 687 | |
<> | 144:ef7eb2e8f9f7 | 688 | if(baudrate > (LEUART_HF_REF_FREQ >> 9)){ |
<> | 144:ef7eb2e8f9f7 | 689 | divisor = 1; |
<> | 144:ef7eb2e8f9f7 | 690 | }else if(baudrate > (LEUART_HF_REF_FREQ >> 10)){ |
<> | 144:ef7eb2e8f9f7 | 691 | divisor = 2; |
<> | 144:ef7eb2e8f9f7 | 692 | }else if(baudrate > (LEUART_HF_REF_FREQ >> 11)){ |
<> | 144:ef7eb2e8f9f7 | 693 | divisor = 4; |
<> | 144:ef7eb2e8f9f7 | 694 | }else{ |
<> | 144:ef7eb2e8f9f7 | 695 | divisor = 8; |
<> | 144:ef7eb2e8f9f7 | 696 | } |
<> | 144:ef7eb2e8f9f7 | 697 | #else // P1 |
<> | 144:ef7eb2e8f9f7 | 698 | /* Check if baudrate is within allowed range */ |
<> | 144:ef7eb2e8f9f7 | 699 | MBED_ASSERT((baudrate <= (LEUART_HF_REF_FREQ >> 1)) && (baudrate > (LEUART_HF_REF_FREQ >> 10))); |
<> | 144:ef7eb2e8f9f7 | 700 | |
<> | 144:ef7eb2e8f9f7 | 701 | CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2); |
<> | 144:ef7eb2e8f9f7 | 702 | |
<> | 144:ef7eb2e8f9f7 | 703 | if(baudrate > (LEUART_HF_REF_FREQ >> 7)){ |
<> | 144:ef7eb2e8f9f7 | 704 | divisor = 1; |
<> | 144:ef7eb2e8f9f7 | 705 | }else if(baudrate > (LEUART_HF_REF_FREQ >> 8)){ |
<> | 144:ef7eb2e8f9f7 | 706 | divisor = 2; |
<> | 144:ef7eb2e8f9f7 | 707 | }else if(baudrate > (LEUART_HF_REF_FREQ >> 9)){ |
<> | 144:ef7eb2e8f9f7 | 708 | divisor = 4; |
<> | 144:ef7eb2e8f9f7 | 709 | }else{ |
<> | 144:ef7eb2e8f9f7 | 710 | divisor = 8; |
<> | 144:ef7eb2e8f9f7 | 711 | } |
<> | 144:ef7eb2e8f9f7 | 712 | #endif |
<> | 144:ef7eb2e8f9f7 | 713 | CMU_ClockDivSet(serial_get_clock(obj), divisor); |
<> | 144:ef7eb2e8f9f7 | 714 | LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_HF_REF_FREQ/divisor, (uint32_t)baudrate); |
<> | 144:ef7eb2e8f9f7 | 715 | }else{ |
<> | 144:ef7eb2e8f9f7 | 716 | CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO); |
<> | 144:ef7eb2e8f9f7 | 717 | CMU_ClockDivSet(serial_get_clock(obj), 1); |
<> | 144:ef7eb2e8f9f7 | 718 | LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_LF_REF_FREQ, (uint32_t)baudrate); |
<> | 144:ef7eb2e8f9f7 | 719 | } |
<> | 144:ef7eb2e8f9f7 | 720 | #else |
<> | 144:ef7eb2e8f9f7 | 721 | /* check if baudrate is within allowed range */ |
<> | 144:ef7eb2e8f9f7 | 722 | MBED_ASSERT((baudrate > (LEUART_REF_FREQ >> 10)) && (baudrate <= (LEUART_REF_FREQ >> 1))); |
<> | 144:ef7eb2e8f9f7 | 723 | uint8_t divisor = 1; |
<> | 144:ef7eb2e8f9f7 | 724 | if(baudrate > (LEUART_REF_FREQ >> 7)){ |
<> | 144:ef7eb2e8f9f7 | 725 | divisor = 1; |
<> | 144:ef7eb2e8f9f7 | 726 | }else if(baudrate > (LEUART_REF_FREQ >> 8)){ |
<> | 144:ef7eb2e8f9f7 | 727 | divisor = 2; |
<> | 144:ef7eb2e8f9f7 | 728 | }else if(baudrate > (LEUART_REF_FREQ >> 9)){ |
<> | 144:ef7eb2e8f9f7 | 729 | divisor = 4; |
<> | 144:ef7eb2e8f9f7 | 730 | }else{ |
<> | 144:ef7eb2e8f9f7 | 731 | divisor = 8; |
<> | 144:ef7eb2e8f9f7 | 732 | } |
<> | 144:ef7eb2e8f9f7 | 733 | CMU_ClockDivSet(serial_get_clock(obj), divisor); |
<> | 144:ef7eb2e8f9f7 | 734 | LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_REF_FREQ/divisor, (uint32_t)baudrate); |
<> | 144:ef7eb2e8f9f7 | 735 | #endif |
<> | 144:ef7eb2e8f9f7 | 736 | } |
<> | 144:ef7eb2e8f9f7 | 737 | |
<> | 144:ef7eb2e8f9f7 | 738 | /** |
<> | 144:ef7eb2e8f9f7 | 739 | * Set UART format by re-initializing the peripheral. |
<> | 144:ef7eb2e8f9f7 | 740 | */ |
<> | 144:ef7eb2e8f9f7 | 741 | void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) |
<> | 144:ef7eb2e8f9f7 | 742 | { |
<> | 144:ef7eb2e8f9f7 | 743 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 744 | /* Save the serial state */ |
<> | 144:ef7eb2e8f9f7 | 745 | uint8_t was_enabled = LEUART_StatusGet(obj->serial.periph.leuart) & (LEUART_STATUS_TXENS | LEUART_STATUS_RXENS); |
<> | 144:ef7eb2e8f9f7 | 746 | uint32_t enabled_interrupts = obj->serial.periph.leuart->IEN; |
<> | 144:ef7eb2e8f9f7 | 747 | |
<> | 144:ef7eb2e8f9f7 | 748 | LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT; |
<> | 144:ef7eb2e8f9f7 | 749 | |
<> | 144:ef7eb2e8f9f7 | 750 | /* We support 8 data bits ONLY on LEUART*/ |
<> | 144:ef7eb2e8f9f7 | 751 | MBED_ASSERT(data_bits == 8); |
<> | 144:ef7eb2e8f9f7 | 752 | |
<> | 144:ef7eb2e8f9f7 | 753 | /* Re-init the UART */ |
<> | 144:ef7eb2e8f9f7 | 754 | init.enable = (was_enabled == 0 ? leuartDisable : leuartEnable); |
<> | 144:ef7eb2e8f9f7 | 755 | init.baudrate = LEUART_BaudrateGet(obj->serial.periph.leuart); |
<> | 144:ef7eb2e8f9f7 | 756 | if (stop_bits == 2) { |
<> | 144:ef7eb2e8f9f7 | 757 | init.stopbits = leuartStopbits2; |
<> | 144:ef7eb2e8f9f7 | 758 | } else { |
<> | 144:ef7eb2e8f9f7 | 759 | init.stopbits = leuartStopbits1; |
<> | 144:ef7eb2e8f9f7 | 760 | } |
<> | 144:ef7eb2e8f9f7 | 761 | switch (parity) { |
<> | 144:ef7eb2e8f9f7 | 762 | case ParityOdd: |
<> | 144:ef7eb2e8f9f7 | 763 | case ParityForced0: |
<> | 144:ef7eb2e8f9f7 | 764 | init.parity = leuartOddParity; |
<> | 144:ef7eb2e8f9f7 | 765 | break; |
<> | 144:ef7eb2e8f9f7 | 766 | case ParityEven: |
<> | 144:ef7eb2e8f9f7 | 767 | case ParityForced1: |
<> | 144:ef7eb2e8f9f7 | 768 | init.parity = leuartEvenParity; |
<> | 144:ef7eb2e8f9f7 | 769 | break; |
<> | 144:ef7eb2e8f9f7 | 770 | default: /* ParityNone */ |
<> | 144:ef7eb2e8f9f7 | 771 | init.parity = leuartNoParity; |
<> | 144:ef7eb2e8f9f7 | 772 | break; |
<> | 144:ef7eb2e8f9f7 | 773 | } |
<> | 144:ef7eb2e8f9f7 | 774 | |
<> | 144:ef7eb2e8f9f7 | 775 | LEUART_Init(obj->serial.periph.leuart, &init); |
<> | 144:ef7eb2e8f9f7 | 776 | |
<> | 144:ef7eb2e8f9f7 | 777 | /* Re-enable pins for UART at correct location */ |
<> | 144:ef7eb2e8f9f7 | 778 | serial_set_route(obj); |
<> | 144:ef7eb2e8f9f7 | 779 | |
<> | 144:ef7eb2e8f9f7 | 780 | /* Re-enable interrupts */ |
<> | 144:ef7eb2e8f9f7 | 781 | if(was_enabled != 0) { |
<> | 144:ef7eb2e8f9f7 | 782 | obj->serial.periph.leuart->IFC = LEUART_IFC_TXC; |
<> | 144:ef7eb2e8f9f7 | 783 | obj->serial.periph.leuart->IEN = enabled_interrupts; |
<> | 144:ef7eb2e8f9f7 | 784 | } |
<> | 144:ef7eb2e8f9f7 | 785 | } else { |
<> | 144:ef7eb2e8f9f7 | 786 | /* Save the serial state */ |
<> | 144:ef7eb2e8f9f7 | 787 | uint8_t was_enabled = USART_StatusGet(obj->serial.periph.uart) & (USART_STATUS_TXENS | USART_STATUS_RXENS); |
<> | 144:ef7eb2e8f9f7 | 788 | uint32_t enabled_interrupts = obj->serial.periph.uart->IEN; |
<> | 144:ef7eb2e8f9f7 | 789 | |
<> | 144:ef7eb2e8f9f7 | 790 | |
<> | 144:ef7eb2e8f9f7 | 791 | USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT; |
<> | 144:ef7eb2e8f9f7 | 792 | |
<> | 144:ef7eb2e8f9f7 | 793 | /* We support 4 to 8 data bits */ |
<> | 144:ef7eb2e8f9f7 | 794 | MBED_ASSERT(data_bits >= 4 && data_bits <= 8); |
<> | 144:ef7eb2e8f9f7 | 795 | |
<> | 144:ef7eb2e8f9f7 | 796 | /* Re-init the UART */ |
<> | 144:ef7eb2e8f9f7 | 797 | init.enable = (was_enabled == 0 ? usartDisable : usartEnable); |
<> | 144:ef7eb2e8f9f7 | 798 | init.baudrate = USART_BaudrateGet(obj->serial.periph.uart); |
<> | 144:ef7eb2e8f9f7 | 799 | init.oversampling = usartOVS16; |
<> | 144:ef7eb2e8f9f7 | 800 | init.databits = (USART_Databits_TypeDef)((data_bits - 3) << _USART_FRAME_DATABITS_SHIFT); |
<> | 144:ef7eb2e8f9f7 | 801 | if (stop_bits == 2) { |
<> | 144:ef7eb2e8f9f7 | 802 | init.stopbits = usartStopbits2; |
<> | 144:ef7eb2e8f9f7 | 803 | } else { |
<> | 144:ef7eb2e8f9f7 | 804 | init.stopbits = usartStopbits1; |
<> | 144:ef7eb2e8f9f7 | 805 | } |
<> | 144:ef7eb2e8f9f7 | 806 | switch (parity) { |
<> | 144:ef7eb2e8f9f7 | 807 | case ParityOdd: |
<> | 144:ef7eb2e8f9f7 | 808 | case ParityForced0: |
<> | 144:ef7eb2e8f9f7 | 809 | init.parity = usartOddParity; |
<> | 144:ef7eb2e8f9f7 | 810 | break; |
<> | 144:ef7eb2e8f9f7 | 811 | case ParityEven: |
<> | 144:ef7eb2e8f9f7 | 812 | case ParityForced1: |
<> | 144:ef7eb2e8f9f7 | 813 | init.parity = usartEvenParity; |
<> | 144:ef7eb2e8f9f7 | 814 | break; |
<> | 144:ef7eb2e8f9f7 | 815 | default: /* ParityNone */ |
<> | 144:ef7eb2e8f9f7 | 816 | init.parity = usartNoParity; |
<> | 144:ef7eb2e8f9f7 | 817 | break; |
<> | 144:ef7eb2e8f9f7 | 818 | } |
<> | 144:ef7eb2e8f9f7 | 819 | |
<> | 144:ef7eb2e8f9f7 | 820 | USART_InitAsync(obj->serial.periph.uart, &init); |
<> | 144:ef7eb2e8f9f7 | 821 | |
<> | 144:ef7eb2e8f9f7 | 822 | /* Re-enable pins for UART at correct location */ |
<> | 144:ef7eb2e8f9f7 | 823 | serial_set_route(obj); |
<> | 144:ef7eb2e8f9f7 | 824 | |
<> | 144:ef7eb2e8f9f7 | 825 | /* Re-enable interrupts */ |
<> | 144:ef7eb2e8f9f7 | 826 | if(was_enabled != 0) { |
<> | 144:ef7eb2e8f9f7 | 827 | obj->serial.periph.uart->IFC = USART_IFC_TXC; |
<> | 144:ef7eb2e8f9f7 | 828 | obj->serial.periph.uart->IEN = enabled_interrupts; |
<> | 144:ef7eb2e8f9f7 | 829 | } |
<> | 144:ef7eb2e8f9f7 | 830 | } |
<> | 144:ef7eb2e8f9f7 | 831 | } |
<> | 144:ef7eb2e8f9f7 | 832 | |
<> | 144:ef7eb2e8f9f7 | 833 | /****************************************************************************** |
<> | 144:ef7eb2e8f9f7 | 834 | * INTERRUPTS * |
<> | 144:ef7eb2e8f9f7 | 835 | ******************************************************************************/ |
<> | 144:ef7eb2e8f9f7 | 836 | uint8_t serial_tx_ready(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 837 | { |
<> | 144:ef7eb2e8f9f7 | 838 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 839 | return (obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXBL) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 840 | } else { |
<> | 144:ef7eb2e8f9f7 | 841 | return (obj->serial.periph.uart->STATUS & USART_STATUS_TXBL) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 842 | } |
<> | 144:ef7eb2e8f9f7 | 843 | } |
<> | 144:ef7eb2e8f9f7 | 844 | |
<> | 144:ef7eb2e8f9f7 | 845 | uint8_t serial_rx_ready(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 846 | { |
<> | 144:ef7eb2e8f9f7 | 847 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 848 | return (obj->serial.periph.leuart->STATUS & LEUART_STATUS_RXDATAV) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 849 | } else { |
<> | 144:ef7eb2e8f9f7 | 850 | return (obj->serial.periph.uart->STATUS & USART_STATUS_RXDATAV) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 851 | } |
<> | 144:ef7eb2e8f9f7 | 852 | } |
<> | 144:ef7eb2e8f9f7 | 853 | |
<> | 144:ef7eb2e8f9f7 | 854 | void serial_write_asynch(serial_t *obj, int data) |
<> | 144:ef7eb2e8f9f7 | 855 | { |
<> | 144:ef7eb2e8f9f7 | 856 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 857 | obj->serial.periph.leuart->TXDATA = (uint32_t)data; |
<> | 144:ef7eb2e8f9f7 | 858 | } else { |
<> | 144:ef7eb2e8f9f7 | 859 | obj->serial.periph.uart->TXDATA = (uint32_t)data; |
<> | 144:ef7eb2e8f9f7 | 860 | } |
<> | 144:ef7eb2e8f9f7 | 861 | } |
<> | 144:ef7eb2e8f9f7 | 862 | |
<> | 144:ef7eb2e8f9f7 | 863 | int serial_read_asynch(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 864 | { |
<> | 144:ef7eb2e8f9f7 | 865 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 866 | return (int)obj->serial.periph.leuart->RXDATA; |
<> | 144:ef7eb2e8f9f7 | 867 | } else { |
<> | 144:ef7eb2e8f9f7 | 868 | return (int)obj->serial.periph.uart->RXDATA; |
<> | 144:ef7eb2e8f9f7 | 869 | } |
<> | 144:ef7eb2e8f9f7 | 870 | } |
<> | 144:ef7eb2e8f9f7 | 871 | |
<> | 144:ef7eb2e8f9f7 | 872 | uint8_t serial_tx_int_flag(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 873 | { |
<> | 144:ef7eb2e8f9f7 | 874 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 875 | return (obj->serial.periph.leuart->IF & LEUART_IF_TXBL) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 876 | } else { |
<> | 144:ef7eb2e8f9f7 | 877 | return (obj->serial.periph.uart->IF & USART_IF_TXBL) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 878 | } |
<> | 144:ef7eb2e8f9f7 | 879 | } |
<> | 144:ef7eb2e8f9f7 | 880 | |
<> | 144:ef7eb2e8f9f7 | 881 | uint8_t serial_rx_int_flag(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 882 | { |
<> | 144:ef7eb2e8f9f7 | 883 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 884 | return (obj->serial.periph.leuart->IF & LEUART_IF_RXDATAV) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 885 | } else { |
<> | 144:ef7eb2e8f9f7 | 886 | return (obj->serial.periph.uart->IF & USART_IF_RXDATAV) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 887 | } |
<> | 144:ef7eb2e8f9f7 | 888 | } |
<> | 144:ef7eb2e8f9f7 | 889 | |
<> | 144:ef7eb2e8f9f7 | 890 | void serial_read_asynch_complete(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 891 | { |
<> | 144:ef7eb2e8f9f7 | 892 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 893 | obj->serial.periph.leuart->IFC |= LEUART_IFC_RXOF; // in case it got full |
<> | 144:ef7eb2e8f9f7 | 894 | } else { |
<> | 144:ef7eb2e8f9f7 | 895 | obj->serial.periph.uart->IFC |= USART_IFC_RXFULL; // in case it got full |
<> | 144:ef7eb2e8f9f7 | 896 | } |
<> | 144:ef7eb2e8f9f7 | 897 | } |
<> | 144:ef7eb2e8f9f7 | 898 | |
<> | 144:ef7eb2e8f9f7 | 899 | void serial_write_asynch_complete(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 900 | { |
<> | 144:ef7eb2e8f9f7 | 901 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 902 | obj->serial.periph.leuart->IFC |= LEUART_IFC_TXC; |
<> | 144:ef7eb2e8f9f7 | 903 | } else { |
<> | 144:ef7eb2e8f9f7 | 904 | obj->serial.periph.uart->IFC |= USART_IFC_TXC; |
<> | 144:ef7eb2e8f9f7 | 905 | } |
<> | 144:ef7eb2e8f9f7 | 906 | } |
<> | 144:ef7eb2e8f9f7 | 907 | |
<> | 144:ef7eb2e8f9f7 | 908 | /** Enable and set the interrupt handler for write (TX) |
<> | 144:ef7eb2e8f9f7 | 909 | * |
<> | 144:ef7eb2e8f9f7 | 910 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 911 | * @param address The address of TX handler |
<> | 144:ef7eb2e8f9f7 | 912 | * @param enable Set to non-zero to enable or zero to disable |
<> | 144:ef7eb2e8f9f7 | 913 | */ |
<> | 144:ef7eb2e8f9f7 | 914 | void serial_write_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable) |
<> | 144:ef7eb2e8f9f7 | 915 | { |
<> | 144:ef7eb2e8f9f7 | 916 | NVIC_SetVector(serial_get_tx_irq_index(obj), address); |
<> | 144:ef7eb2e8f9f7 | 917 | serial_irq_set(obj, (SerialIrq)1, enable); |
<> | 144:ef7eb2e8f9f7 | 918 | } |
<> | 144:ef7eb2e8f9f7 | 919 | |
<> | 144:ef7eb2e8f9f7 | 920 | /** Enable and set the interrupt handler for read (RX) |
<> | 144:ef7eb2e8f9f7 | 921 | * |
<> | 144:ef7eb2e8f9f7 | 922 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 923 | * @param address The address of RX handler |
<> | 144:ef7eb2e8f9f7 | 924 | * @param enable Set to non-zero to enable or zero to disable |
<> | 144:ef7eb2e8f9f7 | 925 | */ |
<> | 144:ef7eb2e8f9f7 | 926 | void serial_read_enable_interrupt(serial_t *obj, uint32_t address, uint8_t enable) |
<> | 144:ef7eb2e8f9f7 | 927 | { |
<> | 144:ef7eb2e8f9f7 | 928 | NVIC_SetVector(serial_get_rx_irq_index(obj), address); |
<> | 144:ef7eb2e8f9f7 | 929 | serial_irq_set(obj, (SerialIrq)0, enable); |
<> | 144:ef7eb2e8f9f7 | 930 | } |
<> | 144:ef7eb2e8f9f7 | 931 | |
<> | 144:ef7eb2e8f9f7 | 932 | uint8_t serial_interrupt_enabled(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 933 | { |
<> | 144:ef7eb2e8f9f7 | 934 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 935 | return (obj->serial.periph.leuart->IEN & (LEUART_IEN_RXDATAV | LEUART_IEN_TXBL)) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 936 | } else { |
<> | 144:ef7eb2e8f9f7 | 937 | return (obj->serial.periph.uart->IEN & (USART_IEN_RXDATAV | USART_IEN_TXBL)) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 938 | } |
<> | 144:ef7eb2e8f9f7 | 939 | } |
<> | 144:ef7eb2e8f9f7 | 940 | |
<> | 144:ef7eb2e8f9f7 | 941 | /** |
<> | 144:ef7eb2e8f9f7 | 942 | * Set handler for all serial interrupts (is probably SerialBase::_handler()) |
<> | 144:ef7eb2e8f9f7 | 943 | * and store IRQ ID to be returned to the handler upon interrupt. ID is |
<> | 144:ef7eb2e8f9f7 | 944 | * probably a pointer to the calling Serial object. |
<> | 144:ef7eb2e8f9f7 | 945 | */ |
<> | 144:ef7eb2e8f9f7 | 946 | void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) |
<> | 144:ef7eb2e8f9f7 | 947 | { |
<> | 144:ef7eb2e8f9f7 | 948 | irq_handler = handler; |
<> | 144:ef7eb2e8f9f7 | 949 | serial_irq_ids[serial_get_index(obj)] = id; |
<> | 144:ef7eb2e8f9f7 | 950 | } |
<> | 144:ef7eb2e8f9f7 | 951 | |
<> | 144:ef7eb2e8f9f7 | 952 | /** |
<> | 144:ef7eb2e8f9f7 | 953 | * Generic ISR for all UARTs, both TX and RX |
<> | 144:ef7eb2e8f9f7 | 954 | */ |
<> | 144:ef7eb2e8f9f7 | 955 | static void uart_irq(UARTName name, SerialIrq irq) |
<> | 144:ef7eb2e8f9f7 | 956 | { |
<> | 144:ef7eb2e8f9f7 | 957 | uint8_t index = serial_pointer_get_index((uint32_t)name); |
<> | 144:ef7eb2e8f9f7 | 958 | if (serial_irq_ids[index] != 0) { |
<> | 144:ef7eb2e8f9f7 | 959 | /* Pass interrupt on to mbed common handler */ |
<> | 144:ef7eb2e8f9f7 | 960 | irq_handler(serial_irq_ids[index], irq); |
<> | 144:ef7eb2e8f9f7 | 961 | /* Clearing interrupt not necessary */ |
<> | 144:ef7eb2e8f9f7 | 962 | } |
<> | 144:ef7eb2e8f9f7 | 963 | } |
<> | 144:ef7eb2e8f9f7 | 964 | |
<> | 144:ef7eb2e8f9f7 | 965 | /** |
<> | 144:ef7eb2e8f9f7 | 966 | * Set ISR for a given UART and interrupt event (TX or RX) |
<> | 144:ef7eb2e8f9f7 | 967 | */ |
<> | 144:ef7eb2e8f9f7 | 968 | void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) |
<> | 144:ef7eb2e8f9f7 | 969 | { |
<> | 144:ef7eb2e8f9f7 | 970 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 971 | /* Enable or disable interrupt */ |
<> | 144:ef7eb2e8f9f7 | 972 | if (enable) { |
<> | 144:ef7eb2e8f9f7 | 973 | if (irq == RxIrq) { /* RX */ |
<> | 144:ef7eb2e8f9f7 | 974 | obj->serial.periph.leuart->IEN |= LEUART_IEN_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 975 | NVIC_ClearPendingIRQ(serial_get_rx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 976 | NVIC_EnableIRQ(serial_get_rx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 977 | } else { /* TX */ |
<> | 144:ef7eb2e8f9f7 | 978 | obj->serial.periph.leuart->IEN |= LEUART_IEN_TXC; |
<> | 144:ef7eb2e8f9f7 | 979 | NVIC_ClearPendingIRQ(serial_get_tx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 980 | NVIC_SetPriority(serial_get_tx_irq_index(obj), 1); |
<> | 144:ef7eb2e8f9f7 | 981 | NVIC_EnableIRQ(serial_get_tx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 982 | } |
<> | 144:ef7eb2e8f9f7 | 983 | } else { |
<> | 144:ef7eb2e8f9f7 | 984 | if (irq == RxIrq) { /* RX */ |
<> | 144:ef7eb2e8f9f7 | 985 | obj->serial.periph.leuart->IEN &= ~LEUART_IEN_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 986 | NVIC_DisableIRQ(serial_get_rx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 987 | } else { /* TX */ |
<> | 144:ef7eb2e8f9f7 | 988 | obj->serial.periph.leuart->IEN &= ~LEUART_IEN_TXC; |
<> | 144:ef7eb2e8f9f7 | 989 | NVIC_DisableIRQ(serial_get_tx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 990 | } |
<> | 144:ef7eb2e8f9f7 | 991 | } |
<> | 144:ef7eb2e8f9f7 | 992 | } else { |
<> | 144:ef7eb2e8f9f7 | 993 | /* Enable or disable interrupt */ |
<> | 144:ef7eb2e8f9f7 | 994 | if (enable) { |
<> | 144:ef7eb2e8f9f7 | 995 | if (irq == RxIrq) { /* RX */ |
<> | 144:ef7eb2e8f9f7 | 996 | obj->serial.periph.uart->IEN |= USART_IEN_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 997 | NVIC_ClearPendingIRQ(serial_get_rx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 998 | NVIC_EnableIRQ(serial_get_rx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 999 | } else { /* TX */ |
<> | 144:ef7eb2e8f9f7 | 1000 | obj->serial.periph.uart->IEN |= USART_IEN_TXC; |
<> | 144:ef7eb2e8f9f7 | 1001 | NVIC_ClearPendingIRQ(serial_get_tx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 1002 | NVIC_SetPriority(serial_get_tx_irq_index(obj), 1); |
<> | 144:ef7eb2e8f9f7 | 1003 | NVIC_EnableIRQ(serial_get_tx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 1004 | } |
<> | 144:ef7eb2e8f9f7 | 1005 | } else { |
<> | 144:ef7eb2e8f9f7 | 1006 | if (irq == RxIrq) { /* RX */ |
<> | 144:ef7eb2e8f9f7 | 1007 | obj->serial.periph.uart->IEN &= ~USART_IEN_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1008 | NVIC_DisableIRQ(serial_get_rx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 1009 | } else { /* TX */ |
<> | 144:ef7eb2e8f9f7 | 1010 | obj->serial.periph.uart->IEN &= ~USART_IEN_TXC; |
<> | 144:ef7eb2e8f9f7 | 1011 | NVIC_DisableIRQ(serial_get_tx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 1012 | } |
<> | 144:ef7eb2e8f9f7 | 1013 | } |
<> | 144:ef7eb2e8f9f7 | 1014 | } |
<> | 144:ef7eb2e8f9f7 | 1015 | } |
<> | 144:ef7eb2e8f9f7 | 1016 | |
<> | 144:ef7eb2e8f9f7 | 1017 | /****************************************************************************** |
<> | 144:ef7eb2e8f9f7 | 1018 | * READ/WRITE * |
<> | 144:ef7eb2e8f9f7 | 1019 | ******************************************************************************/ |
<> | 144:ef7eb2e8f9f7 | 1020 | |
<> | 144:ef7eb2e8f9f7 | 1021 | /** |
<> | 144:ef7eb2e8f9f7 | 1022 | * Get one char from serial link |
<> | 144:ef7eb2e8f9f7 | 1023 | */ |
<> | 144:ef7eb2e8f9f7 | 1024 | int serial_getc(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1025 | { |
<> | 144:ef7eb2e8f9f7 | 1026 | /* Emlib USART_Rx blocks until data is available, so we don't need to use |
<> | 144:ef7eb2e8f9f7 | 1027 | * serial_readable(). Use USART_RxDataGet() to read register directly. */ |
<> | 144:ef7eb2e8f9f7 | 1028 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1029 | return LEUART_Rx(obj->serial.periph.leuart); |
<> | 144:ef7eb2e8f9f7 | 1030 | } else { |
<> | 144:ef7eb2e8f9f7 | 1031 | return USART_Rx(obj->serial.periph.uart); |
<> | 144:ef7eb2e8f9f7 | 1032 | } |
<> | 144:ef7eb2e8f9f7 | 1033 | } |
<> | 144:ef7eb2e8f9f7 | 1034 | |
<> | 144:ef7eb2e8f9f7 | 1035 | /* |
<> | 144:ef7eb2e8f9f7 | 1036 | * Send one char over serial link |
<> | 144:ef7eb2e8f9f7 | 1037 | */ |
<> | 144:ef7eb2e8f9f7 | 1038 | void serial_putc(serial_t *obj, int c) |
<> | 144:ef7eb2e8f9f7 | 1039 | { |
<> | 144:ef7eb2e8f9f7 | 1040 | /* Emlib USART_Tx blocks until buffer is writable (non-full), so we don't |
<> | 144:ef7eb2e8f9f7 | 1041 | * need to use serial_writable(). */ |
<> | 144:ef7eb2e8f9f7 | 1042 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1043 | LEUART_Tx(obj->serial.periph.leuart, (uint8_t)(c)); |
<> | 144:ef7eb2e8f9f7 | 1044 | while (!(obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXC)); |
<> | 144:ef7eb2e8f9f7 | 1045 | } else { |
<> | 144:ef7eb2e8f9f7 | 1046 | USART_Tx(obj->serial.periph.uart, (uint8_t)(c)); |
<> | 144:ef7eb2e8f9f7 | 1047 | while (!(obj->serial.periph.uart->STATUS & USART_STATUS_TXC)); |
<> | 144:ef7eb2e8f9f7 | 1048 | } |
<> | 144:ef7eb2e8f9f7 | 1049 | } |
<> | 144:ef7eb2e8f9f7 | 1050 | |
<> | 144:ef7eb2e8f9f7 | 1051 | /** |
<> | 144:ef7eb2e8f9f7 | 1052 | * Check if data is available in RX data vector |
<> | 144:ef7eb2e8f9f7 | 1053 | */ |
<> | 144:ef7eb2e8f9f7 | 1054 | int serial_readable(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1055 | { |
<> | 144:ef7eb2e8f9f7 | 1056 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1057 | return obj->serial.periph.leuart->STATUS & LEUART_STATUS_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1058 | } else { |
<> | 144:ef7eb2e8f9f7 | 1059 | return obj->serial.periph.uart->STATUS & USART_STATUS_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1060 | } |
<> | 144:ef7eb2e8f9f7 | 1061 | } |
<> | 144:ef7eb2e8f9f7 | 1062 | |
<> | 144:ef7eb2e8f9f7 | 1063 | /** |
<> | 144:ef7eb2e8f9f7 | 1064 | * Check if TX buffer is empty |
<> | 144:ef7eb2e8f9f7 | 1065 | */ |
<> | 144:ef7eb2e8f9f7 | 1066 | int serial_writable(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1067 | { |
<> | 144:ef7eb2e8f9f7 | 1068 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1069 | return obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1070 | } else { |
<> | 144:ef7eb2e8f9f7 | 1071 | return obj->serial.periph.uart->STATUS & USART_STATUS_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1072 | } |
<> | 144:ef7eb2e8f9f7 | 1073 | } |
<> | 144:ef7eb2e8f9f7 | 1074 | |
<> | 144:ef7eb2e8f9f7 | 1075 | /** |
<> | 144:ef7eb2e8f9f7 | 1076 | * Clear UART interrupts |
<> | 144:ef7eb2e8f9f7 | 1077 | */ |
<> | 144:ef7eb2e8f9f7 | 1078 | void serial_clear(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1079 | { |
<> | 144:ef7eb2e8f9f7 | 1080 | /* Interrupts automatically clear when condition is not met anymore */ |
<> | 144:ef7eb2e8f9f7 | 1081 | } |
<> | 144:ef7eb2e8f9f7 | 1082 | |
<> | 144:ef7eb2e8f9f7 | 1083 | void serial_break_set(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1084 | { |
<> | 144:ef7eb2e8f9f7 | 1085 | /* Send transmission break */ |
<> | 144:ef7eb2e8f9f7 | 1086 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1087 | obj->serial.periph.leuart->TXDATAX = LEUART_TXDATAX_TXBREAK; |
<> | 144:ef7eb2e8f9f7 | 1088 | } else { |
<> | 144:ef7eb2e8f9f7 | 1089 | obj->serial.periph.uart->TXDATAX = USART_TXDATAX_TXBREAK; |
<> | 144:ef7eb2e8f9f7 | 1090 | } |
<> | 144:ef7eb2e8f9f7 | 1091 | } |
<> | 144:ef7eb2e8f9f7 | 1092 | |
<> | 144:ef7eb2e8f9f7 | 1093 | void serial_break_clear(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1094 | { |
<> | 144:ef7eb2e8f9f7 | 1095 | /* No need to clear break, it is automatically cleared after one frame. |
<> | 144:ef7eb2e8f9f7 | 1096 | * From the reference manual: |
<> | 144:ef7eb2e8f9f7 | 1097 | * |
<> | 144:ef7eb2e8f9f7 | 1098 | * By setting TXBREAK, the output will be held low during the stop-bit |
<> | 144:ef7eb2e8f9f7 | 1099 | * period to generate a framing error. A receiver that supports break |
<> | 144:ef7eb2e8f9f7 | 1100 | * detection detects this state, allowing it to be used e.g. for framing |
<> | 144:ef7eb2e8f9f7 | 1101 | * of larger data packets. The line is driven high before the next frame |
<> | 144:ef7eb2e8f9f7 | 1102 | * is transmitted so the next start condition can be identified correctly |
<> | 144:ef7eb2e8f9f7 | 1103 | * by the recipient. Continuous breaks lasting longer than a USART frame |
<> | 144:ef7eb2e8f9f7 | 1104 | * are thus not supported by the USART. GPIO can be used for this. |
<> | 144:ef7eb2e8f9f7 | 1105 | */ |
<> | 144:ef7eb2e8f9f7 | 1106 | } |
<> | 144:ef7eb2e8f9f7 | 1107 | |
<> | 144:ef7eb2e8f9f7 | 1108 | void serial_pinout_tx(PinName tx) |
<> | 144:ef7eb2e8f9f7 | 1109 | { |
<> | 144:ef7eb2e8f9f7 | 1110 | /* 0x10 sets DOUT high. Prevents false start. */ |
<> | 144:ef7eb2e8f9f7 | 1111 | pin_mode(tx, PushPull | 0x10); |
<> | 144:ef7eb2e8f9f7 | 1112 | } |
<> | 144:ef7eb2e8f9f7 | 1113 | |
<> | 144:ef7eb2e8f9f7 | 1114 | /************************************************************************************ |
<> | 144:ef7eb2e8f9f7 | 1115 | * DMA helper functions * |
<> | 144:ef7eb2e8f9f7 | 1116 | ************************************************************************************/ |
<> | 144:ef7eb2e8f9f7 | 1117 | /****************************************** |
<> | 144:ef7eb2e8f9f7 | 1118 | * static void serial_dmaTransferComplete(uint channel, bool primary, void* user) |
<> | 144:ef7eb2e8f9f7 | 1119 | * |
<> | 144:ef7eb2e8f9f7 | 1120 | * Callback function which gets called upon DMA transfer completion |
<> | 144:ef7eb2e8f9f7 | 1121 | * the user-defined pointer is pointing to the CPP-land thunk |
<> | 144:ef7eb2e8f9f7 | 1122 | ******************************************/ |
<> | 144:ef7eb2e8f9f7 | 1123 | static void serial_dmaTransferComplete(unsigned int channel, bool primary, void *user) |
<> | 144:ef7eb2e8f9f7 | 1124 | { |
<> | 144:ef7eb2e8f9f7 | 1125 | /* Store information about which channel triggered because CPP doesn't take arguments */ |
<> | 144:ef7eb2e8f9f7 | 1126 | serial_dma_irq_fired[channel] = true; |
<> | 144:ef7eb2e8f9f7 | 1127 | |
<> | 144:ef7eb2e8f9f7 | 1128 | /* User pointer should be a thunk to CPP land */ |
<> | 144:ef7eb2e8f9f7 | 1129 | if (user != NULL) { |
<> | 144:ef7eb2e8f9f7 | 1130 | ((DMACallback)user)(); |
<> | 144:ef7eb2e8f9f7 | 1131 | } |
<> | 144:ef7eb2e8f9f7 | 1132 | } |
<> | 144:ef7eb2e8f9f7 | 1133 | |
<> | 144:ef7eb2e8f9f7 | 1134 | #ifndef LDMA_PRESENT |
<> | 144:ef7eb2e8f9f7 | 1135 | |
<> | 144:ef7eb2e8f9f7 | 1136 | /****************************************** |
<> | 144:ef7eb2e8f9f7 | 1137 | * static void serial_setupDmaChannel(serial_t *obj, bool tx_nrx) |
<> | 144:ef7eb2e8f9f7 | 1138 | * |
<> | 144:ef7eb2e8f9f7 | 1139 | * Sets up the DMA configuration block for the assigned channel |
<> | 144:ef7eb2e8f9f7 | 1140 | * tx_nrx: true if configuring TX, false if configuring RX. |
<> | 144:ef7eb2e8f9f7 | 1141 | ******************************************/ |
<> | 144:ef7eb2e8f9f7 | 1142 | static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx) |
<> | 144:ef7eb2e8f9f7 | 1143 | { |
<> | 144:ef7eb2e8f9f7 | 1144 | DMA_CfgChannel_TypeDef channelConfig; |
<> | 144:ef7eb2e8f9f7 | 1145 | |
<> | 144:ef7eb2e8f9f7 | 1146 | if(tx_nrx) { |
<> | 144:ef7eb2e8f9f7 | 1147 | //setup TX channel |
<> | 144:ef7eb2e8f9f7 | 1148 | channelConfig.highPri = false; |
<> | 144:ef7eb2e8f9f7 | 1149 | channelConfig.enableInt = true; |
<> | 144:ef7eb2e8f9f7 | 1150 | channelConfig.cb = &(obj->serial.dmaOptionsTX.dmaCallback); |
<> | 144:ef7eb2e8f9f7 | 1151 | |
<> | 144:ef7eb2e8f9f7 | 1152 | switch((uint32_t)(obj->serial.periph.uart)) { |
<> | 144:ef7eb2e8f9f7 | 1153 | #ifdef UART0 |
<> | 144:ef7eb2e8f9f7 | 1154 | case UART_0: |
<> | 144:ef7eb2e8f9f7 | 1155 | channelConfig.select = DMAREQ_UART0_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1156 | break; |
<> | 144:ef7eb2e8f9f7 | 1157 | #endif |
<> | 144:ef7eb2e8f9f7 | 1158 | #ifdef UART1 |
<> | 144:ef7eb2e8f9f7 | 1159 | case UART_1: |
<> | 144:ef7eb2e8f9f7 | 1160 | channelConfig.select = DMAREQ_UART1_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1161 | break; |
<> | 144:ef7eb2e8f9f7 | 1162 | #endif |
<> | 144:ef7eb2e8f9f7 | 1163 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 1164 | case USART_0: |
<> | 144:ef7eb2e8f9f7 | 1165 | channelConfig.select = DMAREQ_USART0_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1166 | break; |
<> | 144:ef7eb2e8f9f7 | 1167 | #endif |
<> | 144:ef7eb2e8f9f7 | 1168 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 1169 | case USART_1: |
<> | 144:ef7eb2e8f9f7 | 1170 | channelConfig.select = DMAREQ_USART1_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1171 | break; |
<> | 144:ef7eb2e8f9f7 | 1172 | #endif |
<> | 144:ef7eb2e8f9f7 | 1173 | #ifdef USART2 |
<> | 144:ef7eb2e8f9f7 | 1174 | case USART_2: |
<> | 144:ef7eb2e8f9f7 | 1175 | channelConfig.select = DMAREQ_USART2_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1176 | break; |
<> | 144:ef7eb2e8f9f7 | 1177 | #endif |
<> | 144:ef7eb2e8f9f7 | 1178 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 1179 | case LEUART_0: |
<> | 144:ef7eb2e8f9f7 | 1180 | channelConfig.select = DMAREQ_LEUART0_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1181 | break; |
<> | 144:ef7eb2e8f9f7 | 1182 | #endif |
<> | 144:ef7eb2e8f9f7 | 1183 | #ifdef LEUART1 |
<> | 144:ef7eb2e8f9f7 | 1184 | case LEUART_1: |
<> | 144:ef7eb2e8f9f7 | 1185 | channelConfig.select = DMAREQ_LEUART1_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1186 | break; |
<> | 144:ef7eb2e8f9f7 | 1187 | #endif |
<> | 144:ef7eb2e8f9f7 | 1188 | } |
<> | 144:ef7eb2e8f9f7 | 1189 | |
<> | 144:ef7eb2e8f9f7 | 1190 | DMA_CfgChannel(obj->serial.dmaOptionsTX.dmaChannel, &channelConfig); |
<> | 144:ef7eb2e8f9f7 | 1191 | } else { |
<> | 144:ef7eb2e8f9f7 | 1192 | //setup RX channel |
<> | 144:ef7eb2e8f9f7 | 1193 | channelConfig.highPri = true; |
<> | 144:ef7eb2e8f9f7 | 1194 | channelConfig.enableInt = true; |
<> | 144:ef7eb2e8f9f7 | 1195 | channelConfig.cb = &(obj->serial.dmaOptionsRX.dmaCallback); |
<> | 144:ef7eb2e8f9f7 | 1196 | |
<> | 144:ef7eb2e8f9f7 | 1197 | switch((uint32_t)(obj->serial.periph.uart)) { |
<> | 144:ef7eb2e8f9f7 | 1198 | #ifdef UART0 |
<> | 144:ef7eb2e8f9f7 | 1199 | case UART_0: |
<> | 144:ef7eb2e8f9f7 | 1200 | channelConfig.select = DMAREQ_UART0_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1201 | break; |
<> | 144:ef7eb2e8f9f7 | 1202 | #endif |
<> | 144:ef7eb2e8f9f7 | 1203 | #ifdef UART1 |
<> | 144:ef7eb2e8f9f7 | 1204 | case UART_1: |
<> | 144:ef7eb2e8f9f7 | 1205 | channelConfig.select = DMAREQ_UART1_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1206 | break; |
<> | 144:ef7eb2e8f9f7 | 1207 | #endif |
<> | 144:ef7eb2e8f9f7 | 1208 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 1209 | case USART_0: |
<> | 144:ef7eb2e8f9f7 | 1210 | channelConfig.select = DMAREQ_USART0_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1211 | break; |
<> | 144:ef7eb2e8f9f7 | 1212 | #endif |
<> | 144:ef7eb2e8f9f7 | 1213 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 1214 | case USART_1: |
<> | 144:ef7eb2e8f9f7 | 1215 | channelConfig.select = DMAREQ_USART1_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1216 | break; |
<> | 144:ef7eb2e8f9f7 | 1217 | #endif |
<> | 144:ef7eb2e8f9f7 | 1218 | #ifdef USART2 |
<> | 144:ef7eb2e8f9f7 | 1219 | case USART_2: |
<> | 144:ef7eb2e8f9f7 | 1220 | channelConfig.select = DMAREQ_USART2_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1221 | break; |
<> | 144:ef7eb2e8f9f7 | 1222 | #endif |
<> | 144:ef7eb2e8f9f7 | 1223 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 1224 | case LEUART_0: |
<> | 144:ef7eb2e8f9f7 | 1225 | channelConfig.select = DMAREQ_LEUART0_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1226 | break; |
<> | 144:ef7eb2e8f9f7 | 1227 | #endif |
<> | 144:ef7eb2e8f9f7 | 1228 | #ifdef LEUART1 |
<> | 144:ef7eb2e8f9f7 | 1229 | case LEUART_1: |
<> | 144:ef7eb2e8f9f7 | 1230 | channelConfig.select = DMAREQ_LEUART1_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1231 | break; |
<> | 144:ef7eb2e8f9f7 | 1232 | #endif |
<> | 144:ef7eb2e8f9f7 | 1233 | } |
<> | 144:ef7eb2e8f9f7 | 1234 | |
<> | 144:ef7eb2e8f9f7 | 1235 | DMA_CfgChannel(obj->serial.dmaOptionsRX.dmaChannel, &channelConfig); |
<> | 144:ef7eb2e8f9f7 | 1236 | } |
<> | 144:ef7eb2e8f9f7 | 1237 | } |
<> | 144:ef7eb2e8f9f7 | 1238 | |
<> | 144:ef7eb2e8f9f7 | 1239 | #endif /* LDMA_PRESENT */ |
<> | 144:ef7eb2e8f9f7 | 1240 | |
<> | 144:ef7eb2e8f9f7 | 1241 | /****************************************** |
<> | 144:ef7eb2e8f9f7 | 1242 | * static void serial_dmaTrySetState(DMA_OPTIONS_t *obj, DMAUsage requestedState) |
<> | 144:ef7eb2e8f9f7 | 1243 | * |
<> | 144:ef7eb2e8f9f7 | 1244 | * Tries to set the passed DMA state to the requested state. |
<> | 144:ef7eb2e8f9f7 | 1245 | * |
<> | 144:ef7eb2e8f9f7 | 1246 | * requested state possibilities: |
<> | 144:ef7eb2e8f9f7 | 1247 | * * NEVER: |
<> | 144:ef7eb2e8f9f7 | 1248 | * if the previous state was always, will deallocate the channel |
<> | 144:ef7eb2e8f9f7 | 1249 | * * OPPORTUNISTIC: |
<> | 144:ef7eb2e8f9f7 | 1250 | * If the previous state was always, will reuse that channel but free upon next completion. |
<> | 144:ef7eb2e8f9f7 | 1251 | * If not, will try to acquire a channel. |
<> | 144:ef7eb2e8f9f7 | 1252 | * When allocated, state changes to DMA_USAGE_TEMPORARY_ALLOCATED. |
<> | 144:ef7eb2e8f9f7 | 1253 | * * ALWAYS: |
<> | 144:ef7eb2e8f9f7 | 1254 | * Will try to allocate a channel and keep it. |
<> | 144:ef7eb2e8f9f7 | 1255 | * If succesfully allocated, state changes to DMA_USAGE_ALLOCATED. |
<> | 144:ef7eb2e8f9f7 | 1256 | ******************************************/ |
<> | 144:ef7eb2e8f9f7 | 1257 | static void serial_dmaTrySetState(DMA_OPTIONS_t *obj, DMAUsage requestedState, serial_t *serialPtr, bool tx_nrx) |
<> | 144:ef7eb2e8f9f7 | 1258 | { |
<> | 144:ef7eb2e8f9f7 | 1259 | DMAUsage currentState = obj->dmaUsageState; |
<> | 144:ef7eb2e8f9f7 | 1260 | int tempDMAChannel = -1; |
<> | 144:ef7eb2e8f9f7 | 1261 | |
<> | 144:ef7eb2e8f9f7 | 1262 | if ((requestedState == DMA_USAGE_ALWAYS) && (currentState != DMA_USAGE_ALLOCATED)) { |
<> | 144:ef7eb2e8f9f7 | 1263 | /* Try to allocate channel */ |
<> | 144:ef7eb2e8f9f7 | 1264 | tempDMAChannel = dma_channel_allocate(DMA_CAP_NONE); |
<> | 144:ef7eb2e8f9f7 | 1265 | if(tempDMAChannel >= 0) { |
<> | 144:ef7eb2e8f9f7 | 1266 | obj->dmaChannel = tempDMAChannel; |
<> | 144:ef7eb2e8f9f7 | 1267 | obj->dmaUsageState = DMA_USAGE_ALLOCATED; |
<> | 144:ef7eb2e8f9f7 | 1268 | dma_init(); |
<> | 144:ef7eb2e8f9f7 | 1269 | serial_dmaSetupChannel(serialPtr, tx_nrx); |
<> | 144:ef7eb2e8f9f7 | 1270 | } |
<> | 144:ef7eb2e8f9f7 | 1271 | } else if (requestedState == DMA_USAGE_OPPORTUNISTIC) { |
<> | 144:ef7eb2e8f9f7 | 1272 | if (currentState == DMA_USAGE_ALLOCATED) { |
<> | 144:ef7eb2e8f9f7 | 1273 | /* Channels have already been allocated previously by an ALWAYS state, so after this transfer, we will release them */ |
<> | 144:ef7eb2e8f9f7 | 1274 | obj->dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED; |
<> | 144:ef7eb2e8f9f7 | 1275 | } else { |
<> | 144:ef7eb2e8f9f7 | 1276 | /* Try to allocate channel */ |
<> | 144:ef7eb2e8f9f7 | 1277 | tempDMAChannel = dma_channel_allocate(DMA_CAP_NONE); |
<> | 144:ef7eb2e8f9f7 | 1278 | if(tempDMAChannel >= 0) { |
<> | 144:ef7eb2e8f9f7 | 1279 | obj->dmaChannel = tempDMAChannel; |
<> | 144:ef7eb2e8f9f7 | 1280 | obj->dmaUsageState = DMA_USAGE_TEMPORARY_ALLOCATED; |
<> | 144:ef7eb2e8f9f7 | 1281 | dma_init(); |
<> | 144:ef7eb2e8f9f7 | 1282 | serial_dmaSetupChannel(serialPtr, tx_nrx); |
<> | 144:ef7eb2e8f9f7 | 1283 | } |
<> | 144:ef7eb2e8f9f7 | 1284 | } |
<> | 144:ef7eb2e8f9f7 | 1285 | } else if (requestedState == DMA_USAGE_NEVER) { |
<> | 144:ef7eb2e8f9f7 | 1286 | /* If channel is allocated, get rid of it */ |
<> | 144:ef7eb2e8f9f7 | 1287 | dma_channel_free(obj->dmaChannel); |
<> | 144:ef7eb2e8f9f7 | 1288 | obj->dmaChannel = -1; |
<> | 144:ef7eb2e8f9f7 | 1289 | obj->dmaUsageState = DMA_USAGE_NEVER; |
<> | 144:ef7eb2e8f9f7 | 1290 | } |
<> | 144:ef7eb2e8f9f7 | 1291 | } |
<> | 144:ef7eb2e8f9f7 | 1292 | |
<> | 144:ef7eb2e8f9f7 | 1293 | #ifndef LDMA_PRESENT |
<> | 144:ef7eb2e8f9f7 | 1294 | |
<> | 144:ef7eb2e8f9f7 | 1295 | static void serial_dmaActivate(serial_t *obj, void* cb, void* buffer, int length, bool tx_nrx) |
<> | 144:ef7eb2e8f9f7 | 1296 | { |
<> | 144:ef7eb2e8f9f7 | 1297 | DMA_CfgDescr_TypeDef channelConfig; |
<> | 144:ef7eb2e8f9f7 | 1298 | |
<> | 144:ef7eb2e8f9f7 | 1299 | if(tx_nrx) { |
<> | 144:ef7eb2e8f9f7 | 1300 | // Set DMA callback |
<> | 144:ef7eb2e8f9f7 | 1301 | obj->serial.dmaOptionsTX.dmaCallback.cbFunc = serial_dmaTransferComplete; |
<> | 144:ef7eb2e8f9f7 | 1302 | obj->serial.dmaOptionsTX.dmaCallback.userPtr = NULL; |
<> | 144:ef7eb2e8f9f7 | 1303 | |
<> | 144:ef7eb2e8f9f7 | 1304 | // Set up configuration structure |
<> | 144:ef7eb2e8f9f7 | 1305 | channelConfig.dstInc = dmaDataIncNone; |
<> | 144:ef7eb2e8f9f7 | 1306 | channelConfig.srcInc = dmaDataInc1; |
<> | 144:ef7eb2e8f9f7 | 1307 | channelConfig.size = dmaDataSize1; |
<> | 144:ef7eb2e8f9f7 | 1308 | channelConfig.arbRate = dmaArbitrate1; |
<> | 144:ef7eb2e8f9f7 | 1309 | channelConfig.hprot = 0; |
<> | 144:ef7eb2e8f9f7 | 1310 | |
<> | 144:ef7eb2e8f9f7 | 1311 | // Clear TXC |
<> | 144:ef7eb2e8f9f7 | 1312 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1313 | LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_TXC); |
<> | 144:ef7eb2e8f9f7 | 1314 | } else { |
<> | 144:ef7eb2e8f9f7 | 1315 | USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC); |
<> | 144:ef7eb2e8f9f7 | 1316 | } |
<> | 144:ef7eb2e8f9f7 | 1317 | |
<> | 144:ef7eb2e8f9f7 | 1318 | // Set callback and enable TXC. This will fire once the |
<> | 144:ef7eb2e8f9f7 | 1319 | // serial transfer finishes |
<> | 144:ef7eb2e8f9f7 | 1320 | NVIC_SetVector(serial_get_tx_irq_index(obj), (uint32_t)cb); |
<> | 144:ef7eb2e8f9f7 | 1321 | serial_irq_set(obj, TxIrq, true); |
<> | 144:ef7eb2e8f9f7 | 1322 | |
<> | 144:ef7eb2e8f9f7 | 1323 | DMA_CfgDescr(obj->serial.dmaOptionsTX.dmaChannel, true, &channelConfig); |
<> | 144:ef7eb2e8f9f7 | 1324 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1325 | // Activate TX and clear TX buffer (note that clear must be done |
<> | 144:ef7eb2e8f9f7 | 1326 | // separately and before TXEN or DMA will die on some platforms) |
<> | 144:ef7eb2e8f9f7 | 1327 | obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARTX; |
<> | 144:ef7eb2e8f9f7 | 1328 | obj->serial.periph.leuart->CMD = LEUART_CMD_TXEN; |
<> | 144:ef7eb2e8f9f7 | 1329 | while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD); |
<> | 144:ef7eb2e8f9f7 | 1330 | |
<> | 144:ef7eb2e8f9f7 | 1331 | // Kick off TX DMA |
<> | 144:ef7eb2e8f9f7 | 1332 | DMA_ActivateBasic(obj->serial.dmaOptionsTX.dmaChannel, true, false, (void*) &(obj->serial.periph.leuart->TXDATA), buffer, length - 1); |
<> | 144:ef7eb2e8f9f7 | 1333 | } else { |
<> | 144:ef7eb2e8f9f7 | 1334 | // Activate TX amd clear TX buffer |
<> | 144:ef7eb2e8f9f7 | 1335 | obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX; |
<> | 144:ef7eb2e8f9f7 | 1336 | |
<> | 144:ef7eb2e8f9f7 | 1337 | // Kick off TX DMA |
<> | 144:ef7eb2e8f9f7 | 1338 | DMA_ActivateBasic(obj->serial.dmaOptionsTX.dmaChannel, true, false, (void*) &(obj->serial.periph.uart->TXDATA), buffer, length - 1); |
<> | 144:ef7eb2e8f9f7 | 1339 | } |
<> | 144:ef7eb2e8f9f7 | 1340 | |
<> | 144:ef7eb2e8f9f7 | 1341 | |
<> | 144:ef7eb2e8f9f7 | 1342 | } else { |
<> | 144:ef7eb2e8f9f7 | 1343 | // Set DMA callback |
<> | 144:ef7eb2e8f9f7 | 1344 | obj->serial.dmaOptionsRX.dmaCallback.cbFunc = serial_dmaTransferComplete; |
<> | 144:ef7eb2e8f9f7 | 1345 | obj->serial.dmaOptionsRX.dmaCallback.userPtr = cb; |
<> | 144:ef7eb2e8f9f7 | 1346 | |
<> | 144:ef7eb2e8f9f7 | 1347 | // Set up configuration structure |
<> | 144:ef7eb2e8f9f7 | 1348 | channelConfig.dstInc = dmaDataInc1; |
<> | 144:ef7eb2e8f9f7 | 1349 | channelConfig.srcInc = dmaDataIncNone; |
<> | 144:ef7eb2e8f9f7 | 1350 | channelConfig.size = dmaDataSize1; |
<> | 144:ef7eb2e8f9f7 | 1351 | channelConfig.arbRate = dmaArbitrate1; |
<> | 144:ef7eb2e8f9f7 | 1352 | channelConfig.hprot = 0; |
<> | 144:ef7eb2e8f9f7 | 1353 | |
<> | 144:ef7eb2e8f9f7 | 1354 | DMA_CfgDescr(obj->serial.dmaOptionsRX.dmaChannel, true, &channelConfig); |
<> | 144:ef7eb2e8f9f7 | 1355 | |
<> | 144:ef7eb2e8f9f7 | 1356 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1357 | // Activate RX and clear RX buffer |
<> | 144:ef7eb2e8f9f7 | 1358 | obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARRX; |
<> | 144:ef7eb2e8f9f7 | 1359 | obj->serial.periph.leuart->CMD = LEUART_CMD_RXEN; |
<> | 144:ef7eb2e8f9f7 | 1360 | while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD); |
<> | 144:ef7eb2e8f9f7 | 1361 | |
<> | 144:ef7eb2e8f9f7 | 1362 | // Kick off RX DMA |
<> | 144:ef7eb2e8f9f7 | 1363 | DMA_ActivateBasic(obj->serial.dmaOptionsRX.dmaChannel, true, false, buffer, (void*) &(obj->serial.periph.leuart->RXDATA), length - 1); |
<> | 144:ef7eb2e8f9f7 | 1364 | } else { |
<> | 144:ef7eb2e8f9f7 | 1365 | // Activate RX and clear RX buffer |
<> | 144:ef7eb2e8f9f7 | 1366 | obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX; |
<> | 144:ef7eb2e8f9f7 | 1367 | |
<> | 144:ef7eb2e8f9f7 | 1368 | // Kick off RX DMA |
<> | 144:ef7eb2e8f9f7 | 1369 | DMA_ActivateBasic(obj->serial.dmaOptionsRX.dmaChannel, true, false, buffer, (void*) &(obj->serial.periph.uart->RXDATA), length - 1); |
<> | 144:ef7eb2e8f9f7 | 1370 | } |
<> | 144:ef7eb2e8f9f7 | 1371 | } |
<> | 144:ef7eb2e8f9f7 | 1372 | } |
<> | 144:ef7eb2e8f9f7 | 1373 | |
<> | 144:ef7eb2e8f9f7 | 1374 | #endif |
<> | 144:ef7eb2e8f9f7 | 1375 | |
<> | 144:ef7eb2e8f9f7 | 1376 | |
<> | 144:ef7eb2e8f9f7 | 1377 | #ifdef LDMA_PRESENT |
<> | 144:ef7eb2e8f9f7 | 1378 | |
<> | 144:ef7eb2e8f9f7 | 1379 | static void serial_dmaSetupChannel(serial_t *obj, bool tx_nrx) |
<> | 144:ef7eb2e8f9f7 | 1380 | { |
<> | 144:ef7eb2e8f9f7 | 1381 | } |
<> | 144:ef7eb2e8f9f7 | 1382 | |
<> | 144:ef7eb2e8f9f7 | 1383 | static void serial_dmaActivate(serial_t *obj, void* cb, void* buffer, int length, bool tx_nrx) |
<> | 144:ef7eb2e8f9f7 | 1384 | { |
<> | 144:ef7eb2e8f9f7 | 1385 | LDMA_PeripheralSignal_t dma_periph; |
<> | 144:ef7eb2e8f9f7 | 1386 | |
<> | 144:ef7eb2e8f9f7 | 1387 | obj->serial.dmaOptionsRX.dmaCallback.userPtr = cb; |
<> | 144:ef7eb2e8f9f7 | 1388 | |
<> | 144:ef7eb2e8f9f7 | 1389 | if( tx_nrx ) { |
<> | 144:ef7eb2e8f9f7 | 1390 | volatile void *target_addr; |
<> | 144:ef7eb2e8f9f7 | 1391 | |
<> | 144:ef7eb2e8f9f7 | 1392 | // Clear TXC |
<> | 144:ef7eb2e8f9f7 | 1393 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1394 | LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_TXC); |
<> | 144:ef7eb2e8f9f7 | 1395 | } else { |
<> | 144:ef7eb2e8f9f7 | 1396 | USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC); |
<> | 144:ef7eb2e8f9f7 | 1397 | } |
<> | 144:ef7eb2e8f9f7 | 1398 | |
<> | 144:ef7eb2e8f9f7 | 1399 | switch((uint32_t)(obj->serial.periph.uart)) { |
<> | 144:ef7eb2e8f9f7 | 1400 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 1401 | case USART_0: |
<> | 144:ef7eb2e8f9f7 | 1402 | dma_periph = ldmaPeripheralSignal_USART0_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1403 | target_addr = &USART0->TXDATA; |
<> | 144:ef7eb2e8f9f7 | 1404 | obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX; |
<> | 144:ef7eb2e8f9f7 | 1405 | break; |
<> | 144:ef7eb2e8f9f7 | 1406 | #endif |
<> | 144:ef7eb2e8f9f7 | 1407 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 1408 | case USART_1: |
<> | 144:ef7eb2e8f9f7 | 1409 | dma_periph = ldmaPeripheralSignal_USART1_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1410 | target_addr = &USART1->TXDATA; |
<> | 144:ef7eb2e8f9f7 | 1411 | obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX; |
<> | 144:ef7eb2e8f9f7 | 1412 | break; |
<> | 144:ef7eb2e8f9f7 | 1413 | #endif |
<> | 144:ef7eb2e8f9f7 | 1414 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 1415 | case LEUART_0: |
<> | 144:ef7eb2e8f9f7 | 1416 | dma_periph = ldmaPeripheralSignal_LEUART0_TXBL; |
<> | 144:ef7eb2e8f9f7 | 1417 | target_addr = &LEUART0->TXDATA; |
<> | 144:ef7eb2e8f9f7 | 1418 | obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARTX; |
<> | 144:ef7eb2e8f9f7 | 1419 | obj->serial.periph.leuart->CMD = LEUART_CMD_TXEN; |
<> | 144:ef7eb2e8f9f7 | 1420 | while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD); |
<> | 144:ef7eb2e8f9f7 | 1421 | break; |
<> | 144:ef7eb2e8f9f7 | 1422 | #endif |
<> | 144:ef7eb2e8f9f7 | 1423 | default: |
<> | 144:ef7eb2e8f9f7 | 1424 | MBED_ASSERT(0); |
<> | 144:ef7eb2e8f9f7 | 1425 | while(1); |
<> | 144:ef7eb2e8f9f7 | 1426 | break; |
<> | 144:ef7eb2e8f9f7 | 1427 | } |
<> | 144:ef7eb2e8f9f7 | 1428 | |
<> | 144:ef7eb2e8f9f7 | 1429 | // Set callback and enable TXC. This will fire once the |
<> | 144:ef7eb2e8f9f7 | 1430 | // serial transfer finishes |
<> | 144:ef7eb2e8f9f7 | 1431 | NVIC_SetVector(serial_get_tx_irq_index(obj), (uint32_t)cb); |
<> | 144:ef7eb2e8f9f7 | 1432 | serial_irq_set(obj, TxIrq, true); |
<> | 144:ef7eb2e8f9f7 | 1433 | |
<> | 144:ef7eb2e8f9f7 | 1434 | // Start DMA transfer |
<> | 144:ef7eb2e8f9f7 | 1435 | LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph); |
<> | 144:ef7eb2e8f9f7 | 1436 | LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_M2P_BYTE(buffer, target_addr, length); |
<> | 144:ef7eb2e8f9f7 | 1437 | LDMAx_StartTransfer(obj->serial.dmaOptionsTX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete, NULL); |
<> | 144:ef7eb2e8f9f7 | 1438 | |
<> | 144:ef7eb2e8f9f7 | 1439 | } else { |
<> | 144:ef7eb2e8f9f7 | 1440 | volatile const void *source_addr; |
<> | 144:ef7eb2e8f9f7 | 1441 | |
<> | 144:ef7eb2e8f9f7 | 1442 | switch((uint32_t)(obj->serial.periph.uart)) { |
<> | 144:ef7eb2e8f9f7 | 1443 | #ifdef USART0 |
<> | 144:ef7eb2e8f9f7 | 1444 | case USART_0: |
<> | 144:ef7eb2e8f9f7 | 1445 | dma_periph = ldmaPeripheralSignal_USART0_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1446 | source_addr = &USART0->RXDATA; |
<> | 144:ef7eb2e8f9f7 | 1447 | obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX; |
<> | 144:ef7eb2e8f9f7 | 1448 | break; |
<> | 144:ef7eb2e8f9f7 | 1449 | #endif |
<> | 144:ef7eb2e8f9f7 | 1450 | #ifdef USART1 |
<> | 144:ef7eb2e8f9f7 | 1451 | case USART_1: |
<> | 144:ef7eb2e8f9f7 | 1452 | dma_periph = ldmaPeripheralSignal_USART1_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1453 | source_addr = &USART1->RXDATA; |
<> | 144:ef7eb2e8f9f7 | 1454 | obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX; |
<> | 144:ef7eb2e8f9f7 | 1455 | break; |
<> | 144:ef7eb2e8f9f7 | 1456 | #endif |
<> | 144:ef7eb2e8f9f7 | 1457 | #ifdef LEUART0 |
<> | 144:ef7eb2e8f9f7 | 1458 | case LEUART_0: |
<> | 144:ef7eb2e8f9f7 | 1459 | dma_periph = ldmaPeripheralSignal_LEUART0_RXDATAV; |
<> | 144:ef7eb2e8f9f7 | 1460 | source_addr = &LEUART0->RXDATA; |
<> | 144:ef7eb2e8f9f7 | 1461 | obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARRX; |
<> | 144:ef7eb2e8f9f7 | 1462 | obj->serial.periph.leuart->CMD = LEUART_CMD_RXEN; |
<> | 144:ef7eb2e8f9f7 | 1463 | while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD); |
<> | 144:ef7eb2e8f9f7 | 1464 | break; |
<> | 144:ef7eb2e8f9f7 | 1465 | #endif |
<> | 144:ef7eb2e8f9f7 | 1466 | default: |
<> | 144:ef7eb2e8f9f7 | 1467 | MBED_ASSERT(0); |
<> | 144:ef7eb2e8f9f7 | 1468 | while(1); |
<> | 144:ef7eb2e8f9f7 | 1469 | break; |
<> | 144:ef7eb2e8f9f7 | 1470 | } |
<> | 144:ef7eb2e8f9f7 | 1471 | |
<> | 144:ef7eb2e8f9f7 | 1472 | LDMA_TransferCfg_t xferConf = LDMA_TRANSFER_CFG_PERIPHERAL(dma_periph); |
<> | 144:ef7eb2e8f9f7 | 1473 | LDMA_Descriptor_t desc = LDMA_DESCRIPTOR_SINGLE_P2M_BYTE(source_addr, buffer, length); |
<> | 144:ef7eb2e8f9f7 | 1474 | LDMAx_StartTransfer(obj->serial.dmaOptionsRX.dmaChannel, &xferConf, &desc, serial_dmaTransferComplete, cb); |
<> | 144:ef7eb2e8f9f7 | 1475 | } |
<> | 144:ef7eb2e8f9f7 | 1476 | } |
<> | 144:ef7eb2e8f9f7 | 1477 | |
<> | 144:ef7eb2e8f9f7 | 1478 | #endif /* LDMA_PRESENT */ |
<> | 144:ef7eb2e8f9f7 | 1479 | |
<> | 144:ef7eb2e8f9f7 | 1480 | /************************************************************************************ |
<> | 144:ef7eb2e8f9f7 | 1481 | * ASYNCHRONOUS HAL * |
<> | 144:ef7eb2e8f9f7 | 1482 | ************************************************************************************/ |
<> | 144:ef7eb2e8f9f7 | 1483 | |
<> | 144:ef7eb2e8f9f7 | 1484 | #if DEVICE_SERIAL_ASYNCH |
<> | 144:ef7eb2e8f9f7 | 1485 | |
<> | 144:ef7eb2e8f9f7 | 1486 | /************************************ |
<> | 144:ef7eb2e8f9f7 | 1487 | * HELPER FUNCTIONS * |
<> | 144:ef7eb2e8f9f7 | 1488 | ***********************************/ |
<> | 144:ef7eb2e8f9f7 | 1489 | |
<> | 144:ef7eb2e8f9f7 | 1490 | /** Configure TX events |
<> | 144:ef7eb2e8f9f7 | 1491 | * |
<> | 144:ef7eb2e8f9f7 | 1492 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 1493 | * @param event The logical OR of the TX events to configure |
<> | 144:ef7eb2e8f9f7 | 1494 | * @param enable Set to non-zero to enable events, or zero to disable them |
<> | 144:ef7eb2e8f9f7 | 1495 | */ |
<> | 144:ef7eb2e8f9f7 | 1496 | void serial_tx_enable_event(serial_t *obj, int event, uint8_t enable) |
<> | 144:ef7eb2e8f9f7 | 1497 | { |
<> | 144:ef7eb2e8f9f7 | 1498 | // Shouldn't have to enable TX interrupt here, just need to keep track of the requested events. |
<> | 144:ef7eb2e8f9f7 | 1499 | if(enable) obj->serial.events |= event; |
<> | 144:ef7eb2e8f9f7 | 1500 | else obj->serial.events &= ~event; |
<> | 144:ef7eb2e8f9f7 | 1501 | } |
<> | 144:ef7eb2e8f9f7 | 1502 | |
<> | 144:ef7eb2e8f9f7 | 1503 | /** |
<> | 144:ef7eb2e8f9f7 | 1504 | * @param obj The serial object. |
<> | 144:ef7eb2e8f9f7 | 1505 | * @param event The logical OR of the RX events to configure |
<> | 144:ef7eb2e8f9f7 | 1506 | * @param enable Set to non-zero to enable events, or zero to disable them |
<> | 144:ef7eb2e8f9f7 | 1507 | */ |
<> | 144:ef7eb2e8f9f7 | 1508 | void serial_rx_enable_event(serial_t *obj, int event, uint8_t enable) |
<> | 144:ef7eb2e8f9f7 | 1509 | { |
<> | 144:ef7eb2e8f9f7 | 1510 | if(enable) { |
<> | 144:ef7eb2e8f9f7 | 1511 | obj->serial.events |= event; |
<> | 144:ef7eb2e8f9f7 | 1512 | } else { |
<> | 144:ef7eb2e8f9f7 | 1513 | obj->serial.events &= ~event; |
<> | 144:ef7eb2e8f9f7 | 1514 | } |
<> | 144:ef7eb2e8f9f7 | 1515 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1516 | if(event & SERIAL_EVENT_RX_FRAMING_ERROR) { |
<> | 144:ef7eb2e8f9f7 | 1517 | //FERR interrupt source |
<> | 144:ef7eb2e8f9f7 | 1518 | if(enable) obj->serial.periph.leuart->IEN |= LEUART_IEN_FERR; |
<> | 144:ef7eb2e8f9f7 | 1519 | else obj->serial.periph.leuart->IEN &= ~LEUART_IEN_FERR; |
<> | 144:ef7eb2e8f9f7 | 1520 | } |
<> | 144:ef7eb2e8f9f7 | 1521 | if(event & SERIAL_EVENT_RX_PARITY_ERROR) { |
<> | 144:ef7eb2e8f9f7 | 1522 | //PERR interrupt source |
<> | 144:ef7eb2e8f9f7 | 1523 | if(enable) obj->serial.periph.leuart->IEN |= LEUART_IEN_PERR; |
<> | 144:ef7eb2e8f9f7 | 1524 | else obj->serial.periph.leuart->IEN &= ~LEUART_IEN_PERR; |
<> | 144:ef7eb2e8f9f7 | 1525 | } |
<> | 144:ef7eb2e8f9f7 | 1526 | if(event & SERIAL_EVENT_RX_OVERFLOW) { |
<> | 144:ef7eb2e8f9f7 | 1527 | //RXOF interrupt source |
<> | 144:ef7eb2e8f9f7 | 1528 | if(enable) obj->serial.periph.leuart->IEN |= LEUART_IEN_RXOF; |
<> | 144:ef7eb2e8f9f7 | 1529 | else obj->serial.periph.leuart->IEN &= ~LEUART_IEN_RXOF; |
<> | 144:ef7eb2e8f9f7 | 1530 | } |
<> | 144:ef7eb2e8f9f7 | 1531 | } else { |
<> | 144:ef7eb2e8f9f7 | 1532 | if(event & SERIAL_EVENT_RX_FRAMING_ERROR) { |
<> | 144:ef7eb2e8f9f7 | 1533 | //FERR interrupt source |
<> | 144:ef7eb2e8f9f7 | 1534 | if(enable) obj->serial.periph.uart->IEN |= USART_IEN_FERR; |
<> | 144:ef7eb2e8f9f7 | 1535 | else obj->serial.periph.uart->IEN &= ~USART_IEN_FERR; |
<> | 144:ef7eb2e8f9f7 | 1536 | } |
<> | 144:ef7eb2e8f9f7 | 1537 | if(event & SERIAL_EVENT_RX_PARITY_ERROR) { |
<> | 144:ef7eb2e8f9f7 | 1538 | //PERR interrupt source |
<> | 144:ef7eb2e8f9f7 | 1539 | if(enable) obj->serial.periph.uart->IEN |= USART_IEN_PERR; |
<> | 144:ef7eb2e8f9f7 | 1540 | else obj->serial.periph.uart->IEN &= ~USART_IEN_PERR; |
<> | 144:ef7eb2e8f9f7 | 1541 | } |
<> | 144:ef7eb2e8f9f7 | 1542 | if(event & SERIAL_EVENT_RX_OVERFLOW) { |
<> | 144:ef7eb2e8f9f7 | 1543 | //RXOF interrupt source |
<> | 144:ef7eb2e8f9f7 | 1544 | if(enable) obj->serial.periph.uart->IEN |= USART_IEN_RXOF; |
<> | 144:ef7eb2e8f9f7 | 1545 | else obj->serial.periph.uart->IEN &= ~USART_IEN_RXOF; |
<> | 144:ef7eb2e8f9f7 | 1546 | } |
<> | 144:ef7eb2e8f9f7 | 1547 | } |
<> | 144:ef7eb2e8f9f7 | 1548 | } |
<> | 144:ef7eb2e8f9f7 | 1549 | |
<> | 144:ef7eb2e8f9f7 | 1550 | /** Configure the TX buffer for an asynchronous write serial transaction |
<> | 144:ef7eb2e8f9f7 | 1551 | * |
<> | 144:ef7eb2e8f9f7 | 1552 | * @param obj The serial object. |
<> | 144:ef7eb2e8f9f7 | 1553 | * @param tx The buffer for sending. |
<> | 144:ef7eb2e8f9f7 | 1554 | * @param tx_length The number of words to transmit. |
<> | 144:ef7eb2e8f9f7 | 1555 | */ |
<> | 144:ef7eb2e8f9f7 | 1556 | void serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width) |
<> | 144:ef7eb2e8f9f7 | 1557 | { |
<> | 144:ef7eb2e8f9f7 | 1558 | // We only support byte buffers for now |
<> | 144:ef7eb2e8f9f7 | 1559 | MBED_ASSERT(width == 8); |
<> | 144:ef7eb2e8f9f7 | 1560 | |
<> | 144:ef7eb2e8f9f7 | 1561 | if(serial_tx_active(obj)) return; |
<> | 144:ef7eb2e8f9f7 | 1562 | |
<> | 144:ef7eb2e8f9f7 | 1563 | obj->tx_buff.buffer = tx; |
<> | 144:ef7eb2e8f9f7 | 1564 | obj->tx_buff.length = tx_length; |
<> | 144:ef7eb2e8f9f7 | 1565 | obj->tx_buff.pos = 0; |
<> | 144:ef7eb2e8f9f7 | 1566 | |
<> | 144:ef7eb2e8f9f7 | 1567 | return; |
<> | 144:ef7eb2e8f9f7 | 1568 | } |
<> | 144:ef7eb2e8f9f7 | 1569 | |
<> | 144:ef7eb2e8f9f7 | 1570 | /** Configure the TX buffer for an asynchronous read serial transaction |
<> | 144:ef7eb2e8f9f7 | 1571 | * |
<> | 144:ef7eb2e8f9f7 | 1572 | * @param obj The serial object. |
<> | 144:ef7eb2e8f9f7 | 1573 | * @param rx The buffer for receiving. |
<> | 144:ef7eb2e8f9f7 | 1574 | * @param rx_length The number of words to read. |
<> | 144:ef7eb2e8f9f7 | 1575 | */ |
<> | 144:ef7eb2e8f9f7 | 1576 | void serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width) |
<> | 144:ef7eb2e8f9f7 | 1577 | { |
<> | 144:ef7eb2e8f9f7 | 1578 | // We only support byte buffers for now |
<> | 144:ef7eb2e8f9f7 | 1579 | MBED_ASSERT(width == 8); |
<> | 144:ef7eb2e8f9f7 | 1580 | |
<> | 144:ef7eb2e8f9f7 | 1581 | if(serial_rx_active(obj)) return; |
<> | 144:ef7eb2e8f9f7 | 1582 | |
<> | 144:ef7eb2e8f9f7 | 1583 | obj->rx_buff.buffer = rx; |
<> | 144:ef7eb2e8f9f7 | 1584 | obj->rx_buff.length = rx_length; |
<> | 144:ef7eb2e8f9f7 | 1585 | obj->rx_buff.pos = 0; |
<> | 144:ef7eb2e8f9f7 | 1586 | |
<> | 144:ef7eb2e8f9f7 | 1587 | return; |
<> | 144:ef7eb2e8f9f7 | 1588 | } |
<> | 144:ef7eb2e8f9f7 | 1589 | |
<> | 144:ef7eb2e8f9f7 | 1590 | /************************************ |
<> | 144:ef7eb2e8f9f7 | 1591 | * TRANSFER FUNCTIONS * |
<> | 144:ef7eb2e8f9f7 | 1592 | ***********************************/ |
<> | 144:ef7eb2e8f9f7 | 1593 | |
<> | 144:ef7eb2e8f9f7 | 1594 | /** Begin asynchronous TX transfer. The used buffer is specified in the serial object, |
<> | 144:ef7eb2e8f9f7 | 1595 | * tx_buff |
<> | 144:ef7eb2e8f9f7 | 1596 | * |
<> | 144:ef7eb2e8f9f7 | 1597 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 1598 | * @param cb The function to call when an event occurs |
<> | 144:ef7eb2e8f9f7 | 1599 | * @param hint A suggestion for how to use DMA with this transfer |
<> | 144:ef7eb2e8f9f7 | 1600 | * @return Returns number of data transfered, or 0 otherwise |
<> | 144:ef7eb2e8f9f7 | 1601 | */ |
<> | 144:ef7eb2e8f9f7 | 1602 | 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 | 1603 | { |
<> | 144:ef7eb2e8f9f7 | 1604 | // Check that a buffer has indeed been set up |
<> | 144:ef7eb2e8f9f7 | 1605 | MBED_ASSERT(tx != (void*)0); |
<> | 144:ef7eb2e8f9f7 | 1606 | if(tx_length == 0) return 0; |
<> | 144:ef7eb2e8f9f7 | 1607 | |
<> | 144:ef7eb2e8f9f7 | 1608 | // Set up buffer |
<> | 144:ef7eb2e8f9f7 | 1609 | serial_tx_buffer_set(obj, (void *)tx, tx_length, tx_width); |
<> | 144:ef7eb2e8f9f7 | 1610 | |
<> | 144:ef7eb2e8f9f7 | 1611 | // Set up events |
<> | 144:ef7eb2e8f9f7 | 1612 | serial_tx_enable_event(obj, SERIAL_EVENT_TX_ALL, false); |
<> | 144:ef7eb2e8f9f7 | 1613 | serial_tx_enable_event(obj, event, true); |
<> | 144:ef7eb2e8f9f7 | 1614 | |
<> | 144:ef7eb2e8f9f7 | 1615 | // Set up sleepmode |
<> | 144:ef7eb2e8f9f7 | 1616 | serial_block_sleep(obj); |
<> | 144:ef7eb2e8f9f7 | 1617 | |
<> | 144:ef7eb2e8f9f7 | 1618 | // Determine DMA strategy |
<> | 144:ef7eb2e8f9f7 | 1619 | serial_dmaTrySetState(&(obj->serial.dmaOptionsTX), hint, obj, true); |
<> | 144:ef7eb2e8f9f7 | 1620 | |
<> | 144:ef7eb2e8f9f7 | 1621 | // If DMA, kick off DMA transfer |
<> | 144:ef7eb2e8f9f7 | 1622 | if(obj->serial.dmaOptionsTX.dmaChannel >= 0) { |
<> | 144:ef7eb2e8f9f7 | 1623 | serial_dmaActivate(obj, (void*)handler, obj->tx_buff.buffer, obj->tx_buff.length, true); |
<> | 144:ef7eb2e8f9f7 | 1624 | } |
<> | 144:ef7eb2e8f9f7 | 1625 | // Else, activate interrupt. TXBL will take care of buffer filling through ISR. |
<> | 144:ef7eb2e8f9f7 | 1626 | else { |
<> | 144:ef7eb2e8f9f7 | 1627 | // Store callback |
<> | 144:ef7eb2e8f9f7 | 1628 | NVIC_ClearPendingIRQ(serial_get_tx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 1629 | NVIC_DisableIRQ(serial_get_tx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 1630 | NVIC_SetPriority(serial_get_tx_irq_index(obj), 1); |
<> | 144:ef7eb2e8f9f7 | 1631 | NVIC_SetVector(serial_get_tx_irq_index(obj), (uint32_t)handler); |
<> | 144:ef7eb2e8f9f7 | 1632 | NVIC_EnableIRQ(serial_get_tx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 1633 | |
<> | 144:ef7eb2e8f9f7 | 1634 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1635 | // Activate TX and clear TX buffer |
<> | 144:ef7eb2e8f9f7 | 1636 | obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARTX; |
<> | 144:ef7eb2e8f9f7 | 1637 | obj->serial.periph.leuart->CMD = LEUART_CMD_TXEN; |
<> | 144:ef7eb2e8f9f7 | 1638 | while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD); |
<> | 144:ef7eb2e8f9f7 | 1639 | |
<> | 144:ef7eb2e8f9f7 | 1640 | // Enable interrupt |
<> | 144:ef7eb2e8f9f7 | 1641 | LEUART_IntEnable(obj->serial.periph.leuart, LEUART_IEN_TXBL); |
<> | 144:ef7eb2e8f9f7 | 1642 | } else { |
<> | 144:ef7eb2e8f9f7 | 1643 | // Activate TX and clear TX buffer |
<> | 144:ef7eb2e8f9f7 | 1644 | obj->serial.periph.uart->CMD = USART_CMD_TXEN | USART_CMD_CLEARTX; |
<> | 144:ef7eb2e8f9f7 | 1645 | |
<> | 144:ef7eb2e8f9f7 | 1646 | // Enable interrupt |
<> | 144:ef7eb2e8f9f7 | 1647 | USART_IntEnable(obj->serial.periph.uart, USART_IEN_TXBL); |
<> | 144:ef7eb2e8f9f7 | 1648 | } |
<> | 144:ef7eb2e8f9f7 | 1649 | } |
<> | 144:ef7eb2e8f9f7 | 1650 | |
<> | 144:ef7eb2e8f9f7 | 1651 | return 0; |
<> | 144:ef7eb2e8f9f7 | 1652 | } |
<> | 144:ef7eb2e8f9f7 | 1653 | |
<> | 144:ef7eb2e8f9f7 | 1654 | /** Begin asynchronous RX transfer (enable interrupt for data collecting) |
<> | 144:ef7eb2e8f9f7 | 1655 | * The used buffer is specified in the serial object - rx_buff |
<> | 144:ef7eb2e8f9f7 | 1656 | * |
<> | 144:ef7eb2e8f9f7 | 1657 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 1658 | * @param cb The function to call when an event occurs |
<> | 144:ef7eb2e8f9f7 | 1659 | * @param hint A suggestion for how to use DMA with this transfer |
<> | 144:ef7eb2e8f9f7 | 1660 | */ |
<> | 144:ef7eb2e8f9f7 | 1661 | 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 | 1662 | { |
<> | 144:ef7eb2e8f9f7 | 1663 | // Check that a buffer has indeed been set up |
<> | 144:ef7eb2e8f9f7 | 1664 | MBED_ASSERT(rx != (void*)0); |
<> | 144:ef7eb2e8f9f7 | 1665 | if(rx_length == 0) return; |
<> | 144:ef7eb2e8f9f7 | 1666 | |
<> | 144:ef7eb2e8f9f7 | 1667 | // Set up buffer |
<> | 144:ef7eb2e8f9f7 | 1668 | serial_rx_buffer_set(obj,(void*) rx, rx_length, rx_width); |
<> | 144:ef7eb2e8f9f7 | 1669 | |
<> | 144:ef7eb2e8f9f7 | 1670 | //disable character match if no character is specified |
<> | 144:ef7eb2e8f9f7 | 1671 | if(char_match == SERIAL_RESERVED_CHAR_MATCH){ |
<> | 144:ef7eb2e8f9f7 | 1672 | event &= ~SERIAL_EVENT_RX_CHARACTER_MATCH; |
<> | 144:ef7eb2e8f9f7 | 1673 | } |
<> | 144:ef7eb2e8f9f7 | 1674 | |
<> | 144:ef7eb2e8f9f7 | 1675 | /*clear all set interrupts*/ |
<> | 144:ef7eb2e8f9f7 | 1676 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1677 | LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_PERR | LEUART_IFC_FERR | LEUART_IFC_RXOF); |
<> | 144:ef7eb2e8f9f7 | 1678 | }else{ |
<> | 144:ef7eb2e8f9f7 | 1679 | USART_IntClear(obj->serial.periph.uart, USART_IFC_PERR | USART_IFC_FERR | USART_IFC_RXOF); |
<> | 144:ef7eb2e8f9f7 | 1680 | } |
<> | 144:ef7eb2e8f9f7 | 1681 | |
<> | 144:ef7eb2e8f9f7 | 1682 | // Set up events |
<> | 144:ef7eb2e8f9f7 | 1683 | serial_rx_enable_event(obj, SERIAL_EVENT_RX_ALL, false); |
<> | 144:ef7eb2e8f9f7 | 1684 | serial_rx_enable_event(obj, event, true); |
<> | 144:ef7eb2e8f9f7 | 1685 | obj->char_match = char_match; |
<> | 144:ef7eb2e8f9f7 | 1686 | |
<> | 144:ef7eb2e8f9f7 | 1687 | // Set up sleepmode |
<> | 144:ef7eb2e8f9f7 | 1688 | serial_block_sleep(obj); |
<> | 144:ef7eb2e8f9f7 | 1689 | |
<> | 144:ef7eb2e8f9f7 | 1690 | // Determine DMA strategy |
<> | 144:ef7eb2e8f9f7 | 1691 | // If character match is enabled, we can't use DMA, sadly. We could when using LEUART though, but that support is not in here yet. |
<> | 144:ef7eb2e8f9f7 | 1692 | // TODO: add DMA support for character matching with leuart |
<> | 144:ef7eb2e8f9f7 | 1693 | if(!(event & SERIAL_EVENT_RX_CHARACTER_MATCH)) { |
<> | 144:ef7eb2e8f9f7 | 1694 | serial_dmaTrySetState(&(obj->serial.dmaOptionsRX), hint, obj, false); |
<> | 144:ef7eb2e8f9f7 | 1695 | }else{ |
<> | 144:ef7eb2e8f9f7 | 1696 | serial_dmaTrySetState(&(obj->serial.dmaOptionsRX), DMA_USAGE_NEVER, obj, false); |
<> | 144:ef7eb2e8f9f7 | 1697 | } |
<> | 144:ef7eb2e8f9f7 | 1698 | |
<> | 144:ef7eb2e8f9f7 | 1699 | // If DMA, kick off DMA |
<> | 144:ef7eb2e8f9f7 | 1700 | if(obj->serial.dmaOptionsRX.dmaChannel >= 0) { |
<> | 144:ef7eb2e8f9f7 | 1701 | serial_dmaActivate(obj, (void*)handler, obj->rx_buff.buffer, obj->rx_buff.length, false); |
<> | 144:ef7eb2e8f9f7 | 1702 | } |
<> | 144:ef7eb2e8f9f7 | 1703 | // Else, activate interrupt. RXDATAV is responsible for incoming data notification. |
<> | 144:ef7eb2e8f9f7 | 1704 | else { |
<> | 144:ef7eb2e8f9f7 | 1705 | // Store callback |
<> | 144:ef7eb2e8f9f7 | 1706 | NVIC_ClearPendingIRQ(serial_get_rx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 1707 | NVIC_SetVector(serial_get_rx_irq_index(obj), (uint32_t)handler); |
<> | 144:ef7eb2e8f9f7 | 1708 | NVIC_EnableIRQ(serial_get_rx_irq_index(obj)); |
<> | 144:ef7eb2e8f9f7 | 1709 | |
<> | 144:ef7eb2e8f9f7 | 1710 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1711 | // Activate RX and clear RX buffer |
<> | 144:ef7eb2e8f9f7 | 1712 | obj->serial.periph.leuart->CMD = LEUART_CMD_CLEARRX; |
<> | 144:ef7eb2e8f9f7 | 1713 | obj->serial.periph.leuart->CMD = LEUART_CMD_RXEN; |
<> | 144:ef7eb2e8f9f7 | 1714 | while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD); |
<> | 144:ef7eb2e8f9f7 | 1715 | |
<> | 144:ef7eb2e8f9f7 | 1716 | // Enable interrupt |
<> | 144:ef7eb2e8f9f7 | 1717 | LEUART_IntEnable(obj->serial.periph.leuart, LEUART_IEN_RXDATAV); |
<> | 144:ef7eb2e8f9f7 | 1718 | } else { |
<> | 144:ef7eb2e8f9f7 | 1719 | // Activate RX and clear RX buffer |
<> | 144:ef7eb2e8f9f7 | 1720 | obj->serial.periph.uart->CMD = USART_CMD_RXEN | USART_CMD_CLEARRX; |
<> | 144:ef7eb2e8f9f7 | 1721 | |
<> | 144:ef7eb2e8f9f7 | 1722 | // Clear RXFULL |
<> | 144:ef7eb2e8f9f7 | 1723 | USART_IntClear(obj->serial.periph.uart, USART_IFC_RXFULL); |
<> | 144:ef7eb2e8f9f7 | 1724 | |
<> | 144:ef7eb2e8f9f7 | 1725 | // Enable interrupt |
<> | 144:ef7eb2e8f9f7 | 1726 | USART_IntEnable(obj->serial.periph.uart, USART_IEN_RXDATAV); |
<> | 144:ef7eb2e8f9f7 | 1727 | } |
<> | 144:ef7eb2e8f9f7 | 1728 | } |
<> | 144:ef7eb2e8f9f7 | 1729 | |
<> | 144:ef7eb2e8f9f7 | 1730 | return; |
<> | 144:ef7eb2e8f9f7 | 1731 | } |
<> | 144:ef7eb2e8f9f7 | 1732 | |
<> | 144:ef7eb2e8f9f7 | 1733 | /** Attempts to determine if the serial peripheral is already in use for TX |
<> | 144:ef7eb2e8f9f7 | 1734 | * |
<> | 144:ef7eb2e8f9f7 | 1735 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 1736 | * @return Non-zero if the TX transaction is ongoing, 0 otherwise |
<> | 144:ef7eb2e8f9f7 | 1737 | */ |
<> | 144:ef7eb2e8f9f7 | 1738 | uint8_t serial_tx_active(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1739 | { |
<> | 144:ef7eb2e8f9f7 | 1740 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1741 | return (obj->serial.periph.leuart->IEN & (LEUART_IEN_TXBL|LEUART_IEN_TXC)) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 1742 | } else { |
<> | 144:ef7eb2e8f9f7 | 1743 | return (obj->serial.periph.uart->IEN & (USART_IEN_TXBL|USART_IEN_TXC)) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 1744 | } |
<> | 144:ef7eb2e8f9f7 | 1745 | } |
<> | 144:ef7eb2e8f9f7 | 1746 | |
<> | 144:ef7eb2e8f9f7 | 1747 | /** Attempts to determine if the serial peripheral is already in use for RX |
<> | 144:ef7eb2e8f9f7 | 1748 | * |
<> | 144:ef7eb2e8f9f7 | 1749 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 1750 | * @return Non-zero if the RX transaction is ongoing, 0 otherwise |
<> | 144:ef7eb2e8f9f7 | 1751 | */ |
<> | 144:ef7eb2e8f9f7 | 1752 | uint8_t serial_rx_active(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1753 | { |
<> | 144:ef7eb2e8f9f7 | 1754 | switch(obj->serial.dmaOptionsRX.dmaUsageState) { |
<> | 144:ef7eb2e8f9f7 | 1755 | case DMA_USAGE_TEMPORARY_ALLOCATED: |
<> | 144:ef7eb2e8f9f7 | 1756 | /* Temporary allocation always means its active, as this state gets cleared afterwards */ |
<> | 144:ef7eb2e8f9f7 | 1757 | return 1; |
<> | 144:ef7eb2e8f9f7 | 1758 | case DMA_USAGE_ALLOCATED: |
<> | 144:ef7eb2e8f9f7 | 1759 | /* Check whether the allocated DMA channel is active by checking the DMA transfer */ |
<> | 144:ef7eb2e8f9f7 | 1760 | #ifndef LDMA_PRESENT |
<> | 144:ef7eb2e8f9f7 | 1761 | return DMA_ChannelEnabled(obj->serial.dmaOptionsRX.dmaChannel); |
<> | 144:ef7eb2e8f9f7 | 1762 | #else |
<> | 144:ef7eb2e8f9f7 | 1763 | // LDMA_TransferDone does not work since the CHDONE bits get cleared, |
<> | 144:ef7eb2e8f9f7 | 1764 | // so just check if the channel is enabled |
<> | 144:ef7eb2e8f9f7 | 1765 | return LDMA->CHEN & (1 << obj->serial.dmaOptionsRX.dmaChannel); |
<> | 144:ef7eb2e8f9f7 | 1766 | #endif |
<> | 144:ef7eb2e8f9f7 | 1767 | default: |
<> | 144:ef7eb2e8f9f7 | 1768 | /* Check whether interrupt for serial TX is enabled */ |
<> | 144:ef7eb2e8f9f7 | 1769 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1770 | return (obj->serial.periph.leuart->IEN & (LEUART_IEN_RXDATAV)) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 1771 | } else { |
<> | 144:ef7eb2e8f9f7 | 1772 | return (obj->serial.periph.uart->IEN & (USART_IEN_RXDATAV)) ? true : false; |
<> | 144:ef7eb2e8f9f7 | 1773 | } |
<> | 144:ef7eb2e8f9f7 | 1774 | } |
<> | 144:ef7eb2e8f9f7 | 1775 | } |
<> | 144:ef7eb2e8f9f7 | 1776 | |
<> | 144:ef7eb2e8f9f7 | 1777 | /** The asynchronous TX handler. Writes to the TX FIFO and checks for events. |
<> | 144:ef7eb2e8f9f7 | 1778 | * If any TX event has occured, the TX abort function is called. |
<> | 144:ef7eb2e8f9f7 | 1779 | * |
<> | 144:ef7eb2e8f9f7 | 1780 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 1781 | * @return Returns event flags if a TX transfer termination condition was met or 0 otherwise |
<> | 144:ef7eb2e8f9f7 | 1782 | */ |
<> | 144:ef7eb2e8f9f7 | 1783 | int serial_tx_irq_handler_asynch(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1784 | { |
<> | 144:ef7eb2e8f9f7 | 1785 | /* This interrupt handler is called from USART irq */ |
<> | 144:ef7eb2e8f9f7 | 1786 | uint8_t *buf = obj->tx_buff.buffer; |
<> | 144:ef7eb2e8f9f7 | 1787 | |
<> | 144:ef7eb2e8f9f7 | 1788 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1789 | if(obj->serial.periph.leuart->IEN & LEUART_IEN_TXBL){ |
<> | 144:ef7eb2e8f9f7 | 1790 | /* There is still data to send */ |
<> | 144:ef7eb2e8f9f7 | 1791 | while((LEUART_StatusGet(obj->serial.periph.leuart) & LEUART_STATUS_TXBL) && (obj->tx_buff.pos <= (obj->tx_buff.length - 1))) { |
<> | 144:ef7eb2e8f9f7 | 1792 | while (obj->serial.periph.leuart->SYNCBUSY); |
<> | 144:ef7eb2e8f9f7 | 1793 | LEUART_Tx(obj->serial.periph.leuart, buf[obj->tx_buff.pos]); |
<> | 144:ef7eb2e8f9f7 | 1794 | obj->tx_buff.pos++; |
<> | 144:ef7eb2e8f9f7 | 1795 | } |
<> | 144:ef7eb2e8f9f7 | 1796 | if(obj->tx_buff.pos >= obj->tx_buff.length){ |
<> | 144:ef7eb2e8f9f7 | 1797 | /* Last byte has been put in TX, set up TXC interrupt */ |
<> | 144:ef7eb2e8f9f7 | 1798 | LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_TXBL); |
<> | 144:ef7eb2e8f9f7 | 1799 | LEUART_IntEnable(obj->serial.periph.leuart, LEUART_IEN_TXC); |
<> | 144:ef7eb2e8f9f7 | 1800 | while (obj->serial.periph.leuart->SYNCBUSY); |
<> | 144:ef7eb2e8f9f7 | 1801 | } |
<> | 144:ef7eb2e8f9f7 | 1802 | }else if (obj->serial.periph.leuart->IF & LEUART_IF_TXC){ |
<> | 144:ef7eb2e8f9f7 | 1803 | /* Last byte has been successfully transmitted. Stop the procedure */ |
<> | 144:ef7eb2e8f9f7 | 1804 | serial_tx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1805 | return SERIAL_EVENT_TX_COMPLETE & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 1806 | } |
<> | 144:ef7eb2e8f9f7 | 1807 | } else { |
<> | 144:ef7eb2e8f9f7 | 1808 | if(obj->serial.periph.uart->IEN & USART_IEN_TXBL){ |
<> | 144:ef7eb2e8f9f7 | 1809 | /* There is still data to send */ |
<> | 144:ef7eb2e8f9f7 | 1810 | while((USART_StatusGet(obj->serial.periph.uart) & USART_STATUS_TXBL) && (obj->tx_buff.pos <= (obj->tx_buff.length - 1))) { |
<> | 144:ef7eb2e8f9f7 | 1811 | USART_Tx(obj->serial.periph.uart, buf[obj->tx_buff.pos]); |
<> | 144:ef7eb2e8f9f7 | 1812 | obj->tx_buff.pos++; |
<> | 144:ef7eb2e8f9f7 | 1813 | } |
<> | 144:ef7eb2e8f9f7 | 1814 | if(obj->tx_buff.pos >= obj->tx_buff.length){ |
<> | 144:ef7eb2e8f9f7 | 1815 | /* Last byte has been put in TX, set up TXC interrupt */ |
<> | 144:ef7eb2e8f9f7 | 1816 | USART_IntDisable(obj->serial.periph.uart, USART_IEN_TXBL); |
<> | 144:ef7eb2e8f9f7 | 1817 | USART_IntEnable(obj->serial.periph.uart, USART_IEN_TXC); |
<> | 144:ef7eb2e8f9f7 | 1818 | } |
<> | 144:ef7eb2e8f9f7 | 1819 | } else if (obj->serial.periph.uart->IF & USART_IF_TXC) { |
<> | 144:ef7eb2e8f9f7 | 1820 | /* Last byte has been successfully transmitted. Stop the procedure */ |
<> | 144:ef7eb2e8f9f7 | 1821 | serial_tx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1822 | return SERIAL_EVENT_TX_COMPLETE & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 1823 | } |
<> | 144:ef7eb2e8f9f7 | 1824 | } |
<> | 144:ef7eb2e8f9f7 | 1825 | return 0; |
<> | 144:ef7eb2e8f9f7 | 1826 | } |
<> | 144:ef7eb2e8f9f7 | 1827 | |
<> | 144:ef7eb2e8f9f7 | 1828 | /** The asynchronous RX handler. Reads from the RX FIFOF and checks for events. |
<> | 144:ef7eb2e8f9f7 | 1829 | * If any RX event has occured, the RX abort function is called. |
<> | 144:ef7eb2e8f9f7 | 1830 | * |
<> | 144:ef7eb2e8f9f7 | 1831 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 1832 | * @return Returns event flags if a RX transfer termination condition was met or 0 otherwise |
<> | 144:ef7eb2e8f9f7 | 1833 | */ |
<> | 144:ef7eb2e8f9f7 | 1834 | int serial_rx_irq_handler_asynch(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1835 | { |
<> | 144:ef7eb2e8f9f7 | 1836 | int event = 0; |
<> | 144:ef7eb2e8f9f7 | 1837 | |
<> | 144:ef7eb2e8f9f7 | 1838 | /* This interrupt handler is called from USART irq */ |
<> | 144:ef7eb2e8f9f7 | 1839 | uint8_t *buf = (uint8_t*)obj->rx_buff.buffer; |
<> | 144:ef7eb2e8f9f7 | 1840 | |
<> | 144:ef7eb2e8f9f7 | 1841 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1842 | /* Determine the source of the interrupt */ |
<> | 144:ef7eb2e8f9f7 | 1843 | if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_PERR) { |
<> | 144:ef7eb2e8f9f7 | 1844 | /* Parity error has occurred, and we are notifying. */ |
<> | 144:ef7eb2e8f9f7 | 1845 | LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_PERR); |
<> | 144:ef7eb2e8f9f7 | 1846 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1847 | return SERIAL_EVENT_RX_PARITY_ERROR; |
<> | 144:ef7eb2e8f9f7 | 1848 | } |
<> | 144:ef7eb2e8f9f7 | 1849 | |
<> | 144:ef7eb2e8f9f7 | 1850 | if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_FERR) { |
<> | 144:ef7eb2e8f9f7 | 1851 | /* Framing error has occurred, and we are notifying */ |
<> | 144:ef7eb2e8f9f7 | 1852 | LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_FERR); |
<> | 144:ef7eb2e8f9f7 | 1853 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1854 | return SERIAL_EVENT_RX_FRAMING_ERROR; |
<> | 144:ef7eb2e8f9f7 | 1855 | } |
<> | 144:ef7eb2e8f9f7 | 1856 | |
<> | 144:ef7eb2e8f9f7 | 1857 | if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_RXOF) { |
<> | 144:ef7eb2e8f9f7 | 1858 | /* RX buffer overflow has occurred, and we are notifying */ |
<> | 144:ef7eb2e8f9f7 | 1859 | LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_RXOF); |
<> | 144:ef7eb2e8f9f7 | 1860 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1861 | return SERIAL_EVENT_RX_OVERFLOW; |
<> | 144:ef7eb2e8f9f7 | 1862 | } |
<> | 144:ef7eb2e8f9f7 | 1863 | |
<> | 144:ef7eb2e8f9f7 | 1864 | if((LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_RXDATAV) || (LEUART_StatusGet(obj->serial.periph.leuart) & LEUART_STATUS_RXDATAV)) { |
<> | 144:ef7eb2e8f9f7 | 1865 | /* Valid data in buffer. Determine course of action: continue receiving or interrupt */ |
<> | 144:ef7eb2e8f9f7 | 1866 | if(obj->rx_buff.pos >= (obj->rx_buff.length - 1)) { |
<> | 144:ef7eb2e8f9f7 | 1867 | /* Last char, transfer complete. Switch off interrupt and return event. */ |
<> | 144:ef7eb2e8f9f7 | 1868 | buf[obj->rx_buff.pos] = LEUART_RxDataGet(obj->serial.periph.leuart); |
<> | 144:ef7eb2e8f9f7 | 1869 | |
<> | 144:ef7eb2e8f9f7 | 1870 | event |= SERIAL_EVENT_RX_COMPLETE; |
<> | 144:ef7eb2e8f9f7 | 1871 | |
<> | 144:ef7eb2e8f9f7 | 1872 | if((buf[obj->rx_buff.pos] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) event |= SERIAL_EVENT_RX_CHARACTER_MATCH; |
<> | 144:ef7eb2e8f9f7 | 1873 | |
<> | 144:ef7eb2e8f9f7 | 1874 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1875 | return event & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 1876 | } else { |
<> | 144:ef7eb2e8f9f7 | 1877 | /* There's still space in the receive buffer */ |
<> | 144:ef7eb2e8f9f7 | 1878 | while((LEUART_StatusGet(obj->serial.periph.leuart) & LEUART_STATUS_RXDATAV) && (obj->rx_buff.pos <= (obj->rx_buff.length - 1))) { |
<> | 144:ef7eb2e8f9f7 | 1879 | bool aborting = false; |
<> | 144:ef7eb2e8f9f7 | 1880 | buf[obj->rx_buff.pos] = LEUART_RxDataGet(obj->serial.periph.leuart); |
<> | 144:ef7eb2e8f9f7 | 1881 | obj->rx_buff.pos++; |
<> | 144:ef7eb2e8f9f7 | 1882 | |
<> | 144:ef7eb2e8f9f7 | 1883 | /* Check for character match event */ |
<> | 144:ef7eb2e8f9f7 | 1884 | if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) { |
<> | 144:ef7eb2e8f9f7 | 1885 | aborting = true; |
<> | 144:ef7eb2e8f9f7 | 1886 | event |= SERIAL_EVENT_RX_CHARACTER_MATCH; |
<> | 144:ef7eb2e8f9f7 | 1887 | } |
<> | 144:ef7eb2e8f9f7 | 1888 | |
<> | 144:ef7eb2e8f9f7 | 1889 | /* Check for final char event */ |
<> | 144:ef7eb2e8f9f7 | 1890 | if(obj->rx_buff.pos >= (obj->rx_buff.length)) { |
<> | 144:ef7eb2e8f9f7 | 1891 | aborting = true; |
<> | 144:ef7eb2e8f9f7 | 1892 | event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 1893 | } |
<> | 144:ef7eb2e8f9f7 | 1894 | |
<> | 144:ef7eb2e8f9f7 | 1895 | if(aborting) { |
<> | 144:ef7eb2e8f9f7 | 1896 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1897 | return event & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 1898 | } |
<> | 144:ef7eb2e8f9f7 | 1899 | } |
<> | 144:ef7eb2e8f9f7 | 1900 | } |
<> | 144:ef7eb2e8f9f7 | 1901 | } |
<> | 144:ef7eb2e8f9f7 | 1902 | } else { |
<> | 144:ef7eb2e8f9f7 | 1903 | /* Determine the source of the interrupt */ |
<> | 144:ef7eb2e8f9f7 | 1904 | if(USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_PERR) { |
<> | 144:ef7eb2e8f9f7 | 1905 | /* Parity error has occurred, and we are notifying. */ |
<> | 144:ef7eb2e8f9f7 | 1906 | USART_IntClear(obj->serial.periph.uart, USART_IFC_PERR); |
<> | 144:ef7eb2e8f9f7 | 1907 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1908 | return SERIAL_EVENT_RX_PARITY_ERROR; |
<> | 144:ef7eb2e8f9f7 | 1909 | } |
<> | 144:ef7eb2e8f9f7 | 1910 | |
<> | 144:ef7eb2e8f9f7 | 1911 | if(USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_FERR) { |
<> | 144:ef7eb2e8f9f7 | 1912 | /* Framing error has occurred, and we are notifying */ |
<> | 144:ef7eb2e8f9f7 | 1913 | USART_IntClear(obj->serial.periph.uart, USART_IFC_FERR); |
<> | 144:ef7eb2e8f9f7 | 1914 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1915 | return SERIAL_EVENT_RX_FRAMING_ERROR; |
<> | 144:ef7eb2e8f9f7 | 1916 | } |
<> | 144:ef7eb2e8f9f7 | 1917 | |
<> | 144:ef7eb2e8f9f7 | 1918 | if(USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_RXOF) { |
<> | 144:ef7eb2e8f9f7 | 1919 | /* RX buffer overflow has occurred, and we are notifying */ |
<> | 144:ef7eb2e8f9f7 | 1920 | USART_IntClear(obj->serial.periph.uart, USART_IFC_RXOF); |
<> | 144:ef7eb2e8f9f7 | 1921 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1922 | return SERIAL_EVENT_RX_OVERFLOW; |
<> | 144:ef7eb2e8f9f7 | 1923 | } |
<> | 144:ef7eb2e8f9f7 | 1924 | |
<> | 144:ef7eb2e8f9f7 | 1925 | if((USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_RXDATAV) || (USART_StatusGet(obj->serial.periph.uart) & USART_STATUS_RXFULL)) { |
<> | 144:ef7eb2e8f9f7 | 1926 | /* Valid data in buffer. Determine course of action: continue receiving or interrupt */ |
<> | 144:ef7eb2e8f9f7 | 1927 | if(obj->rx_buff.pos >= (obj->rx_buff.length - 1)) { |
<> | 144:ef7eb2e8f9f7 | 1928 | /* Last char, transfer complete. Switch off interrupt and return event. */ |
<> | 144:ef7eb2e8f9f7 | 1929 | buf[obj->rx_buff.pos] = USART_RxDataGet(obj->serial.periph.uart); |
<> | 144:ef7eb2e8f9f7 | 1930 | |
<> | 144:ef7eb2e8f9f7 | 1931 | event |= SERIAL_EVENT_RX_COMPLETE; |
<> | 144:ef7eb2e8f9f7 | 1932 | |
<> | 144:ef7eb2e8f9f7 | 1933 | if((buf[obj->rx_buff.pos] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) event |= SERIAL_EVENT_RX_CHARACTER_MATCH; |
<> | 144:ef7eb2e8f9f7 | 1934 | |
<> | 144:ef7eb2e8f9f7 | 1935 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1936 | return event & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 1937 | } else { |
<> | 144:ef7eb2e8f9f7 | 1938 | /* There's still space in the receive buffer */ |
<> | 144:ef7eb2e8f9f7 | 1939 | while(((USART_StatusGet(obj->serial.periph.uart) & USART_STATUS_RXDATAV) || (USART_StatusGet(obj->serial.periph.uart) & USART_IF_RXFULL)) && (obj->rx_buff.pos <= (obj->rx_buff.length - 1))) { |
<> | 144:ef7eb2e8f9f7 | 1940 | bool aborting = false; |
<> | 144:ef7eb2e8f9f7 | 1941 | buf[obj->rx_buff.pos] = USART_RxDataGet(obj->serial.periph.uart); |
<> | 144:ef7eb2e8f9f7 | 1942 | obj->rx_buff.pos++; |
<> | 144:ef7eb2e8f9f7 | 1943 | |
<> | 144:ef7eb2e8f9f7 | 1944 | /* Check for character match event */ |
<> | 144:ef7eb2e8f9f7 | 1945 | if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) { |
<> | 144:ef7eb2e8f9f7 | 1946 | aborting = true; |
<> | 144:ef7eb2e8f9f7 | 1947 | event |= SERIAL_EVENT_RX_CHARACTER_MATCH; |
<> | 144:ef7eb2e8f9f7 | 1948 | } |
<> | 144:ef7eb2e8f9f7 | 1949 | |
<> | 144:ef7eb2e8f9f7 | 1950 | /* Check for final char event */ |
<> | 144:ef7eb2e8f9f7 | 1951 | if(obj->rx_buff.pos >= (obj->rx_buff.length)) { |
<> | 144:ef7eb2e8f9f7 | 1952 | aborting = true; |
<> | 144:ef7eb2e8f9f7 | 1953 | event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 1954 | } |
<> | 144:ef7eb2e8f9f7 | 1955 | |
<> | 144:ef7eb2e8f9f7 | 1956 | if(aborting) { |
<> | 144:ef7eb2e8f9f7 | 1957 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1958 | return event & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 1959 | } |
<> | 144:ef7eb2e8f9f7 | 1960 | } |
<> | 144:ef7eb2e8f9f7 | 1961 | } |
<> | 144:ef7eb2e8f9f7 | 1962 | } |
<> | 144:ef7eb2e8f9f7 | 1963 | } |
<> | 144:ef7eb2e8f9f7 | 1964 | |
<> | 144:ef7eb2e8f9f7 | 1965 | /* All events should have generated a return, if no return has happened, no event has been caught */ |
<> | 144:ef7eb2e8f9f7 | 1966 | return 0; |
<> | 144:ef7eb2e8f9f7 | 1967 | } |
<> | 144:ef7eb2e8f9f7 | 1968 | |
<> | 144:ef7eb2e8f9f7 | 1969 | /** Unified IRQ handler. Determines the appropriate handler to execute and returns the flags. |
<> | 144:ef7eb2e8f9f7 | 1970 | * |
<> | 144:ef7eb2e8f9f7 | 1971 | * WARNING: this code should be stateless, as re-entrancy is very possible in interrupt-based mode. |
<> | 144:ef7eb2e8f9f7 | 1972 | */ |
<> | 144:ef7eb2e8f9f7 | 1973 | int serial_irq_handler_asynch(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 1974 | { |
<> | 144:ef7eb2e8f9f7 | 1975 | uint32_t txc_int; |
<> | 144:ef7eb2e8f9f7 | 1976 | |
<> | 144:ef7eb2e8f9f7 | 1977 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1978 | txc_int = LEUART_IntGetEnabled(obj->serial.periph.leuart) & LEUART_IF_TXC; |
<> | 144:ef7eb2e8f9f7 | 1979 | } else { |
<> | 144:ef7eb2e8f9f7 | 1980 | txc_int = USART_IntGetEnabled(obj->serial.periph.uart) & USART_IF_TXC; |
<> | 144:ef7eb2e8f9f7 | 1981 | } |
<> | 144:ef7eb2e8f9f7 | 1982 | |
<> | 144:ef7eb2e8f9f7 | 1983 | /* First, check if we're running in DMA mode */ |
<> | 144:ef7eb2e8f9f7 | 1984 | if( (obj->serial.dmaOptionsRX.dmaChannel != -1) && |
<> | 144:ef7eb2e8f9f7 | 1985 | serial_dma_irq_fired[obj->serial.dmaOptionsRX.dmaChannel]) { |
<> | 144:ef7eb2e8f9f7 | 1986 | /* Clean up */ |
<> | 144:ef7eb2e8f9f7 | 1987 | serial_dma_irq_fired[obj->serial.dmaOptionsRX.dmaChannel] = false; |
<> | 144:ef7eb2e8f9f7 | 1988 | serial_rx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1989 | |
<> | 144:ef7eb2e8f9f7 | 1990 | /* Notify CPP land of RX completion */ |
<> | 144:ef7eb2e8f9f7 | 1991 | return SERIAL_EVENT_RX_COMPLETE & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 1992 | } else if (txc_int && (obj->serial.dmaOptionsTX.dmaChannel != -1) && |
<> | 144:ef7eb2e8f9f7 | 1993 | serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel]) { |
<> | 144:ef7eb2e8f9f7 | 1994 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 1995 | /* Clean up */ |
<> | 144:ef7eb2e8f9f7 | 1996 | serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel] = false; |
<> | 144:ef7eb2e8f9f7 | 1997 | serial_tx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 1998 | /* Notify CPP land of completion */ |
<> | 144:ef7eb2e8f9f7 | 1999 | return SERIAL_EVENT_TX_COMPLETE & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 2000 | }else{ |
<> | 144:ef7eb2e8f9f7 | 2001 | /* Clean up */ |
<> | 144:ef7eb2e8f9f7 | 2002 | serial_dma_irq_fired[obj->serial.dmaOptionsTX.dmaChannel] = false; |
<> | 144:ef7eb2e8f9f7 | 2003 | serial_tx_abort_asynch_intern(obj, 1); |
<> | 144:ef7eb2e8f9f7 | 2004 | /* Notify CPP land of completion */ |
<> | 144:ef7eb2e8f9f7 | 2005 | return SERIAL_EVENT_TX_COMPLETE & obj->serial.events; |
<> | 144:ef7eb2e8f9f7 | 2006 | } |
<> | 144:ef7eb2e8f9f7 | 2007 | } else { |
<> | 144:ef7eb2e8f9f7 | 2008 | /* Check the NVIC to see which interrupt we're running from |
<> | 144:ef7eb2e8f9f7 | 2009 | * Also make sure to prioritize RX */ |
<> | 144:ef7eb2e8f9f7 | 2010 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 2011 | //Different method of checking tx vs rx for LEUART |
<> | 144:ef7eb2e8f9f7 | 2012 | if(LEUART_IntGetEnabled(obj->serial.periph.leuart) & (LEUART_IF_RXDATAV | LEUART_IF_FERR | LEUART_IF_PERR | LEUART_IF_RXOF)) { |
<> | 144:ef7eb2e8f9f7 | 2013 | return serial_rx_irq_handler_asynch(obj); |
<> | 144:ef7eb2e8f9f7 | 2014 | } else if(LEUART_StatusGet(obj->serial.periph.leuart) & (LEUART_STATUS_TXBL | LEUART_STATUS_TXC)) { |
<> | 144:ef7eb2e8f9f7 | 2015 | return serial_tx_irq_handler_asynch(obj); |
<> | 144:ef7eb2e8f9f7 | 2016 | } |
<> | 144:ef7eb2e8f9f7 | 2017 | } else { |
<> | 144:ef7eb2e8f9f7 | 2018 | if(USART_IntGetEnabled(obj->serial.periph.uart) & (USART_IF_RXDATAV | USART_IF_RXOF | USART_IF_PERR | USART_IF_FERR)) { |
<> | 144:ef7eb2e8f9f7 | 2019 | return serial_rx_irq_handler_asynch(obj); |
<> | 144:ef7eb2e8f9f7 | 2020 | } else if(USART_StatusGet(obj->serial.periph.uart) & (USART_STATUS_TXBL | USART_STATUS_TXC)){ |
<> | 144:ef7eb2e8f9f7 | 2021 | return serial_tx_irq_handler_asynch(obj); |
<> | 144:ef7eb2e8f9f7 | 2022 | } |
<> | 144:ef7eb2e8f9f7 | 2023 | } |
<> | 144:ef7eb2e8f9f7 | 2024 | } |
<> | 144:ef7eb2e8f9f7 | 2025 | |
<> | 144:ef7eb2e8f9f7 | 2026 | // All should be done now |
<> | 144:ef7eb2e8f9f7 | 2027 | return 0; |
<> | 144:ef7eb2e8f9f7 | 2028 | } |
<> | 144:ef7eb2e8f9f7 | 2029 | |
<> | 144:ef7eb2e8f9f7 | 2030 | /** Abort the ongoing TX transaction. It disables the enabled interupt for TX and |
<> | 144:ef7eb2e8f9f7 | 2031 | * flush TX hardware buffer if TX FIFO is used |
<> | 144:ef7eb2e8f9f7 | 2032 | * |
<> | 144:ef7eb2e8f9f7 | 2033 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 2034 | */ |
<> | 144:ef7eb2e8f9f7 | 2035 | void serial_tx_abort_asynch(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 2036 | { |
<> | 144:ef7eb2e8f9f7 | 2037 | serial_tx_abort_asynch_intern(obj, 0); |
<> | 144:ef7eb2e8f9f7 | 2038 | } |
<> | 144:ef7eb2e8f9f7 | 2039 | |
<> | 144:ef7eb2e8f9f7 | 2040 | static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep) |
<> | 144:ef7eb2e8f9f7 | 2041 | { |
<> | 144:ef7eb2e8f9f7 | 2042 | // Transmitter should be disabled here but there are multiple issues |
<> | 144:ef7eb2e8f9f7 | 2043 | // making that quite difficult. |
<> | 144:ef7eb2e8f9f7 | 2044 | // |
<> | 144:ef7eb2e8f9f7 | 2045 | // - Disabling the transmitter when using DMA on platforms prior to |
<> | 144:ef7eb2e8f9f7 | 2046 | // Pearl can cause the UART to leave the line low, generating a break |
<> | 144:ef7eb2e8f9f7 | 2047 | // condition until the next transmission begins. |
<> | 144:ef7eb2e8f9f7 | 2048 | // |
<> | 144:ef7eb2e8f9f7 | 2049 | // - On (at least) Pearl, once TXC interrupt has fired it will take some time |
<> | 144:ef7eb2e8f9f7 | 2050 | // (some tens of microsec) for TXC to be set in STATUS. If we turn off |
<> | 144:ef7eb2e8f9f7 | 2051 | // the transmitter before this, bad things will happen. |
<> | 144:ef7eb2e8f9f7 | 2052 | // |
<> | 144:ef7eb2e8f9f7 | 2053 | // - On (at least) Pearl, when using TX DMA it is possible for the USART |
<> | 144:ef7eb2e8f9f7 | 2054 | // status to be: TXENS TXBL TXIDLE = 1, TXBUFCNT = 0, but TXC = 0. |
<> | 144:ef7eb2e8f9f7 | 2055 | // |
<> | 144:ef7eb2e8f9f7 | 2056 | // All in all, the logic was so fragile it's best to leave it out. |
<> | 144:ef7eb2e8f9f7 | 2057 | |
<> | 144:ef7eb2e8f9f7 | 2058 | /* Clean up */ |
<> | 144:ef7eb2e8f9f7 | 2059 | switch(obj->serial.dmaOptionsTX.dmaUsageState) { |
<> | 144:ef7eb2e8f9f7 | 2060 | case DMA_USAGE_ALLOCATED: |
<> | 144:ef7eb2e8f9f7 | 2061 | /* stop DMA transfer */ |
<> | 144:ef7eb2e8f9f7 | 2062 | #ifndef LDMA_PRESENT |
<> | 144:ef7eb2e8f9f7 | 2063 | DMA_ChannelEnable(obj->serial.dmaOptionsTX.dmaChannel, false); |
<> | 144:ef7eb2e8f9f7 | 2064 | #else |
<> | 144:ef7eb2e8f9f7 | 2065 | LDMA_StopTransfer(obj->serial.dmaOptionsTX.dmaChannel); |
<> | 144:ef7eb2e8f9f7 | 2066 | #endif |
<> | 144:ef7eb2e8f9f7 | 2067 | break; |
<> | 144:ef7eb2e8f9f7 | 2068 | case DMA_USAGE_TEMPORARY_ALLOCATED: |
<> | 144:ef7eb2e8f9f7 | 2069 | /* stop DMA transfer and release channel */ |
<> | 144:ef7eb2e8f9f7 | 2070 | #ifndef LDMA_PRESENT |
<> | 144:ef7eb2e8f9f7 | 2071 | DMA_ChannelEnable(obj->serial.dmaOptionsTX.dmaChannel, false); |
<> | 144:ef7eb2e8f9f7 | 2072 | #else |
<> | 144:ef7eb2e8f9f7 | 2073 | LDMA_StopTransfer(obj->serial.dmaOptionsTX.dmaChannel); |
<> | 144:ef7eb2e8f9f7 | 2074 | #endif |
<> | 144:ef7eb2e8f9f7 | 2075 | dma_channel_free(obj->serial.dmaOptionsTX.dmaChannel); |
<> | 144:ef7eb2e8f9f7 | 2076 | obj->serial.dmaOptionsTX.dmaChannel = -1; |
<> | 144:ef7eb2e8f9f7 | 2077 | obj->serial.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC; |
<> | 144:ef7eb2e8f9f7 | 2078 | break; |
<> | 144:ef7eb2e8f9f7 | 2079 | default: |
<> | 144:ef7eb2e8f9f7 | 2080 | break; |
<> | 144:ef7eb2e8f9f7 | 2081 | } |
<> | 144:ef7eb2e8f9f7 | 2082 | |
<> | 144:ef7eb2e8f9f7 | 2083 | /* stop interrupting */ |
<> | 144:ef7eb2e8f9f7 | 2084 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 2085 | LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_TXBL); |
<> | 144:ef7eb2e8f9f7 | 2086 | LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_TXC); |
<> | 144:ef7eb2e8f9f7 | 2087 | LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_TXC); |
<> | 144:ef7eb2e8f9f7 | 2088 | } else { |
<> | 144:ef7eb2e8f9f7 | 2089 | USART_IntDisable(obj->serial.periph.uart, USART_IEN_TXBL); |
<> | 144:ef7eb2e8f9f7 | 2090 | USART_IntDisable(obj->serial.periph.uart, USART_IEN_TXC); |
<> | 144:ef7eb2e8f9f7 | 2091 | USART_IntClear(obj->serial.periph.uart, USART_IFC_TXC); |
<> | 144:ef7eb2e8f9f7 | 2092 | } |
<> | 144:ef7eb2e8f9f7 | 2093 | |
<> | 144:ef7eb2e8f9f7 | 2094 | /* Say that we can stop using this emode */ |
<> | 144:ef7eb2e8f9f7 | 2095 | if(unblock_sleep) |
<> | 144:ef7eb2e8f9f7 | 2096 | serial_unblock_sleep(obj); |
<> | 144:ef7eb2e8f9f7 | 2097 | } |
<> | 144:ef7eb2e8f9f7 | 2098 | |
<> | 144:ef7eb2e8f9f7 | 2099 | |
<> | 144:ef7eb2e8f9f7 | 2100 | static void serial_unblock_sleep(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 2101 | { |
<> | 144:ef7eb2e8f9f7 | 2102 | if( obj->serial.sleep_blocked > 0 ) { |
<> | 144:ef7eb2e8f9f7 | 2103 | #ifdef LEUART_USING_LFXO |
<> | 144:ef7eb2e8f9f7 | 2104 | if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){ |
<> | 144:ef7eb2e8f9f7 | 2105 | unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART); |
<> | 144:ef7eb2e8f9f7 | 2106 | }else{ |
<> | 144:ef7eb2e8f9f7 | 2107 | unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE); |
<> | 144:ef7eb2e8f9f7 | 2108 | } |
<> | 144:ef7eb2e8f9f7 | 2109 | #else |
<> | 144:ef7eb2e8f9f7 | 2110 | unblockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE); |
<> | 144:ef7eb2e8f9f7 | 2111 | #endif |
<> | 144:ef7eb2e8f9f7 | 2112 | obj->serial.sleep_blocked--; |
<> | 144:ef7eb2e8f9f7 | 2113 | } |
<> | 144:ef7eb2e8f9f7 | 2114 | } |
<> | 144:ef7eb2e8f9f7 | 2115 | |
<> | 144:ef7eb2e8f9f7 | 2116 | static void serial_block_sleep(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 2117 | { |
<> | 144:ef7eb2e8f9f7 | 2118 | obj->serial.sleep_blocked++; |
<> | 144:ef7eb2e8f9f7 | 2119 | #ifdef LEUART_USING_LFXO |
<> | 144:ef7eb2e8f9f7 | 2120 | if(LEUART_REF_VALID(obj->serial.periph.leuart) && (LEUART_BaudrateGet(obj->serial.periph.leuart) <= (LEUART_LF_REF_FREQ/2))){ |
<> | 144:ef7eb2e8f9f7 | 2121 | blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE_LEUART); |
<> | 144:ef7eb2e8f9f7 | 2122 | }else{ |
<> | 144:ef7eb2e8f9f7 | 2123 | blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE); |
<> | 144:ef7eb2e8f9f7 | 2124 | } |
<> | 144:ef7eb2e8f9f7 | 2125 | #else |
<> | 144:ef7eb2e8f9f7 | 2126 | blockSleepMode(SERIAL_LEAST_ACTIVE_SLEEPMODE); |
<> | 144:ef7eb2e8f9f7 | 2127 | #endif |
<> | 144:ef7eb2e8f9f7 | 2128 | } |
<> | 144:ef7eb2e8f9f7 | 2129 | |
<> | 144:ef7eb2e8f9f7 | 2130 | /** Abort the ongoing RX transaction It disables the enabled interrupt for RX and |
<> | 144:ef7eb2e8f9f7 | 2131 | * flush RX hardware buffer if RX FIFO is used |
<> | 144:ef7eb2e8f9f7 | 2132 | * |
<> | 144:ef7eb2e8f9f7 | 2133 | * @param obj The serial object |
<> | 144:ef7eb2e8f9f7 | 2134 | */ |
<> | 144:ef7eb2e8f9f7 | 2135 | void serial_rx_abort_asynch(serial_t *obj) |
<> | 144:ef7eb2e8f9f7 | 2136 | { |
<> | 144:ef7eb2e8f9f7 | 2137 | serial_rx_abort_asynch_intern(obj, 0); |
<> | 144:ef7eb2e8f9f7 | 2138 | } |
<> | 144:ef7eb2e8f9f7 | 2139 | |
<> | 144:ef7eb2e8f9f7 | 2140 | static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep) |
<> | 144:ef7eb2e8f9f7 | 2141 | { |
<> | 144:ef7eb2e8f9f7 | 2142 | /* Stop receiver */ |
<> | 144:ef7eb2e8f9f7 | 2143 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 2144 | obj->serial.periph.leuart->CMD = LEUART_CMD_RXDIS; |
<> | 144:ef7eb2e8f9f7 | 2145 | while(obj->serial.periph.leuart->SYNCBUSY & LEUART_SYNCBUSY_CMD); |
<> | 144:ef7eb2e8f9f7 | 2146 | } else { |
<> | 144:ef7eb2e8f9f7 | 2147 | obj->serial.periph.uart->CMD = USART_CMD_RXDIS; |
<> | 144:ef7eb2e8f9f7 | 2148 | } |
<> | 144:ef7eb2e8f9f7 | 2149 | |
<> | 144:ef7eb2e8f9f7 | 2150 | /* Clean up */ |
<> | 144:ef7eb2e8f9f7 | 2151 | switch(obj->serial.dmaOptionsRX.dmaUsageState) { |
<> | 144:ef7eb2e8f9f7 | 2152 | case DMA_USAGE_ALLOCATED: |
<> | 144:ef7eb2e8f9f7 | 2153 | /* stop DMA transfer */ |
<> | 144:ef7eb2e8f9f7 | 2154 | #ifndef LDMA_PRESENT |
<> | 144:ef7eb2e8f9f7 | 2155 | DMA_ChannelEnable(obj->serial.dmaOptionsRX.dmaChannel, false); |
<> | 144:ef7eb2e8f9f7 | 2156 | #else |
<> | 144:ef7eb2e8f9f7 | 2157 | LDMA_StopTransfer(obj->serial.dmaOptionsRX.dmaChannel); |
<> | 144:ef7eb2e8f9f7 | 2158 | #endif |
<> | 144:ef7eb2e8f9f7 | 2159 | break; |
<> | 144:ef7eb2e8f9f7 | 2160 | case DMA_USAGE_TEMPORARY_ALLOCATED: |
<> | 144:ef7eb2e8f9f7 | 2161 | /* stop DMA transfer and release channel */ |
<> | 144:ef7eb2e8f9f7 | 2162 | #ifndef LDMA_PRESENT |
<> | 144:ef7eb2e8f9f7 | 2163 | DMA_ChannelEnable(obj->serial.dmaOptionsRX.dmaChannel, false); |
<> | 144:ef7eb2e8f9f7 | 2164 | #else |
<> | 144:ef7eb2e8f9f7 | 2165 | LDMA_StopTransfer(obj->serial.dmaOptionsRX.dmaChannel); |
<> | 144:ef7eb2e8f9f7 | 2166 | #endif |
<> | 144:ef7eb2e8f9f7 | 2167 | dma_channel_free(obj->serial.dmaOptionsRX.dmaChannel); |
<> | 144:ef7eb2e8f9f7 | 2168 | obj->serial.dmaOptionsRX.dmaChannel = -1; |
<> | 144:ef7eb2e8f9f7 | 2169 | obj->serial.dmaOptionsRX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC; |
<> | 144:ef7eb2e8f9f7 | 2170 | break; |
<> | 144:ef7eb2e8f9f7 | 2171 | default: |
<> | 144:ef7eb2e8f9f7 | 2172 | /* stop interrupting */ |
<> | 144:ef7eb2e8f9f7 | 2173 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 2174 | LEUART_IntDisable(obj->serial.periph.leuart, LEUART_IEN_RXDATAV | LEUART_IEN_PERR | LEUART_IEN_FERR | LEUART_IEN_RXOF); |
<> | 144:ef7eb2e8f9f7 | 2175 | } else { |
<> | 144:ef7eb2e8f9f7 | 2176 | USART_IntDisable(obj->serial.periph.uart, USART_IEN_RXDATAV | USART_IEN_PERR | USART_IEN_FERR | USART_IEN_RXOF); |
<> | 144:ef7eb2e8f9f7 | 2177 | } |
<> | 144:ef7eb2e8f9f7 | 2178 | break; |
<> | 144:ef7eb2e8f9f7 | 2179 | } |
<> | 144:ef7eb2e8f9f7 | 2180 | |
<> | 144:ef7eb2e8f9f7 | 2181 | /*clear all set interrupts*/ |
<> | 144:ef7eb2e8f9f7 | 2182 | if(LEUART_REF_VALID(obj->serial.periph.leuart)) { |
<> | 144:ef7eb2e8f9f7 | 2183 | LEUART_IntClear(obj->serial.periph.leuart, LEUART_IFC_PERR | LEUART_IFC_FERR | LEUART_IFC_RXOF); |
<> | 144:ef7eb2e8f9f7 | 2184 | }else{ |
<> | 144:ef7eb2e8f9f7 | 2185 | USART_IntClear(obj->serial.periph.uart, USART_IFC_PERR | USART_IFC_FERR | USART_IFC_RXOF); |
<> | 144:ef7eb2e8f9f7 | 2186 | } |
<> | 144:ef7eb2e8f9f7 | 2187 | |
<> | 144:ef7eb2e8f9f7 | 2188 | /* Say that we can stop using this emode */ |
<> | 144:ef7eb2e8f9f7 | 2189 | if( unblock_sleep ) |
<> | 144:ef7eb2e8f9f7 | 2190 | serial_unblock_sleep(obj); |
<> | 144:ef7eb2e8f9f7 | 2191 | } |
<> | 144:ef7eb2e8f9f7 | 2192 | |
<> | 144:ef7eb2e8f9f7 | 2193 | #endif //DEVICE_SERIAL_ASYNCH |
<> | 144:ef7eb2e8f9f7 | 2194 | #endif //DEVICE_SERIAL |