added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
mbed_official
Date:
Tue Nov 17 10:15:10 2015 +0000
Revision:
22:9c52de9bc1d7
Parent:
0:9b334a45a8ff
Child:
50:a417edff4437
Synchronized with git revision 8c540341dd44e9b99388db7b8389d756a7103dfd

Full URL: https://github.com/mbedmicro/mbed/commit/8c540341dd44e9b99388db7b8389d756a7103dfd/

Bugfixes to EFM32 serial, spi and sleep HAL

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