mbed SDK library sources

Fork of mbed-src by mbed official

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:
Mon Dec 16 09:15:05 2013 +0000
Revision:
59:ef93cc6bbf65
Parent:
51:7838415c99e7
Synchronized with git revision 5dea203d16a93915c80553c1d95b26625bc077f8

Full URL: https://github.com/mbedmicro/mbed/commit/5dea203d16a93915c80553c1d95b26625bc077f8/

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