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