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:
Wed Aug 07 16:43:59 2013 +0300
Revision:
15:4892fe388435
Child:
20:4263a77256ae
Added LPC4088 target and interrupt chaining code

Who changed what in which revision?

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