Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers uart.c Source File

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 }