mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Committer:
be_bryan
Date:
Mon Dec 11 17:54:04 2017 +0000
Revision:
0:b74591d5ab33
motor ++

Who changed what in which revision?

UserRevisionLine numberNew contents of line
be_bryan 0:b74591d5ab33 1 /* mbed Microcontroller Library
be_bryan 0:b74591d5ab33 2 * Copyright (c) 2016 u-blox
be_bryan 0:b74591d5ab33 3 *
be_bryan 0:b74591d5ab33 4 * Licensed under the Apache License, Version 2.0 (the "License");
be_bryan 0:b74591d5ab33 5 * you may not use this file except in compliance with the License.
be_bryan 0:b74591d5ab33 6 * You may obtain a copy of the License at
be_bryan 0:b74591d5ab33 7 *
be_bryan 0:b74591d5ab33 8 * http://www.apache.org/licenses/LICENSE-2.0
be_bryan 0:b74591d5ab33 9 *
be_bryan 0:b74591d5ab33 10 * Unless required by applicable law or agreed to in writing, software
be_bryan 0:b74591d5ab33 11 * distributed under the License is distributed on an "AS IS" BASIS,
be_bryan 0:b74591d5ab33 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
be_bryan 0:b74591d5ab33 13 * See the License for the specific language governing permissions and
be_bryan 0:b74591d5ab33 14 * limitations under the License.
be_bryan 0:b74591d5ab33 15 */
be_bryan 0:b74591d5ab33 16
be_bryan 0:b74591d5ab33 17 /* The serial driver connects UART HW to mbed and also associates the UART
be_bryan 0:b74591d5ab33 18 * HW with physical pins. Any physical pin can be linked to any UART,
be_bryan 0:b74591d5ab33 19 * however the mbed serial port initialisation API makes no mention of
be_bryan 0:b74591d5ab33 20 * which UART HW is to be used (only the pins) and hence the driver needs
be_bryan 0:b74591d5ab33 21 * to make some decisions for itself.
be_bryan 0:b74591d5ab33 22 *
be_bryan 0:b74591d5ab33 23 * There are two and a half UARTs on the chip: UART0, UART1 and a
be_bryan 0:b74591d5ab33 24 * lower-power, receive-only UART that is clocked from 32 kHz and can
be_bryan 0:b74591d5ab33 25 * therefore be awake while the rest of the chip is sleeping peacefully.
be_bryan 0:b74591d5ab33 26 * This provides maximal power saving, however the LP UART can only run
be_bryan 0:b74591d5ab33 27 * at 9600 bits/s (which is quite sufficient for all NB-IoT needs).
be_bryan 0:b74591d5ab33 28 *
be_bryan 0:b74591d5ab33 29 * So, if the baud rate is 9600 the driver code configures the LP UART
be_bryan 0:b74591d5ab33 30 * for Rx and UART0 for Tx. If the baud rate is not 9600 then it configures
be_bryan 0:b74591d5ab33 31 * UART0 for both Rx and Tx. Unless... the Tx pin is the pin UART1_TX (it
be_bryan 0:b74591d5ab33 32 * is an mbed convention to use the Tx pin), which is p6, in which case UART1
be_bryan 0:b74591d5ab33 33 * is configured instead. This latter is not the normal case as this pin
be_bryan 0:b74591d5ab33 34 * is intended to be used as a GPIO.
be_bryan 0:b74591d5ab33 35 *
be_bryan 0:b74591d5ab33 36 * If the baud rate is changed the driver reconfigures to match.
be_bryan 0:b74591d5ab33 37 *
be_bryan 0:b74591d5ab33 38 * TODO: implement asynchronous and flow control APIs.
be_bryan 0:b74591d5ab33 39 */
be_bryan 0:b74591d5ab33 40
be_bryan 0:b74591d5ab33 41 #include "mbed_assert.h"
be_bryan 0:b74591d5ab33 42 #include "serial_api.h"
be_bryan 0:b74591d5ab33 43 #include "pinmap.h"
be_bryan 0:b74591d5ab33 44
be_bryan 0:b74591d5ab33 45 #include "cmsis.h"
be_bryan 0:b74591d5ab33 46
be_bryan 0:b74591d5ab33 47 /* ----------------------------------------------------------------
be_bryan 0:b74591d5ab33 48 * MACROS
be_bryan 0:b74591d5ab33 49 * ----------------------------------------------------------------*/
be_bryan 0:b74591d5ab33 50
be_bryan 0:b74591d5ab33 51 /* Registers banks for the standard UARTs */
be_bryan 0:b74591d5ab33 52 #define UART0_REG (*(volatile uart_ctrl_t *) UART0_BASE)
be_bryan 0:b74591d5ab33 53 #define UART1_REG (*(volatile uart_ctrl_t *) UART1_BASE)
be_bryan 0:b74591d5ab33 54
be_bryan 0:b74591d5ab33 55 /* Masks for the UART control bits in the reset and clock enable registers */
be_bryan 0:b74591d5ab33 56 #define UART0_CTRL (1 << 3)
be_bryan 0:b74591d5ab33 57 #define UART1_CTRL (1 << 4)
be_bryan 0:b74591d5ab33 58 #define UARTLP_CTRL (1 << 6)
be_bryan 0:b74591d5ab33 59
be_bryan 0:b74591d5ab33 60 /* Convert number of data bits to register values */
be_bryan 0:b74591d5ab33 61 #define MIN_NUM_UART_DATA_BITS 5
be_bryan 0:b74591d5ab33 62 #define MAX_NUM_UART_DATA_BITS 8
be_bryan 0:b74591d5ab33 63 #define REGISTER_DATA_BITS(x) ((x) - MIN_NUM_UART_DATA_BITS)
be_bryan 0:b74591d5ab33 64
be_bryan 0:b74591d5ab33 65 /* Number of stop bits */
be_bryan 0:b74591d5ab33 66 #define NUM_UART_STOP_BITS_1 1
be_bryan 0:b74591d5ab33 67 #define NUM_UART_STOP_BITS_2 2
be_bryan 0:b74591d5ab33 68
be_bryan 0:b74591d5ab33 69 /* ----------------------------------------------------------------
be_bryan 0:b74591d5ab33 70 * TYPES
be_bryan 0:b74591d5ab33 71 * ----------------------------------------------------------------*/
be_bryan 0:b74591d5ab33 72
be_bryan 0:b74591d5ab33 73 /* Enum to identify the interrupt to the UART handler */
be_bryan 0:b74591d5ab33 74 typedef enum {
be_bryan 0:b74591d5ab33 75 IRQ_UART_ID_0_AND_LP,
be_bryan 0:b74591d5ab33 76 IRQ_UART_ID_1,
be_bryan 0:b74591d5ab33 77 NUM_IRQ_IDS
be_bryan 0:b74591d5ab33 78 } irq_uart_id_t;
be_bryan 0:b74591d5ab33 79
be_bryan 0:b74591d5ab33 80 /* ----------------------------------------------------------------
be_bryan 0:b74591d5ab33 81 * GLOBAL VARIABLES
be_bryan 0:b74591d5ab33 82 * ----------------------------------------------------------------*/
be_bryan 0:b74591d5ab33 83
be_bryan 0:b74591d5ab33 84 /* The IRQ configuration variables, set up and named by mbed */
be_bryan 0:b74591d5ab33 85 static uint32_t serial_irq_ids[NUM_IRQ_IDS] = {0};
be_bryan 0:b74591d5ab33 86 static uart_irq_handler irq_handler = NULL;
be_bryan 0:b74591d5ab33 87
be_bryan 0:b74591d5ab33 88 /* RTX needs these */
be_bryan 0:b74591d5ab33 89 int stdio_uart_inited = 0;
be_bryan 0:b74591d5ab33 90 serial_t stdio_uart;
be_bryan 0:b74591d5ab33 91
be_bryan 0:b74591d5ab33 92 /* ----------------------------------------------------------------
be_bryan 0:b74591d5ab33 93 * FUNCTION PROTOTYPES
be_bryan 0:b74591d5ab33 94 * ----------------------------------------------------------------*/
be_bryan 0:b74591d5ab33 95
be_bryan 0:b74591d5ab33 96 static void init_config(serial_t *obj);
be_bryan 0:b74591d5ab33 97 static void deinit_config(serial_t *obj);
be_bryan 0:b74591d5ab33 98 static void set_baud(serial_t *obj, uint32_t baud_rate);
be_bryan 0:b74591d5ab33 99 static void irq_enable(serial_t *obj);
be_bryan 0:b74591d5ab33 100 static void irq_disable(serial_t *obj);
be_bryan 0:b74591d5ab33 101
be_bryan 0:b74591d5ab33 102 /* ----------------------------------------------------------------
be_bryan 0:b74591d5ab33 103 * NON-API FUNCTIONS
be_bryan 0:b74591d5ab33 104 * ----------------------------------------------------------------*/
be_bryan 0:b74591d5ab33 105
be_bryan 0:b74591d5ab33 106 /* Initialise the given serial config by setting the pin functions
be_bryan 0:b74591d5ab33 107 * and then resetting the relevant HW */
be_bryan 0:b74591d5ab33 108 static void init_config(serial_t *obj)
be_bryan 0:b74591d5ab33 109 {
be_bryan 0:b74591d5ab33 110 uint32_t x;
be_bryan 0:b74591d5ab33 111
be_bryan 0:b74591d5ab33 112 switch (obj->config) {
be_bryan 0:b74591d5ab33 113 case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
be_bryan 0:b74591d5ab33 114 {
be_bryan 0:b74591d5ab33 115 pin_function(obj->rx_pin, PIN_FUNCTION_LP_UART);
be_bryan 0:b74591d5ab33 116 pin_function(obj->tx_pin, PIN_FUNCTION_UART0_TXD);
be_bryan 0:b74591d5ab33 117 CLKEN_REG_BITSET = UARTLP_CTRL | UART0_CTRL;
be_bryan 0:b74591d5ab33 118 obj->reg_base = &UART0_REG;
be_bryan 0:b74591d5ab33 119 obj->index = IRQ_UART_ID_0_AND_LP;
be_bryan 0:b74591d5ab33 120 /* Reset the LPUART and UART0 HW */
be_bryan 0:b74591d5ab33 121 /* NOTE: RESET_REG_BITTOG doesn't have the desired
be_bryan 0:b74591d5ab33 122 * effect, need to use BITSET and then BITCLR */
be_bryan 0:b74591d5ab33 123 RESET_REG_BITSET |= 1ul << 6;
be_bryan 0:b74591d5ab33 124 RESET_REG_BITCLR |= 1ul << 6;
be_bryan 0:b74591d5ab33 125 RESET_REG_BITSET |= 1ul << 3;
be_bryan 0:b74591d5ab33 126 RESET_REG_BITCLR |= 1ul << 3;
be_bryan 0:b74591d5ab33 127 }
be_bryan 0:b74591d5ab33 128 break;
be_bryan 0:b74591d5ab33 129 case SERIAL_CONFIG_UART0_RX_UART0_TX:
be_bryan 0:b74591d5ab33 130 {
be_bryan 0:b74591d5ab33 131 pin_function(obj->rx_pin, PIN_FUNCTION_UART0_RXD);
be_bryan 0:b74591d5ab33 132 pin_function(obj->tx_pin, PIN_FUNCTION_UART0_TXD);
be_bryan 0:b74591d5ab33 133 CLKEN_REG_BITSET = UART0_CTRL;
be_bryan 0:b74591d5ab33 134 obj->reg_base = &UART0_REG;
be_bryan 0:b74591d5ab33 135 obj->index = IRQ_UART_ID_0_AND_LP;
be_bryan 0:b74591d5ab33 136 /* Reset the UART0 HW */
be_bryan 0:b74591d5ab33 137 RESET_REG_BITSET |= 1ul << 3;
be_bryan 0:b74591d5ab33 138 RESET_REG_BITCLR |= 1ul << 3;
be_bryan 0:b74591d5ab33 139 }
be_bryan 0:b74591d5ab33 140 break;
be_bryan 0:b74591d5ab33 141 case SERIAL_CONFIG_UART1_RX_UART1_TX:
be_bryan 0:b74591d5ab33 142 {
be_bryan 0:b74591d5ab33 143 pin_function(obj->rx_pin, PIN_FUNCTION_UART1_RXD);
be_bryan 0:b74591d5ab33 144 pin_function(obj->tx_pin, PIN_FUNCTION_UART1_TXD);
be_bryan 0:b74591d5ab33 145 CLKEN_REG_BITSET = UART1_CTRL;
be_bryan 0:b74591d5ab33 146 obj->reg_base = &UART1_REG;
be_bryan 0:b74591d5ab33 147 obj->index = IRQ_UART_ID_1;
be_bryan 0:b74591d5ab33 148 /* Reset the UART1 HW */
be_bryan 0:b74591d5ab33 149 RESET_REG_BITSET |= 1ul << 4;
be_bryan 0:b74591d5ab33 150 RESET_REG_BITCLR |= 1ul << 4;
be_bryan 0:b74591d5ab33 151 }
be_bryan 0:b74591d5ab33 152 break;
be_bryan 0:b74591d5ab33 153 default:
be_bryan 0:b74591d5ab33 154 {
be_bryan 0:b74591d5ab33 155 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 156 }
be_bryan 0:b74591d5ab33 157 break;
be_bryan 0:b74591d5ab33 158 }
be_bryan 0:b74591d5ab33 159
be_bryan 0:b74591d5ab33 160 /* Tickle the UART control register to make sure it is updated */
be_bryan 0:b74591d5ab33 161 x = obj->reg_base->UARTLCR_H;
be_bryan 0:b74591d5ab33 162 obj->reg_base->UARTLCR_H = x;
be_bryan 0:b74591d5ab33 163
be_bryan 0:b74591d5ab33 164 /* Set the FIFO. The meaning of the three FIFO interrupt-level
be_bryan 0:b74591d5ab33 165 * bits are as follows:
be_bryan 0:b74591d5ab33 166 *
be_bryan 0:b74591d5ab33 167 * 0 = 1/8 full
be_bryan 0:b74591d5ab33 168 * 1 = 1/4 full
be_bryan 0:b74591d5ab33 169 * 2 = 1/2 full
be_bryan 0:b74591d5ab33 170 * 3 = 3/4 full
be_bryan 0:b74591d5ab33 171 * 4 = 7/8 full
be_bryan 0:b74591d5ab33 172 *
be_bryan 0:b74591d5ab33 173 * Set up the Rx FIFO to be used fully (but we will also set
be_bryan 0:b74591d5ab33 174 * a timeout to get immediate notice) and also the Tx FIFO
be_bryan 0:b74591d5ab33 175 * to be fully used. */
be_bryan 0:b74591d5ab33 176 obj->reg_base->UARTIFLS = (obj->reg_base->UARTIFLS & ~(0x07 << 0)) | (4 << 0);
be_bryan 0:b74591d5ab33 177 obj->reg_base->UARTIFLS = (obj->reg_base->UARTIFLS & ~(0x07 << 3)) | (4 << 3);
be_bryan 0:b74591d5ab33 178 obj->reg_base->UARTLCR_H |= 1 << 4;
be_bryan 0:b74591d5ab33 179
be_bryan 0:b74591d5ab33 180 /* Enable for Tx and Rx (TODO: add CTS when we add flow control) */
be_bryan 0:b74591d5ab33 181 obj->reg_base->UARTCR |= (1 << 8) | (1 << 9);
be_bryan 0:b74591d5ab33 182
be_bryan 0:b74591d5ab33 183 /* Now enable it */
be_bryan 0:b74591d5ab33 184 obj->reg_base->UARTCR |= 1 << 0;
be_bryan 0:b74591d5ab33 185
be_bryan 0:b74591d5ab33 186 obj->format_set = false;
be_bryan 0:b74591d5ab33 187 obj->baud_rate = 0;
be_bryan 0:b74591d5ab33 188 obj->irq_rx_setting = IRQ_NOT_SET;
be_bryan 0:b74591d5ab33 189 obj->irq_tx_setting = IRQ_NOT_SET;
be_bryan 0:b74591d5ab33 190 }
be_bryan 0:b74591d5ab33 191
be_bryan 0:b74591d5ab33 192 /* Release a serial port */
be_bryan 0:b74591d5ab33 193 static void deinit_config(serial_t *obj)
be_bryan 0:b74591d5ab33 194 {
be_bryan 0:b74591d5ab33 195 pin_function(obj->rx_pin, PIN_FUNCTION_UNCLAIMED);
be_bryan 0:b74591d5ab33 196 pin_function(obj->tx_pin, PIN_FUNCTION_UNCLAIMED);
be_bryan 0:b74591d5ab33 197
be_bryan 0:b74591d5ab33 198 /* Disable UART */
be_bryan 0:b74591d5ab33 199 obj->reg_base->UARTCR &= ~(1 << 0);
be_bryan 0:b74591d5ab33 200
be_bryan 0:b74591d5ab33 201 /* Flush transmit FIFO */
be_bryan 0:b74591d5ab33 202 obj->reg_base->UARTLCR_H = 0;
be_bryan 0:b74591d5ab33 203
be_bryan 0:b74591d5ab33 204 /* Disable everything */
be_bryan 0:b74591d5ab33 205 obj->reg_base->UARTCR = 0;
be_bryan 0:b74591d5ab33 206
be_bryan 0:b74591d5ab33 207 switch (obj->config) {
be_bryan 0:b74591d5ab33 208 case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
be_bryan 0:b74591d5ab33 209 {
be_bryan 0:b74591d5ab33 210 CLKEN_REG_BITCLR = UARTLP_CTRL | UART0_CTRL;
be_bryan 0:b74591d5ab33 211 LP_UART_CTRL &= ~(0xF << 20); /* Disable all LP interrupts */
be_bryan 0:b74591d5ab33 212 }
be_bryan 0:b74591d5ab33 213 break;
be_bryan 0:b74591d5ab33 214 case SERIAL_CONFIG_UART0_RX_UART0_TX:
be_bryan 0:b74591d5ab33 215 {
be_bryan 0:b74591d5ab33 216 CLKEN_REG_BITCLR = UART0_CTRL;
be_bryan 0:b74591d5ab33 217 }
be_bryan 0:b74591d5ab33 218 break;
be_bryan 0:b74591d5ab33 219 case SERIAL_CONFIG_UART1_RX_UART1_TX:
be_bryan 0:b74591d5ab33 220 {
be_bryan 0:b74591d5ab33 221 CLKEN_REG_BITCLR = UART1_CTRL;
be_bryan 0:b74591d5ab33 222 }
be_bryan 0:b74591d5ab33 223 break;
be_bryan 0:b74591d5ab33 224 default:
be_bryan 0:b74591d5ab33 225 {
be_bryan 0:b74591d5ab33 226 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 227 }
be_bryan 0:b74591d5ab33 228 break;
be_bryan 0:b74591d5ab33 229 }
be_bryan 0:b74591d5ab33 230
be_bryan 0:b74591d5ab33 231 obj->config = MAX_NUM_SERIAL_CONFIGS;
be_bryan 0:b74591d5ab33 232 obj->reg_base = NULL;
be_bryan 0:b74591d5ab33 233 }
be_bryan 0:b74591d5ab33 234
be_bryan 0:b74591d5ab33 235 /* Set the baud rate for either of the two (non-LP) UARTS */
be_bryan 0:b74591d5ab33 236 static void set_baud(serial_t *obj, uint32_t baud_rate)
be_bryan 0:b74591d5ab33 237 {
be_bryan 0:b74591d5ab33 238 uint32_t baud_rate_divider_i;
be_bryan 0:b74591d5ab33 239 uint32_t baud_rate_divider_f;
be_bryan 0:b74591d5ab33 240 uint32_t remainder;
be_bryan 0:b74591d5ab33 241 uint32_t core_clock;
be_bryan 0:b74591d5ab33 242 uint32_t x;
be_bryan 0:b74591d5ab33 243
be_bryan 0:b74591d5ab33 244 /* Baud rate divider calculation:
be_bryan 0:b74591d5ab33 245 *
be_bryan 0:b74591d5ab33 246 * The integer part is: clock / (16 * baud)
be_bryan 0:b74591d5ab33 247 *
be_bryan 0:b74591d5ab33 248 * The fractional part is: round (decimal_part * 64),
be_bryan 0:b74591d5ab33 249 * ...where decimal part is, for example, 0.085
be_bryan 0:b74591d5ab33 250 *
be_bryan 0:b74591d5ab33 251 * decimal_part is: remainder / (16 * baud),
be_bryan 0:b74591d5ab33 252 * ...where: remainder = core_clock % (baud * 16),
be_bryan 0:b74591d5ab33 253 *
be_bryan 0:b74591d5ab33 254 * So the fractional part becomes:
be_bryan 0:b74591d5ab33 255 * round (decimal_part * 64) = round (remainder * 64 / (16 * baud)) = round (remainder * 4 / baud)
be_bryan 0:b74591d5ab33 256 */
be_bryan 0:b74591d5ab33 257
be_bryan 0:b74591d5ab33 258 /* Get the mean clock frequency */
be_bryan 0:b74591d5ab33 259 core_clock = (CLK_FREQ_HIGHTARGET >> 1) + (CLK_FREQ_LOWTARGET >> 1);
be_bryan 0:b74591d5ab33 260 /* Work out the actual clock frequency */
be_bryan 0:b74591d5ab33 261 core_clock = (core_clock * CLOCKS_REFERENCE_CLOCK_FREQ) / (((CLK_FREQ_NREFCLKS + 1) & 0xFFFF) * (CLK_GATE_SYS & 0xFF));
be_bryan 0:b74591d5ab33 262 baud_rate_divider_i = core_clock / (baud_rate << 4);
be_bryan 0:b74591d5ab33 263 remainder = core_clock % (baud_rate << 4);
be_bryan 0:b74591d5ab33 264 baud_rate_divider_f = ((remainder << 3) / baud_rate) >> 1;
be_bryan 0:b74591d5ab33 265 /* Round it */
be_bryan 0:b74591d5ab33 266 baud_rate_divider_f += ((remainder << 3) / baud_rate) & 1;
be_bryan 0:b74591d5ab33 267
be_bryan 0:b74591d5ab33 268 /* Disable UART while writing to control registers */
be_bryan 0:b74591d5ab33 269 obj->reg_base->UARTCR &= ~(1 << 0);
be_bryan 0:b74591d5ab33 270
be_bryan 0:b74591d5ab33 271 obj->reg_base->UARTIBRD = baud_rate_divider_i;
be_bryan 0:b74591d5ab33 272 obj->reg_base->UARTFBRD = baud_rate_divider_f;
be_bryan 0:b74591d5ab33 273
be_bryan 0:b74591d5ab33 274 /* Make IBRD and FBRD update */
be_bryan 0:b74591d5ab33 275 x = obj->reg_base->UARTLCR_H;
be_bryan 0:b74591d5ab33 276 obj->reg_base->UARTLCR_H = x;
be_bryan 0:b74591d5ab33 277
be_bryan 0:b74591d5ab33 278 /* Now enable the UART again */
be_bryan 0:b74591d5ab33 279 obj->reg_base->UARTCR |= 1 << 0;
be_bryan 0:b74591d5ab33 280 }
be_bryan 0:b74591d5ab33 281
be_bryan 0:b74591d5ab33 282 /* Set the NVIC bits */
be_bryan 0:b74591d5ab33 283 static void irq_enable(serial_t *obj)
be_bryan 0:b74591d5ab33 284 {
be_bryan 0:b74591d5ab33 285 switch (obj->config) {
be_bryan 0:b74591d5ab33 286 case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
be_bryan 0:b74591d5ab33 287 {
be_bryan 0:b74591d5ab33 288 NVIC_EnableIRQ(UART0_IRQn);
be_bryan 0:b74591d5ab33 289 NVIC_EnableIRQ(LPUART_IRQn);
be_bryan 0:b74591d5ab33 290 }
be_bryan 0:b74591d5ab33 291 break;
be_bryan 0:b74591d5ab33 292 case SERIAL_CONFIG_UART0_RX_UART0_TX:
be_bryan 0:b74591d5ab33 293 {
be_bryan 0:b74591d5ab33 294 NVIC_EnableIRQ(UART0_IRQn);
be_bryan 0:b74591d5ab33 295 }
be_bryan 0:b74591d5ab33 296 break;
be_bryan 0:b74591d5ab33 297 case SERIAL_CONFIG_UART1_RX_UART1_TX:
be_bryan 0:b74591d5ab33 298 {
be_bryan 0:b74591d5ab33 299 NVIC_EnableIRQ(UART1_IRQn);
be_bryan 0:b74591d5ab33 300 }
be_bryan 0:b74591d5ab33 301 break;
be_bryan 0:b74591d5ab33 302 default:
be_bryan 0:b74591d5ab33 303 {
be_bryan 0:b74591d5ab33 304 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 305 }
be_bryan 0:b74591d5ab33 306 break;
be_bryan 0:b74591d5ab33 307 }
be_bryan 0:b74591d5ab33 308 }
be_bryan 0:b74591d5ab33 309
be_bryan 0:b74591d5ab33 310 /* Unset the NVIC bits */
be_bryan 0:b74591d5ab33 311 static void irq_disable(serial_t *obj)
be_bryan 0:b74591d5ab33 312 {
be_bryan 0:b74591d5ab33 313 switch (obj->config) {
be_bryan 0:b74591d5ab33 314 case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
be_bryan 0:b74591d5ab33 315 {
be_bryan 0:b74591d5ab33 316 NVIC_DisableIRQ(UART0_IRQn);
be_bryan 0:b74591d5ab33 317 NVIC_DisableIRQ(LPUART_IRQn);
be_bryan 0:b74591d5ab33 318 }
be_bryan 0:b74591d5ab33 319 break;
be_bryan 0:b74591d5ab33 320 case SERIAL_CONFIG_UART0_RX_UART0_TX:
be_bryan 0:b74591d5ab33 321 {
be_bryan 0:b74591d5ab33 322 NVIC_DisableIRQ(UART0_IRQn);
be_bryan 0:b74591d5ab33 323 }
be_bryan 0:b74591d5ab33 324 break;
be_bryan 0:b74591d5ab33 325 case SERIAL_CONFIG_UART1_RX_UART1_TX:
be_bryan 0:b74591d5ab33 326 {
be_bryan 0:b74591d5ab33 327 NVIC_DisableIRQ(UART1_IRQn);
be_bryan 0:b74591d5ab33 328 }
be_bryan 0:b74591d5ab33 329 break;
be_bryan 0:b74591d5ab33 330 default:
be_bryan 0:b74591d5ab33 331 {
be_bryan 0:b74591d5ab33 332 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 333 }
be_bryan 0:b74591d5ab33 334 break;
be_bryan 0:b74591d5ab33 335 }
be_bryan 0:b74591d5ab33 336 }
be_bryan 0:b74591d5ab33 337
be_bryan 0:b74591d5ab33 338 /* UART0 IRQ */
be_bryan 0:b74591d5ab33 339 void IRQ7_UART0_Handler()
be_bryan 0:b74591d5ab33 340 {
be_bryan 0:b74591d5ab33 341 uint32_t id = serial_irq_ids[IRQ_UART_ID_0_AND_LP];
be_bryan 0:b74591d5ab33 342
be_bryan 0:b74591d5ab33 343 /* Check Rx and Rx Timeout bit */
be_bryan 0:b74591d5ab33 344 if (UART0_REG.UARTMIS & ((1 << 4) | (1 << 6))) {
be_bryan 0:b74591d5ab33 345 if (id != 0) {
be_bryan 0:b74591d5ab33 346 irq_handler(id, RxIrq);
be_bryan 0:b74591d5ab33 347 /* Reading the character clears the interrupt,
be_bryan 0:b74591d5ab33 348 * no way to protect against another arriving
be_bryan 0:b74591d5ab33 349 * while processing one */
be_bryan 0:b74591d5ab33 350 }
be_bryan 0:b74591d5ab33 351 }
be_bryan 0:b74591d5ab33 352 /* Check Tx bit */
be_bryan 0:b74591d5ab33 353 if (UART0_REG.UARTMIS & (1 << 5)) {
be_bryan 0:b74591d5ab33 354 if (id != 0) {
be_bryan 0:b74591d5ab33 355 irq_handler(id, TxIrq);
be_bryan 0:b74591d5ab33 356 }
be_bryan 0:b74591d5ab33 357 /* Not sure what clears the interrupt so clear it explicitly */
be_bryan 0:b74591d5ab33 358 NVIC_ClearPendingIRQ(UART1_IRQn);
be_bryan 0:b74591d5ab33 359 }
be_bryan 0:b74591d5ab33 360 }
be_bryan 0:b74591d5ab33 361
be_bryan 0:b74591d5ab33 362 /* UART1 IRQ */
be_bryan 0:b74591d5ab33 363 void IRQ8_UART1_Handler()
be_bryan 0:b74591d5ab33 364 {
be_bryan 0:b74591d5ab33 365 uint32_t id = serial_irq_ids[IRQ_UART_ID_1];
be_bryan 0:b74591d5ab33 366
be_bryan 0:b74591d5ab33 367 /* Check Rx and Rx Timeout bit */
be_bryan 0:b74591d5ab33 368 if (UART1_REG.UARTMIS & ((1 << 4) | (1 << 6))) {
be_bryan 0:b74591d5ab33 369 if (id != 0) {
be_bryan 0:b74591d5ab33 370 irq_handler(id, RxIrq);
be_bryan 0:b74591d5ab33 371 }
be_bryan 0:b74591d5ab33 372 /* Reading the character clears the interrupt,
be_bryan 0:b74591d5ab33 373 * no way to protect against another arriving
be_bryan 0:b74591d5ab33 374 * while processing one */
be_bryan 0:b74591d5ab33 375 }
be_bryan 0:b74591d5ab33 376 /* Check Tx bit */
be_bryan 0:b74591d5ab33 377 if (UART1_REG.UARTMIS & (1 << 5)) {
be_bryan 0:b74591d5ab33 378 if (id != 0) {
be_bryan 0:b74591d5ab33 379 irq_handler(id, TxIrq);
be_bryan 0:b74591d5ab33 380 }
be_bryan 0:b74591d5ab33 381 /* Not sure what clears the interrupt so clear it explicitly */
be_bryan 0:b74591d5ab33 382 NVIC_ClearPendingIRQ(UART1_IRQn);
be_bryan 0:b74591d5ab33 383 }
be_bryan 0:b74591d5ab33 384 }
be_bryan 0:b74591d5ab33 385
be_bryan 0:b74591d5ab33 386 /* LP UART IRQ, receive only */
be_bryan 0:b74591d5ab33 387 void IRQ16_LPUART_Handler()
be_bryan 0:b74591d5ab33 388 {
be_bryan 0:b74591d5ab33 389 uint32_t id = serial_irq_ids[IRQ_UART_ID_0_AND_LP];
be_bryan 0:b74591d5ab33 390
be_bryan 0:b74591d5ab33 391 if (id != 0) {
be_bryan 0:b74591d5ab33 392 irq_handler(id, RxIrq);
be_bryan 0:b74591d5ab33 393
be_bryan 0:b74591d5ab33 394 /* Another character might have arrived while
be_bryan 0:b74591d5ab33 395 * we are processing the last, so
be_bryan 0:b74591d5ab33 396 * check status bits 8 to 10 again and pend
be_bryan 0:b74591d5ab33 397 * interrupt if there's something there */
be_bryan 0:b74591d5ab33 398 if (((LP_UART_STATUS >> 8) & 0x07) != 0) {
be_bryan 0:b74591d5ab33 399 NVIC_SetPendingIRQ(LPUART_IRQn);
be_bryan 0:b74591d5ab33 400 } else {
be_bryan 0:b74591d5ab33 401 LP_UART_CTRL |= 1 << 27; /* Clear the interrupt */
be_bryan 0:b74591d5ab33 402 }
be_bryan 0:b74591d5ab33 403 }
be_bryan 0:b74591d5ab33 404 }
be_bryan 0:b74591d5ab33 405
be_bryan 0:b74591d5ab33 406 /* ----------------------------------------------------------------
be_bryan 0:b74591d5ab33 407 * MBED API CALLS: SETUP FUNCTIONS
be_bryan 0:b74591d5ab33 408 * ----------------------------------------------------------------*/
be_bryan 0:b74591d5ab33 409
be_bryan 0:b74591d5ab33 410 void serial_init(serial_t *obj, PinName tx, PinName rx)
be_bryan 0:b74591d5ab33 411 {
be_bryan 0:b74591d5ab33 412 uint32_t clock = CLK_FREQ_DIG_CLKS;
be_bryan 0:b74591d5ab33 413
be_bryan 0:b74591d5ab33 414 /* There are two and a half UARTs on the chip. The normal
be_bryan 0:b74591d5ab33 415 * configuration is to use the LP_UART for Rx and UART0 for
be_bryan 0:b74591d5ab33 416 * Tx. This gives maximal power saving in that the chip can
be_bryan 0:b74591d5ab33 417 * wake up on receipt of data. However, this only works if the
be_bryan 0:b74591d5ab33 418 * data rate is 9600 because that's the only data rate that
be_bryan 0:b74591d5ab33 419 * the 32 kHz (i.e. RTC) clock driving the LP UART can support.
be_bryan 0:b74591d5ab33 420 *
be_bryan 0:b74591d5ab33 421 * So, if the data rate is 9600, use the LP_UART/UART0
be_bryan 0:b74591d5ab33 422 * combination, otherwise use UART0 for both Rx and Tx. However,
be_bryan 0:b74591d5ab33 423 * we don't know the data rate at this point so assume LP_UART
be_bryan 0:b74591d5ab33 424 * (as this works at the default baud rate) and we can change
be_bryan 0:b74591d5ab33 425 * our minds later.
be_bryan 0:b74591d5ab33 426 *
be_bryan 0:b74591d5ab33 427 * There is another serial port, UART1, which is normally used
be_bryan 0:b74591d5ab33 428 * by the modem processor to send out debug. We only initialise
be_bryan 0:b74591d5ab33 429 * that here if the Tx pin is UART1_TX. */
be_bryan 0:b74591d5ab33 430
be_bryan 0:b74591d5ab33 431 /* Wait for the clock to be stable */
be_bryan 0:b74591d5ab33 432 while ((clock < CLK_FREQ_LOWTARGET) || (clock > CLK_FREQ_HIGHTARGET)) {
be_bryan 0:b74591d5ab33 433 clock = CLK_FREQ_DIG_CLKS;
be_bryan 0:b74591d5ab33 434 }
be_bryan 0:b74591d5ab33 435
be_bryan 0:b74591d5ab33 436 if (tx == UART1_TX) {
be_bryan 0:b74591d5ab33 437 /* Use UART1 for Rx and Tx */
be_bryan 0:b74591d5ab33 438 obj->config = SERIAL_CONFIG_UART1_RX_UART1_TX;
be_bryan 0:b74591d5ab33 439 } else {
be_bryan 0:b74591d5ab33 440 /* Use LP_UART for Rx, UART0 for Tx */
be_bryan 0:b74591d5ab33 441 obj->config = SERIAL_CONFIG_UARTLP_RX_UART0_TX;
be_bryan 0:b74591d5ab33 442 }
be_bryan 0:b74591d5ab33 443
be_bryan 0:b74591d5ab33 444 obj->rx_pin = rx;
be_bryan 0:b74591d5ab33 445 obj->tx_pin = tx;
be_bryan 0:b74591d5ab33 446 init_config(obj);
be_bryan 0:b74591d5ab33 447
be_bryan 0:b74591d5ab33 448 /* TODO: set rx pin Pull mode ? */
be_bryan 0:b74591d5ab33 449
be_bryan 0:b74591d5ab33 450 /* set default baud rate and format */
be_bryan 0:b74591d5ab33 451 serial_baud(obj, 9600);
be_bryan 0:b74591d5ab33 452 serial_format(obj, 8, ParityNone, 1);
be_bryan 0:b74591d5ab33 453
be_bryan 0:b74591d5ab33 454 if (tx == UART0_TX) {
be_bryan 0:b74591d5ab33 455 /* The UART0 pins are the stdio pins */
be_bryan 0:b74591d5ab33 456 stdio_uart_inited = 1;
be_bryan 0:b74591d5ab33 457 stdio_uart = *obj;
be_bryan 0:b74591d5ab33 458 }
be_bryan 0:b74591d5ab33 459 }
be_bryan 0:b74591d5ab33 460
be_bryan 0:b74591d5ab33 461 void serial_free(serial_t *obj)
be_bryan 0:b74591d5ab33 462 {
be_bryan 0:b74591d5ab33 463 if (obj->tx_pin == UART0_TX) {
be_bryan 0:b74591d5ab33 464 stdio_uart_inited = 0;
be_bryan 0:b74591d5ab33 465 }
be_bryan 0:b74591d5ab33 466
be_bryan 0:b74591d5ab33 467 serial_irq_ids[obj->index] = 0;
be_bryan 0:b74591d5ab33 468
be_bryan 0:b74591d5ab33 469 /* Release the port HW */
be_bryan 0:b74591d5ab33 470 deinit_config(obj);
be_bryan 0:b74591d5ab33 471 }
be_bryan 0:b74591d5ab33 472
be_bryan 0:b74591d5ab33 473 void serial_baud(serial_t *obj, int baudrate)
be_bryan 0:b74591d5ab33 474 {
be_bryan 0:b74591d5ab33 475 bool switch_port_config = false;
be_bryan 0:b74591d5ab33 476 bool format_set = obj->format_set;
be_bryan 0:b74591d5ab33 477 uint8_t stop_bits = obj->format.stop_bits;
be_bryan 0:b74591d5ab33 478 uint8_t data_bits = obj->format.data_bits;
be_bryan 0:b74591d5ab33 479 SerialParity parity = (SerialParity) obj->format.parity;
be_bryan 0:b74591d5ab33 480 irq_setting_t irq_rx_setting = obj->irq_rx_setting;
be_bryan 0:b74591d5ab33 481 irq_setting_t irq_tx_setting = obj->irq_tx_setting;
be_bryan 0:b74591d5ab33 482
be_bryan 0:b74591d5ab33 483 if ((obj->config == SERIAL_CONFIG_UARTLP_RX_UART0_TX) && (baudrate != 9600)) {
be_bryan 0:b74591d5ab33 484 /* If we were on LP UART but the baud rate is not 9600 then
be_bryan 0:b74591d5ab33 485 * switch to the standard UART (as the LP UART can't go any higher
be_bryan 0:b74591d5ab33 486 * because it's clocked from 32 kHz) */
be_bryan 0:b74591d5ab33 487 deinit_config(obj);
be_bryan 0:b74591d5ab33 488 obj->config = SERIAL_CONFIG_UART0_RX_UART0_TX;
be_bryan 0:b74591d5ab33 489 init_config(obj);
be_bryan 0:b74591d5ab33 490 switch_port_config = true;
be_bryan 0:b74591d5ab33 491 } else if ((obj->config == SERIAL_CONFIG_UART0_RX_UART0_TX) && (baudrate == 9600)) {
be_bryan 0:b74591d5ab33 492 /* If we were on UART0 but the baud rate is 9600 then switch to the
be_bryan 0:b74591d5ab33 493 * LP UART for receive */
be_bryan 0:b74591d5ab33 494 deinit_config(obj);
be_bryan 0:b74591d5ab33 495 obj->config = SERIAL_CONFIG_UARTLP_RX_UART0_TX;
be_bryan 0:b74591d5ab33 496 init_config(obj);
be_bryan 0:b74591d5ab33 497 switch_port_config = true;
be_bryan 0:b74591d5ab33 498 }
be_bryan 0:b74591d5ab33 499
be_bryan 0:b74591d5ab33 500 /* Disable UART while writing to control registers */
be_bryan 0:b74591d5ab33 501 obj->reg_base->UARTCR &= ~(1 << 0);
be_bryan 0:b74591d5ab33 502
be_bryan 0:b74591d5ab33 503 if (switch_port_config) {
be_bryan 0:b74591d5ab33 504 /* If the port was switched, switch the port configuration also */
be_bryan 0:b74591d5ab33 505 if (format_set) {
be_bryan 0:b74591d5ab33 506 /* This serial port has been previously set up so switch the
be_bryan 0:b74591d5ab33 507 * settings across to this new configuration */
be_bryan 0:b74591d5ab33 508 serial_format(obj, data_bits, parity, stop_bits);
be_bryan 0:b74591d5ab33 509 }
be_bryan 0:b74591d5ab33 510 if (irq_rx_setting != IRQ_NOT_SET) {
be_bryan 0:b74591d5ab33 511 /* Do the same for Rx interrupts, if they were set */
be_bryan 0:b74591d5ab33 512 serial_irq_set(obj, RxIrq, (irq_rx_setting == IRQ_ON));
be_bryan 0:b74591d5ab33 513 }
be_bryan 0:b74591d5ab33 514 if (irq_tx_setting != IRQ_NOT_SET) {
be_bryan 0:b74591d5ab33 515 /* Do the same for Tx interrupts, if they were set */
be_bryan 0:b74591d5ab33 516 serial_irq_set(obj, TxIrq, (irq_tx_setting == IRQ_ON));
be_bryan 0:b74591d5ab33 517 }
be_bryan 0:b74591d5ab33 518 }
be_bryan 0:b74591d5ab33 519
be_bryan 0:b74591d5ab33 520 switch (obj->config) {
be_bryan 0:b74591d5ab33 521 case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
be_bryan 0:b74591d5ab33 522 {
be_bryan 0:b74591d5ab33 523 /* Set LP UART to 9600 (numerator 75 (0x4B), denominator 256 (00 == 256)) */
be_bryan 0:b74591d5ab33 524 LP_UART_CTRL = (LP_UART_CTRL & ~0xFFFF) | 0x004B;
be_bryan 0:b74591d5ab33 525 set_baud(obj, baudrate);
be_bryan 0:b74591d5ab33 526 }
be_bryan 0:b74591d5ab33 527 break;
be_bryan 0:b74591d5ab33 528 case SERIAL_CONFIG_UART0_RX_UART0_TX:
be_bryan 0:b74591d5ab33 529 case SERIAL_CONFIG_UART1_RX_UART1_TX:
be_bryan 0:b74591d5ab33 530 {
be_bryan 0:b74591d5ab33 531 set_baud(obj, baudrate);
be_bryan 0:b74591d5ab33 532 }
be_bryan 0:b74591d5ab33 533 break;
be_bryan 0:b74591d5ab33 534 default:
be_bryan 0:b74591d5ab33 535 {
be_bryan 0:b74591d5ab33 536 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 537 }
be_bryan 0:b74591d5ab33 538 break;
be_bryan 0:b74591d5ab33 539 }
be_bryan 0:b74591d5ab33 540
be_bryan 0:b74591d5ab33 541 /* Enable the UART again */
be_bryan 0:b74591d5ab33 542 obj->reg_base->UARTCR |= 1 << 0;
be_bryan 0:b74591d5ab33 543
be_bryan 0:b74591d5ab33 544 obj->baud_rate = baudrate;
be_bryan 0:b74591d5ab33 545 }
be_bryan 0:b74591d5ab33 546
be_bryan 0:b74591d5ab33 547 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
be_bryan 0:b74591d5ab33 548 {
be_bryan 0:b74591d5ab33 549 bool lp_also = false;
be_bryan 0:b74591d5ab33 550
be_bryan 0:b74591d5ab33 551 MBED_ASSERT(data_bits >= MIN_NUM_UART_DATA_BITS);
be_bryan 0:b74591d5ab33 552 MBED_ASSERT(data_bits <= MAX_NUM_UART_DATA_BITS);
be_bryan 0:b74591d5ab33 553 MBED_ASSERT(stop_bits >= NUM_UART_STOP_BITS_1);
be_bryan 0:b74591d5ab33 554 MBED_ASSERT(stop_bits <= NUM_UART_STOP_BITS_2);
be_bryan 0:b74591d5ab33 555
be_bryan 0:b74591d5ab33 556 /* The LP UART is different to UARTs 0 and 1 so deal with it
be_bryan 0:b74591d5ab33 557 * explicitly when required */
be_bryan 0:b74591d5ab33 558 if (obj->config == SERIAL_CONFIG_UARTLP_RX_UART0_TX) {
be_bryan 0:b74591d5ab33 559 lp_also = true;
be_bryan 0:b74591d5ab33 560 }
be_bryan 0:b74591d5ab33 561
be_bryan 0:b74591d5ab33 562 /* Disable UART while writing to control registers */
be_bryan 0:b74591d5ab33 563 obj->reg_base->UARTCR &= ~(1 << 0);
be_bryan 0:b74591d5ab33 564
be_bryan 0:b74591d5ab33 565 /* Set data bits (bits 5 and 6 of the UART0/1 register, bits 18 and 19 of the LP UART register) */
be_bryan 0:b74591d5ab33 566 obj->reg_base->UARTLCR_H = (obj->reg_base->UARTLCR_H & ~(0x03 << 5)) | (REGISTER_DATA_BITS(data_bits) << 5);
be_bryan 0:b74591d5ab33 567 if (lp_also) {
be_bryan 0:b74591d5ab33 568 LP_UART_CTRL = (LP_UART_CTRL & ~(0x03 << 18)) | (REGISTER_DATA_BITS(data_bits) << 18);
be_bryan 0:b74591d5ab33 569 }
be_bryan 0:b74591d5ab33 570 obj->format.data_bits = (uint8_t) data_bits;
be_bryan 0:b74591d5ab33 571
be_bryan 0:b74591d5ab33 572 /* Set stop bits (bit 7 of the UART0/1 register) (there is no such setting for the LP UART) */
be_bryan 0:b74591d5ab33 573 if (stop_bits == NUM_UART_STOP_BITS_1) {
be_bryan 0:b74591d5ab33 574 /* Clear 2-stop-bits bit */
be_bryan 0:b74591d5ab33 575 obj->reg_base->UARTLCR_H &= ~(1 << 7);
be_bryan 0:b74591d5ab33 576 } else {
be_bryan 0:b74591d5ab33 577 /* Set 2-stop-bits bit */
be_bryan 0:b74591d5ab33 578 obj->reg_base->UARTLCR_H |= 1 << 7;
be_bryan 0:b74591d5ab33 579 }
be_bryan 0:b74591d5ab33 580 obj->format.stop_bits = (uint8_t) stop_bits;
be_bryan 0:b74591d5ab33 581
be_bryan 0:b74591d5ab33 582 /* Set parity */
be_bryan 0:b74591d5ab33 583 switch (parity) {
be_bryan 0:b74591d5ab33 584 case ParityNone:
be_bryan 0:b74591d5ab33 585 {
be_bryan 0:b74591d5ab33 586 /* Disable parity */
be_bryan 0:b74591d5ab33 587 obj->reg_base->UARTLCR_H &= ~0x02;
be_bryan 0:b74591d5ab33 588 if (lp_also)
be_bryan 0:b74591d5ab33 589 {
be_bryan 0:b74591d5ab33 590 LP_UART_CTRL &= ~(1 << 24);
be_bryan 0:b74591d5ab33 591 }
be_bryan 0:b74591d5ab33 592 }
be_bryan 0:b74591d5ab33 593 break;
be_bryan 0:b74591d5ab33 594 case ParityOdd:
be_bryan 0:b74591d5ab33 595 {
be_bryan 0:b74591d5ab33 596 /* Set even bit and enable parity */
be_bryan 0:b74591d5ab33 597 obj->reg_base->UARTLCR_H = (obj->reg_base->UARTLCR_H | (1 << 3)) | (1 << 2);
be_bryan 0:b74591d5ab33 598 if (lp_also)
be_bryan 0:b74591d5ab33 599 {
be_bryan 0:b74591d5ab33 600 LP_UART_CTRL |= (1 << 24) | (1 << 25);
be_bryan 0:b74591d5ab33 601 }
be_bryan 0:b74591d5ab33 602 }
be_bryan 0:b74591d5ab33 603 break;
be_bryan 0:b74591d5ab33 604 case ParityEven:
be_bryan 0:b74591d5ab33 605 {
be_bryan 0:b74591d5ab33 606 /* Clear even bit and enable parity */
be_bryan 0:b74591d5ab33 607 obj->reg_base->UARTLCR_H = (obj->reg_base->UARTLCR_H & ~(1 << 3)) | (1 << 2);
be_bryan 0:b74591d5ab33 608 if (lp_also)
be_bryan 0:b74591d5ab33 609 {
be_bryan 0:b74591d5ab33 610 LP_UART_CTRL &= ~(1 << 25);
be_bryan 0:b74591d5ab33 611 LP_UART_CTRL |= 1 << 24;
be_bryan 0:b74591d5ab33 612 }
be_bryan 0:b74591d5ab33 613 }
be_bryan 0:b74591d5ab33 614 break;
be_bryan 0:b74591d5ab33 615 default:
be_bryan 0:b74591d5ab33 616 {
be_bryan 0:b74591d5ab33 617 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 618 }
be_bryan 0:b74591d5ab33 619 break;
be_bryan 0:b74591d5ab33 620 }
be_bryan 0:b74591d5ab33 621
be_bryan 0:b74591d5ab33 622 /* Enable the UART again */
be_bryan 0:b74591d5ab33 623 obj->reg_base->UARTCR |= 1 << 0;
be_bryan 0:b74591d5ab33 624
be_bryan 0:b74591d5ab33 625 obj->format.parity = (uint8_t) parity;
be_bryan 0:b74591d5ab33 626 obj->format_set = true;
be_bryan 0:b74591d5ab33 627 }
be_bryan 0:b74591d5ab33 628
be_bryan 0:b74591d5ab33 629 /* ----------------------------------------------------------------
be_bryan 0:b74591d5ab33 630 * MBED API CALLS: INTERRUPT FUNCTIONS
be_bryan 0:b74591d5ab33 631 * ----------------------------------------------------------------*/
be_bryan 0:b74591d5ab33 632
be_bryan 0:b74591d5ab33 633 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
be_bryan 0:b74591d5ab33 634 {
be_bryan 0:b74591d5ab33 635 irq_handler = handler;
be_bryan 0:b74591d5ab33 636 serial_irq_ids[obj->index] = id;
be_bryan 0:b74591d5ab33 637 }
be_bryan 0:b74591d5ab33 638
be_bryan 0:b74591d5ab33 639 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
be_bryan 0:b74591d5ab33 640 {
be_bryan 0:b74591d5ab33 641 bool lp_also = false;
be_bryan 0:b74591d5ab33 642
be_bryan 0:b74591d5ab33 643 if (obj->config == SERIAL_CONFIG_UARTLP_RX_UART0_TX) {
be_bryan 0:b74591d5ab33 644 lp_also = true;
be_bryan 0:b74591d5ab33 645 }
be_bryan 0:b74591d5ab33 646
be_bryan 0:b74591d5ab33 647 /* Disable UART while writing to control registers */
be_bryan 0:b74591d5ab33 648 obj->reg_base->UARTCR &= ~(1 << 0);
be_bryan 0:b74591d5ab33 649
be_bryan 0:b74591d5ab33 650 if (enable) {
be_bryan 0:b74591d5ab33 651 switch (irq) {
be_bryan 0:b74591d5ab33 652 case RxIrq:
be_bryan 0:b74591d5ab33 653 {
be_bryan 0:b74591d5ab33 654 /* Bit 4 for Rx and bit 6 for Rx Timeout */
be_bryan 0:b74591d5ab33 655 obj->reg_base->UARTIMSC |= (1 << 4) | (1 << 6);
be_bryan 0:b74591d5ab33 656 if (lp_also)
be_bryan 0:b74591d5ab33 657 {
be_bryan 0:b74591d5ab33 658 /* "Word Received" IRQ */
be_bryan 0:b74591d5ab33 659 LP_UART_CTRL |= 1 << 23;
be_bryan 0:b74591d5ab33 660 }
be_bryan 0:b74591d5ab33 661 obj->irq_rx_setting = IRQ_ON;
be_bryan 0:b74591d5ab33 662 irq_enable(obj);
be_bryan 0:b74591d5ab33 663 }
be_bryan 0:b74591d5ab33 664 break;
be_bryan 0:b74591d5ab33 665 case TxIrq:
be_bryan 0:b74591d5ab33 666 {
be_bryan 0:b74591d5ab33 667 /* Bit 5 */
be_bryan 0:b74591d5ab33 668 obj->reg_base->UARTIMSC |= 1 << 5;
be_bryan 0:b74591d5ab33 669 obj->irq_tx_setting = IRQ_ON;
be_bryan 0:b74591d5ab33 670 irq_enable(obj);
be_bryan 0:b74591d5ab33 671 }
be_bryan 0:b74591d5ab33 672 break;
be_bryan 0:b74591d5ab33 673 default:
be_bryan 0:b74591d5ab33 674 {
be_bryan 0:b74591d5ab33 675 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 676 }
be_bryan 0:b74591d5ab33 677 break;
be_bryan 0:b74591d5ab33 678 }
be_bryan 0:b74591d5ab33 679 } else {
be_bryan 0:b74591d5ab33 680 switch (irq) {
be_bryan 0:b74591d5ab33 681 case RxIrq:
be_bryan 0:b74591d5ab33 682 {
be_bryan 0:b74591d5ab33 683 /* Bit 4 for Rx and bit 6 for Rx Timeout */
be_bryan 0:b74591d5ab33 684 obj->reg_base->UARTIMSC &= ~((1 << 4) | (1 << 6));
be_bryan 0:b74591d5ab33 685 if (lp_also)
be_bryan 0:b74591d5ab33 686 {
be_bryan 0:b74591d5ab33 687 /* "Word Received" IRQ */
be_bryan 0:b74591d5ab33 688 LP_UART_CTRL &= ~(1 << 23);
be_bryan 0:b74591d5ab33 689 }
be_bryan 0:b74591d5ab33 690 obj->irq_rx_setting = IRQ_OFF;
be_bryan 0:b74591d5ab33 691 }
be_bryan 0:b74591d5ab33 692 break;
be_bryan 0:b74591d5ab33 693 case TxIrq:
be_bryan 0:b74591d5ab33 694 {
be_bryan 0:b74591d5ab33 695 /* Bit 5 */
be_bryan 0:b74591d5ab33 696 obj->reg_base->UARTIMSC &= ~(1 << 5);
be_bryan 0:b74591d5ab33 697 obj->irq_tx_setting = IRQ_OFF;
be_bryan 0:b74591d5ab33 698 }
be_bryan 0:b74591d5ab33 699 break;
be_bryan 0:b74591d5ab33 700 default:
be_bryan 0:b74591d5ab33 701 {
be_bryan 0:b74591d5ab33 702 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 703 }
be_bryan 0:b74591d5ab33 704 break;
be_bryan 0:b74591d5ab33 705 }
be_bryan 0:b74591d5ab33 706
be_bryan 0:b74591d5ab33 707 if ((obj->irq_rx_setting == IRQ_OFF) && (obj->irq_tx_setting == IRQ_OFF)) {
be_bryan 0:b74591d5ab33 708 irq_disable(obj);
be_bryan 0:b74591d5ab33 709 }
be_bryan 0:b74591d5ab33 710 }
be_bryan 0:b74591d5ab33 711
be_bryan 0:b74591d5ab33 712 /* Enable the UART again */
be_bryan 0:b74591d5ab33 713 obj->reg_base->UARTCR |= 1 << 0;
be_bryan 0:b74591d5ab33 714 }
be_bryan 0:b74591d5ab33 715
be_bryan 0:b74591d5ab33 716 /* ----------------------------------------------------------------
be_bryan 0:b74591d5ab33 717 * MBED API CALLS: TRANSMIT AND RECEIVE FUNCTIONS
be_bryan 0:b74591d5ab33 718 * ----------------------------------------------------------------*/
be_bryan 0:b74591d5ab33 719
be_bryan 0:b74591d5ab33 720 int serial_getc(serial_t *obj)
be_bryan 0:b74591d5ab33 721 {
be_bryan 0:b74591d5ab33 722 uint8_t data = 0;
be_bryan 0:b74591d5ab33 723
be_bryan 0:b74591d5ab33 724 /* Block until there is data to read */
be_bryan 0:b74591d5ab33 725 while (!serial_readable(obj)) {}
be_bryan 0:b74591d5ab33 726
be_bryan 0:b74591d5ab33 727 /* Read the data */
be_bryan 0:b74591d5ab33 728 switch (obj->config) {
be_bryan 0:b74591d5ab33 729 case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
be_bryan 0:b74591d5ab33 730 {
be_bryan 0:b74591d5ab33 731 data = (uint8_t) LP_UART_DATA;
be_bryan 0:b74591d5ab33 732 }
be_bryan 0:b74591d5ab33 733 break;
be_bryan 0:b74591d5ab33 734 case SERIAL_CONFIG_UART0_RX_UART0_TX:
be_bryan 0:b74591d5ab33 735 case SERIAL_CONFIG_UART1_RX_UART1_TX:
be_bryan 0:b74591d5ab33 736 {
be_bryan 0:b74591d5ab33 737 data = (uint8_t) obj->reg_base->UARTDR;
be_bryan 0:b74591d5ab33 738 }
be_bryan 0:b74591d5ab33 739 break;
be_bryan 0:b74591d5ab33 740 default:
be_bryan 0:b74591d5ab33 741 {
be_bryan 0:b74591d5ab33 742 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 743 }
be_bryan 0:b74591d5ab33 744 break;
be_bryan 0:b74591d5ab33 745 }
be_bryan 0:b74591d5ab33 746
be_bryan 0:b74591d5ab33 747 return (int) data;
be_bryan 0:b74591d5ab33 748 }
be_bryan 0:b74591d5ab33 749
be_bryan 0:b74591d5ab33 750 void serial_putc(serial_t *obj, int c)
be_bryan 0:b74591d5ab33 751 {
be_bryan 0:b74591d5ab33 752 /* Block until there is room to write */
be_bryan 0:b74591d5ab33 753 while (!serial_writable(obj)) {}
be_bryan 0:b74591d5ab33 754
be_bryan 0:b74591d5ab33 755 /* Write the data */
be_bryan 0:b74591d5ab33 756 obj->reg_base->UARTDR = (uint8_t) c;
be_bryan 0:b74591d5ab33 757 }
be_bryan 0:b74591d5ab33 758
be_bryan 0:b74591d5ab33 759 int serial_readable(serial_t *obj)
be_bryan 0:b74591d5ab33 760 {
be_bryan 0:b74591d5ab33 761 bool readable = false;
be_bryan 0:b74591d5ab33 762
be_bryan 0:b74591d5ab33 763 switch (obj->config) {
be_bryan 0:b74591d5ab33 764 case SERIAL_CONFIG_UARTLP_RX_UART0_TX:
be_bryan 0:b74591d5ab33 765 {
be_bryan 0:b74591d5ab33 766 /* Check the status register, bits 8 to 10 indicate
be_bryan 0:b74591d5ab33 767 * the number of Rx bytes (make sure it's the status
be_bryan 0:b74591d5ab33 768 * register not the data register as a read from that
be_bryan 0:b74591d5ab33 769 * register would clear the Rx interrupt) */
be_bryan 0:b74591d5ab33 770 readable = (((LP_UART_STATUS >> 8) & 0x07) != 0);
be_bryan 0:b74591d5ab33 771 }
be_bryan 0:b74591d5ab33 772 break;
be_bryan 0:b74591d5ab33 773 case SERIAL_CONFIG_UART0_RX_UART0_TX:
be_bryan 0:b74591d5ab33 774 case SERIAL_CONFIG_UART1_RX_UART1_TX:
be_bryan 0:b74591d5ab33 775 {
be_bryan 0:b74591d5ab33 776 /* Check the Rx FIFO Empty bit */
be_bryan 0:b74591d5ab33 777 readable = ((obj->reg_base->UARTFR & (1 << 4)) != (1 << 4));
be_bryan 0:b74591d5ab33 778 }
be_bryan 0:b74591d5ab33 779 break;
be_bryan 0:b74591d5ab33 780 default:
be_bryan 0:b74591d5ab33 781 {
be_bryan 0:b74591d5ab33 782 MBED_ASSERT(false);
be_bryan 0:b74591d5ab33 783 }
be_bryan 0:b74591d5ab33 784 break;
be_bryan 0:b74591d5ab33 785 }
be_bryan 0:b74591d5ab33 786
be_bryan 0:b74591d5ab33 787 return (int) readable;
be_bryan 0:b74591d5ab33 788 }
be_bryan 0:b74591d5ab33 789
be_bryan 0:b74591d5ab33 790 int serial_writable(serial_t *obj)
be_bryan 0:b74591d5ab33 791 {
be_bryan 0:b74591d5ab33 792 /* Check the "UART TX FIFO full" bit:
be_bryan 0:b74591d5ab33 793 * only if this is 0 can we transmit */
be_bryan 0:b74591d5ab33 794 return (obj->reg_base->UARTFR & (1 << 5)) != (1 << 5);
be_bryan 0:b74591d5ab33 795 }
be_bryan 0:b74591d5ab33 796
be_bryan 0:b74591d5ab33 797 void serial_break_set(serial_t *obj)
be_bryan 0:b74591d5ab33 798 {
be_bryan 0:b74591d5ab33 799 /* Disable UART while writing to control registers */
be_bryan 0:b74591d5ab33 800 obj->reg_base->UARTCR &= ~(1 << 0);
be_bryan 0:b74591d5ab33 801
be_bryan 0:b74591d5ab33 802 /* Set bit 1 of the line control register */
be_bryan 0:b74591d5ab33 803 obj->reg_base->UARTLCR_H |= 1 << 0;
be_bryan 0:b74591d5ab33 804
be_bryan 0:b74591d5ab33 805 /* Enable the UART again */
be_bryan 0:b74591d5ab33 806 obj->reg_base->UARTCR |= 1 << 0;
be_bryan 0:b74591d5ab33 807 }
be_bryan 0:b74591d5ab33 808
be_bryan 0:b74591d5ab33 809 void serial_break_clear(serial_t *obj)
be_bryan 0:b74591d5ab33 810 {
be_bryan 0:b74591d5ab33 811 /* Disable UART while writing to control registers */
be_bryan 0:b74591d5ab33 812 obj->reg_base->UARTCR &= ~(1 << 0);
be_bryan 0:b74591d5ab33 813
be_bryan 0:b74591d5ab33 814 /* Clear bit 1 of the line control register */
be_bryan 0:b74591d5ab33 815 obj->reg_base->UARTLCR_H &= ~(1 << 0);
be_bryan 0:b74591d5ab33 816
be_bryan 0:b74591d5ab33 817 /* Enable the UART again */
be_bryan 0:b74591d5ab33 818 obj->reg_base->UARTCR |= 1 << 0;
be_bryan 0:b74591d5ab33 819 }