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 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
