Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 static const PinMap PinMap_UART_TX[] = { 00029 {P0_0, UART_3, 2}, 00030 {P0_2, UART_0, 1}, 00031 {P0_10, UART_2, 1}, 00032 {P0_15, UART_1, 1}, 00033 {P1_29, UART_4, 5}, 00034 {P0_25, UART_3, 3}, 00035 {P2_0 , UART_1, 2}, 00036 {P2_8 , UART_2, 2}, 00037 {P3_16, UART_1, 3}, 00038 {P4_22, UART_2, 2}, 00039 {P4_28, UART_3, 2}, 00040 {P5_4, UART_4, 4}, 00041 {NC , NC , 0} 00042 }; 00043 00044 static const PinMap PinMap_UART_RX[] = { 00045 {P0_1 , UART_3, 2}, 00046 {P0_3 , UART_0, 1}, 00047 {P0_11, UART_2, 1}, 00048 {P0_16, UART_1, 1}, 00049 {P0_26, UART_3, 3}, 00050 {P2_1 , UART_1, 2}, 00051 {P2_9 , UART_2, 2}, 00052 {P3_17, UART_1, 3}, 00053 {P4_23, UART_2, 2}, 00054 {P4_29, UART_3, 2}, 00055 {P5_3, UART_4, 4}, 00056 {NC , NC , 0} 00057 }; 00058 00059 #define UART_NUM 5 00060 00061 static uint32_t serial_irq_ids[UART_NUM] = {0}; 00062 static uart_irq_handler irq_handler; 00063 00064 int stdio_uart_inited = 0; 00065 serial_t stdio_uart; 00066 00067 void serial_init(serial_t *obj, PinName tx, PinName rx) { 00068 int is_stdio_uart = 0; 00069 00070 // determine the UART to use 00071 UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX); 00072 UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX); 00073 UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx); 00074 if ((int)uart == NC) { 00075 error("Serial pinout mapping failed"); 00076 } 00077 00078 obj->uart = (LPC_UART_TypeDef *)uart; 00079 // enable power 00080 switch (uart) { 00081 case UART_0: LPC_SC->PCONP |= 1 << 3; break; 00082 case UART_1: LPC_SC->PCONP |= 1 << 4; break; 00083 case UART_2: LPC_SC->PCONP |= 1 << 24; break; 00084 case UART_3: LPC_SC->PCONP |= 1 << 25; break; 00085 case UART_4: LPC_SC->PCONP |= 1 << 8; break; 00086 } 00087 00088 // enable fifos and default rx trigger level 00089 obj->uart->FCR = 1 << 0 // FIFO Enable - 0 = Disables, 1 = Enabled 00090 | 0 << 1 // Rx Fifo Reset 00091 | 0 << 2 // Tx Fifo Reset 00092 | 0 << 6; // Rx irq trigger level - 0 = 1 char, 1 = 4 chars, 2 = 8 chars, 3 = 14 chars 00093 00094 // disable irqs 00095 obj->uart->IER = 0 << 0 // Rx Data available irq enable 00096 | 0 << 1 // Tx Fifo empty irq enable 00097 | 0 << 2; // Rx Line Status irq enable 00098 00099 // set default baud rate and format 00100 serial_baud (obj, 9600); 00101 serial_format(obj, 8, ParityNone, 1); 00102 00103 // pinout the chosen uart 00104 pinmap_pinout(tx, PinMap_UART_TX); 00105 pinmap_pinout(rx, PinMap_UART_RX); 00106 00107 // set rx/tx pins in PullUp mode 00108 pin_mode(tx, PullUp); 00109 pin_mode(rx, PullUp); 00110 00111 switch (uart) { 00112 case UART_0: obj->index = 0; break; 00113 case UART_1: obj->index = 1; break; 00114 case UART_2: obj->index = 2; break; 00115 case UART_3: obj->index = 3; break; 00116 case UART_4: obj->index = 4; break; 00117 } 00118 00119 is_stdio_uart = (uart == STDIO_UART) ? (1) : (0); 00120 00121 if (is_stdio_uart) { 00122 stdio_uart_inited = 1; 00123 memcpy(&stdio_uart, obj, sizeof(serial_t)); 00124 } 00125 } 00126 00127 void serial_free(serial_t *obj) { 00128 serial_irq_ids[obj->index] = 0; 00129 } 00130 00131 // serial_baud 00132 // set the baud rate, taking in to account the current SystemFrequency 00133 void serial_baud(serial_t *obj, int baudrate) { 00134 uint32_t PCLK = PeripheralClock ; 00135 00136 // First we check to see if the basic divide with no DivAddVal/MulVal 00137 // ratio gives us an integer result. If it does, we set DivAddVal = 0, 00138 // MulVal = 1. Otherwise, we search the valid ratio value range to find 00139 // the closest match. This could be more elegant, using search methods 00140 // and/or lookup tables, but the brute force method is not that much 00141 // slower, and is more maintainable. 00142 uint16_t DL = PCLK / (16 * baudrate); 00143 00144 uint8_t DivAddVal = 0; 00145 uint8_t MulVal = 1; 00146 int hit = 0; 00147 uint16_t dlv; 00148 uint8_t mv, dav; 00149 if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder 00150 float err_best = (float) baudrate; 00151 uint16_t dlmax = DL; 00152 for ( dlv = (dlmax/2); (dlv <= dlmax) && !hit; dlv++) { 00153 for ( mv = 1; mv <= 15; mv++) { 00154 for ( dav = 1; dav < mv; dav++) { 00155 float ratio = 1.0f + ((float) dav / (float) mv); 00156 float calcbaud = (float)PCLK / (16.0f * (float) dlv * ratio); 00157 float err = fabs(((float) baudrate - calcbaud) / (float) baudrate); 00158 if (err < err_best) { 00159 DL = dlv; 00160 DivAddVal = dav; 00161 MulVal = mv; 00162 err_best = err; 00163 if (err < 0.001f) { 00164 hit = 1; 00165 } 00166 } 00167 } 00168 } 00169 } 00170 } 00171 00172 // set LCR[DLAB] to enable writing to divider registers 00173 obj->uart->LCR |= (1 << 7); 00174 00175 // set divider values 00176 obj->uart->DLM = (DL >> 8) & 0xFF; 00177 obj->uart->DLL = (DL >> 0) & 0xFF; 00178 obj->uart->FDR = (uint32_t) DivAddVal << 0 00179 | (uint32_t) MulVal << 4; 00180 00181 // clear LCR[DLAB] 00182 obj->uart->LCR &= ~(1 << 7); 00183 } 00184 00185 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) { 00186 // 0: 1 stop bits, 1: 2 stop bits 00187 if (stop_bits != 1 && stop_bits != 2) { 00188 error("Invalid stop bits specified"); 00189 } 00190 stop_bits -= 1; 00191 00192 // 0: 5 data bits ... 3: 8 data bits 00193 if (data_bits < 5 || data_bits > 8) { 00194 error("Invalid number of bits (%d) in serial format, should be 5..8", data_bits); 00195 } 00196 data_bits -= 5; 00197 00198 int parity_enable, parity_select; 00199 switch (parity) { 00200 case ParityNone: parity_enable = 0; parity_select = 0; break; 00201 case ParityOdd : parity_enable = 1; parity_select = 0; break; 00202 case ParityEven: parity_enable = 1; parity_select = 1; break; 00203 case ParityForced1: parity_enable = 1; parity_select = 2; break; 00204 case ParityForced0: parity_enable = 1; parity_select = 3; break; 00205 default: 00206 error("Invalid serial parity setting"); 00207 return; 00208 } 00209 00210 obj->uart->LCR = data_bits << 0 00211 | stop_bits << 2 00212 | parity_enable << 3 00213 | parity_select << 4; 00214 } 00215 00216 /****************************************************************************** 00217 * INTERRUPTS HANDLING 00218 ******************************************************************************/ 00219 static inline void uart_irq(uint32_t iir, uint32_t index) { 00220 // [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling 00221 SerialIrq irq_type; 00222 switch (iir) { 00223 case 1: irq_type = TxIrq; break; 00224 case 2: irq_type = RxIrq; break; 00225 default: return; 00226 } 00227 00228 if (serial_irq_ids[index] != 0) 00229 irq_handler(serial_irq_ids[index], irq_type); 00230 } 00231 00232 void uart0_irq() {uart_irq((LPC_UART0->IIR >> 1) & 0x7, 0);} 00233 void uart1_irq() {uart_irq((LPC_UART1->IIR >> 1) & 0x7, 1);} 00234 void uart2_irq() {uart_irq((LPC_UART2->IIR >> 1) & 0x7, 2);} 00235 void uart3_irq() {uart_irq((LPC_UART3->IIR >> 1) & 0x7, 3);} 00236 void uart4_irq() {uart_irq((LPC_UART4->IIR >> 1) & 0x7, 4);} 00237 00238 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) { 00239 irq_handler = handler; 00240 serial_irq_ids[obj->index] = id; 00241 } 00242 00243 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { 00244 IRQn_Type irq_n = (IRQn_Type )0; 00245 uint32_t vector = 0; 00246 switch ((int)obj->uart) { 00247 case UART_0: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break; 00248 case UART_1: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break; 00249 case UART_2: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break; 00250 case UART_3: irq_n=UART3_IRQn ; vector = (uint32_t)&uart3_irq; break; 00251 case UART_4: irq_n=UART4_IRQn ; vector = (uint32_t)&uart4_irq; break; 00252 } 00253 00254 if (enable) { 00255 obj->uart->IER |= 1 << irq; 00256 NVIC_SetVector(irq_n, vector); 00257 NVIC_EnableIRQ(irq_n); 00258 } else { // disable 00259 int all_disabled = 0; 00260 SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq); 00261 obj->uart->IER &= ~(1 << irq); 00262 all_disabled = (obj->uart->IER & (1 << other_irq)) == 0; 00263 if (all_disabled) 00264 NVIC_DisableIRQ(irq_n); 00265 } 00266 } 00267 00268 /****************************************************************************** 00269 * READ/WRITE 00270 ******************************************************************************/ 00271 int serial_getc(serial_t *obj) { 00272 while (!serial_readable(obj)); 00273 return obj->uart->RBR; 00274 } 00275 00276 void serial_putc(serial_t *obj, int c) { 00277 while (!serial_writable(obj)); 00278 obj->uart->THR = c; 00279 00280 uint32_t lsr = obj->uart->LSR; 00281 lsr = lsr; 00282 uint32_t thr = obj->uart->THR; 00283 thr = thr; 00284 } 00285 00286 int serial_readable(serial_t *obj) { 00287 return obj->uart->LSR & 0x01; 00288 } 00289 00290 int serial_writable(serial_t *obj) { 00291 return obj->uart->LSR & 0x20; 00292 } 00293 00294 void serial_clear(serial_t *obj) { 00295 obj->uart->FCR = 1 << 1 // rx FIFO reset 00296 | 1 << 2 // tx FIFO reset 00297 | 0 << 6; // interrupt depth 00298 } 00299 00300 void serial_pinout_tx(PinName tx) { 00301 pinmap_pinout(tx, PinMap_UART_TX); 00302 }
Generated on Tue Jul 12 2022 13:47:02 by
1.7.2
