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