mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Committer:
mbed_official
Date:
Tue Feb 03 17:00:07 2015 +0000
Revision:
463:5c73c3744533
Parent:
339:40bd4701f3e2
Synchronized with git revision 134a67aab259d410373367cb96b73420b390d385

Full URL: https://github.com/mbedmicro/mbed/commit/134a67aab259d410373367cb96b73420b390d385/

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bogdanm 13:0645d8841f51 1 /* mbed Microcontroller Library
bogdanm 13:0645d8841f51 2 * Copyright (c) 2006-2013 ARM Limited
bogdanm 13:0645d8841f51 3 *
bogdanm 13:0645d8841f51 4 * Licensed under the Apache License, Version 2.0 (the "License");
bogdanm 13:0645d8841f51 5 * you may not use this file except in compliance with the License.
bogdanm 13:0645d8841f51 6 * You may obtain a copy of the License at
bogdanm 13:0645d8841f51 7 *
bogdanm 13:0645d8841f51 8 * http://www.apache.org/licenses/LICENSE-2.0
bogdanm 13:0645d8841f51 9 *
bogdanm 13:0645d8841f51 10 * Unless required by applicable law or agreed to in writing, software
bogdanm 13:0645d8841f51 11 * distributed under the License is distributed on an "AS IS" BASIS,
bogdanm 13:0645d8841f51 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
bogdanm 13:0645d8841f51 13 * See the License for the specific language governing permissions and
bogdanm 13:0645d8841f51 14 * limitations under the License.
bogdanm 13:0645d8841f51 15 */
bogdanm 13:0645d8841f51 16 // math.h required for floating point operations for baud rate calculation
bogdanm 13:0645d8841f51 17 #include <math.h>
bogdanm 13:0645d8841f51 18 #include <string.h>
mbed_official 140:ca60b7a31055 19 #include <stdlib.h>
bogdanm 13:0645d8841f51 20
bogdanm 13:0645d8841f51 21 #include "serial_api.h"
bogdanm 13:0645d8841f51 22 #include "cmsis.h"
bogdanm 13:0645d8841f51 23 #include "pinmap.h"
mbed_official 274:6937b19af361 24 #include "PeripheralPins.h" // For the Peripheral to Pin Definitions found in the individual Target's Platform
bogdanm 13:0645d8841f51 25
bogdanm 13:0645d8841f51 26 /******************************************************************************
bogdanm 13:0645d8841f51 27 * INITIALIZATION
bogdanm 13:0645d8841f51 28 ******************************************************************************/
bogdanm 13:0645d8841f51 29 #define UART_NUM 1
bogdanm 13:0645d8841f51 30
bogdanm 13:0645d8841f51 31 static uint32_t serial_irq_ids[UART_NUM] = {0};
bogdanm 13:0645d8841f51 32 static uart_irq_handler irq_handler;
bogdanm 13:0645d8841f51 33
bogdanm 13:0645d8841f51 34 int stdio_uart_inited = 0;
bogdanm 13:0645d8841f51 35 serial_t stdio_uart;
bogdanm 13:0645d8841f51 36
bogdanm 13:0645d8841f51 37 void serial_init(serial_t *obj, PinName tx, PinName rx) {
bogdanm 13:0645d8841f51 38 int is_stdio_uart = 0;
bogdanm 13:0645d8841f51 39
bogdanm 13:0645d8841f51 40 // determine the UART to use
bogdanm 13:0645d8841f51 41 UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
bogdanm 13:0645d8841f51 42 UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
bogdanm 13:0645d8841f51 43 UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
mbed_official 227:7bd0639b8911 44 MBED_ASSERT((int)uart != NC);
mbed_official 227:7bd0639b8911 45
bogdanm 13:0645d8841f51 46 obj->uart = (LPC_USART_Type *)uart;
bogdanm 13:0645d8841f51 47 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12);
bogdanm 13:0645d8841f51 48
bogdanm 13:0645d8841f51 49 // [TODO] Consider more elegant approach
bogdanm 13:0645d8841f51 50 // disconnect USBTX/RX mapping mux, for case when switching ports
mbed_official 59:ef93cc6bbf65 51 #ifdef USBTX
bogdanm 13:0645d8841f51 52 pin_function(USBTX, 0);
bogdanm 13:0645d8841f51 53 pin_function(USBRX, 0);
mbed_official 59:ef93cc6bbf65 54 #endif
mbed_official 59:ef93cc6bbf65 55
bogdanm 13:0645d8841f51 56 // enable fifos and default rx trigger level
bogdanm 13:0645d8841f51 57 obj->uart->FCR = 1 << 0 // FIFO Enable - 0 = Disables, 1 = Enabled
bogdanm 13:0645d8841f51 58 | 0 << 1 // Rx Fifo Reset
bogdanm 13:0645d8841f51 59 | 0 << 2 // Tx Fifo Reset
bogdanm 13:0645d8841f51 60 | 0 << 6; // Rx irq trigger level - 0 = 1 char, 1 = 4 chars, 2 = 8 chars, 3 = 14 chars
bogdanm 13:0645d8841f51 61
bogdanm 13:0645d8841f51 62 // disable irqs
bogdanm 13:0645d8841f51 63 obj->uart->IER = 0 << 0 // Rx Data available irq enable
bogdanm 13:0645d8841f51 64 | 0 << 1 // Tx Fifo empty irq enable
bogdanm 13:0645d8841f51 65 | 0 << 2; // Rx Line Status irq enable
bogdanm 13:0645d8841f51 66
bogdanm 13:0645d8841f51 67 // set default baud rate and format
bogdanm 13:0645d8841f51 68 serial_baud (obj, 9600);
bogdanm 13:0645d8841f51 69 serial_format(obj, 8, ParityNone, 1);
bogdanm 13:0645d8841f51 70
bogdanm 13:0645d8841f51 71 // pinout the chosen uart
bogdanm 13:0645d8841f51 72 pinmap_pinout(tx, PinMap_UART_TX);
bogdanm 13:0645d8841f51 73 pinmap_pinout(rx, PinMap_UART_RX);
bogdanm 13:0645d8841f51 74
bogdanm 13:0645d8841f51 75 // set rx/tx pins in PullUp mode
mbed_official 339:40bd4701f3e2 76 if (tx != NC) {
mbed_official 339:40bd4701f3e2 77 pin_mode(tx, PullUp);
mbed_official 339:40bd4701f3e2 78 }
mbed_official 339:40bd4701f3e2 79 if (rx != NC) {
mbed_official 339:40bd4701f3e2 80 pin_mode(rx, PullUp);
mbed_official 339:40bd4701f3e2 81 }
bogdanm 13:0645d8841f51 82
bogdanm 13:0645d8841f51 83 switch (uart) {
bogdanm 13:0645d8841f51 84 case UART_0: obj->index = 0; break;
bogdanm 13:0645d8841f51 85 }
bogdanm 13:0645d8841f51 86
bogdanm 13:0645d8841f51 87 is_stdio_uart = (uart == STDIO_UART) ? (1) : (0);
bogdanm 13:0645d8841f51 88
bogdanm 13:0645d8841f51 89 if (is_stdio_uart) {
bogdanm 13:0645d8841f51 90 stdio_uart_inited = 1;
bogdanm 13:0645d8841f51 91 memcpy(&stdio_uart, obj, sizeof(serial_t));
bogdanm 13:0645d8841f51 92 }
bogdanm 13:0645d8841f51 93 }
bogdanm 13:0645d8841f51 94
bogdanm 13:0645d8841f51 95 void serial_free(serial_t *obj) {
bogdanm 13:0645d8841f51 96 serial_irq_ids[obj->index] = 0;
bogdanm 13:0645d8841f51 97 }
bogdanm 13:0645d8841f51 98
bogdanm 13:0645d8841f51 99 // serial_baud
bogdanm 13:0645d8841f51 100 // set the baud rate, taking in to account the current SystemFrequency
bogdanm 13:0645d8841f51 101 void serial_baud(serial_t *obj, int baudrate) {
bogdanm 13:0645d8841f51 102 LPC_SYSCON->UARTCLKDIV = 0x1;
bogdanm 13:0645d8841f51 103 uint32_t PCLK = SystemCoreClock;
bogdanm 13:0645d8841f51 104 // First we check to see if the basic divide with no DivAddVal/MulVal
bogdanm 13:0645d8841f51 105 // ratio gives us an integer result. If it does, we set DivAddVal = 0,
bogdanm 13:0645d8841f51 106 // MulVal = 1. Otherwise, we search the valid ratio value range to find
bogdanm 13:0645d8841f51 107 // the closest match. This could be more elegant, using search methods
bogdanm 13:0645d8841f51 108 // and/or lookup tables, but the brute force method is not that much
bogdanm 13:0645d8841f51 109 // slower, and is more maintainable.
bogdanm 13:0645d8841f51 110 uint16_t DL = PCLK / (16 * baudrate);
bogdanm 13:0645d8841f51 111
bogdanm 13:0645d8841f51 112 uint8_t DivAddVal = 0;
bogdanm 13:0645d8841f51 113 uint8_t MulVal = 1;
bogdanm 13:0645d8841f51 114 int hit = 0;
bogdanm 13:0645d8841f51 115 uint16_t dlv;
bogdanm 13:0645d8841f51 116 uint8_t mv, dav;
bogdanm 13:0645d8841f51 117 if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder
mbed_official 51:7838415c99e7 118 int err_best = baudrate, b;
mbed_official 51:7838415c99e7 119 for (mv = 1; mv < 16 && !hit; mv++)
mbed_official 51:7838415c99e7 120 {
mbed_official 51:7838415c99e7 121 for (dav = 0; dav < mv; dav++)
mbed_official 51:7838415c99e7 122 {
mbed_official 51:7838415c99e7 123 // baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul))
mbed_official 51:7838415c99e7 124 // solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul))
mbed_official 51:7838415c99e7 125 // mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding
mbed_official 51:7838415c99e7 126 // for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision
mbed_official 51:7838415c99e7 127 // note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding
mbed_official 51:7838415c99e7 128
mbed_official 51:7838415c99e7 129 if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom
mbed_official 51:7838415c99e7 130 dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2;
mbed_official 51:7838415c99e7 131 else // 2 bits headroom, use more precision
mbed_official 51:7838415c99e7 132 dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2;
mbed_official 51:7838415c99e7 133
mbed_official 51:7838415c99e7 134 // datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood
mbed_official 51:7838415c99e7 135 if (dlv == 0)
mbed_official 51:7838415c99e7 136 dlv = 1;
mbed_official 51:7838415c99e7 137
mbed_official 51:7838415c99e7 138 // datasheet says if dav > 0 then DL must be >= 2
mbed_official 51:7838415c99e7 139 if ((dav > 0) && (dlv < 2))
mbed_official 51:7838415c99e7 140 dlv = 2;
mbed_official 51:7838415c99e7 141
mbed_official 51:7838415c99e7 142 // integer rearrangement of the baudrate equation (with rounding)
mbed_official 51:7838415c99e7 143 b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2;
mbed_official 51:7838415c99e7 144
mbed_official 51:7838415c99e7 145 // check to see how we went
mbed_official 51:7838415c99e7 146 b = abs(b - baudrate);
mbed_official 51:7838415c99e7 147 if (b < err_best)
mbed_official 51:7838415c99e7 148 {
mbed_official 51:7838415c99e7 149 err_best = b;
mbed_official 51:7838415c99e7 150
mbed_official 51:7838415c99e7 151 DL = dlv;
mbed_official 51:7838415c99e7 152 MulVal = mv;
mbed_official 51:7838415c99e7 153 DivAddVal = dav;
mbed_official 51:7838415c99e7 154
mbed_official 51:7838415c99e7 155 if (b == baudrate)
mbed_official 51:7838415c99e7 156 {
mbed_official 51:7838415c99e7 157 hit = 1;
mbed_official 51:7838415c99e7 158 break;
bogdanm 13:0645d8841f51 159 }
bogdanm 13:0645d8841f51 160 }
bogdanm 13:0645d8841f51 161 }
bogdanm 13:0645d8841f51 162 }
bogdanm 13:0645d8841f51 163 }
bogdanm 13:0645d8841f51 164
bogdanm 13:0645d8841f51 165 // set LCR[DLAB] to enable writing to divider registers
bogdanm 13:0645d8841f51 166 obj->uart->LCR |= (1 << 7);
bogdanm 13:0645d8841f51 167
bogdanm 13:0645d8841f51 168 // set divider values
bogdanm 13:0645d8841f51 169 obj->uart->DLM = (DL >> 8) & 0xFF;
bogdanm 13:0645d8841f51 170 obj->uart->DLL = (DL >> 0) & 0xFF;
bogdanm 13:0645d8841f51 171 obj->uart->FDR = (uint32_t) DivAddVal << 0
bogdanm 13:0645d8841f51 172 | (uint32_t) MulVal << 4;
bogdanm 13:0645d8841f51 173
bogdanm 13:0645d8841f51 174 // clear LCR[DLAB]
bogdanm 13:0645d8841f51 175 obj->uart->LCR &= ~(1 << 7);
bogdanm 13:0645d8841f51 176 }
bogdanm 13:0645d8841f51 177
bogdanm 13:0645d8841f51 178 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
mbed_official 227:7bd0639b8911 179 MBED_ASSERT((stop_bits == 1) || (stop_bits == 2)); // 0: 1 stop bits, 1: 2 stop bits
mbed_official 227:7bd0639b8911 180 MBED_ASSERT((data_bits > 4) && (data_bits < 9)); // 0: 5 data bits ... 3: 8 data bits
mbed_official 227:7bd0639b8911 181 MBED_ASSERT((parity == ParityNone) || (parity == ParityOdd) || (parity == ParityEven) ||
mbed_official 227:7bd0639b8911 182 (parity == ParityForced1) || (parity == ParityForced0));
mbed_official 227:7bd0639b8911 183
bogdanm 13:0645d8841f51 184 stop_bits -= 1;
bogdanm 13:0645d8841f51 185 data_bits -= 5;
bogdanm 13:0645d8841f51 186
mbed_official 243:1b2bee05fe98 187 int parity_enable = 0, parity_select = 0;
bogdanm 13:0645d8841f51 188 switch (parity) {
bogdanm 13:0645d8841f51 189 case ParityNone: parity_enable = 0; parity_select = 0; break;
bogdanm 13:0645d8841f51 190 case ParityOdd : parity_enable = 1; parity_select = 0; break;
bogdanm 13:0645d8841f51 191 case ParityEven: parity_enable = 1; parity_select = 1; break;
bogdanm 13:0645d8841f51 192 case ParityForced1: parity_enable = 1; parity_select = 2; break;
bogdanm 13:0645d8841f51 193 case ParityForced0: parity_enable = 1; parity_select = 3; break;
bogdanm 13:0645d8841f51 194 default:
mbed_official 227:7bd0639b8911 195 break;
bogdanm 13:0645d8841f51 196 }
bogdanm 13:0645d8841f51 197
bogdanm 13:0645d8841f51 198 obj->uart->LCR = data_bits << 0
bogdanm 13:0645d8841f51 199 | stop_bits << 2
bogdanm 13:0645d8841f51 200 | parity_enable << 3
bogdanm 13:0645d8841f51 201 | parity_select << 4;
bogdanm 13:0645d8841f51 202 }
bogdanm 13:0645d8841f51 203
bogdanm 13:0645d8841f51 204 /******************************************************************************
bogdanm 13:0645d8841f51 205 * INTERRUPTS HANDLING
bogdanm 13:0645d8841f51 206 ******************************************************************************/
bogdanm 13:0645d8841f51 207 static inline void uart_irq(uint32_t iir, uint32_t index) {
bogdanm 13:0645d8841f51 208 // [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling
bogdanm 13:0645d8841f51 209 SerialIrq irq_type;
bogdanm 13:0645d8841f51 210 switch (iir) {
bogdanm 13:0645d8841f51 211 case 1: irq_type = TxIrq; break;
bogdanm 13:0645d8841f51 212 case 2: irq_type = RxIrq; break;
bogdanm 13:0645d8841f51 213 default: return;
bogdanm 13:0645d8841f51 214 }
bogdanm 13:0645d8841f51 215
bogdanm 13:0645d8841f51 216 if (serial_irq_ids[index] != 0)
bogdanm 13:0645d8841f51 217 irq_handler(serial_irq_ids[index], irq_type);
bogdanm 13:0645d8841f51 218 }
bogdanm 13:0645d8841f51 219
bogdanm 13:0645d8841f51 220 void uart0_irq() {uart_irq((LPC_USART->IIR >> 1) & 0x7, 0);}
bogdanm 13:0645d8841f51 221
bogdanm 13:0645d8841f51 222 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
bogdanm 13:0645d8841f51 223 irq_handler = handler;
bogdanm 13:0645d8841f51 224 serial_irq_ids[obj->index] = id;
bogdanm 13:0645d8841f51 225 }
bogdanm 13:0645d8841f51 226
bogdanm 13:0645d8841f51 227 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
bogdanm 13:0645d8841f51 228 IRQn_Type irq_n = (IRQn_Type)0;
bogdanm 13:0645d8841f51 229 uint32_t vector = 0;
bogdanm 13:0645d8841f51 230 switch ((int)obj->uart) {
bogdanm 13:0645d8841f51 231 case UART_0: irq_n=UART_IRQn ; vector = (uint32_t)&uart0_irq; break;
bogdanm 13:0645d8841f51 232 }
bogdanm 13:0645d8841f51 233
bogdanm 13:0645d8841f51 234 if (enable) {
bogdanm 13:0645d8841f51 235 obj->uart->IER |= 1 << irq;
bogdanm 13:0645d8841f51 236 NVIC_SetVector(irq_n, vector);
bogdanm 13:0645d8841f51 237 NVIC_EnableIRQ(irq_n);
bogdanm 13:0645d8841f51 238 } else { // disable
bogdanm 13:0645d8841f51 239 int all_disabled = 0;
bogdanm 13:0645d8841f51 240 SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
bogdanm 13:0645d8841f51 241
bogdanm 13:0645d8841f51 242 obj->uart->IER &= ~(1 << irq);
bogdanm 13:0645d8841f51 243 all_disabled = (obj->uart->IER & (1 << other_irq)) == 0;
bogdanm 13:0645d8841f51 244
bogdanm 13:0645d8841f51 245 if (all_disabled)
bogdanm 13:0645d8841f51 246 NVIC_DisableIRQ(irq_n);
bogdanm 13:0645d8841f51 247 }
bogdanm 13:0645d8841f51 248 }
bogdanm 13:0645d8841f51 249
bogdanm 13:0645d8841f51 250 /******************************************************************************
bogdanm 13:0645d8841f51 251 * READ/WRITE
bogdanm 13:0645d8841f51 252 ******************************************************************************/
bogdanm 13:0645d8841f51 253 int serial_getc(serial_t *obj) {
bogdanm 13:0645d8841f51 254 while (!serial_readable(obj));
bogdanm 13:0645d8841f51 255 return obj->uart->RBR;
bogdanm 13:0645d8841f51 256 }
bogdanm 13:0645d8841f51 257
bogdanm 13:0645d8841f51 258 void serial_putc(serial_t *obj, int c) {
bogdanm 13:0645d8841f51 259 while (!serial_writable(obj));
bogdanm 13:0645d8841f51 260 obj->uart->THR = c;
bogdanm 13:0645d8841f51 261 }
bogdanm 13:0645d8841f51 262
bogdanm 13:0645d8841f51 263 int serial_readable(serial_t *obj) {
bogdanm 13:0645d8841f51 264 return obj->uart->LSR & 0x01;
bogdanm 13:0645d8841f51 265 }
bogdanm 13:0645d8841f51 266
bogdanm 13:0645d8841f51 267 int serial_writable(serial_t *obj) {
bogdanm 13:0645d8841f51 268 return obj->uart->LSR & 0x20;
bogdanm 13:0645d8841f51 269 }
bogdanm 13:0645d8841f51 270
bogdanm 13:0645d8841f51 271 void serial_clear(serial_t *obj) {
bogdanm 13:0645d8841f51 272 obj->uart->FCR = 1 << 1 // rx FIFO reset
bogdanm 13:0645d8841f51 273 | 1 << 2 // tx FIFO reset
bogdanm 13:0645d8841f51 274 | 0 << 6; // interrupt depth
bogdanm 13:0645d8841f51 275 }
bogdanm 13:0645d8841f51 276
bogdanm 13:0645d8841f51 277 void serial_pinout_tx(PinName tx) {
bogdanm 13:0645d8841f51 278 pinmap_pinout(tx, PinMap_UART_TX);
bogdanm 13:0645d8841f51 279 }
bogdanm 13:0645d8841f51 280
bogdanm 13:0645d8841f51 281 void serial_break_set(serial_t *obj) {
bogdanm 13:0645d8841f51 282 obj->uart->LCR |= (1 << 6);
bogdanm 13:0645d8841f51 283 }
bogdanm 13:0645d8841f51 284
bogdanm 13:0645d8841f51 285 void serial_break_clear(serial_t *obj) {
bogdanm 13:0645d8841f51 286 obj->uart->LCR &= ~(1 << 6);
bogdanm 13:0645d8841f51 287 }
bogdanm 13:0645d8841f51 288