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 #include "serial_api.h" 00017 00018 // math.h required for floating point operations for baud rate calculation 00019 #include <math.h> 00020 00021 #include <string.h> 00022 00023 #include "cmsis.h" 00024 #include "pinmap.h" 00025 #include "error.h" 00026 00027 /****************************************************************************** 00028 * INITIALIZATION 00029 ******************************************************************************/ 00030 static const PinMap PinMap_UART_TX[] = { 00031 {PTC4, UART_1, 3}, 00032 {PTA2, UART_0, 2}, 00033 {PTD5, UART_2, 3}, 00034 {PTD3, UART_2, 3}, 00035 {NC , NC , 0} 00036 }; 00037 00038 static const PinMap PinMap_UART_RX[] = { 00039 {PTC3, UART_1, 3}, 00040 {PTA1, UART_0, 2}, 00041 {PTD4, UART_2, 3}, 00042 {PTD2, UART_2, 3}, 00043 {NC , NC , 0} 00044 }; 00045 00046 #define UART_NUM 3 00047 static uint32_t serial_irq_ids[UART_NUM] = {0}; 00048 static uart_irq_handler irq_handler; 00049 00050 int stdio_uart_inited = 0; 00051 serial_t stdio_uart; 00052 00053 void serial_init(serial_t *obj, PinName tx, PinName rx) { 00054 // determine the UART to use 00055 UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX); 00056 UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX); 00057 UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx); 00058 if ((int)uart == NC) { 00059 error("Serial pinout mapping failed"); 00060 } 00061 00062 obj->uart = (UARTLP_Type *)uart; 00063 // enable clk 00064 switch (uart) { 00065 case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<<SIM_SOPT2_UART0SRC_SHIFT); 00066 SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break; 00067 case UART_1: SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break; 00068 case UART_2: SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break; 00069 } 00070 // Disable UART before changing registers 00071 obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK); 00072 00073 switch (uart) { 00074 case UART_0: obj->index = 0; break; 00075 case UART_1: obj->index = 1; break; 00076 case UART_2: obj->index = 2; break; 00077 } 00078 00079 // set default baud rate and format 00080 serial_baud (obj, 9600); 00081 serial_format(obj, 8, ParityNone, 1); 00082 00083 // pinout the chosen uart 00084 pinmap_pinout(tx, PinMap_UART_TX); 00085 pinmap_pinout(rx, PinMap_UART_RX); 00086 00087 // set rx/tx pins in PullUp mode 00088 pin_mode(tx, PullUp); 00089 pin_mode(rx, PullUp); 00090 00091 obj->uart->C2 |= (UART_C2_RE_MASK | UART_C2_TE_MASK); 00092 00093 if (uart == STDIO_UART) { 00094 stdio_uart_inited = 1; 00095 memcpy(&stdio_uart, obj, sizeof(serial_t)); 00096 } 00097 } 00098 00099 void serial_free(serial_t *obj) { 00100 serial_irq_ids[obj->index] = 0; 00101 } 00102 00103 // serial_baud 00104 // 00105 // set the baud rate, taking in to account the current SystemFrequency 00106 // 00107 // The LPC2300 and LPC1700 have a divider and a fractional divider to control the 00108 // baud rate. The formula is: 00109 // 00110 // Baudrate = (1 / PCLK) * 16 * DL * (1 + DivAddVal / MulVal) 00111 // where: 00112 // 1 < MulVal <= 15 00113 // 0 <= DivAddVal < 14 00114 // DivAddVal < MulVal 00115 // 00116 void serial_baud(serial_t *obj, int baudrate) { 00117 00118 // save C2 state 00119 uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK)); 00120 00121 // Disable UART before changing registers 00122 obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK); 00123 00124 // [TODO] not hardcode this value 00125 uint32_t PCLK = (obj->uart == UART0) ? 48000000u : 24000000u; 00126 00127 // First we check to see if the basic divide with no DivAddVal/MulVal 00128 // ratio gives us an integer result. If it does, we set DivAddVal = 0, 00129 // MulVal = 1. Otherwise, we search the valid ratio value range to find 00130 // the closest match. This could be more elegant, using search methods 00131 // and/or lookup tables, but the brute force method is not that much 00132 // slower, and is more maintainable. 00133 uint16_t DL = PCLK / (16 * baudrate); 00134 00135 // set BDH and BDL 00136 obj->uart->BDH = (obj->uart->BDH & ~(0x1f)) | ((DL >> 8) & 0x1f); 00137 obj->uart->BDL = (obj->uart->BDL & ~(0xff)) | ((DL >> 0) & 0xff); 00138 00139 // restore C2 state 00140 obj->uart->C2 |= c2_state; 00141 } 00142 00143 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) { 00144 uint8_t m10 = 0; 00145 00146 // save C2 state 00147 uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK)); 00148 00149 // Disable UART before changing registers 00150 obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK); 00151 00152 // 8 data bits = 0 ... 9 data bits = 1 00153 if ((data_bits < 8) || (data_bits > 9)) { 00154 error("Invalid number of bits (%d) in serial format, should be 8..9\r\n", data_bits); 00155 } 00156 data_bits -= 8; 00157 00158 uint8_t parity_enable, parity_select; 00159 switch (parity) { 00160 case ParityNone: parity_enable = 0; parity_select = 0; break; 00161 case ParityOdd : parity_enable = 1; parity_select = 1; data_bits++; break; 00162 case ParityEven: parity_enable = 1; parity_select = 0; data_bits++; break; 00163 default: 00164 error("Invalid serial parity setting\r\n"); 00165 return; 00166 } 00167 00168 // 1 stop bits = 0, 2 stop bits = 1 00169 if ((stop_bits != 1) && (stop_bits != 2)) { 00170 error("Invalid stop bits specified\r\n"); 00171 } 00172 stop_bits -= 1; 00173 00174 // 9 data bits + parity 00175 if (data_bits == 2) { 00176 // only uart0 supports 10 bit communication 00177 if (obj->index != 0) { 00178 error("Invalid number of bits (9) to be used with parity\r\n"); 00179 } 00180 data_bits = 0; 00181 m10 = 1; 00182 } 00183 00184 // data bits, parity and parity mode 00185 obj->uart->C1 = ((data_bits << 4) 00186 | (parity_enable << 1) 00187 | (parity_select << 0)); 00188 00189 // enable 10bit mode if needed 00190 if (obj->index == 0) { 00191 obj->uart->C4 &= ~UARTLP_C4_M10_MASK; 00192 obj->uart->C4 |= (m10 << UARTLP_C4_M10_SHIFT); 00193 } 00194 00195 // stop bits 00196 obj->uart->BDH &= ~UART_BDH_SBNS_MASK; 00197 obj->uart->BDH |= (stop_bits << UART_BDH_SBNS_SHIFT); 00198 00199 // restore C2 state 00200 obj->uart->C2 |= c2_state; 00201 } 00202 00203 /****************************************************************************** 00204 * INTERRUPTS HANDLING 00205 ******************************************************************************/ 00206 static inline void uart_irq(uint8_t status, uint32_t index) { 00207 if (serial_irq_ids[index] != 0) { 00208 if (status & UART_S1_TDRE_MASK) 00209 irq_handler(serial_irq_ids[index], TxIrq); 00210 00211 if (status & UART_S1_RDRF_MASK) 00212 irq_handler(serial_irq_ids[index], RxIrq); 00213 } 00214 } 00215 00216 void uart0_irq() { 00217 uart_irq(UART0->S1, 0); 00218 if (UART0->S1 & UART_S1_OR_MASK) 00219 UART0->S1 |= UART_S1_OR_MASK; 00220 } 00221 void uart1_irq() {uart_irq(UART1->S1, 1);} 00222 void uart2_irq() {uart_irq(UART2->S1, 2);} 00223 00224 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) { 00225 irq_handler = handler; 00226 serial_irq_ids[obj->index] = id; 00227 } 00228 00229 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { 00230 IRQn_Type irq_n = (IRQn_Type )0; 00231 uint32_t vector = 0; 00232 switch ((int)obj->uart) { 00233 case UART_0: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break; 00234 case UART_1: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break; 00235 case UART_2: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break; 00236 } 00237 00238 if (enable) { 00239 switch (irq) { 00240 case RxIrq: obj->uart->C2 |= (UART_C2_RIE_MASK); break; 00241 case TxIrq: obj->uart->C2 |= (UART_C2_TIE_MASK); break; 00242 } 00243 NVIC_SetVector(irq_n, vector); 00244 NVIC_EnableIRQ(irq_n); 00245 00246 } else { // disable 00247 int all_disabled = 0; 00248 SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq); 00249 switch (irq) { 00250 case RxIrq: obj->uart->C2 &= ~(UART_C2_RIE_MASK); break; 00251 case TxIrq: obj->uart->C2 &= ~(UART_C2_TIE_MASK); break; 00252 } 00253 switch (other_irq) { 00254 case RxIrq: all_disabled = (obj->uart->C2 & (UART_C2_RIE_MASK)) == 0; break; 00255 case TxIrq: all_disabled = (obj->uart->C2 & (UART_C2_TIE_MASK)) == 0; break; 00256 } 00257 if (all_disabled) 00258 NVIC_DisableIRQ(irq_n); 00259 } 00260 } 00261 00262 /****************************************************************************** 00263 * READ/WRITE 00264 ******************************************************************************/ 00265 int serial_getc(serial_t *obj) { 00266 while (!serial_readable(obj)); 00267 return obj->uart->D; 00268 } 00269 00270 void serial_putc(serial_t *obj, int c) { 00271 while (!serial_writable(obj)); 00272 obj->uart->D = c; 00273 } 00274 00275 int serial_readable(serial_t *obj) { 00276 // check overrun 00277 if (obj->uart->S1 & UART_S1_OR_MASK) { 00278 obj->uart->S1 |= UART_S1_OR_MASK; 00279 } 00280 return (obj->uart->S1 & UART_S1_RDRF_MASK); 00281 } 00282 00283 int serial_writable(serial_t *obj) { 00284 // check overrun 00285 if (obj->uart->S1 & UART_S1_OR_MASK) { 00286 obj->uart->S1 |= UART_S1_OR_MASK; 00287 } 00288 return (obj->uart->S1 & UART_S1_TDRE_MASK); 00289 } 00290 00291 void serial_clear(serial_t *obj) { 00292 } 00293 00294 void serial_pinout_tx(PinName tx) { 00295 pinmap_pinout(tx, PinMap_UART_TX); 00296 }
Generated on Tue Jul 12 2022 13:47:01 by
1.7.2
