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.
uart.c
00001 /** 00002 * @file uart.c 00003 * @brief 00004 * 00005 * DAPLink Interface Firmware 00006 * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved 00007 * SPDX-License-Identifier: Apache-2.0 00008 * 00009 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00010 * not use this file except in compliance with the License. 00011 * You may obtain a copy of the License at 00012 * 00013 * http://www.apache.org/licenses/LICENSE-2.0 00014 * 00015 * Unless required by applicable law or agreed to in writing, software 00016 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00017 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00018 * See the License for the specific language governing permissions and 00019 * limitations under the License. 00020 */ 00021 00022 #include "LPC11Uxx.h" 00023 #include "uart.h" 00024 #include "util.h" 00025 #include "circ_buf.h" 00026 #include "settings.h" // for config_get_overflow_detect 00027 00028 static uint32_t baudrate; 00029 static uint32_t dll; 00030 static uint32_t tx_in_progress; 00031 00032 extern uint32_t SystemCoreClock; 00033 00034 #define RX_OVRF_MSG "<DAPLink:Overflow>\n" 00035 #define RX_OVRF_MSG_SIZE (sizeof(RX_OVRF_MSG) - 1) 00036 #define BUFFER_SIZE (64) 00037 00038 circ_buf_t write_buffer; 00039 uint8_t write_buffer_data[BUFFER_SIZE]; 00040 circ_buf_t read_buffer; 00041 uint8_t read_buffer_data[BUFFER_SIZE]; 00042 00043 static uint8_t flow_control_enabled = 0; 00044 00045 static int32_t reset(void); 00046 00047 int32_t uart_initialize(void) 00048 { 00049 NVIC_DisableIRQ(UART_IRQn); 00050 LPC_SYSCON->SYSAHBCLKCTRL |= ((1UL << 6) | // enable clock for GPIO 00051 (1UL << 16)); // enable clock for IOCON 00052 // enable clk for usart 00053 LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 12); 00054 // usart clk divider = 1 00055 LPC_SYSCON->UARTCLKDIV = (1UL << 0); 00056 // alternate function USART and PullNone 00057 LPC_IOCON->PIO0_18 |= 0x01; 00058 LPC_IOCON->PIO0_19 |= 0x01; 00059 // enable FIFOs (trigger level 1) and clear them 00060 LPC_USART->FCR = 0x87; 00061 // Transmit Enable 00062 LPC_USART->TER = 0x80; 00063 // reset uart 00064 reset(); 00065 // enable rx and tx interrupt 00066 LPC_USART->IER |= (1 << 0) | (1 << 1); 00067 NVIC_EnableIRQ(UART_IRQn); 00068 return 1; 00069 } 00070 00071 int32_t uart_uninitialize(void) 00072 { 00073 // disable interrupt 00074 LPC_USART->IER &= ~(0x7); 00075 NVIC_DisableIRQ(UART_IRQn); 00076 // reset uart 00077 reset(); 00078 return 1; 00079 } 00080 00081 int32_t uart_reset(void) 00082 { 00083 // disable interrupt 00084 NVIC_DisableIRQ(UART_IRQn); 00085 // reset uart 00086 reset(); 00087 // enable interrupt 00088 NVIC_EnableIRQ(UART_IRQn); 00089 return 1; 00090 } 00091 00092 int32_t uart_set_configuration(UART_Configuration *config) 00093 { 00094 uint8_t DivAddVal = 0; 00095 uint8_t MulVal = 1; 00096 uint8_t mv, data_bits = 8, parity, stop_bits = 0; 00097 // disable interrupt 00098 NVIC_DisableIRQ(UART_IRQn); 00099 // reset uart 00100 reset(); 00101 baudrate = config->Baudrate; 00102 // Compute baud rate dividers 00103 mv = 15; 00104 dll = util_div_round_down(SystemCoreClock, 16 * config->Baudrate); 00105 DivAddVal = util_div_round(SystemCoreClock * mv, dll * config->Baudrate * 16) - mv; 00106 // set LCR[DLAB] to enable writing to divider registers 00107 LPC_USART->LCR |= (1 << 7); 00108 // set divider values 00109 LPC_USART->DLM = (dll >> 8) & 0xFF; 00110 LPC_USART->DLL = (dll >> 0) & 0xFF; 00111 LPC_USART->FDR = (uint32_t) DivAddVal << 0 00112 | (uint32_t) MulVal << 4; 00113 // clear LCR[DLAB] 00114 LPC_USART->LCR &= ~(1 << 7); 00115 00116 // set data bits, stop bits, parity 00117 if ((config->DataBits < 5) || (config->DataBits > 8)) { 00118 data_bits = 8; 00119 } 00120 00121 data_bits -= 5; 00122 00123 if (config->StopBits != 1 && config->StopBits != 2) { 00124 stop_bits = 1; 00125 } 00126 00127 stop_bits -= 1; 00128 00129 switch (config->Parity) { 00130 case UART_PARITY_ODD: 00131 parity = 0x01; 00132 break; // Parity Odd 00133 00134 case UART_PARITY_EVEN: 00135 parity = 0x03; 00136 break; // Parity Even 00137 00138 case UART_PARITY_MARK: 00139 parity = 0x05; 00140 break; // Parity Mark 00141 00142 case UART_PARITY_SPACE: 00143 parity = 0x07; 00144 break; // Parity Space 00145 00146 case UART_PARITY_NONE: // Parity None 00147 default: 00148 parity = 0x00; 00149 break; 00150 } 00151 00152 if (flow_control_enabled) { 00153 LPC_IOCON->PIO0_17 |= 0x01; // RTS 00154 LPC_IOCON->PIO0_7 |= 0x01; // CTS 00155 // enable auto RTS and CTS 00156 LPC_USART->MCR = (1 << 6) | (1 << 7); 00157 } else { 00158 LPC_IOCON->PIO0_17 &= ~0x01; // RTS 00159 LPC_IOCON->PIO0_7 &= ~0x01; // CTS 00160 // disable auto RTS and CTS 00161 LPC_USART->MCR = (0 << 6) | (0 << 7); 00162 } 00163 00164 LPC_USART->LCR = (data_bits << 0) 00165 | (stop_bits << 2) 00166 | (parity << 3); 00167 // Enable UART interrupt 00168 NVIC_EnableIRQ(UART_IRQn); 00169 return 1; 00170 } 00171 00172 int32_t uart_get_configuration(UART_Configuration *config) 00173 { 00174 float br; 00175 uint32_t lcr; 00176 // line control parameter 00177 lcr = LPC_USART->LCR; 00178 // baudrate 00179 br = SystemCoreClock / (dll * 16); 00180 00181 // If inside +/- 2% tolerance 00182 if (((br * 100) <= (baudrate * 102)) && ((br * 100) >= (baudrate * 98))) { 00183 config->Baudrate = baudrate; 00184 } else { 00185 config->Baudrate = br; 00186 } 00187 00188 // get data bits 00189 switch ((lcr >> 0) & 3) { 00190 case 0: 00191 config->DataBits = UART_DATA_BITS_5; 00192 break; 00193 00194 case 1: 00195 config->DataBits = UART_DATA_BITS_6; 00196 break; 00197 00198 case 2: 00199 config->DataBits = UART_DATA_BITS_7; 00200 break; 00201 00202 case 3: 00203 config->DataBits = UART_DATA_BITS_8; 00204 break; 00205 00206 default: 00207 return 0; 00208 } 00209 00210 // get parity 00211 switch ((lcr >> 3) & 7) { 00212 case 0: 00213 case 2: 00214 case 4: 00215 case 6: 00216 config->Parity = UART_PARITY_NONE; 00217 break; 00218 00219 case 1: 00220 config->Parity = UART_PARITY_ODD; 00221 break; 00222 00223 case 3: 00224 config->Parity = UART_PARITY_MARK; 00225 break; 00226 00227 case 5: 00228 config->Parity = UART_PARITY_EVEN; 00229 break; 00230 00231 case 7: 00232 config->Parity = UART_PARITY_SPACE; 00233 break; 00234 00235 default: 00236 return 0; 00237 } 00238 00239 // get stop bits 00240 switch ((lcr >> 2) & 1) { 00241 case 0: 00242 config->StopBits = UART_STOP_BITS_1; 00243 break; 00244 00245 case 1: 00246 config->StopBits = UART_STOP_BITS_2; 00247 break; 00248 00249 default: 00250 return 0; 00251 } 00252 00253 // get flow control 00254 if (flow_control_enabled) { 00255 config->FlowControl = UART_FLOW_CONTROL_RTS_CTS; 00256 } 00257 else { 00258 config->FlowControl = UART_FLOW_CONTROL_NONE; 00259 } 00260 return 1; 00261 } 00262 00263 int32_t uart_write_free(void) 00264 { 00265 return circ_buf_count_free(&write_buffer); 00266 } 00267 00268 int32_t uart_write_data(uint8_t *data, uint16_t size) 00269 { 00270 uint32_t cnt; 00271 00272 cnt = circ_buf_write(&write_buffer, data, size); 00273 00274 // enable THRE interrupt 00275 LPC_USART->IER |= (1 << 1); 00276 00277 if (!tx_in_progress) { 00278 // force THRE interrupt to start 00279 NVIC_SetPendingIRQ(UART_IRQn); 00280 } 00281 00282 return cnt; 00283 } 00284 00285 00286 int32_t uart_read_data(uint8_t *data, uint16_t size) 00287 { 00288 return circ_buf_read(&read_buffer, data, size); 00289 } 00290 00291 void uart_enable_flow_control(bool enabled) 00292 { 00293 flow_control_enabled = (uint8_t)enabled; 00294 } 00295 00296 void UART_IRQHandler(void) 00297 { 00298 uint32_t iir; 00299 // read interrupt status 00300 iir = LPC_USART->IIR; 00301 00302 // handle character to transmit 00303 if (circ_buf_count_used(&write_buffer) > 0) { 00304 // if THR is empty 00305 if (LPC_USART->LSR & (1 << 5)) { 00306 LPC_USART->THR = circ_buf_pop(&write_buffer); 00307 tx_in_progress = 1; 00308 } 00309 00310 } else if (tx_in_progress) { 00311 tx_in_progress = 0; 00312 // disable THRE interrupt 00313 LPC_USART->IER &= ~(1 << 1); 00314 } 00315 00316 // handle received character 00317 if (((iir & 0x0E) == 0x04) || // Rx interrupt (RDA) 00318 ((iir & 0x0E) == 0x0C)) { // Rx interrupt (CTI) 00319 while (LPC_USART->LSR & 0x01) { 00320 uint32_t free; 00321 uint8_t data; 00322 00323 data = LPC_USART->RBR; 00324 free = circ_buf_count_free(&read_buffer); 00325 if (free > RX_OVRF_MSG_SIZE) { 00326 circ_buf_push(&read_buffer, data); 00327 } else if (config_get_overflow_detect()) { 00328 if (RX_OVRF_MSG_SIZE == free) { 00329 circ_buf_write(&read_buffer, (uint8_t*)RX_OVRF_MSG, RX_OVRF_MSG_SIZE); 00330 } else { 00331 // Drop newest 00332 } 00333 } else { 00334 // Drop oldest 00335 circ_buf_pop(&read_buffer); 00336 circ_buf_push(&read_buffer, data); 00337 } 00338 } 00339 } 00340 00341 LPC_USART->LSR; 00342 } 00343 00344 static int32_t reset(void) 00345 { 00346 uint32_t mcr; 00347 // Reset FIFOs 00348 LPC_USART->FCR = 0x06; 00349 baudrate = 0; 00350 dll = 0; 00351 tx_in_progress = 0; 00352 00353 circ_buf_init(&write_buffer, write_buffer_data, sizeof(write_buffer_data)); 00354 circ_buf_init(&read_buffer, read_buffer_data, sizeof(read_buffer_data)); 00355 00356 // Enable loopback mode to drain remaining bytes (even if flow control is on) 00357 mcr = LPC_USART->MCR; 00358 LPC_USART->MCR = mcr | (1 << 4); 00359 00360 // Ensure a clean start, no data in either TX or RX FIFO 00361 while ((LPC_USART->LSR & ((1 << 5) | (1 << 6))) != ((1 << 5) | (1 << 6))) { 00362 LPC_USART->FCR = (1 << 1) | (1 << 2); 00363 } 00364 00365 // Restore previous mode (loopback off) 00366 LPC_USART->MCR = mcr; 00367 00368 while (LPC_USART->LSR & 0x01) { 00369 LPC_USART->RBR; // Dump data from RX FIFO 00370 } 00371 00372 return 1; 00373 }
Generated on Tue Jul 12 2022 15:37:26 by
