From 39021902482ee2309e9234bb6f5c642500629b2b Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 2 Apr 2010 14:38:08 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1834 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/LPC111x/platform.mk | 3 +- os/hal/platforms/LPC111x/serial_lld.c | 331 ++++++++++++++++++++++++++++++++++ os/hal/platforms/LPC111x/serial_lld.h | 158 ++++++++++++++++ os/hal/platforms/LPC214x/serial_lld.c | 3 - os/hal/platforms/LPC214x/serial_lld.h | 2 +- 5 files changed, 492 insertions(+), 5 deletions(-) create mode 100644 os/hal/platforms/LPC111x/serial_lld.c create mode 100644 os/hal/platforms/LPC111x/serial_lld.h (limited to 'os/hal/platforms') diff --git a/os/hal/platforms/LPC111x/platform.mk b/os/hal/platforms/LPC111x/platform.mk index b3f7fd976..99b6a10ba 100644 --- a/os/hal/platforms/LPC111x/platform.mk +++ b/os/hal/platforms/LPC111x/platform.mk @@ -1,6 +1,7 @@ # List of all the LPC111x platform files. PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/LPC111x/hal_lld.c \ - ${CHIBIOS}/os/hal/platforms/LPC111x/pal_lld.c + ${CHIBIOS}/os/hal/platforms/LPC111x/pal_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC111x/serial_lld.c # Required include directories PLATFORMINC = ${CHIBIOS}/os/hal/platforms/LPC111x diff --git a/os/hal/platforms/LPC111x/serial_lld.c b/os/hal/platforms/LPC111x/serial_lld.c new file mode 100644 index 000000000..8b8fb5fd1 --- /dev/null +++ b/os/hal/platforms/LPC111x/serial_lld.c @@ -0,0 +1,331 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file LPC111x/serial_lld.c + * @brief LPC111x low level serial driver code. + * + * @addtogroup LPC111x_SERIAL + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if CH_HAL_USE_SERIAL || defined(__DOXYGEN__) + +#define IIR_SRC_MASK 0x0F +#define IIR_SRC_NONE 0x01 +#define IIR_SRC_TX 0x02 +#define IIR_SRC_RX 0x04 +#define IIR_SRC_ERROR 0x06 +#define IIR_SRC_TIMEOUT 0x0C + +#define IER_RBR 1 +#define IER_THRE 2 +#define IER_STATUS 4 + +#define IIR_INT_PENDING 1 + +#define LCR_WL5 0 +#define LCR_WL6 1 +#define LCR_WL7 2 +#define LCR_WL8 3 +#define LCR_STOP1 0 +#define LCR_STOP2 4 +#define LCR_NOPARITY 0 +#define LCR_PARITYODD 0x08 +#define LCR_PARITYEVEN 0x18 +#define LCR_PARITYONE 0x28 +#define LCR_PARITYZERO 0x38 +#define LCR_BREAK_ON 0x40 +#define LCR_DLAB 0x80 + +#define FCR_ENABLE 1 +#define FCR_RXRESET 2 +#define FCR_TXRESET 4 +#define FCR_TRIGGER0 0 +#define FCR_TRIGGER1 0x40 +#define FCR_TRIGGER2 0x80 +#define FCR_TRIGGER3 0xC0 + +#define LSR_RBR_FULL 1 +#define LSR_OVERRUN 2 +#define LSR_PARITY 4 +#define LSR_FRAMING 8 +#define LSR_BREAK 0x10 +#define LSR_THRE 0x20 +#define LSR_TEMT 0x40 +#define LSR_RXFE 0x80 + +#define TER_ENABLE 0x80 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if USE_LPC111x_UART0 || defined(__DOXYGEN__) +/** @brief UART0 serial driver identifier.*/ +SerialDriver SD1; +#endif + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/** @brief Driver default configuration.*/ +static const SerialConfig default_config = { + SERIAL_DEFAULT_BITRATE, + LCR_WL8 | LCR_STOP1 | LCR_NOPARITY, + FCR_TRIGGER0 +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief UART initialization. + * + * @param[in] sdp communication channel associated to the UART + */ +static void uart_init(SerialDriver *sdp) { + LPC_UART_TypeDef *u = sdp->uart; + + uint32_t div = PCLK / (sdp->config->sc_speed << 4); + u->UART_LCR = sdp->config->sc_lcr | LCR_DLAB; + u->UART_DLL = div; + u->UART_DLM = div >> 8; + u->UART_LCR = sdp->config->sc_lcr; + u->UART_FCR = FCR_ENABLE | FCR_RXRESET | FCR_TXRESET | sdp->config->sc_fcr; + u->UART_ACR = 0; + u->UART_FDR = 0x10; + u->UART_TER = TER_ENABLE; + u->UART_IER = IER_RBR | IER_STATUS; +} + +/** + * @brief UART de-initialization. + * + * @param[in] u pointer to an UART I/O block + */ +static void uart_deinit(UART *u) { + + u->UART_LCR = LCR_DLAB; + u->UART_DLL = 1; + u->UART_DLM = 0; + u->UART_LCR = 0; + u->UART_FDR = 0x10; + u->UART_IER = 0; + u->UART_FCR = FCR_RXRESET | FCR_TXRESET; + u->UART_ACR = 0; + u->UART_TER = TER_ENABLE; +} + +/** + * @brief Error handling routine. + * + * @param[in] sdp communication channel associated to the UART + * @param[in] err UART LSR register value + */ +static void set_error(SerialDriver *sdp, IOREG32 err) { + sdflags_t sts = 0; + + if (err & LSR_OVERRUN) + sts |= SD_OVERRUN_ERROR; + if (err & LSR_PARITY) + sts |= SD_PARITY_ERROR; + if (err & LSR_FRAMING) + sts |= SD_FRAMING_ERROR; + if (err & LSR_BREAK) + sts |= SD_BREAK_DETECTED; + chSysLockFromIsr(); + sdAddFlagsI(sdp, sts); + chSysUnlockFromIsr(); +} + +/** + * @brief Common IRQ handler. + * @note Tries hard to clear all the pending interrupt sources, we don't + * want to go through the whole ISR and have another interrupt soon + * after. + * + * @param[in] u pointer to an UART I/O block + * @param[in] sdp communication channel associated to the UART + */ +static void serve_interrupt(SerialDriver *sdp) { + UART *u = sdp->uart; + + while (TRUE) { + switch (u->UART_IIR & IIR_SRC_MASK) { + case IIR_SRC_NONE: + return; + case IIR_SRC_ERROR: + set_error(sdp, u->UART_LSR); + break; + case IIR_SRC_TIMEOUT: + case IIR_SRC_RX: + chSysLockFromIsr(); + if (chIQIsEmpty(&sdp->iqueue)) + chEvtBroadcastI(&sdp->ievent); + chSysUnlockFromIsr(); + while (u->UART_LSR & LSR_RBR_FULL) { + chSysLockFromIsr(); + if (chIQPutI(&sdp->iqueue, u->UART_RBR) < Q_OK) + sdAddFlagsI(sdp, SD_OVERRUN_ERROR); + chSysUnlockFromIsr(); + } + break; + case IIR_SRC_TX: + { + int i = LPC214x_UART_FIFO_PRELOAD; + do { + msg_t b; + + chSysLockFromIsr(); + b = chOQGetI(&sdp->oqueue); + chSysUnlockFromIsr(); + if (b < Q_OK) { + u->UART_IER &= ~IER_THRE; + chSysLockFromIsr(); + chEvtBroadcastI(&sdp->oevent); + chSysUnlockFromIsr(); + break; + } + u->UART_THR = b; + } while (--i); + } + break; + default: + (void) u->UART_THR; + (void) u->UART_RBR; + } + } +} + +/** + * @brief Attempts a TX FIFO preload. + */ +static void preload(SerialDriver *sdp) { + UART *u = sdp->uart; + + if (u->UART_LSR & LSR_THRE) { + int i = LPC214x_UART_FIFO_PRELOAD; + do { + msg_t b = chOQGetI(&sdp->oqueue); + if (b < Q_OK) { + chEvtBroadcastI(&sdp->oevent); + return; + } + u->UART_THR = b; + } while (--i); + } + u->UART_IER |= IER_THRE; +} + +/** + * @brief Driver SD1 output notification. + */ +#if USE_LPC111x_UART0 || defined(__DOXYGEN__) +static void notify1(void) { + + preload(&SD1); +} +#endif + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief UART0 IRQ handler. + */ +#if USE_LPC111x_UART0 || defined(__DOXYGEN__) +CH_IRQ_HANDLER(UART0IrqHandler) { + + CH_IRQ_PROLOGUE(); + + serve_interrupt(&SD1); + VICVectAddr = 0; + + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level serial driver initialization. + */ +void sd_lld_init(void) { + +#if USE_LPC111x_UART0 + sdObjectInit(&SD1, NULL, notify1); + SD1.uart = U0Base; + SetVICVector(UART0IrqHandler, LPC214x_UART0_PRIORITY, SOURCE_UART0); +#endif +} + +/** + * @brief Low level serial driver configuration and (re)start. + * + * @param[in] sdp pointer to a @p SerialDriver object + */ +void sd_lld_start(SerialDriver *sdp) { + + if (sdp->config == NULL) + sdp->config = &default_config; + + if (sdp->state == SD_STOP) { +#if USE_LPC111x_UART0 + if (&SD1 == sdp) { + PCONP = (PCONP & PCALL) | PCUART0; + VICIntEnable = INTMASK(SOURCE_UART0); + } +#endif + } + uart_init(sdp); +} + +/** + * @brief Low level serial driver stop. + * @details De-initializes the UART, stops the associated clock, resets the + * interrupt vector. + * + * @param[in] sdp pointer to a @p SerialDriver object + */ +void sd_lld_stop(SerialDriver *sdp) { + + if (sdp->state == SD_READY) { + uart_deinit(sdp->uart); +#if USE_LPC111x_UART0 + if (&SD1 == sdp) { + PCONP = (PCONP & PCALL) & ~PCUART0; + VICIntEnClear = INTMASK(SOURCE_UART0); + return; + } +#endif + } +} + +#endif /* CH_HAL_USE_SERIAL */ + +/** @} */ diff --git a/os/hal/platforms/LPC111x/serial_lld.h b/os/hal/platforms/LPC111x/serial_lld.h new file mode 100644 index 000000000..f98e19050 --- /dev/null +++ b/os/hal/platforms/LPC111x/serial_lld.h @@ -0,0 +1,158 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file LPC111x/serial_lld.h + * @brief LPC111x low level serial driver header. + * + * @addtogroup LPC111x_SERIAL + * @{ + */ + +#ifndef _SERIAL_LLD_H_ +#define _SERIAL_LLD_H_ + +#if CH_HAL_USE_SERIAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief UART0 driver enable switch. + * @details If set to @p TRUE the support for UART0 is included. + * @note The default is @p TRUE . + */ +#if !defined(USE_LPC111x_UART0) || defined(__DOXYGEN__) +#define USE_LPC111x_UART0 TRUE +#endif + +/** + * @brief FIFO preload parameter. + * @details Configuration parameter, this values defines how many bytes are + * preloaded in the HW transmit FIFO for each interrupt, the maximum value is + * 16 the minimum is 1. + * @note An high value reduces the number of interrupts generated but can + * also increase the worst case interrupt response time because the + * preload loops. + */ +#if !defined(LPC111x_UART_FIFO_PRELOAD) || defined(__DOXYGEN__) +#define LPC111x_UART_FIFO_PRELOAD 16 +#endif + +/** + * @brief UART0 interrupt priority level setting. + */ +#if !defined(LPC111x_UART0_PRIORITY) || defined(__DOXYGEN__) +#define LPC111x_UART0_PRIORITY 3 +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (LPC111x_UART_FIFO_PRELOAD < 1) || (LPC111x_UART_FIFO_PRELOAD > 16) +#error "invalid LPC214x_UART_FIFO_PRELOAD setting" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Serial Driver condition flags type. + */ +typedef uint32_t sdflags_t; + +/** + * @brief LPC214x 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. + */ +typedef struct { + /** + * @brief Bit rate. + */ + uint32_t sc_speed; + /** + * @brief Initialization value for the LCR register. + */ + uint32_t sc_lcr; + /** + * @brief Initialization value for the FCR register. + */ + uint32_t sc_fcr; +} SerialConfig; + +/** + * @brief @p SerialDriver specific data. + */ +#define _serial_driver_data \ + _base_asynchronous_channel_data \ + /* Driver state.*/ \ + sdstate_t state; \ + /* Current configuration data.*/ \ + const SerialConfig *config; \ + /* Input queue.*/ \ + InputQueue iqueue; \ + /* Output queue.*/ \ + OutputQueue oqueue; \ + /* Status Change @p EventSource.*/ \ + EventSource sevent; \ + /* I/O driver status flags.*/ \ + sdflags_t flags; \ + /* Input circular buffer.*/ \ + uint8_t ib[SERIAL_BUFFERS_SIZE]; \ + /* Output circular buffer.*/ \ + uint8_t ob[SERIAL_BUFFERS_SIZE]; \ + /* End of the mandatory fields.*/ \ + /* Pointer to the USART registers block.*/ \ + LPC_UART_TypeDef *uart; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if USE_LPC111x_UART0 && !defined(__DOXYGEN__) +extern SerialDriver SD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sd_lld_init(void); + void sd_lld_start(SerialDriver *sdp); + void sd_lld_stop(SerialDriver *sdp); +#ifdef __cplusplus +} +#endif + +#endif /* CH_HAL_USE_SERIAL */ + +#endif /* _SERIAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC214x/serial_lld.c b/os/hal/platforms/LPC214x/serial_lld.c index 673c737f3..d79ba22d2 100644 --- a/os/hal/platforms/LPC214x/serial_lld.c +++ b/os/hal/platforms/LPC214x/serial_lld.c @@ -208,7 +208,6 @@ static void notify1(void) { } #endif - /** * @brief Driver SD2 output notification. */ @@ -238,7 +237,6 @@ CH_IRQ_HANDLER(UART0IrqHandler) { } #endif - /** * @brief UART1 IRQ handler. */ @@ -254,7 +252,6 @@ CH_IRQ_HANDLER(UART1IrqHandler) { } #endif - /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ diff --git a/os/hal/platforms/LPC214x/serial_lld.h b/os/hal/platforms/LPC214x/serial_lld.h index 34da8c8d4..6d47f9d95 100644 --- a/os/hal/platforms/LPC214x/serial_lld.h +++ b/os/hal/platforms/LPC214x/serial_lld.h @@ -64,7 +64,7 @@ * also increase the worst case interrupt response time because the * preload loops. */ -#if !defined(UART_FIFO_PRELOAD) || defined(__DOXYGEN__) +#if !defined(LPC214x_UART_FIFO_PRELOAD) || defined(__DOXYGEN__) #define LPC214x_UART_FIFO_PRELOAD 16 #endif -- cgit v1.2.3