added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
mbed_official
Date:
Fri Jan 15 07:45:16 2016 +0000
Revision:
50:a417edff4437
Parent:
22:9c52de9bc1d7
Child:
52:4ce9155acc4d
Synchronized with git revision 6010f32619bfcbb01cc73747d4ff9040863482d9

Full URL: https://github.com/mbedmicro/mbed/commit/6010f32619bfcbb01cc73747d4ff9040863482d9/

Remove doubling of buffer size in realiseEndpoint()

Who changed what in which revision?

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