From dae27fbf5f7eccfac303c5ea569e92166d60a1cb Mon Sep 17 00:00:00 2001 From: codetector Date: Thu, 3 Dec 2020 22:31:21 -0500 Subject: [PATCH] UART + Serial Driver --- os/common/ext/CMSIS/LPC/LPC11Uxx.h | 36 +++ os/hal/ports/LPC/LLD/UART/driver.mk | 4 + os/hal/ports/LPC/LLD/UART/hal_serial_lld.c | 208 ++++++++++++++++ os/hal/ports/LPC/LLD/UART/hal_serial_lld.h | 134 ++++++++++ os/hal/ports/LPC/LLD/UART/hal_uart_lld.c | 276 +++++++++++++++++++++ os/hal/ports/LPC/LLD/UART/hal_uart_lld.h | 216 ++++++++++++++++ os/hal/ports/LPC/LPC11Uxx/lpc_registry.h | 2 +- os/hal/ports/LPC/LPC11Uxx/platform.mk | 1 + 8 files changed, 876 insertions(+), 1 deletion(-) create mode 100644 os/hal/ports/LPC/LLD/UART/driver.mk create mode 100644 os/hal/ports/LPC/LLD/UART/hal_serial_lld.c create mode 100644 os/hal/ports/LPC/LLD/UART/hal_serial_lld.h create mode 100644 os/hal/ports/LPC/LLD/UART/hal_uart_lld.c create mode 100644 os/hal/ports/LPC/LLD/UART/hal_uart_lld.h diff --git a/os/common/ext/CMSIS/LPC/LPC11Uxx.h b/os/common/ext/CMSIS/LPC/LPC11Uxx.h index 5cc6eb72..317ca885 100644 --- a/os/common/ext/CMSIS/LPC/LPC11Uxx.h +++ b/os/common/ext/CMSIS/LPC/LPC11Uxx.h @@ -200,6 +200,42 @@ typedef struct { /*!< (@ 0x40008000) USART Structure __IO uint32_t SYNCCTRL; } LPC_USART_Type; +#define USART_FCR_FIFOEN (1U << 0U) +#define USART_FCR_RX_RST (1U << 1U) +#define USART_FCR_TX_RST (1U << 2U) +#define USART_FCR_RXTL_POS (6U) +#define USART_FCR_RXTL_1B (0x0 << USART_FCR_RXTL_POS) +#define USART_FCR_RXTL_4B (0x1 << USART_FCR_RXTL_POS) +#define USART_FCR_RXTL_8B (0x2 << USART_FCR_RXTL_POS) +#define USART_FCR_RXTL_14B (0x3 << USART_FCR_RXTL_POS) +#define USART_FCR_RXTL_MASK (0x3 << USART_FCR_RXTL_POS) + +#define USART_LCR_WLS_POS (0U) +#define USART_LCR_WLS_5B (0x0U << USART_LCR_WLS_POS) +#define USART_LCR_WLS_6B (0x1U << USART_LCR_WLS_POS) +#define USART_LCR_WLS_7B (0x2U << USART_LCR_WLS_POS) +#define USART_LCR_WLS_8B (0x3U << USART_LCR_WLS_POS) +#define USART_LCR_WLS_MASK (0x3U << USART_LCR_WLS_POS) +#define USART_LCR_SBS_POS (2U) +#define USART_LCR_SBS_1B (0U << USART_LCR_SBS_POS) +#define USART_LCR_SBS_2B (0U << USART_LCR_SBS_POS) +#define USART_LCR_SBS_MASK (0x1 << USART_LCR_SBS_POS) +#define USART_LCR_PE (1U << 3U) +#define USART_LCR_PS_POS (4U) +#define USART_LCR_PS_ODD (0x0U << USART_LCR_PS_POS) +#define USART_LCR_PS_EVEN (0x1U << USART_LCR_PS_POS) +#define USART_LCR_PS_F1 (0x2U << USART_LCR_PS_POS) +#define USART_LCR_PS_F0 (0x3U << USART_LCR_PS_POS) +#define USART_LCR_PS_MASK (0x3U << USART_LCR_PS_POS) +#define USART_LCR_DLAB (1U << 7U) + +#define USART_LSR_RDR (1U << 0U) +#define USART_LSR_THRE (1U << 5U) + +#define USART_TER_TXEN (1U << 7U) + +#define USART_IER_RBRINTEN (1U << 0U) // Rx Has Data +#define USART_IER_THRINTEN (1U << 1U) // Tx Empty // ------------------------------------------------------------------------------------------------ // ----- Timer ----- diff --git a/os/hal/ports/LPC/LLD/UART/driver.mk b/os/hal/ports/LPC/LLD/UART/driver.mk new file mode 100644 index 00000000..c87d9fa3 --- /dev/null +++ b/os/hal/ports/LPC/LLD/UART/driver.mk @@ -0,0 +1,4 @@ +PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/UART/hal_uart_lld.c \ + $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/UART/hal_serial_lld.c + +PLATFORMINC += $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/UART diff --git a/os/hal/ports/LPC/LLD/UART/hal_serial_lld.c b/os/hal/ports/LPC/LLD/UART/hal_serial_lld.c new file mode 100644 index 00000000..638ecb67 --- /dev/null +++ b/os/hal/ports/LPC/LLD/UART/hal_serial_lld.c @@ -0,0 +1,208 @@ +/* + ChibiOS - Copyright (C) 2020 Yaotian Feng + + 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. +*/ + +/** + * @file hal_serial_lld.c + * @brief LPC11Uxx serial subsystem low level driver source. + * + * @addtogroup SERIAL + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief USART1 serial driver identifier.*/ +#if (LPC_SERIAL_USE_UART1 == TRUE) || defined(__DOXYGEN__) +SerialDriver SD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Driver default configuration. + */ +static const SerialConfig default_config = { + 9600 +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static void load(SerialDriver *sdp) { + if (&SD1 == sdp) { + if (LPC_USART->LSR & USART_LSR_THRE) { + msg_t b; + osalSysLock(); + b = oqGetI(&sdp->oqueue); + osalSysUnlock(); + if (b >= MSG_OK) { + LPC_USART->THR = b; + } + } + LPC_USART->IER |= USART_IER_THRINTEN; // Enable Tx Empty + } +} + +#if LPC_SERIAL_USE_UART1 == TRUE +static void notify1(io_queue_t *qp) { + (void)qp; + load(&SD1); +} +#endif + +static void serial_interrupt(SerialDriver *sdp) { + if (LPC_USART->LSR & USART_LSR_RDR) { + // Rx Pending + osalSysLockFromISR(); + if (iqIsEmptyI(&sdp->iqueue)) { + chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); + } + osalSysUnlockFromISR(); + + while(LPC_USART->LSR & USART_LSR_RDR) { + osalSysLockFromISR(); + if (iqPutI(&sdp->iqueue, LPC_USART->RBR) < MSG_OK) { + chnAddFlagsI(sdp, SD_OVERRUN_ERROR); + } + osalSysUnlockFromISR(); + } + } + + if (LPC_USART->LSR & USART_LSR_THRE) { + msg_t b; + osalSysLockFromISR(); + b = oqGetI(&sdp->oqueue); + osalSysUnlockFromISR(); + if (b >= MSG_OK) { + LPC_USART->THR = b; + } else { + LPC_USART->IER &= ~USART_IER_THRINTEN; + osalSysLockFromISR(); + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + osalSysUnlockFromISR(); + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (LPC_SERIAL_USE_UART1 == TRUE) || defined(__DOXYGEN__) +CH_IRQ_HANDLER(LPC_UART_IRQ_VECTOR) { + CH_IRQ_PROLOGUE(); + serial_interrupt(&SD1); + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level serial driver initialization. + * + * @notapi + */ +void sd_lld_init(void) { +#if LPC_SERIAL_USE_UART1 == TRUE + sdObjectInit(&SD1, NULL, notify1); + LPC_SYSCON->UARTCLKDIV = LPC_UART_PCLK_DIV; // Set Proper Clock Divider + LPC_SYSCON->SYSAHBCLKCTRL |= SYSCON_SYSAHBCLKCTRL_USART; // Enable USART Clock +#endif +} + +/** + * @brief Low level serial driver configuration and (re)start. + * + * @param[in] sdp pointer to a @p SerialDriver object + * @param[in] config the architecture-dependent serial driver configuration. + * If this parameter is set to @p NULL then a default + * configuration is used. + * + * @notapi + */ +void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { + + if (config == NULL) { + config = &default_config; + } + + if (sdp->state == SD_STOP) { +#if LPC_SERIAL_USE_UART1 == TRUE + if (&SD1 == sdp) { + // Disable Auto Baudrate. Not helpful + LPC_USART->ACR = 0; + LPC_USART->TER = USART_TER_TXEN; + /* Clock should be set to 16x baudrate */ + uint16_t uart_div = (LPC_UART_PCLK_FREQUENCY / 16) / config->speed; + LPC_USART->LCR = USART_LCR_DLAB; + LPC_USART->DLL = (uint8_t)uart_div; + LPC_USART->DLM = (uint8_t)(uart_div >> 8); + // TODO: Support user configurable Parity and word length. + LPC_USART->LCR = USART_LCR_WLS_8B; + // FIFO Reset & Enable + LPC_USART->FCR = USART_FCR_FIFOEN | USART_FCR_TX_RST | USART_FCR_RX_RST | + USART_FCR_RXTL_1B; + + #if !defined(LPC_UART_UART1_IRQ_PRIORITY) + #error "LPC_UART_UART1_IRQ_PRIORITY is not defined" + #endif + nvicEnableVector(UART_IRQn, LPC_UART_UART1_IRQ_PRIORITY); + LPC_USART->IER = USART_IER_RBRINTEN; + } +#endif + } +} + +/** + * @brief Low level serial driver stop. + * @details De-initializes the USART, stops the associated clock, resets the + * interrupt vector. + * + * @param[in] sdp pointer to a @p SerialDriver object + * + * @notapi + */ +void sd_lld_stop(SerialDriver *sdp) { + + if (sdp->state == SD_READY) { +#if LPC_SERIAL_USE_UART1 == TRUE + if (&SD1 == sdp) { + nvicDisableVector(UART_IRQn); + LPC_USART->IER = 0; + } +#endif + } +} + +#endif /* HAL_USE_SERIAL == TRUE */ + +/** @} */ diff --git a/os/hal/ports/LPC/LLD/UART/hal_serial_lld.h b/os/hal/ports/LPC/LLD/UART/hal_serial_lld.h new file mode 100644 index 00000000..72d3325f --- /dev/null +++ b/os/hal/ports/LPC/LLD/UART/hal_serial_lld.h @@ -0,0 +1,134 @@ +/* + ChibiOS - Copyright (C) 2020 Yaotian Feng + + 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. +*/ + +/** + * @file hal_serial_lld.h + * @brief PLATFORM serial subsystem low level driver header. + * + * @addtogroup SERIAL + * @{ + */ + +#ifndef HAL_SERIAL_LLD_H +#define HAL_SERIAL_LLD_H + +#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name LPC Serial configuration options + * @{ + */ +/** + * @brief UART1 driver enable switch. + * @details If set to @p TRUE the support for UART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(LPC_SERIAL_USE_UART1) || defined(__DOXYGEN__) +#define LPC_SERIAL_USE_UART1 FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if LPC_SERIAL_USE_UART1 == TRUE +/** + * @brief UART PCLK DIVIDER setting. + * @details If this is not set, then we default to generate a PCLK as close to + * 1.8432MHz as possible. This is the standard clock to a 16550. + * The LPC UART is pretty much a 16550 if you look at the registers. + */ +#if !defined(LPC_UART_PCLK_DIV) || defined(__DOXYGEN__) +#define LPC_UART_PCLK_DIV (LPC_MAINCLK_FREQUENCY / 1843200) +#endif + +#define LPC_UART_PCLK_FREQUENCY \ + (LPC_MAINCLK_FREQUENCY / LPC_UART_PCLK_DIV) + +#endif +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief PLATFORM Serial Driver configuration structure. + * @details An instance of this structure must be passed to @p sdStart() + * in order to configure and start a serial driver operations. + * @note This structure content is architecture dependent, each driver + * implementation defines its own version and the custom static + * initializers. + */ +typedef struct { + /** + * @brief Bit rate. + */ + uint32_t speed; + /* End of the mandatory fields.*/ +} SerialConfig; + +/** + * @brief @p SerialDriver specific data. + */ +#define _serial_driver_data \ + _base_asynchronous_channel_data \ + /* Driver state.*/ \ + sdstate_t state; \ + /* Input queue.*/ \ + input_queue_t iqueue; \ + /* Output queue.*/ \ + output_queue_t oqueue; \ + /* Input circular buffer.*/ \ + uint8_t ib[SERIAL_BUFFERS_SIZE]; \ + /* Output circular buffer.*/ \ + uint8_t ob[SERIAL_BUFFERS_SIZE]; \ + /* End of the mandatory fields.*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (LPC_SERIAL_USE_UART1 == TRUE) && !defined(__DOXYGEN__) +extern SerialDriver SD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sd_lld_init(void); + void sd_lld_start(SerialDriver *sdp, const SerialConfig *config); + void sd_lld_stop(SerialDriver *sdp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SERIAL == TRUE */ + +#endif /* HAL_SERIAL_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/LPC/LLD/UART/hal_uart_lld.c b/os/hal/ports/LPC/LLD/UART/hal_uart_lld.c new file mode 100644 index 00000000..2cc9e2fa --- /dev/null +++ b/os/hal/ports/LPC/LLD/UART/hal_uart_lld.c @@ -0,0 +1,276 @@ +/* + ChibiOS - Copyright (C) 2020 Yaotian Feng / Codetector + + 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. +*/ + +/** + * @file hal_uart_lld.c + * @brief LPC11Uxx UART subsystem low level driver source. + * + * @addtogroup UART + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief UART1 driver identifier. + */ +#if (LPC_UART_USE_UART1 == TRUE) || defined(__DOXYGEN__) +UARTDriver UARTD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#define uart_enter_rx_idle_loop(uartp) (void)uartp + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if LPC_UART_USE_UART1 == TRUE + +#ifndef LPC_UART_IRQ_VECTOR +#error "LPC_UART_IRQ_VECTOR not defined" +#endif + +OSAL_IRQ_HANDLER(LPC_UART_IRQ_VECTOR) { + OSAL_IRQ_PROLOGUE(); + + // UARTDriver *uartp = &UARTD1; + // // Pending Recieve + + + // while ((uartp->rx_cnt < uartp->rx_size) && + // (LPC_USART->LSR & USART_LSR_RDR)) + // { + // uint8_t tmp = LPC_USART->RBR; + // if (uartp->rxbuf != NULL) { + // uartp->rxbuf[uartp->rx_cnt] = tmp; + // } + // uartp->rx_cnt++; + // } + + // if (uartp->rx_size > 0 && uartp->rx_cnt >= uartp->rx_size) { + // uartp->rx_cnt = 0; + // uartp->rx_size = 0; + // LPC_USART->IER &= ~USART_IER_RBRINTEN; // Disable Rx Interrupt + // _uart_rx_complete_isr_code(uartp); + // } + + // // Check if a pending transimit + // while ((uartp->txbuf != NULL) && // have a buffer to Tx + // (uartp->tx_cnt < uartp->tx_size) && // More bytes needs to be sent + // (LPC_USART->LSR & USART_LSR_THRE)) // have space in buffer + // { + // LPC_USART->THR = uartp->txbuf[uartp->tx_cnt]; + // uartp->tx_cnt++; + // } + + // if (uartp->tx_size > 0 && uartp->tx_cnt >= uartp->tx_size) { + // uartp->tx_cnt = 0; + // uartp->tx_size = 0; + // uartp->txbuf = NULL; + // LPC_USART->IER &= ~USART_IER_THRINTEN; // Disable Tx Interrupt + // _uart_tx1_isr_code(uartp); + // } + + OSAL_IRQ_EPILOGUE(); +} + +#endif + + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level UART driver initialization. + * + * @notapi + */ +void uart_lld_init(void) { + +#if LPC_UART_USE_UART1 == TRUE + /* Driver initialization.*/ + uartObjectInit(&UARTD1); + /* Initialize Clock */ + LPC_SYSCON->UARTCLKDIV = LPC_UART_PCLK_DIV; // Set Proper Clock Divider + LPC_SYSCON->SYSAHBCLKCTRL |= SYSCON_SYSAHBCLKCTRL_USART; // Enable USART Clock +#endif +} + +/** + * @brief Configures and activates the UART peripheral. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @notapi + */ +void uart_lld_start(UARTDriver *uartp) { + + if (uartp->state == UART_STOP) { + /* Enables the peripheral.*/ +#if LPC_UART_USE_UART1 == TRUE + if (&UARTD1 == uartp) { + // Disable Auto Baudrate. Not helpful + LPC_USART->ACR = 0; + LPC_USART->TER = USART_TER_TXEN; + /* Clock should be set to 16x baudrate */ + uint16_t uart_div = (LPC_UART_PCLK_FREQUENCY / 16) / uartp->config->baudrate; + LPC_USART->LCR = USART_LCR_DLAB; + LPC_USART->DLL = (uint8_t)uart_div; + LPC_USART->DLM = (uint8_t)(uart_div >> 8); + // TODO: Support user configurable Parity and word length. + LPC_USART->LCR = USART_LCR_WLS_8B; + // FIFO Reset & Enable + LPC_USART->FCR = USART_FCR_FIFOEN | USART_FCR_TX_RST | USART_FCR_RX_RST | + USART_FCR_RXTL_1B; + + #if !defined(LPC_UART_UART1_IRQ_PRIORITY) + #error "LPC_UART_UART1_IRQ_PRIORITY is not defined" + #endif + nvicEnableVector(UART_IRQn, LPC_UART_UART1_IRQ_PRIORITY); + LPC_USART->IER = USART_IER_RBRINTEN; + } +#endif + } + /* Configures the peripheral.*/ + +} + +/** + * @brief Deactivates the UART peripheral. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @notapi + */ +void uart_lld_stop(UARTDriver *uartp) { + + if (uartp->state == UART_READY) { + /* Resets the peripheral.*/ + + /* Disables the peripheral.*/ +#if LPC_UART_USE_UART1 == TRUE + if (&UARTD1 == uartp) { + LPC_USART->IER = 0; + nvicDisableVector(UART_IRQn); + } +#endif + } +} + +/** + * @brief Starts a transmission on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) { + const uint8_t* buf = txbuf; + if (buf == NULL) { + return; + } + size_t i = 0; + while(n > 0) { + if(LPC_USART->LSR & USART_LSR_THRE) { + LPC_USART->THR = buf[i++]; + n--; + } + } +} + +/** + * @brief Stops any ongoing transmission. + * @note Stopping a transmission also suppresses the transmission callbacks. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not transmitted by the + * stopped transmit operation. + * + * @notapi + */ +size_t uart_lld_stop_send(UARTDriver *uartp) { + (void)uartp; + return 0; +} + +/** + * @brief Starts a receive operation on the UART peripheral. + * @note The buffers are organized as uint8_t arrays for data sizes below + * or equal to 8 bits else it is organized as uint16_t arrays. + * + * @param[in] uartp pointer to the @p UARTDriver object + * @param[in] n number of data frames to send + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) { + const uint8_t* buf = rxbuf; + if (buf == NULL) { + return; + } + size_t i = 0; + while(n > 0) { + if(LPC_USART->LSR & USART_LSR_RDR) { + buf[i++] = LPC_USART->RBR; + n--; + } + } +} + +/** + * @brief Stops any ongoing receive operation. + * @note Stopping a receive operation also suppresses the receive callbacks. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @return The number of data frames not received by the + * stopped receive operation. + * + * @notapi + */ +size_t uart_lld_stop_receive(UARTDriver *uartp) { + (void)uartp; + return 0; +} + +#endif /* HAL_USE_UART == TRUE */ + +/** @} */ diff --git a/os/hal/ports/LPC/LLD/UART/hal_uart_lld.h b/os/hal/ports/LPC/LLD/UART/hal_uart_lld.h new file mode 100644 index 00000000..a7824859 --- /dev/null +++ b/os/hal/ports/LPC/LLD/UART/hal_uart_lld.h @@ -0,0 +1,216 @@ +/* + ChibiOS - Copyright (C) 2020 Yaotian Feng / Codetector + + 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. +*/ + +/** + * @file hal_uart_lld.h + * @brief LPC11Uxx UART subsystem low level driver header. + * + * @addtogroup UART + * @{ + */ + +#ifndef HAL_UART_LLD_H +#define HAL_UART_LLD_H + +#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name LPC11Uxx configuration options + * @{ + */ +/** + * @brief UART driver enable switch. + * @details If set to @p TRUE the support for UART1 is included. + * @note The default is @p FALSE. + */ +#if !defined(LPC_UART_USE_UART1) || defined(__DOXYGEN__) +#define LPC_UART_USE_UART1 FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ +/** + * @brief UART PCLK DIVIDER setting. + * @details If this is not set, then we default to generate a PCLK as close to + * 1.8432MHz as possible. This is the standard clock to a 16550. + * The LPC UART is pretty much a 16550 if you look at the registers. + */ +#if !defined(LPC_UART_PCLK_DIV) || defined(__DOXYGEN__) +#define LPC_UART_PCLK_DIV (LPC_MAINCLK_FREQUENCY / 1843200) +#endif + +#define LPC_UART_PCLK_FREQUENCY \ + (LPC_MAINCLK_FREQUENCY / LPC_UART_PCLK_DIV) + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief UART driver condition flags type. + */ +typedef uint32_t uartflags_t; + +/** + * @brief Type of structure representing an UART driver. + */ +typedef struct UARTDriver UARTDriver; + +/** + * @brief Generic UART notification callback type. + * + * @param[in] uartp pointer to the @p UARTDriver object + */ +typedef void (*uartcb_t)(UARTDriver *uartp); + +/** + * @brief Character received UART notification callback type. + * + * @param[in] uartp pointer to the @p UARTDriver object triggering the + * callback + * @param[in] c received character + */ +typedef void (*uartccb_t)(UARTDriver *uartp, uint16_t c); + +/** + * @brief Receive error UART notification callback type. + * + * @param[in] uartp pointer to the @p UARTDriver object triggering the + * callback + * @param[in] e receive error mask + */ +typedef void (*uartecb_t)(UARTDriver *uartp, uartflags_t e); + +/** + * @brief Driver configuration structure. + * @note Implementations may extend this structure to contain more, + * architecture dependent, fields. + */ +typedef struct { + /** + * @brief End of transmission buffer callback. + */ + uartcb_t txend1_cb; + /** + * @brief Physical end of transmission callback. + */ + uartcb_t txend2_cb; + /** + * @brief Receive buffer filled callback. + */ + uartcb_t rxend_cb; + /** + * @brief Character received while out of the @p UART_RECEIVE state. + */ + uartccb_t rxchar_cb; + /** + * @brief Receive error callback. + */ + uartecb_t rxerr_cb; + /* End of the mandatory fields.*/ + + uint32_t baudrate; +} UARTConfig; + +/** + * @brief Structure representing an UART driver. + * @note Implementations may extend this structure to contain more, + * architecture dependent, fields. + */ +struct UARTDriver { + /** + * @brief Driver state. + */ + uartstate_t state; + /** + * @brief Transmitter state. + */ + uarttxstate_t txstate; + /** + * @brief Receiver state. + */ + uartrxstate_t rxstate; + /** + * @brief Current configuration data. + */ + const UARTConfig *config; +#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Synchronization flag for transmit operations. + */ + bool early; + /** + * @brief Waiting thread on RX. + */ + thread_reference_t threadrx; + /** + * @brief Waiting thread on TX. + */ + thread_reference_t threadtx; +#endif /* UART_USE_WAIT */ +#if (UART_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the peripheral. + */ + mutex_t mutex; +#endif /* UART_USE_MUTUAL_EXCLUSION */ +#if defined(UART_DRIVER_EXT_FIELDS) + UART_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (LPC_UART_USE_UART1 == TRUE) && !defined(__DOXYGEN__) +extern UARTDriver UARTD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void uart_lld_init(void); + void uart_lld_start(UARTDriver *uartp); + void uart_lld_stop(UARTDriver *uartp); + void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf); + size_t uart_lld_stop_send(UARTDriver *uartp); + void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf); + size_t uart_lld_stop_receive(UARTDriver *uartp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_UART == TRUE */ + +#endif /* HAL_UART_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/LPC/LPC11Uxx/lpc_registry.h b/os/hal/ports/LPC/LPC11Uxx/lpc_registry.h index 6954c7b9..266f2068 100644 --- a/os/hal/ports/LPC/LPC11Uxx/lpc_registry.h +++ b/os/hal/ports/LPC/LPC11Uxx/lpc_registry.h @@ -41,10 +41,10 @@ defined(__DOXYGEN__) #define LPC_HAS_USB TRUE #define LPC_USB_IRQ_VECTOR Vector98 - #define LPC_SSP0_IRQ_VECTOR Vector90 #define LPC_SSP1_IRQ_VECTOR Vector78 +#define LPC_UART_IRQ_VECTOR Vector94 #endif diff --git a/os/hal/ports/LPC/LPC11Uxx/platform.mk b/os/hal/ports/LPC/LPC11Uxx/platform.mk index 8d839c0f..cb20aa45 100644 --- a/os/hal/ports/LPC/LPC11Uxx/platform.mk +++ b/os/hal/ports/LPC/LPC11Uxx/platform.mk @@ -10,6 +10,7 @@ include $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/STM/driver.mk include $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/GPIO/driver.mk include $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/USB/driver.mk include $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/SPI/driver.mk +include $(CHIBIOS_CONTRIB)/os/hal/ports/LPC/LLD/UART/driver.mk # Shared variables ALLCSRC += $(PLATFORMSRC)