fix for mbed lib issue 3 (i2c problem) see also https://mbed.org/users/mbed_official/code/mbed/issues/3 affected implementations: LPC812, LPC11U24, LPC1768, LPC2368, LPC4088

Fork of mbed-src by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers serial_api.c Source File

serial_api.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "serial_api.h"
00017 
00018 // math.h required for floating point operations for baud rate calculation
00019 #include <math.h>
00020 
00021 #include <string.h>
00022 
00023 #include "cmsis.h"
00024 #include "pinmap.h"
00025 #include "error.h"
00026 
00027 /******************************************************************************
00028  * INITIALIZATION
00029  ******************************************************************************/
00030 static const PinMap PinMap_UART_TX[] = {
00031     {PTC4, UART_1, 3},
00032     {PTA2, UART_0, 2},
00033     {PTD5, UART_2, 3},
00034     {PTD3, UART_2, 3},
00035     {NC  , NC    , 0}
00036 };
00037 
00038 static const PinMap PinMap_UART_RX[] = {
00039     {PTC3, UART_1, 3},
00040     {PTA1, UART_0, 2},
00041     {PTD4, UART_2, 3},
00042     {PTD2, UART_2, 3},
00043     {NC  , NC    , 0}
00044 };
00045 
00046 #define UART_NUM    3
00047 static uint32_t serial_irq_ids[UART_NUM] = {0};
00048 static uart_irq_handler irq_handler;
00049 
00050 int stdio_uart_inited = 0;
00051 serial_t stdio_uart;
00052 
00053 void serial_init(serial_t *obj, PinName tx, PinName rx) {
00054     // determine the UART to use
00055     UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
00056     UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
00057     UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
00058     if ((int)uart == NC) {
00059         error("Serial pinout mapping failed");
00060     }
00061 
00062     obj->uart = (UARTLP_Type *)uart;
00063     // enable clk
00064     switch (uart) {
00065         case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<<SIM_SOPT2_UART0SRC_SHIFT);
00066                      SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break;
00067         case UART_1: SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break;
00068         case UART_2: SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break;
00069     }
00070     // Disable UART before changing registers
00071     obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
00072     
00073     switch (uart) {
00074         case UART_0: obj->index = 0; break;
00075         case UART_1: obj->index = 1; break;
00076         case UART_2: obj->index = 2; break;
00077     }
00078 
00079     // set default baud rate and format
00080     serial_baud  (obj, 9600);
00081     serial_format(obj, 8, ParityNone, 1);
00082 
00083     // pinout the chosen uart
00084     pinmap_pinout(tx, PinMap_UART_TX);
00085     pinmap_pinout(rx, PinMap_UART_RX);
00086 
00087     // set rx/tx pins in PullUp mode
00088     pin_mode(tx, PullUp);
00089     pin_mode(rx, PullUp);
00090 
00091     obj->uart->C2 |= (UART_C2_RE_MASK | UART_C2_TE_MASK);
00092 
00093     if (uart == STDIO_UART) {
00094         stdio_uart_inited = 1;
00095         memcpy(&stdio_uart, obj, sizeof(serial_t));
00096     }
00097 }
00098 
00099 void serial_free(serial_t *obj) {
00100     serial_irq_ids[obj->index] = 0;
00101 }
00102 
00103 // serial_baud
00104 //
00105 // set the baud rate, taking in to account the current SystemFrequency
00106 //
00107 // The LPC2300 and LPC1700 have a divider and a fractional divider to control the
00108 // baud rate. The formula is:
00109 //
00110 // Baudrate = (1 / PCLK) * 16 * DL * (1 + DivAddVal / MulVal)
00111 //   where:
00112 //     1 < MulVal <= 15
00113 //     0 <= DivAddVal < 14
00114 //     DivAddVal < MulVal
00115 //
00116 void serial_baud(serial_t *obj, int baudrate) {
00117     
00118     // save C2 state
00119     uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
00120     
00121     // Disable UART before changing registers
00122     obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
00123     
00124     // [TODO] not hardcode this value
00125     uint32_t PCLK = (obj->uart == UART0) ? 48000000u : 24000000u;
00126 
00127     // First we check to see if the basic divide with no DivAddVal/MulVal
00128     // ratio gives us an integer result. If it does, we set DivAddVal = 0,
00129     // MulVal = 1. Otherwise, we search the valid ratio value range to find
00130     // the closest match. This could be more elegant, using search methods
00131     // and/or lookup tables, but the brute force method is not that much
00132     // slower, and is more maintainable.
00133     uint16_t DL = PCLK / (16 * baudrate);
00134 
00135     // set BDH and BDL
00136     obj->uart->BDH = (obj->uart->BDH & ~(0x1f)) | ((DL >> 8) & 0x1f);
00137     obj->uart->BDL = (obj->uart->BDL & ~(0xff)) | ((DL >> 0) & 0xff);
00138     
00139     // restore C2 state
00140     obj->uart->C2 |= c2_state;
00141 }
00142 
00143 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
00144     uint8_t m10 = 0;
00145     
00146     // save C2 state
00147     uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
00148     
00149     // Disable UART before changing registers
00150     obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
00151     
00152     // 8 data bits = 0 ... 9 data bits = 1
00153     if ((data_bits < 8) || (data_bits > 9)) {
00154         error("Invalid number of bits (%d) in serial format, should be 8..9\r\n", data_bits);
00155     }
00156     data_bits -= 8;
00157 
00158     uint8_t parity_enable, parity_select;
00159     switch (parity) {
00160         case ParityNone: parity_enable = 0; parity_select = 0; break;
00161         case ParityOdd : parity_enable = 1; parity_select = 1; data_bits++; break;
00162         case ParityEven: parity_enable = 1; parity_select = 0; data_bits++; break;
00163         default:
00164             error("Invalid serial parity setting\r\n");
00165             return;
00166     }
00167 
00168     // 1 stop bits = 0, 2 stop bits = 1
00169     if ((stop_bits != 1) && (stop_bits != 2)) {
00170         error("Invalid stop bits specified\r\n");
00171     }
00172     stop_bits -= 1;
00173     
00174     // 9 data bits + parity
00175     if (data_bits == 2) {
00176         // only uart0 supports 10 bit communication
00177         if (obj->index != 0) {
00178             error("Invalid number of bits (9) to be used with parity\r\n");
00179         }
00180         data_bits = 0;
00181         m10 = 1;
00182     }
00183 
00184     // data bits, parity and parity mode
00185     obj->uart->C1 = ((data_bits << 4)
00186                   |  (parity_enable << 1)
00187                   |  (parity_select << 0));
00188     
00189     // enable 10bit mode if needed
00190     if (obj->index == 0) {
00191         obj->uart->C4 &= ~UARTLP_C4_M10_MASK;
00192         obj->uart->C4 |= (m10 << UARTLP_C4_M10_SHIFT);
00193     }
00194     
00195     // stop bits
00196     obj->uart->BDH &= ~UART_BDH_SBNS_MASK;
00197     obj->uart->BDH |= (stop_bits << UART_BDH_SBNS_SHIFT);
00198     
00199     // restore C2 state
00200     obj->uart->C2 |= c2_state;
00201 }
00202 
00203 /******************************************************************************
00204  * INTERRUPTS HANDLING
00205  ******************************************************************************/
00206 static inline void uart_irq(uint8_t status, uint32_t index) {
00207     if (serial_irq_ids[index] != 0) {
00208         if (status & UART_S1_TDRE_MASK)
00209             irq_handler(serial_irq_ids[index], TxIrq);
00210 
00211         if (status & UART_S1_RDRF_MASK)
00212             irq_handler(serial_irq_ids[index], RxIrq);
00213     }
00214 }
00215 
00216 void uart0_irq() {
00217     uart_irq(UART0->S1, 0);
00218     if (UART0->S1 & UART_S1_OR_MASK)
00219         UART0->S1 |= UART_S1_OR_MASK;
00220 }
00221 void uart1_irq() {uart_irq(UART1->S1, 1);}
00222 void uart2_irq() {uart_irq(UART2->S1, 2);}
00223 
00224 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
00225     irq_handler = handler;
00226     serial_irq_ids[obj->index] = id;
00227 }
00228 
00229 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
00230     IRQn_Type  irq_n = (IRQn_Type )0;
00231     uint32_t vector = 0;
00232     switch ((int)obj->uart) {
00233         case UART_0: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break;
00234         case UART_1: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break;
00235         case UART_2: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break;
00236     }
00237 
00238     if (enable) {
00239         switch (irq) {
00240             case RxIrq: obj->uart->C2 |= (UART_C2_RIE_MASK); break;
00241             case TxIrq: obj->uart->C2 |= (UART_C2_TIE_MASK); break;
00242         }
00243         NVIC_SetVector(irq_n, vector);
00244         NVIC_EnableIRQ(irq_n);
00245 
00246     } else { // disable
00247         int all_disabled = 0;
00248         SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
00249         switch (irq) {
00250             case RxIrq: obj->uart->C2 &= ~(UART_C2_RIE_MASK); break;
00251             case TxIrq: obj->uart->C2 &= ~(UART_C2_TIE_MASK); break;
00252         }
00253         switch (other_irq) {
00254             case RxIrq: all_disabled = (obj->uart->C2 & (UART_C2_RIE_MASK)) == 0; break;
00255             case TxIrq: all_disabled = (obj->uart->C2 & (UART_C2_TIE_MASK)) == 0; break;
00256         }
00257         if (all_disabled)
00258             NVIC_DisableIRQ(irq_n);
00259     }
00260 }
00261 
00262 /******************************************************************************
00263  * READ/WRITE
00264  ******************************************************************************/
00265 int serial_getc(serial_t *obj) {
00266     while (!serial_readable(obj));
00267     return obj->uart->D;
00268 }
00269 
00270 void serial_putc(serial_t *obj, int c) {
00271     while (!serial_writable(obj));
00272     obj->uart->D = c;
00273 }
00274 
00275 int serial_readable(serial_t *obj) {
00276     // check overrun
00277     if (obj->uart->S1 &  UART_S1_OR_MASK) {
00278         obj->uart->S1 |= UART_S1_OR_MASK;
00279     }
00280     return (obj->uart->S1 & UART_S1_RDRF_MASK);
00281 }
00282 
00283 int serial_writable(serial_t *obj) {
00284     // check overrun
00285     if (obj->uart->S1 &  UART_S1_OR_MASK) {
00286         obj->uart->S1 |= UART_S1_OR_MASK;
00287     }
00288     return (obj->uart->S1 & UART_S1_TDRE_MASK);
00289 }
00290 
00291 void serial_clear(serial_t *obj) {
00292 }
00293 
00294 void serial_pinout_tx(PinName tx) {
00295     pinmap_pinout(tx, PinMap_UART_TX);
00296 }