Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
Diff: source/hic_hal/nxp/lpc11u35/uart.c
- Revision:
- 0:01f31e923fe2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/hic_hal/nxp/lpc11u35/uart.c Tue Apr 07 12:55:42 2020 +0200 @@ -0,0 +1,373 @@ +/** + * @file uart.c + * @brief + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LPC11Uxx.h" +#include "uart.h" +#include "util.h" +#include "circ_buf.h" +#include "settings.h" // for config_get_overflow_detect + +static uint32_t baudrate; +static uint32_t dll; +static uint32_t tx_in_progress; + +extern uint32_t SystemCoreClock; + +#define RX_OVRF_MSG "<DAPLink:Overflow>\n" +#define RX_OVRF_MSG_SIZE (sizeof(RX_OVRF_MSG) - 1) +#define BUFFER_SIZE (64) + +circ_buf_t write_buffer; +uint8_t write_buffer_data[BUFFER_SIZE]; +circ_buf_t read_buffer; +uint8_t read_buffer_data[BUFFER_SIZE]; + +static uint8_t flow_control_enabled = 0; + +static int32_t reset(void); + +int32_t uart_initialize(void) +{ + NVIC_DisableIRQ(UART_IRQn); + LPC_SYSCON->SYSAHBCLKCTRL |= ((1UL << 6) | // enable clock for GPIO + (1UL << 16)); // enable clock for IOCON + // enable clk for usart + LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 12); + // usart clk divider = 1 + LPC_SYSCON->UARTCLKDIV = (1UL << 0); + // alternate function USART and PullNone + LPC_IOCON->PIO0_18 |= 0x01; + LPC_IOCON->PIO0_19 |= 0x01; + // enable FIFOs (trigger level 1) and clear them + LPC_USART->FCR = 0x87; + // Transmit Enable + LPC_USART->TER = 0x80; + // reset uart + reset(); + // enable rx and tx interrupt + LPC_USART->IER |= (1 << 0) | (1 << 1); + NVIC_EnableIRQ(UART_IRQn); + return 1; +} + +int32_t uart_uninitialize(void) +{ + // disable interrupt + LPC_USART->IER &= ~(0x7); + NVIC_DisableIRQ(UART_IRQn); + // reset uart + reset(); + return 1; +} + +int32_t uart_reset(void) +{ + // disable interrupt + NVIC_DisableIRQ(UART_IRQn); + // reset uart + reset(); + // enable interrupt + NVIC_EnableIRQ(UART_IRQn); + return 1; +} + +int32_t uart_set_configuration(UART_Configuration *config) +{ + uint8_t DivAddVal = 0; + uint8_t MulVal = 1; + uint8_t mv, data_bits = 8, parity, stop_bits = 0; + // disable interrupt + NVIC_DisableIRQ(UART_IRQn); + // reset uart + reset(); + baudrate = config->Baudrate; + // Compute baud rate dividers + mv = 15; + dll = util_div_round_down(SystemCoreClock, 16 * config->Baudrate); + DivAddVal = util_div_round(SystemCoreClock * mv, dll * config->Baudrate * 16) - mv; + // set LCR[DLAB] to enable writing to divider registers + LPC_USART->LCR |= (1 << 7); + // set divider values + LPC_USART->DLM = (dll >> 8) & 0xFF; + LPC_USART->DLL = (dll >> 0) & 0xFF; + LPC_USART->FDR = (uint32_t) DivAddVal << 0 + | (uint32_t) MulVal << 4; + // clear LCR[DLAB] + LPC_USART->LCR &= ~(1 << 7); + + // set data bits, stop bits, parity + if ((config->DataBits < 5) || (config->DataBits > 8)) { + data_bits = 8; + } + + data_bits -= 5; + + if (config->StopBits != 1 && config->StopBits != 2) { + stop_bits = 1; + } + + stop_bits -= 1; + + switch (config->Parity) { + case UART_PARITY_ODD: + parity = 0x01; + break; // Parity Odd + + case UART_PARITY_EVEN: + parity = 0x03; + break; // Parity Even + + case UART_PARITY_MARK: + parity = 0x05; + break; // Parity Mark + + case UART_PARITY_SPACE: + parity = 0x07; + break; // Parity Space + + case UART_PARITY_NONE: // Parity None + default: + parity = 0x00; + break; + } + + if (flow_control_enabled) { + LPC_IOCON->PIO0_17 |= 0x01; // RTS + LPC_IOCON->PIO0_7 |= 0x01; // CTS + // enable auto RTS and CTS + LPC_USART->MCR = (1 << 6) | (1 << 7); + } else { + LPC_IOCON->PIO0_17 &= ~0x01; // RTS + LPC_IOCON->PIO0_7 &= ~0x01; // CTS + // disable auto RTS and CTS + LPC_USART->MCR = (0 << 6) | (0 << 7); + } + + LPC_USART->LCR = (data_bits << 0) + | (stop_bits << 2) + | (parity << 3); + // Enable UART interrupt + NVIC_EnableIRQ(UART_IRQn); + return 1; +} + +int32_t uart_get_configuration(UART_Configuration *config) +{ + float br; + uint32_t lcr; + // line control parameter + lcr = LPC_USART->LCR; + // baudrate + br = SystemCoreClock / (dll * 16); + + // If inside +/- 2% tolerance + if (((br * 100) <= (baudrate * 102)) && ((br * 100) >= (baudrate * 98))) { + config->Baudrate = baudrate; + } else { + config->Baudrate = br; + } + + // get data bits + switch ((lcr >> 0) & 3) { + case 0: + config->DataBits = UART_DATA_BITS_5; + break; + + case 1: + config->DataBits = UART_DATA_BITS_6; + break; + + case 2: + config->DataBits = UART_DATA_BITS_7; + break; + + case 3: + config->DataBits = UART_DATA_BITS_8; + break; + + default: + return 0; + } + + // get parity + switch ((lcr >> 3) & 7) { + case 0: + case 2: + case 4: + case 6: + config->Parity = UART_PARITY_NONE; + break; + + case 1: + config->Parity = UART_PARITY_ODD; + break; + + case 3: + config->Parity = UART_PARITY_MARK; + break; + + case 5: + config->Parity = UART_PARITY_EVEN; + break; + + case 7: + config->Parity = UART_PARITY_SPACE; + break; + + default: + return 0; + } + + // get stop bits + switch ((lcr >> 2) & 1) { + case 0: + config->StopBits = UART_STOP_BITS_1; + break; + + case 1: + config->StopBits = UART_STOP_BITS_2; + break; + + default: + return 0; + } + + // get flow control + if (flow_control_enabled) { + config->FlowControl = UART_FLOW_CONTROL_RTS_CTS; + } + else { + config->FlowControl = UART_FLOW_CONTROL_NONE; + } + return 1; +} + +int32_t uart_write_free(void) +{ + return circ_buf_count_free(&write_buffer); +} + +int32_t uart_write_data(uint8_t *data, uint16_t size) +{ + uint32_t cnt; + + cnt = circ_buf_write(&write_buffer, data, size); + + // enable THRE interrupt + LPC_USART->IER |= (1 << 1); + + if (!tx_in_progress) { + // force THRE interrupt to start + NVIC_SetPendingIRQ(UART_IRQn); + } + + return cnt; +} + + +int32_t uart_read_data(uint8_t *data, uint16_t size) +{ + return circ_buf_read(&read_buffer, data, size); +} + +void uart_enable_flow_control(bool enabled) +{ + flow_control_enabled = (uint8_t)enabled; +} + +void UART_IRQHandler(void) +{ + uint32_t iir; + // read interrupt status + iir = LPC_USART->IIR; + + // handle character to transmit + if (circ_buf_count_used(&write_buffer) > 0) { + // if THR is empty + if (LPC_USART->LSR & (1 << 5)) { + LPC_USART->THR = circ_buf_pop(&write_buffer); + tx_in_progress = 1; + } + + } else if (tx_in_progress) { + tx_in_progress = 0; + // disable THRE interrupt + LPC_USART->IER &= ~(1 << 1); + } + + // handle received character + if (((iir & 0x0E) == 0x04) || // Rx interrupt (RDA) + ((iir & 0x0E) == 0x0C)) { // Rx interrupt (CTI) + while (LPC_USART->LSR & 0x01) { + uint32_t free; + uint8_t data; + + data = LPC_USART->RBR; + free = circ_buf_count_free(&read_buffer); + if (free > RX_OVRF_MSG_SIZE) { + circ_buf_push(&read_buffer, data); + } else if (config_get_overflow_detect()) { + if (RX_OVRF_MSG_SIZE == free) { + circ_buf_write(&read_buffer, (uint8_t*)RX_OVRF_MSG, RX_OVRF_MSG_SIZE); + } else { + // Drop newest + } + } else { + // Drop oldest + circ_buf_pop(&read_buffer); + circ_buf_push(&read_buffer, data); + } + } + } + + LPC_USART->LSR; +} + +static int32_t reset(void) +{ + uint32_t mcr; + // Reset FIFOs + LPC_USART->FCR = 0x06; + baudrate = 0; + dll = 0; + tx_in_progress = 0; + + circ_buf_init(&write_buffer, write_buffer_data, sizeof(write_buffer_data)); + circ_buf_init(&read_buffer, read_buffer_data, sizeof(read_buffer_data)); + + // Enable loopback mode to drain remaining bytes (even if flow control is on) + mcr = LPC_USART->MCR; + LPC_USART->MCR = mcr | (1 << 4); + + // Ensure a clean start, no data in either TX or RX FIFO + while ((LPC_USART->LSR & ((1 << 5) | (1 << 6))) != ((1 << 5) | (1 << 6))) { + LPC_USART->FCR = (1 << 1) | (1 << 2); + } + + // Restore previous mode (loopback off) + LPC_USART->MCR = mcr; + + while (LPC_USART->LSR & 0x01) { + LPC_USART->RBR; // Dump data from RX FIFO + } + + return 1; +}