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 "LPC43xx.h" 00023 #include "uart.h" 00024 #include "lpc43xx_cgu.h" 00025 #include "lpc43xx_scu.h" 00026 #include "util.h" 00027 #include "circ_buf.h" 00028 #include "settings.h" // for config_get_overflow_detect 00029 00030 static uint32_t baudrate; 00031 static uint32_t dll; 00032 static uint32_t tx_in_progress; 00033 00034 extern uint32_t SystemCoreClock; 00035 00036 #define RX_OVRF_MSG "<DAPLink:Overflow>\n" 00037 #define RX_OVRF_MSG_SIZE (sizeof(RX_OVRF_MSG) - 1) 00038 #define BUFFER_SIZE (512) 00039 00040 circ_buf_t write_buffer; 00041 uint8_t write_buffer_data[BUFFER_SIZE]; 00042 circ_buf_t read_buffer; 00043 uint8_t read_buffer_data[BUFFER_SIZE]; 00044 00045 static int32_t reset(void); 00046 00047 #define UART_IRQn USART0_IRQn 00048 #define LPC_USART LPC_USART0 00049 #define UART_IRQHandler UART0_IRQHandler 00050 00051 // UART Control Pin P2_2: GPIO5[2] 00052 #define PORT_UARTCTRL 5 00053 #define PIN_UARTCTRL_IN_BIT 2 00054 #define PIN_UARTCTRL (1<<PIN_UARTCTRL_IN_BIT) 00055 00056 00057 int32_t uart_initialize(void) 00058 { 00059 NVIC_DisableIRQ(UART_IRQn); 00060 00061 // The baudrate calculations require the UART to be clocked as SystemCoreClock 00062 CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_UART0); 00063 CGU_EnableEntity(CGU_BASE_UART0, ENABLE); 00064 scu_pinmux(2, 0, UART_RX_TX, FUNC1); /* P2_0: U0_TXD */ 00065 scu_pinmux(2, 1, UART_RX_TX, FUNC1); /* P2_1: U0_RXD */ 00066 00067 scu_pinmux(2, 2, GPIO_NOPULL, FUNC4); /* UARTCTRL: GPIO5[2] */ 00068 // Control target's UART RX: 00069 // UARTCTRL high: The LPC1549 gets uart input from the LPC4322 00070 // UARTCTRL low: The LPC1549 gets uart input from the ISP_RX on the pinlist 00071 LPC_GPIO_PORT->CLR[PORT_UARTCTRL] = PIN_UARTCTRL; 00072 LPC_GPIO_PORT->DIR[PORT_UARTCTRL] |= (PIN_UARTCTRL); 00073 // enable FIFOs (trigger level 1) and clear them 00074 LPC_USART->FCR = 0x87; 00075 // Transmit Enable 00076 LPC_USART->TER = 0x01; 00077 // reset uart 00078 reset(); 00079 // enable rx and tx interrupt 00080 LPC_USART->IER |= (1 << 0) | (1 << 1); 00081 NVIC_EnableIRQ(UART_IRQn); 00082 return 1; 00083 } 00084 00085 int32_t uart_uninitialize(void) 00086 { 00087 // disable interrupt 00088 LPC_USART->IER &= ~(0x7); 00089 NVIC_DisableIRQ(UART_IRQn); 00090 // reset uart 00091 reset(); 00092 return 1; 00093 } 00094 00095 int32_t uart_reset(void) 00096 { 00097 // disable interrupt 00098 NVIC_DisableIRQ(UART_IRQn); 00099 // reset uart 00100 reset(); 00101 // enable interrupt 00102 NVIC_EnableIRQ(UART_IRQn); 00103 return 1; 00104 } 00105 00106 int32_t uart_set_configuration(UART_Configuration *config) 00107 { 00108 uint8_t DivAddVal = 0; 00109 uint8_t MulVal = 1; 00110 uint8_t mv, data_bits = 8, parity, stop_bits = 0; 00111 // disable interrupt 00112 NVIC_DisableIRQ(UART_IRQn); 00113 // reset uart 00114 reset(); 00115 baudrate = config->Baudrate; 00116 // Compute baud rate dividers 00117 mv = 15; 00118 dll = util_div_round_down(SystemCoreClock, 16 * config->Baudrate); 00119 DivAddVal = util_div_round(SystemCoreClock * mv, dll * config->Baudrate * 16) - mv; 00120 // set LCR[DLAB] to enable writing to divider registers 00121 LPC_USART->LCR |= (1 << 7); 00122 // set divider values 00123 LPC_USART->DLM = (dll >> 8) & 0xFF; 00124 LPC_USART->DLL = (dll >> 0) & 0xFF; 00125 LPC_USART->FDR = (uint32_t) DivAddVal << 0 00126 | (uint32_t) MulVal << 4; 00127 // clear LCR[DLAB] 00128 LPC_USART->LCR &= ~(1 << 7); 00129 00130 // set data bits, stop bits, parity 00131 if ((config->DataBits < 5) || (config->DataBits > 8)) { 00132 data_bits = 8; 00133 } 00134 00135 data_bits -= 5; 00136 00137 if (config->StopBits != 1 && config->StopBits != 2) { 00138 stop_bits = 1; 00139 } 00140 00141 stop_bits -= 1; 00142 00143 switch (config->Parity) { 00144 case UART_PARITY_ODD: 00145 parity = 0x01; 00146 break; // Parity Odd 00147 00148 case UART_PARITY_EVEN: 00149 parity = 0x03; 00150 break; // Parity Even 00151 00152 case UART_PARITY_MARK: 00153 parity = 0x05; 00154 break; // Parity Mark 00155 00156 case UART_PARITY_SPACE: 00157 parity = 0x07; 00158 break; // Parity Space 00159 00160 case UART_PARITY_NONE: // Parity None 00161 default: 00162 parity = 0x00; 00163 break; 00164 } 00165 00166 LPC_USART->LCR = (data_bits << 0) 00167 | (stop_bits << 2) 00168 | (parity << 3); 00169 // Enable UART interrupt 00170 NVIC_EnableIRQ(UART_IRQn); 00171 return 1; 00172 } 00173 00174 int32_t uart_get_configuration(UART_Configuration *config) 00175 { 00176 float br; 00177 uint32_t lcr; 00178 // line control parameter 00179 lcr = LPC_USART->LCR; 00180 // baudrate 00181 br = SystemCoreClock / (dll * 16); 00182 00183 // If inside +/- 2% tolerance 00184 if (((br * 100) <= (baudrate * 102)) && ((br * 100) >= (baudrate * 98))) { 00185 config->Baudrate = baudrate; 00186 } else { 00187 config->Baudrate = br; 00188 } 00189 00190 // get data bits 00191 switch ((lcr >> 0) & 3) { 00192 case 0: 00193 config->DataBits = UART_DATA_BITS_5; 00194 break; 00195 00196 case 1: 00197 config->DataBits = UART_DATA_BITS_6; 00198 break; 00199 00200 case 2: 00201 config->DataBits = UART_DATA_BITS_7; 00202 break; 00203 00204 case 3: 00205 config->DataBits = UART_DATA_BITS_8; 00206 break; 00207 00208 default: 00209 return 0; 00210 } 00211 00212 // get parity 00213 switch ((lcr >> 3) & 7) { 00214 case 0: 00215 case 2: 00216 case 4: 00217 case 6: 00218 config->Parity = UART_PARITY_NONE; 00219 break; 00220 00221 case 1: 00222 config->Parity = UART_PARITY_ODD; 00223 break; 00224 00225 case 3: 00226 config->Parity = UART_PARITY_MARK; 00227 break; 00228 00229 case 5: 00230 config->Parity = UART_PARITY_EVEN; 00231 break; 00232 00233 case 7: 00234 config->Parity = UART_PARITY_SPACE; 00235 break; 00236 00237 default: 00238 return 0; 00239 } 00240 00241 // get stop bits 00242 switch ((lcr >> 2) & 1) { 00243 case 0: 00244 config->StopBits = UART_STOP_BITS_1; 00245 break; 00246 00247 case 1: 00248 config->StopBits = UART_STOP_BITS_2; 00249 break; 00250 00251 default: 00252 return 0; 00253 } 00254 00255 // get flow control 00256 config->FlowControl = UART_FLOW_CONTROL_NONE; 00257 return 1; 00258 } 00259 00260 int32_t uart_write_free(void) 00261 { 00262 return circ_buf_count_free(&write_buffer); 00263 } 00264 00265 int32_t uart_write_data(uint8_t *data, uint16_t size) 00266 { 00267 uint32_t cnt; 00268 00269 cnt = circ_buf_write(&write_buffer, data, size); 00270 00271 // Make sure that the target LPC1549 can receive the output 00272 LPC_GPIO_PORT->SET[PORT_UARTCTRL] = PIN_UARTCTRL; 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 not implemented for this platform 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 // Turn back input for the target LPC1549 to it's pinlist 00313 LPC_GPIO_PORT->CLR[PORT_UARTCTRL] = PIN_UARTCTRL; 00314 // disable THRE interrupt 00315 LPC_USART->IER &= ~(1 << 1); 00316 } 00317 00318 // handle received character 00319 if (((iir & 0x0E) == 0x04) || // Rx interrupt (RDA) 00320 ((iir & 0x0E) == 0x0C)) { // Rx interrupt (CTI) 00321 while (LPC_USART->LSR & 0x01) { 00322 uint32_t free; 00323 uint8_t data; 00324 00325 data = LPC_USART->RBR; 00326 free = circ_buf_count_free(&read_buffer); 00327 if (free > RX_OVRF_MSG_SIZE) { 00328 circ_buf_push(&read_buffer, data); 00329 } else if (config_get_overflow_detect()) { 00330 if (RX_OVRF_MSG_SIZE == free) { 00331 circ_buf_write(&read_buffer, (uint8_t*)RX_OVRF_MSG, RX_OVRF_MSG_SIZE); 00332 } else { 00333 // Drop newest 00334 } 00335 } else { 00336 // Drop oldest 00337 circ_buf_pop(&read_buffer); 00338 circ_buf_push(&read_buffer, data); 00339 } 00340 } 00341 } 00342 00343 LPC_USART->LSR; 00344 } 00345 00346 static int32_t reset(void) 00347 { 00348 // Reset FIFOs 00349 LPC_USART->FCR = 0x06; 00350 baudrate = 0; 00351 dll = 0; 00352 tx_in_progress = 0; 00353 00354 circ_buf_init(&write_buffer, write_buffer_data, sizeof(write_buffer_data)); 00355 circ_buf_init(&read_buffer, read_buffer_data, sizeof(read_buffer_data)); 00356 00357 // Ensure a clean start, no data in either TX or RX FIFO 00358 while ((LPC_USART->LSR & ((1 << 5) | (1 << 6))) != ((1 << 5) | (1 << 6))); 00359 00360 while (LPC_USART->LSR & 0x01) { 00361 LPC_USART->RBR; // Dump data from RX FIFO 00362 } 00363 00364 return 1; 00365 }
Generated on Tue Jul 12 2022 15:37:26 by
1.7.2