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
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 1 00029 00030 static const PinMap PinMap_UART_TX[] = { 00031 {P0_19, UART_0, 1}, 00032 {P1_13, UART_0, 3}, 00033 {P1_27, UART_0, 2}, 00034 { NC , NC , 0} 00035 }; 00036 00037 static const PinMap PinMap_UART_RX[] = { 00038 {P0_18, UART_0, 1}, 00039 {P1_14, UART_0, 3}, 00040 {P1_26, UART_0, 2}, 00041 {NC , NC , 0} 00042 }; 00043 00044 static uint32_t serial_irq_ids[UART_NUM] = {0}; 00045 static uart_irq_handler irq_handler; 00046 00047 int stdio_uart_inited = 0; 00048 serial_t stdio_uart; 00049 00050 void serial_init(serial_t *obj, PinName tx, PinName rx) { 00051 int is_stdio_uart = 0; 00052 00053 // determine the UART to use 00054 UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX); 00055 UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX); 00056 UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx); 00057 if ((int)uart == NC) { 00058 error("Serial pinout mapping failed"); 00059 } 00060 00061 obj->uart = (LPC_USART_Type *)uart; 00062 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12); 00063 00064 // [TODO] Consider more elegant approach 00065 // disconnect USBTX/RX mapping mux, for case when switching ports 00066 pin_function(USBTX, 0); 00067 pin_function(USBRX, 0); 00068 00069 // enable fifos and default rx trigger level 00070 obj->uart->FCR = 1 << 0 // FIFO Enable - 0 = Disables, 1 = Enabled 00071 | 0 << 1 // Rx Fifo Reset 00072 | 0 << 2 // Tx Fifo Reset 00073 | 0 << 6; // Rx irq trigger level - 0 = 1 char, 1 = 4 chars, 2 = 8 chars, 3 = 14 chars 00074 00075 // disable irqs 00076 obj->uart->IER = 0 << 0 // Rx Data available irq enable 00077 | 0 << 1 // Tx Fifo empty irq enable 00078 | 0 << 2; // Rx Line Status irq enable 00079 00080 // set default baud rate and format 00081 serial_baud (obj, 9600); 00082 serial_format(obj, 8, ParityNone, 1); 00083 00084 // pinout the chosen uart 00085 pinmap_pinout(tx, PinMap_UART_TX); 00086 pinmap_pinout(rx, PinMap_UART_RX); 00087 00088 // set rx/tx pins in PullUp mode 00089 pin_mode(tx, PullUp); 00090 pin_mode(rx, PullUp); 00091 00092 switch (uart) { 00093 case UART_0: obj->index = 0; break; 00094 } 00095 00096 is_stdio_uart = (uart == STDIO_UART) ? (1) : (0); 00097 00098 if (is_stdio_uart) { 00099 stdio_uart_inited = 1; 00100 memcpy(&stdio_uart, obj, sizeof(serial_t)); 00101 } 00102 } 00103 00104 void serial_free(serial_t *obj) { 00105 serial_irq_ids[obj->index] = 0; 00106 } 00107 00108 // serial_baud 00109 // set the baud rate, taking in to account the current SystemFrequency 00110 void serial_baud(serial_t *obj, int baudrate) { 00111 LPC_SYSCON->UARTCLKDIV = 0x1; 00112 uint32_t PCLK = SystemCoreClock; 00113 // First we check to see if the basic divide with no DivAddVal/MulVal 00114 // ratio gives us an integer result. If it does, we set DivAddVal = 0, 00115 // MulVal = 1. Otherwise, we search the valid ratio value range to find 00116 // the closest match. This could be more elegant, using search methods 00117 // and/or lookup tables, but the brute force method is not that much 00118 // slower, and is more maintainable. 00119 uint16_t DL = PCLK / (16 * baudrate); 00120 00121 uint8_t DivAddVal = 0; 00122 uint8_t MulVal = 1; 00123 int hit = 0; 00124 uint16_t dlv; 00125 uint8_t mv, dav; 00126 if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder 00127 float err_best = (float) baudrate; 00128 uint16_t dlmax = DL; 00129 for ( dlv = (dlmax/2); (dlv <= dlmax) && !hit; dlv++) { 00130 for ( mv = 1; mv <= 15; mv++) { 00131 for ( dav = 1; dav < mv; dav++) { 00132 float ratio = 1.0f + ((float) dav / (float) mv); 00133 float calcbaud = (float)PCLK / (16.0f * (float) dlv * ratio); 00134 float err = fabs(((float) baudrate - calcbaud) / (float) baudrate); 00135 if (err < err_best) { 00136 DL = dlv; 00137 DivAddVal = dav; 00138 MulVal = mv; 00139 err_best = err; 00140 if (err < 0.001f) { 00141 hit = 1; 00142 } 00143 } 00144 } 00145 } 00146 } 00147 } 00148 00149 // set LCR[DLAB] to enable writing to divider registers 00150 obj->uart->LCR |= (1 << 7); 00151 00152 // set divider values 00153 obj->uart->DLM = (DL >> 8) & 0xFF; 00154 obj->uart->DLL = (DL >> 0) & 0xFF; 00155 obj->uart->FDR = (uint32_t) DivAddVal << 0 00156 | (uint32_t) MulVal << 4; 00157 00158 // clear LCR[DLAB] 00159 obj->uart->LCR &= ~(1 << 7); 00160 } 00161 00162 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) { 00163 // 0: 1 stop bits, 1: 2 stop bits 00164 if (stop_bits != 1 && stop_bits != 2) { 00165 error("Invalid stop bits specified"); 00166 } 00167 stop_bits -= 1; 00168 00169 // 0: 5 data bits ... 3: 8 data bits 00170 if (data_bits < 5 || data_bits > 8) { 00171 error("Invalid number of bits (%d) in serial format, should be 5..8", data_bits); 00172 } 00173 data_bits -= 5; 00174 00175 int parity_enable, parity_select; 00176 switch (parity) { 00177 case ParityNone: parity_enable = 0; parity_select = 0; break; 00178 case ParityOdd : parity_enable = 1; parity_select = 0; break; 00179 case ParityEven: parity_enable = 1; parity_select = 1; break; 00180 case ParityForced1: parity_enable = 1; parity_select = 2; break; 00181 case ParityForced0: parity_enable = 1; parity_select = 3; break; 00182 default: 00183 error("Invalid serial parity setting"); 00184 return; 00185 } 00186 00187 obj->uart->LCR = data_bits << 0 00188 | stop_bits << 2 00189 | parity_enable << 3 00190 | parity_select << 4; 00191 } 00192 00193 /****************************************************************************** 00194 * INTERRUPTS HANDLING 00195 ******************************************************************************/ 00196 static inline void uart_irq(uint32_t iir, uint32_t index) { 00197 // [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling 00198 SerialIrq irq_type; 00199 switch (iir) { 00200 case 1: irq_type = TxIrq; break; 00201 case 2: irq_type = RxIrq; break; 00202 default: return; 00203 } 00204 00205 if (serial_irq_ids[index] != 0) 00206 irq_handler(serial_irq_ids[index], irq_type); 00207 } 00208 00209 void uart0_irq() {uart_irq((LPC_USART->IIR >> 1) & 0x7, 0);} 00210 00211 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) { 00212 irq_handler = handler; 00213 serial_irq_ids[obj->index] = id; 00214 } 00215 00216 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { 00217 IRQn_Type irq_n = (IRQn_Type )0; 00218 uint32_t vector = 0; 00219 switch ((int)obj->uart) { 00220 case UART_0: irq_n=UART_IRQn ; vector = (uint32_t)&uart0_irq; break; 00221 } 00222 00223 if (enable) { 00224 obj->uart->IER |= 1 << irq; 00225 NVIC_SetVector(irq_n, vector); 00226 NVIC_EnableIRQ(irq_n); 00227 } else { // disable 00228 int all_disabled = 0; 00229 SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq); 00230 00231 obj->uart->IER &= ~(1 << irq); 00232 all_disabled = (obj->uart->IER & (1 << other_irq)) == 0; 00233 00234 if (all_disabled) 00235 NVIC_DisableIRQ(irq_n); 00236 } 00237 } 00238 00239 /****************************************************************************** 00240 * READ/WRITE 00241 ******************************************************************************/ 00242 int serial_getc(serial_t *obj) { 00243 while (!serial_readable(obj)); 00244 return obj->uart->RBR; 00245 } 00246 00247 void serial_putc(serial_t *obj, int c) { 00248 while (!serial_writable(obj)); 00249 obj->uart->THR = c; 00250 00251 uint32_t lsr = obj->uart->LSR; 00252 lsr = lsr; 00253 uint32_t thr = obj->uart->THR; 00254 thr = thr; 00255 } 00256 00257 int serial_readable(serial_t *obj) { 00258 return obj->uart->LSR & 0x01; 00259 } 00260 00261 int serial_writable(serial_t *obj) { 00262 return obj->uart->LSR & 0x20; 00263 } 00264 00265 void serial_clear(serial_t *obj) { 00266 obj->uart->FCR = 1 << 1 // rx FIFO reset 00267 | 1 << 2 // tx FIFO reset 00268 | 0 << 6; // interrupt depth 00269 } 00270 00271 void serial_pinout_tx(PinName tx) { 00272 pinmap_pinout(tx, PinMap_UART_TX); 00273 }
Generated on Tue Jul 12 2022 13:47:02 by 1.7.2