diff --git a/source/hic_hal/nxp/lpc4322/RTE_Device.h b/source/hic_hal/nxp/lpc4322/RTE_Device.h index 48bdb7fdc..fd75c3642 100644 --- a/source/hic_hal/nxp/lpc4322/RTE_Device.h +++ b/source/hic_hal/nxp/lpc4322/RTE_Device.h @@ -1010,12 +1010,12 @@ // I2C1 (Inter-integrated Circuit Interface 1) [Driver_I2C1] // USART0 (Universal synchronous asynchronous receiver transmitter) [Driver_USART0] -#define RTE_USART0 0 +#define RTE_USART0 1 // Pin Configuration // TX <0=>Not used <1=>P2_0 <2=>P6_4 <3=>P9_5 <4=>PF_10 // USART0 Serial Output pin -#define RTE_USART0_TX_ID 0 +#define RTE_USART0_TX_ID 1 #if (RTE_USART0_TX_ID == 0) #define RTE_USART0_TX_PIN_EN 0 #elif (RTE_USART0_TX_ID == 1) @@ -1042,7 +1042,7 @@ #endif // RX <0=>Not used <1=>P2_1 <2=>P6_5 <3=>P9_6 <4=>PF_11 // USART0 Serial Input pin -#define RTE_USART0_RX_ID 0 +#define RTE_USART0_RX_ID 1 #if (RTE_USART0_RX_ID == 0) #define RTE_USART0_RX_PIN_EN 0 #elif (RTE_USART0_RX_ID == 1) diff --git a/source/hic_hal/nxp/lpc4322/uart.c b/source/hic_hal/nxp/lpc4322/uart.c index b69c12e04..6383265e0 100644 --- a/source/hic_hal/nxp/lpc4322/uart.c +++ b/source/hic_hal/nxp/lpc4322/uart.c @@ -3,7 +3,7 @@ * @brief * * DAPLink Interface Firmware - * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * Copyright (c) 2020 Arm Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -19,245 +19,167 @@ * limitations under the License. */ +#include "string.h" #include "LPC43xx.h" +#include "RTE_Driver/USART_LPC43xx.h" #include "uart.h" -#include "lpc43xx_scu.h" #include "util.h" +#include "cortex_m.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; +#define USART_INSTANCE (Driver_USART0) +#define USART_IRQ (USART0_IRQn) + +extern uint32_t SystemCoreClock; + +static void clear_buffers(void); #define RX_OVRF_MSG "\n" #define RX_OVRF_MSG_SIZE (sizeof(RX_OVRF_MSG) - 1) -#define BUFFER_SIZE (512) +#define BUFFER_SIZE (512) 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 int32_t reset(void); +struct { + // Number of bytes pending to be transferred. This is 0 if there is no + // ongoing transfer and the uart_handler processed the last transfer. + volatile uint32_t tx_size; -#define UART_IRQn USART0_IRQn -#define LPC_USART LPC_USART0 -#define UART_IRQHandler USART0_IRQHandler + uint8_t rx; +} cb_buf; -// UART Control Pin P2_2: GPIO5[2] -#define PORT_UARTCTRL 5 -#define PIN_UARTCTRL_IN_BIT 2 -#define PIN_UARTCTRL (1<BASE_UART0_CLK & ~(0x0F << 24); // clear CLK_SEL. - LPC_CGU->BASE_UART0_CLK = tmp - | (0x01 << 11) // AUTOBLOCK: 0=Disabled, 1=Enabled. - | (0x09 << 24) // CLK_SEL = PLL1. - ; - - LPC_CGU->BASE_UART0_CLK &= ~1; // PD: 0=Power Up. - - scu_pinmux(2, 0, UART_RX_TX, FUNC1); /* P2_0: U0_TXD */ - scu_pinmux(2, 1, UART_RX_TX, FUNC1); /* P2_1: U0_RXD */ - - scu_pinmux(2, 2, GPIO_NOPULL, FUNC4); /* UARTCTRL: GPIO5[2] */ - // Control target's UART RX: - // UARTCTRL high: The LPC1549 gets uart input from the LPC4322 - // UARTCTRL low: The LPC1549 gets uart input from the ISP_RX on the pinlist - LPC_GPIO_PORT->CLR[PORT_UARTCTRL] = PIN_UARTCTRL; - LPC_GPIO_PORT->DIR[PORT_UARTCTRL] |= (PIN_UARTCTRL); - // enable FIFOs (trigger level 1) and clear them - LPC_USART->FCR = 0x87; - // Transmit Enable - LPC_USART->TER = 0x01; - // reset uart - reset(); - // enable rx and tx interrupt - LPC_USART->IER |= (1 << 0) | (1 << 1); - NVIC_EnableIRQ(UART_IRQn); + clear_buffers(); + cb_buf.tx_size = 0; + USART_INSTANCE.Initialize(uart_handler); + USART_INSTANCE.PowerControl(ARM_POWER_FULL); + return 1; } int32_t uart_uninitialize(void) { - // disable interrupt - LPC_USART->IER &= ~(0x7); - NVIC_DisableIRQ(UART_IRQn); - // reset uart - reset(); + USART_INSTANCE.Control(ARM_USART_CONTROL_RX, 0); + USART_INSTANCE.Control(ARM_USART_ABORT_RECEIVE, 0U); + USART_INSTANCE.PowerControl(ARM_POWER_OFF); + USART_INSTANCE.Uninitialize(); + clear_buffers(); + cb_buf.tx_size = 0; + return 1; } int32_t uart_reset(void) { // disable interrupt - NVIC_DisableIRQ(UART_IRQn); - // reset uart - reset(); + NVIC_DisableIRQ(USART_IRQ); + clear_buffers(); // enable interrupt - NVIC_EnableIRQ(UART_IRQn); + NVIC_EnableIRQ(USART_IRQ); + 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 + uint32_t control = ARM_USART_MODE_ASYNCHRONOUS; - case UART_PARITY_NONE: // Parity None - default: - parity = 0x00; + switch (config->DataBits) { + case UART_DATA_BITS_5: + control |= ARM_USART_DATA_BITS_5; break; - } - 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; - } + case UART_DATA_BITS_6: + control |= ARM_USART_DATA_BITS_6; + break; - // get data bits - switch ((lcr >> 0) & 3) { - case 0: - config->DataBits = UART_DATA_BITS_5; + case UART_DATA_BITS_7: + control |= ARM_USART_DATA_BITS_7; break; - case 1: - config->DataBits = UART_DATA_BITS_6; + case UART_DATA_BITS_8: /* fallthrough */ + default: + control |= ARM_USART_DATA_BITS_8; break; + } - case 2: - config->DataBits = UART_DATA_BITS_7; + switch (config->Parity) { + case UART_PARITY_EVEN: + control |= ARM_USART_PARITY_EVEN; break; - case 3: - config->DataBits = UART_DATA_BITS_8; + case UART_PARITY_ODD: + control |= ARM_USART_PARITY_ODD; break; + case UART_PARITY_NONE: /* fallthrough */ default: - return 0; + control |= ARM_USART_PARITY_NONE; + break; } - // get parity - switch ((lcr >> 3) & 7) { - case 0: - case 2: - case 4: - case 6: - config->Parity = UART_PARITY_NONE; + switch (config->StopBits) { + case UART_STOP_BITS_1: /* fallthrough */ + default: + control |= ARM_USART_STOP_BITS_1; break; - case 1: - config->Parity = UART_PARITY_ODD; + case UART_STOP_BITS_1_5: + control |= ARM_USART_STOP_BITS_1_5; break; - case 3: - config->Parity = UART_PARITY_MARK; + case UART_STOP_BITS_2: + control |= ARM_USART_STOP_BITS_2; break; + } - case 5: - config->Parity = UART_PARITY_EVEN; + switch (config->FlowControl) { + case UART_FLOW_CONTROL_NONE: /* fallthrough */ + default: + control |= ARM_USART_FLOW_CONTROL_NONE; break; - case 7: - config->Parity = UART_PARITY_SPACE; + case UART_FLOW_CONTROL_RTS_CTS: + control |= ARM_USART_FLOW_CONTROL_RTS_CTS; break; - - default: - return 0; } - // get stop bits - switch ((lcr >> 2) & 1) { - case 0: - config->StopBits = UART_STOP_BITS_1; - break; + NVIC_DisableIRQ(USART_IRQ); + clear_buffers(); - case 1: - config->StopBits = UART_STOP_BITS_2; - break; + // If there was no Receive() call in progress aborting it is harmless. + USART_INSTANCE.Control(ARM_USART_CONTROL_RX, 0U); + USART_INSTANCE.Control(ARM_USART_ABORT_RECEIVE, 0U); - default: - return 0; + uint32_t r = USART_INSTANCE.Control(control, config->Baudrate); + if (r != ARM_DRIVER_OK) { + return 0; } + USART_INSTANCE.Control(ARM_USART_CONTROL_TX, 1); + USART_INSTANCE.Control(ARM_USART_CONTROL_RX, 1); + USART_INSTANCE.Receive(&(cb_buf.rx), 1); + + NVIC_ClearPendingIRQ(USART_IRQ); + NVIC_EnableIRQ(USART_IRQ); + + return 1; +} - // get flow control - config->FlowControl = UART_FLOW_CONTROL_NONE; +int32_t uart_get_configuration(UART_Configuration *config) +{ return 1; } @@ -270,104 +192,65 @@ int32_t uart_write_free(void) return circ_buf_count_free(&write_buffer); } +// Start a new TX transfer if there are bytes pending to be transferred on the +// write_buffer buffer. The transferred bytes are not removed from the circular +// by this function, only the event handler will remove them once the transfer +// is done. +static void uart_start_tx_transfer() { + uint32_t tx_size = 0; + const uint8_t* buf = circ_buf_peek(&write_buffer, &tx_size); + if (tx_size > BUFFER_SIZE / 4) { + // The bytes being transferred remain on the circular buffer memory + // until the transfer is done. Limiting the UART transfer size + // allows the uart_handler to clear those bytes earlier. + tx_size = BUFFER_SIZE / 4; + } + cb_buf.tx_size = tx_size; + if (tx_size) { + USART_INSTANCE.Send(buf, tx_size); + } +} + int32_t uart_write_data(uint8_t *data, uint16_t size) { - uint32_t cnt; - - cnt = circ_buf_write(&write_buffer, data, size); - - // Make sure that the target LPC1549 can receive the output - LPC_GPIO_PORT->SET[PORT_UARTCTRL] = PIN_UARTCTRL; - - // enable THRE interrupt - LPC_USART->IER |= (1 << 1); + if (size == 0) { + return 0; + } - if (!tx_in_progress) { - // force THRE interrupt to start - NVIC_SetPendingIRQ(UART_IRQn); + uint32_t cnt = circ_buf_write(&write_buffer, data, size); + if (cb_buf.tx_size == 0) { + // There's no pending transfer and the value of cb_buf.tx_size will not + // change to non-zero by the event handler once it is zero. Note that it + // is entirely possible that we transferred all the bytes we added to + // the circular buffer in this function by the time we are in this + // branch, in that case uart_start_tx_transfer() would not schedule any + // transfer. + uart_start_tx_transfer(); } 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 not implemented for this platform -} - -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; +void uart_handler(uint32_t event) { + if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) { + uint32_t free = circ_buf_count_free(&read_buffer); + if (free > RX_OVRF_MSG_SIZE) { + circ_buf_push(&read_buffer, cb_buf.rx); + } else if ((RX_OVRF_MSG_SIZE == free) && config_get_overflow_detect()) { + circ_buf_write(&read_buffer, (uint8_t*)RX_OVRF_MSG, RX_OVRF_MSG_SIZE); + } else { + // Drop character } - - } else if (tx_in_progress) { - tx_in_progress = 0; - // Turn back input for the target LPC1549 to it's pinlist - LPC_GPIO_PORT->CLR[PORT_UARTCTRL] = PIN_UARTCTRL; - // disable THRE interrupt - LPC_USART->IER &= ~(1 << 1); + USART_INSTANCE.Receive(&(cb_buf.rx), 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); - } - } + if (event & ARM_USART_EVENT_SEND_COMPLETE) { + circ_buf_pop_n(&write_buffer, cb_buf.tx_size); + uart_start_tx_transfer(); } - - LPC_USART->LSR; -} - -static int32_t reset(void) -{ - // 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)); - - // Ensure a clean start, no data in either TX or RX FIFO - while ((LPC_USART->LSR & ((1 << 5) | (1 << 6))) != ((1 << 5) | (1 << 6))); - - while (LPC_USART->LSR & 0x01) { - LPC_USART->RBR; // Dump data from RX FIFO - } - - return 1; }