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 // math.h required for floating point operations for baud rate calculation
00017 #include <math.h>
00018 #include <string.h>
00019 
00020 #include "serial_api.h"
00021 #include "cmsis.h"
00022 #include "pinmap.h"
00023 #include "error.h"
00024 
00025 /******************************************************************************
00026  * INITIALIZATION
00027  ******************************************************************************/
00028 #define UART_NUM    3
00029 
00030 static const SWM_Map SWM_UART_TX[] = {
00031     {0, 0},
00032     {1, 8},
00033     {2, 16},
00034 };
00035 
00036 static const SWM_Map SWM_UART_RX[] = {
00037     {0, 8},
00038     {1, 16},
00039     {2, 24},
00040 };
00041 
00042 // bit flags for used UARTs
00043 static unsigned char uart_used = 0;
00044 static int get_available_uart(void) {
00045     int i;
00046     for (i=0; i<3; i++) {
00047         if ((uart_used & (1 << i)) == 0)
00048             return i;
00049     }
00050     return -1;
00051 }
00052 
00053 #define UART_EN       (0x01<<0)
00054 
00055 #define CTS_DELTA     (0x01<<5)
00056 #define RXBRK         (0x01<<10)
00057 #define DELTA_RXBRK   (0x01<<11)
00058 
00059 #define RXRDY         (0x01<<0)
00060 #define TXRDY         (0x01<<2)
00061 
00062 static uint32_t UARTSysClk;
00063 
00064 static uint32_t serial_irq_ids[UART_NUM] = {0};
00065 static uart_irq_handler irq_handler;
00066 
00067 int stdio_uart_inited = 0;
00068 serial_t stdio_uart;
00069 
00070 void serial_init(serial_t *obj, PinName tx, PinName rx) {
00071     int is_stdio_uart = 0;
00072     
00073     int uart_n = get_available_uart();
00074     if (uart_n == -1) {
00075         error("No available UART");
00076     }
00077     obj->index = uart_n;
00078     obj->uart = (LPC_USART_TypeDef *)(LPC_USART0_BASE + (0x4000 * uart_n));
00079     uart_used |= (1 << uart_n);
00080     
00081     const SWM_Map *swm;
00082     uint32_t regVal;
00083     
00084     swm = &SWM_UART_TX[uart_n];
00085     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
00086     LPC_SWM->PINASSIGN[swm->n] = regVal |  (tx   << swm->offset);
00087     
00088     swm = &SWM_UART_RX[uart_n];
00089     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
00090     LPC_SWM->PINASSIGN[swm->n] = regVal |  (rx   << swm->offset);
00091     
00092     /* uart clock divided by 1 */
00093     LPC_SYSCON->UARTCLKDIV = 1;
00094     
00095     /* disable uart interrupts */
00096     NVIC_DisableIRQ((IRQn_Type )(UART0_IRQn + uart_n));
00097     
00098     /* Enable UART clock */
00099     LPC_SYSCON->SYSAHBCLKCTRL |= (1 << (14 + uart_n));
00100     
00101     /* Peripheral reset control to UART, a "1" bring it out of reset. */
00102     LPC_SYSCON->PRESETCTRL &= ~(0x1 << (3 + uart_n));
00103     LPC_SYSCON->PRESETCTRL |=  (0x1 << (3 + uart_n));
00104     
00105     UARTSysClk = SystemCoreClock / LPC_SYSCON->UARTCLKDIV;
00106     
00107     // set default baud rate and format
00108     serial_baud  (obj, 9600);
00109     serial_format(obj, 8, ParityNone, 1);
00110     
00111     /* Clear all status bits. */
00112     obj->uart->STAT = CTS_DELTA | DELTA_RXBRK;
00113     
00114     /* enable uart interrupts */
00115     NVIC_EnableIRQ((IRQn_Type )(UART0_IRQn + uart_n));
00116     
00117     /* Enable UART interrupt */
00118     // obj->uart->INTENSET = RXRDY | TXRDY | DELTA_RXBRK;
00119     
00120     /* Enable UART */
00121     obj->uart->CFG |= UART_EN;
00122     
00123     is_stdio_uart = ((tx == USBTX) && (rx == USBRX));
00124     
00125     if (is_stdio_uart) {
00126         stdio_uart_inited = 1;
00127         memcpy(&stdio_uart, obj, sizeof(serial_t));
00128     }
00129 }
00130 
00131 void serial_free(serial_t *obj) {
00132     uart_used &= ~(1 << obj->index);
00133     serial_irq_ids[obj->index] = 0;
00134 }
00135 
00136 // serial_baud
00137 // set the baud rate, taking in to account the current SystemFrequency
00138 void serial_baud(serial_t *obj, int baudrate) {
00139     /* Integer divider:
00140          BRG = UARTSysClk/(Baudrate * 16) - 1
00141        
00142        Frational divider:
00143          FRG = ((UARTSysClk / (Baudrate * 16 * (BRG + 1))) - 1)
00144        
00145        where
00146          FRG = (LPC_SYSCON->UARTFRDADD + 1) / (LPC_SYSCON->UARTFRDSUB + 1)
00147        
00148        (1) The easiest way is set SUB value to 256, -1 encoded, thus SUB
00149            register is 0xFF.
00150        (2) In ADD register value, depending on the value of UartSysClk,
00151            baudrate, BRG register value, and SUB register value, be careful
00152            about the order of multiplier and divider and make sure any
00153            multiplier doesn't exceed 32-bit boundary and any divider doesn't get
00154            down below one(integer 0).
00155        (3) ADD should be always less than SUB.
00156     */
00157     obj->uart->BRG = UARTSysClk / 16 / baudrate - 1;
00158     
00159     LPC_SYSCON->UARTFRGDIV = 0xFF;
00160     LPC_SYSCON->UARTFRGMULT = ( ((UARTSysClk / 16) * (LPC_SYSCON->UARTFRGDIV + 1)) /
00161                                 (baudrate * (obj->uart->BRG + 1))
00162                               ) - (LPC_SYSCON->UARTFRGDIV + 1);
00163 
00164 }
00165 
00166 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
00167     // 0: 1 stop bits, 1: 2 stop bits
00168     if (stop_bits != 1 && stop_bits != 2) {
00169         error("Invalid stop bits specified");
00170     }
00171     stop_bits -= 1;
00172     
00173     // 0: 7 data bits ... 2: 9 data bits
00174     if (data_bits < 7 || data_bits > 9) {
00175         error("Invalid number of bits (%d) in serial format, should be 7..9", data_bits);
00176     }
00177     data_bits -= 7;
00178     
00179     int paritysel;
00180     switch (parity) {
00181         case ParityNone: paritysel = 0; break;
00182         case ParityEven: paritysel = 2; break;
00183         case ParityOdd : paritysel = 3; break;
00184         default:
00185             error("Invalid serial parity setting");
00186             return;
00187     }
00188     
00189     obj->uart->CFG = (data_bits << 2)
00190                    | (paritysel << 4)
00191                    | (stop_bits << 6);
00192 }
00193 
00194 /******************************************************************************
00195  * INTERRUPTS HANDLING
00196  ******************************************************************************/
00197 static inline void uart_irq(uint32_t iir, uint32_t index) {
00198     // [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling
00199     SerialIrq irq_type;
00200     switch (iir) {
00201         case 1: irq_type = TxIrq; break;
00202         case 2: irq_type = RxIrq; break;
00203         default: return;
00204     }
00205     
00206     if (serial_irq_ids[index] != 0)
00207         irq_handler(serial_irq_ids[index], irq_type);
00208 }
00209 
00210 void uart0_irq() {uart_irq((LPC_USART0->STAT & (1 << 2)) ? 2 : 1, 0);}
00211 void uart1_irq() {uart_irq((LPC_USART1->STAT & (1 << 2)) ? 2 : 1, 1);}
00212 void uart2_irq() {uart_irq((LPC_USART2->STAT & (1 << 2)) ? 2 : 1, 2);}
00213 
00214 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
00215     irq_handler = handler;
00216     serial_irq_ids[obj->index] = id;
00217 }
00218 
00219 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
00220     IRQn_Type  irq_n = (IRQn_Type )0;
00221     uint32_t vector = 0;
00222     switch ((int)obj->uart) {
00223         case LPC_USART0_BASE: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break;
00224         case LPC_USART1_BASE: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break;
00225         case LPC_USART2_BASE: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break;
00226     }
00227     
00228     if (enable) {
00229         obj->uart->INTENSET = (1 << ((irq == RxIrq) ? 0 : 2));
00230         NVIC_SetVector(irq_n, vector);
00231         NVIC_EnableIRQ(irq_n);
00232     } else { // disable
00233         int all_disabled = 0;
00234         SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
00235         obj->uart->INTENSET &= ~(1 << ((irq == RxIrq) ? 0 : 2));
00236         all_disabled = (obj->uart->INTENSET & (1 << ((other_irq == RxIrq) ? 0 : 2))) == 0;
00237         if (all_disabled)
00238             NVIC_DisableIRQ(irq_n);
00239     }
00240 }
00241 
00242 /******************************************************************************
00243  * READ/WRITE
00244  ******************************************************************************/
00245 int serial_getc(serial_t *obj) {
00246     while (!serial_readable(obj));
00247     return obj->uart->RXDATA;
00248 }
00249 
00250 void serial_putc(serial_t *obj, int c) {
00251     while (!serial_writable(obj));
00252     obj->uart->TXDATA = c;
00253 }
00254 
00255 int serial_readable(serial_t *obj) {
00256     return obj->uart->STAT & RXRDY;
00257 }
00258 
00259 int serial_writable(serial_t *obj) {
00260     return obj->uart->STAT & TXRDY;
00261 }
00262 
00263 void serial_clear(serial_t *obj) {
00264     // [TODO]
00265 }
00266 
00267 void serial_pinout_tx(PinName tx) {
00268     
00269 }