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:
bogdanm
Date:
Mon Aug 19 18:17:02 2013 +0300
Revision:
19:398f4c622e1b
Sync with official mbed library release 66

Who changed what in which revision?

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