From 0320aa53143ea1bb908c90c599fa6bdd3fce2c46 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sun, 12 Oct 2014 09:29:12 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@7387 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/ports/LPC/LPC214x/hal_lld.c | 116 ++++++++++++ os/hal/ports/LPC/LPC214x/hal_lld.h | 83 ++++++++ os/hal/ports/LPC/LPC214x/pal_lld.c | 111 +++++++++++ os/hal/ports/LPC/LPC214x/pal_lld.h | 261 +++++++++++++++++++++++++ os/hal/ports/LPC/LPC214x/platform.mk | 9 + os/hal/ports/LPC/LPC214x/serial_lld.c | 346 ++++++++++++++++++++++++++++++++++ os/hal/ports/LPC/LPC214x/serial_lld.h | 163 ++++++++++++++++ os/hal/ports/LPC/LPC214x/spi_lld.c | 337 +++++++++++++++++++++++++++++++++ os/hal/ports/LPC/LPC214x/spi_lld.h | 207 ++++++++++++++++++++ os/hal/ports/LPC/LPC214x/vic.c | 64 +++++++ os/hal/ports/LPC/LPC214x/vic.h | 39 ++++ 11 files changed, 1736 insertions(+) create mode 100644 os/hal/ports/LPC/LPC214x/hal_lld.c create mode 100644 os/hal/ports/LPC/LPC214x/hal_lld.h create mode 100644 os/hal/ports/LPC/LPC214x/pal_lld.c create mode 100644 os/hal/ports/LPC/LPC214x/pal_lld.h create mode 100644 os/hal/ports/LPC/LPC214x/platform.mk create mode 100644 os/hal/ports/LPC/LPC214x/serial_lld.c create mode 100644 os/hal/ports/LPC/LPC214x/serial_lld.h create mode 100644 os/hal/ports/LPC/LPC214x/spi_lld.c create mode 100644 os/hal/ports/LPC/LPC214x/spi_lld.h create mode 100644 os/hal/ports/LPC/LPC214x/vic.c create mode 100644 os/hal/ports/LPC/LPC214x/vic.h (limited to 'os/hal/ports/LPC/LPC214x') diff --git a/os/hal/ports/LPC/LPC214x/hal_lld.c b/os/hal/ports/LPC/LPC214x/hal_lld.c new file mode 100644 index 000000000..cb1aaf3cf --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/hal_lld.c @@ -0,0 +1,116 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/hal_lld.c + * @brief LPC214x HAL subsystem low level driver source. + * + * @addtogroup HAL + * @{ + */ + +#include "hal.h" + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/* + * Non-vectored IRQs handler, the default action can be overridden by + * redefining the @p LPC214x_NON_VECTORED_IRQ_HOOK() hook macro. + */ +static CH_IRQ_HANDLER(irq_handler) { + + CH_IRQ_PROLOGUE(); + + LPC214x_NON_VECTORED_IRQ_HOOK(); + + VICVectAddr = 0; + CH_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level HAL driver initialization. + * + * @notapi + */ +void hal_lld_init(void) { + + vic_init(); + VICDefVectAddr = (IOREG32)irq_handler; + +} + +/** + * @brief LPC214x clocks and PLL initialization. + * @note All the involved constants come from the file @p board.h. + * @note This function must be invoked only after the system reset. + * + * @special + */ +void lpc214x_clock_init(void) { + + /* + * All peripherals clock disabled by default in order to save power. + */ + PCONP = PCRTC | PCTIM0; + + /* + * MAM setup. + */ + MAMTIM = 0x3; /* 3 cycles for flash accesses. */ + MAMCR = 0x2; /* MAM fully enabled. */ + + /* + * PLL setup for Fosc=12MHz and CCLK=48MHz. + * P=2 M=3. + */ + PLL *pll = PLL0Base; + pll->PLL_CFG = 0x23; /* P and M values. */ + pll->PLL_CON = 0x1; /* Enables the PLL 0. */ + pll->PLL_FEED = 0xAA; + pll->PLL_FEED = 0x55; + while (!(pll->PLL_STAT & 0x400)) + ; /* Wait for PLL lock. */ + + pll->PLL_CON = 0x3; /* Connects the PLL. */ + pll->PLL_FEED = 0xAA; + pll->PLL_FEED = 0x55; + + /* + * VPB setup. + * PCLK = CCLK / 4. + */ + VPBDIV = VPD_D4; +} + +/** @} */ diff --git a/os/hal/ports/LPC/LPC214x/hal_lld.h b/os/hal/ports/LPC/LPC214x/hal_lld.h new file mode 100644 index 000000000..8385a99f5 --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/hal_lld.h @@ -0,0 +1,83 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/hal_lld.h + * @brief LPC214x HAL subsystem low level driver header. + * + * @addtogroup HAL + * @{ + */ + +#ifndef _HAL_LLD_H_ +#define _HAL_LLD_H_ + +#include "lpc214x.h" +#include "vic.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Defines the support for realtime counters in the HAL. + */ +#define HAL_IMPLEMENTS_COUNTERS FALSE + +/** + * @brief Platform name. + */ +#define PLATFORM_NAME "LPC214x" + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief Default action for the non vectored IRQ handler, nothing. + */ +#if !defined(LPC214x_NON_VECTORED_IRQ_HOOK) || defined(__DOXYGEN__) +#define LPC214x_NON_VECTORED_IRQ_HOOK() +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void hal_lld_init(void); + void lpc214x_clock_init(void); +#ifdef __cplusplus +} +#endif + +#endif /* _HAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/LPC/LPC214x/pal_lld.c b/os/hal/ports/LPC/LPC214x/pal_lld.c new file mode 100644 index 000000000..4fe66e770 --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/pal_lld.c @@ -0,0 +1,111 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/pal_lld.c + * @brief LPC214x FIO low level driver code. + * + * @addtogroup PAL + * @{ + */ + +#include "hal.h" + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief LPC214x I/O ports configuration. + * @details FIO units and PINSEL registers initialization. + * + * @param[in] config the LPC214x ports configuration + * + * @notapi + */ +void _pal_lld_init(const PALConfig *config) { + + /* Enables the access through the fast registers.*/ + SCS = 3; + + /* I/O pads initial assignment, device drivers may change this setup at a + * later time.*/ + PINSEL0 = config->pinsel0; + PINSEL1 = config->pinsel1; + PINSEL2 = config->pinsel2; + + /* I/O pads direction initial setting.*/ + FIO0Base->FIO_MASK = 0; + FIO0Base->FIO_PIN = config->P0Data.pin; + FIO0Base->FIO_DIR = config->P0Data.dir; + FIO1Base->FIO_MASK = 0; + FIO1Base->FIO_PIN = config->P1Data.pin; + FIO1Base->FIO_DIR = config->P1Data.dir; +} + +/** + * @brief Pads mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with + * high state. + * @note This function does not alter the @p PINSELx registers. Alternate + * functions setup must be handled by device-specific code. + * + * @param[in] port the port identifier + * @param[in] mask the group mask + * @param[in] mode the mode + * + * @notapi + */ +void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode) { + + switch (mode) { + case PAL_MODE_RESET: + case PAL_MODE_INPUT: + port->FIO_DIR &= ~mask; + break; + case PAL_MODE_UNCONNECTED: + port->FIO_PIN |= mask; + case PAL_MODE_OUTPUT_PUSHPULL: + port->FIO_DIR |= mask; + break; + } +} + +#endif /* HAL_USE_PAL */ + +/** @} */ diff --git a/os/hal/ports/LPC/LPC214x/pal_lld.h b/os/hal/ports/LPC/LPC214x/pal_lld.h new file mode 100644 index 000000000..fa91a4b05 --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/pal_lld.h @@ -0,0 +1,261 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/pal_lld.h + * @brief LPC214x FIO low level driver header. + * + * @addtogroup PAL + * @{ + */ + +#ifndef _PAL_LLD_H_ +#define _PAL_LLD_H_ + +#if HAL_USE_PAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Unsupported modes and specific modes */ +/*===========================================================================*/ + +#undef PAL_MODE_INPUT_PULLUP +#undef PAL_MODE_INPUT_PULLDOWN +#undef PAL_MODE_OUTPUT_OPENDRAIN + +/*===========================================================================*/ +/* I/O Ports Types and constants. */ +/*===========================================================================*/ + +/** + * @brief FIO port setup info. + */ +typedef struct { + /** Initial value for FIO_PIN register.*/ + uint32_t pin; + /** Initial value for FIO_DIR register.*/ + uint32_t dir; +} lpc214x_fio_setup_t; + +/** + * @brief LPC214x FIO static initializer. + * @details An instance of this structure must be passed to @p palInit() at + * system startup time in order to initialize the digital I/O + * subsystem. This represents only the initial setup, specific pads + * or whole ports can be reprogrammed at later time. + */ +typedef struct { + /** @brief PINSEL0 initial value.*/ + uint32_t pinsel0; + /** @brief PINSEL1 initial value.*/ + uint32_t pinsel1; + /** @brief PINSEL2 initial value.*/ + uint32_t pinsel2; + /** @brief Port 0 setup data.*/ + lpc214x_fio_setup_t P0Data; + /** @brief Port 1 setup data.*/ + lpc214x_fio_setup_t P1Data; +} PALConfig; + +/** + * @brief Width, in bits, of an I/O port. + */ +#define PAL_IOPORTS_WIDTH 32 + +/** + * @brief Whole port mask. + * @details This macro specifies all the valid bits into a port. + */ +#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFFFFFF) + +/** + * @brief Digital I/O port sized unsigned type. + */ +typedef uint32_t ioportmask_t; + +/** + * @brief Digital I/O modes. + */ +typedef uint32_t iomode_t; + +/** + * @brief Port Identifier. + */ +typedef FIO * ioportid_t; + +/*===========================================================================*/ +/* I/O Ports Identifiers. */ +/*===========================================================================*/ + +/** + * @brief FIO port 0 identifier. + */ +#define IOPORT1 FIO0Base + +/** + * @brief FIO port 1 identifier. + */ +#define IOPORT2 FIO1Base + +/*===========================================================================*/ +/* Implementation, some of the following macros could be implemented as */ +/* functions, if so please put them in pal_lld.c. */ +/*===========================================================================*/ + +/** + * @brief FIO subsystem initialization. + * @details Enables the access through the fast registers. + * + * @notapi + */ +#define pal_lld_init(config) _pal_lld_init(config) + +/** + * @brief Reads an I/O port. + * @details This function is implemented by reading the FIO PIN register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @return The port bits. + * + * @notapi + */ +#define pal_lld_readport(port) ((port)->FIO_PIN) + +/** + * @brief Reads the output latch. + * @details This function is implemented by reading the FIO SET register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @return The latched logical states. + * + * @notapi + */ +#define pal_lld_readlatch(port) ((port)->FIO_SET) + +/** + * @brief Writes a bits mask on a I/O port. + * @details This function is implemented by writing the FIO PIN register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] bits bits to be written on the specified port + * + * @notapi + */ +#define pal_lld_writeport(port, bits) ((port)->FIO_PIN = (bits)) + +/** + * @brief Sets a bits mask on a I/O port. + * @details This function is implemented by writing the FIO SET register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] bits bits to be ORed on the specified port + * + * @notapi + */ +#define pal_lld_setport(port, bits) ((port)->FIO_SET = (bits)) + +/** + * @brief Clears a bits mask on a I/O port. + * @details This function is implemented by writing the FIO CLR register, the + * implementation has no side effects. + * + * @param[in] port port identifier + * @param[in] bits bits to be cleared on the specified port + * + * @notapi + */ +#define pal_lld_clearport(port, bits) ((port)->FIO_CLR = (bits)) + +/** + * @brief Writes a value on an I/O bus. + * @details This function is implemented by writing the FIO PIN and MASK + * registers, the implementation is not atomic because the multiple + * accesses. + * + * @param[in] port port identifier + * @param[in] mask group mask, a logical AND is performed on the + * output data + * @param[in] offset the group bit offset within the port + * @param[in] bits bits to be written. Values exceeding the group + * width are masked. + * + * @notapi + */ +#define pal_lld_writegroup(port, mask, offset, bits) \ + ((port)->FIO_MASK = ~((mask) << (offset)), \ + (port)->FIO_PIN = (bits) << (offset), \ + (port)->FIO_MASK = 0) + +/** + * @brief Pads group mode setup. + * @details This function programs a pads group belonging to the same port + * with the specified mode. + * @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with + * high state. + * @note This function does not alter the @p PINSELx registers. Alternate + * functions setup must be handled by device-specific code. + * + * @param[in] port port identifier + * @param[in] mask group mask + * @param[in] offset group bit offset within the port + * @param[in] mode group mode + * + * @notapi + */ +#define pal_lld_setgroupmode(port, mask, offset, mode) \ + _pal_lld_setgroupmode(port, mask << offset, mode) + +/** + * @brief Writes a logical state on an output pad. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] bit logical value, the value must be @p PAL_LOW or + * @p PAL_HIGH + * + * @notapi + */ +#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit) + +/** + * @brief FIO port setup. + * @details This function programs the pins direction within a port. + * + * @notapi + */ +#define pal_lld_lpc214x_set_direction(port, dir) ((port)->FIO_DIR = (dir)) + +extern const PALConfig pal_default_config; + +#ifdef __cplusplus +extern "C" { +#endif + void _pal_lld_init(const PALConfig *config); + void _pal_lld_setgroupmode(ioportid_t port, + ioportmask_t mask, + iomode_t mode); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_PAL */ + +#endif /* _PAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/LPC/LPC214x/platform.mk b/os/hal/ports/LPC/LPC214x/platform.mk new file mode 100644 index 000000000..bd6b2761e --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/platform.mk @@ -0,0 +1,9 @@ +# List of all the LPC214x platform files. +PLATFORMSRC = ${CHIBIOS}/os/hal/ports/LPC/LPC214x/hal_lld.c \ + ${CHIBIOS}/os/hal/ports/LPC/LPC214x/pal_lld.c \ + ${CHIBIOS}/os/hal/ports/LPC/LPC214x/serial_lld.c \ + ${CHIBIOS}/os/hal/ports/LPC/LPC214x/spi_lld.c \ + ${CHIBIOS}/os/hal/ports/LPC/LPC214x/vic.c + +# Required include directories +PLATFORMINC = ${CHIBIOS}/os/hal/ports/LPC/LPC214x diff --git a/os/hal/ports/LPC/LPC214x/serial_lld.c b/os/hal/ports/LPC/LPC214x/serial_lld.c new file mode 100644 index 000000000..ed5ba96d8 --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/serial_lld.c @@ -0,0 +1,346 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/serial_lld.c + * @brief LPC214x low level serial driver code. + * + * @addtogroup SERIAL + * @{ + */ + +#include "hal.h" + +#if HAL_USE_SERIAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if USE_LPC214x_UART0 || defined(__DOXYGEN__) +/** @brief UART0 serial driver identifier.*/ +SerialDriver SD1; +#endif + +#if USE_LPC214x_UART1 || defined(__DOXYGEN__) +/** @brief UART1 serial driver identifier.*/ +SerialDriver SD2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** @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 + * @param[in] config the architecture-dependent serial driver configuration + */ +static void uart_init(SerialDriver *sdp, const SerialConfig *config) { + UART *u = sdp->uart; + + uint32_t div = PCLK / (config->sc_speed << 4); + u->UART_LCR = config->sc_lcr | LCR_DLAB; + u->UART_DLL = div; + u->UART_DLM = div >> 8; + u->UART_LCR = config->sc_lcr; + u->UART_FCR = FCR_ENABLE | FCR_RXRESET | FCR_TXRESET | 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) { + eventflags_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(); + chnAddFlagsI(sdp, sts); + chSysUnlockFromISR(); +} + +#if defined(__GNUC__) +__attribute__((noinline)) +#endif +/** + * @brief Common IRQ handler. + * @note Tries hard to clear all the pending interrupt sources, we dont want + * to go through the whole ISR and have another interrupt soon after. + * + * @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 (chIQIsEmptyI(&sdp->iqueue)) + chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); + chSysUnlockFromISR(); + while (u->UART_LSR & LSR_RBR_FULL) { + chSysLockFromISR(); + if (chIQPutI(&sdp->iqueue, u->UART_RBR) < Q_OK) + chnAddFlagsI(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(); + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + 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) { + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + return; + } + u->UART_THR = b; + } while (--i); + } + u->UART_IER |= IER_THRE; +} + +/** + * @brief Driver SD1 output notification. + */ +#if USE_LPC214x_UART0 || defined(__DOXYGEN__) +static void notify1(io_queue_t *qp) { + + (void)qp; + preload(&SD1); +} +#endif + +/** + * @brief Driver SD2 output notification. + */ +#if USE_LPC214x_UART1 || defined(__DOXYGEN__) +static void notify2(io_queue_t *qp) { + + (void)qp; + preload(&SD2); +} +#endif + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief UART0 IRQ handler. + * + * @isr + */ +#if USE_LPC214x_UART0 || defined(__DOXYGEN__) +CH_IRQ_HANDLER(UART0IrqHandler) { + + CH_IRQ_PROLOGUE(); + + serve_interrupt(&SD1); + VICVectAddr = 0; + + CH_IRQ_EPILOGUE(); +} +#endif + +/** + * @brief UART1 IRQ handler. + * + * @isr + */ +#if USE_LPC214x_UART1 || defined(__DOXYGEN__) +CH_IRQ_HANDLER(UART1IrqHandler) { + + CH_IRQ_PROLOGUE(); + + serve_interrupt(&SD2); + VICVectAddr = 0; + + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level serial driver initialization. + * + * @notapi + */ +void sd_lld_init(void) { + +#if USE_LPC214x_UART0 + sdObjectInit(&SD1, NULL, notify1); + SD1.uart = U0Base; + SetVICVector(UART0IrqHandler, LPC214x_UART0_PRIORITY, SOURCE_UART0); +#endif +#if USE_LPC214x_UART1 + sdObjectInit(&SD2, NULL, notify2); + SD2.uart = U1Base; + SetVICVector(UART1IrqHandler, LPC214x_UART1_PRIORITY, SOURCE_UART1); +#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 USE_LPC214x_UART0 + if (&SD1 == sdp) { + PCONP = (PCONP & PCALL) | PCUART0; + VICIntEnable = INTMASK(SOURCE_UART0); + } +#endif +#if USE_LPC214x_UART1 + if (&SD2 == sdp) { + PCONP = (PCONP & PCALL) | PCUART1; + VICIntEnable = INTMASK(SOURCE_UART1); + } +#endif + } + uart_init(sdp, config); +} + +/** + * @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 + * + * @notapi + */ +void sd_lld_stop(SerialDriver *sdp) { + + if (sdp->state == SD_READY) { + uart_deinit(sdp->uart); +#if USE_LPC214x_UART0 + if (&SD1 == sdp) { + PCONP = (PCONP & PCALL) & ~PCUART0; + VICIntEnClear = INTMASK(SOURCE_UART0); + return; + } +#endif +#if USE_LPC214x_UART1 + if (&SD2 == sdp) { + PCONP = (PCONP & PCALL) & ~PCUART1; + VICIntEnClear = INTMASK(SOURCE_UART1); + return; + } +#endif + } +} + +#endif /* HAL_USE_SERIAL */ + +/** @} */ diff --git a/os/hal/ports/LPC/LPC214x/serial_lld.h b/os/hal/ports/LPC/LPC214x/serial_lld.h new file mode 100644 index 000000000..d498f7991 --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/serial_lld.h @@ -0,0 +1,163 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/serial_lld.h + * @brief LPC214x low level serial driver header. + * + * @addtogroup SERIAL + * @{ + */ + +#ifndef _SERIAL_LLD_H_ +#define _SERIAL_LLD_H_ + +#if 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_LPC214x_UART0) || defined(__DOXYGEN__) +#define USE_LPC214x_UART0 TRUE +#endif + +/** + * @brief UART1 driver enable switch. + * @details If set to @p TRUE the support for UART1 is included. + * @note The default is @p TRUE. + */ +#if !defined(USE_LPC214x_UART1) || defined(__DOXYGEN__) +#define USE_LPC214x_UART1 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(LPC214x_UART_FIFO_PRELOAD) || defined(__DOXYGEN__) +#define LPC214x_UART_FIFO_PRELOAD 16 +#endif + +/** + * @brief UART0 interrupt priority level setting. + */ +#if !defined(LPC214x_UART0_PRIORITY) || defined(__DOXYGEN__) +#define LPC214x_UART0_PRIORITY 1 +#endif + +/** + * @brief UART1 interrupt priority level setting. + */ +#if !defined(LPC214x_UART1_PRIORITY) || defined(__DOXYGEN__) +#define LPC214x_UART1_PRIORITY 2 +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (LPC214x_UART_FIFO_PRELOAD < 1) || (LPC214x_UART_FIFO_PRELOAD > 16) +#error "invalid LPC214x_UART_FIFO_PRELOAD setting" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @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; \ + /* 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.*/ \ + /* Pointer to the USART registers block.*/ \ + UART *uart; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if USE_LPC214x_UART0 && !defined(__DOXYGEN__) +extern SerialDriver SD1; +#endif +#if USE_LPC214x_UART1 && !defined(__DOXYGEN__) +extern SerialDriver SD2; +#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 */ + +#endif /* _SERIAL_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/LPC/LPC214x/spi_lld.c b/os/hal/ports/LPC/LPC214x/spi_lld.c new file mode 100644 index 000000000..398518f34 --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/spi_lld.c @@ -0,0 +1,337 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/spi_lld.c + * @brief LPC214x low level SPI driver code. + * + * @addtogroup SPI + * @{ + */ + +#include "hal.h" + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +#if LPC214x_SPI_USE_SSP || defined(__DOXYGEN__) +/** @brief SPI1 driver identifier.*/ +SPIDriver SPID1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Preloads the transmit FIFO. + * + * @param[in] spip pointer to the @p SPIDriver object + */ +static void ssp_fifo_preload(SPIDriver *spip) { + SSP *ssp = spip->ssp; + uint32_t n = spip->txcnt > LPC214x_SSP_FIFO_DEPTH ? + LPC214x_SSP_FIFO_DEPTH : spip->txcnt; + + while(((ssp->SSP_SR & SR_TNF) != 0) && (n > 0)) { + if (spip->txptr != NULL) { + if ((ssp->SSP_CR0 & CR0_DSSMASK) > CR0_DSS8BIT) + ssp->SSP_DR = *(uint16_t *)spip->txptr++; + else + ssp->SSP_DR = *(uint8_t *)spip->txptr++; + } + else + ssp->SSP_DR = 0xFFFFFFFF; + n--; + spip->txcnt--; + } +} + +#if defined(__GNUC__) +__attribute__((noinline)) +#endif +/** + * @brief Common IRQ handler. + * + * @param[in] spip pointer to the @p SPIDriver object + */ +static void serve_interrupt(SPIDriver *spip) { + SSP *ssp = spip->ssp; + + if ((ssp->SSP_MIS & MIS_ROR) != 0) { + /* The overflow condition should never happen because priority is given + to receive but a hook macro is provided anyway...*/ + LPC214x_SPI_SSP_ERROR_HOOK(); + } + ssp->SSP_ICR = ICR_RT | ICR_ROR; + while ((ssp->SSP_SR & SR_RNE) != 0) { + if (spip->rxptr != NULL) { + if ((ssp->SSP_CR0 & CR0_DSSMASK) > CR0_DSS8BIT) + *(uint16_t *)spip->rxptr++ = ssp->SSP_DR; + else + *(uint8_t *)spip->rxptr++ = ssp->SSP_DR; + } + else + (void)ssp->SSP_DR; + if (--spip->rxcnt == 0) { + osalDbgAssert(spip->txcnt == 0, "counter out of synch"); + /* Stops the IRQ sources.*/ + ssp->SSP_IMSC = 0; + /* Portable SPI ISR code defined in the high level driver, note, it is + a macro.*/ + _spi_isr_code(spip); + return; + } + } + ssp_fifo_preload(spip); + if (spip->txcnt == 0) + ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_RX; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if LPC214x_SPI_USE_SSP || defined(__DOXYGEN__) +/** + * @brief SPI1 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(SPI1IrqHandler) { + + CH_IRQ_PROLOGUE(); + + serve_interrupt(&SPID1); + VICVectAddr = 0; + + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SPI driver initialization. + * + * @notapi + */ +void spi_lld_init(void) { + +#if LPC214x_SPI_USE_SSP + spiObjectInit(&SPID1); + SPID1.ssp = SSPBase; + SetVICVector(SPI1IrqHandler, LPC214x_SPI_SSP_IRQ_PRIORITY, SOURCE_SPI1); +#endif +} + +/** + * @brief Configures and activates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_start(SPIDriver *spip) { + + if (spip->state == SPI_STOP) { + /* Clock activation.*/ +#if LPC214x_SPI_USE_SSP + if (&SPID1 == spip) { + PCONP = (PCONP & PCALL) | PCSPI1; + VICIntEnable = INTMASK(SOURCE_SPI1); + } +#endif + } + /* Configuration.*/ + spip->ssp->SSP_CR1 = 0; + /* Emptying the receive FIFO, it happens to not be empty while debugging.*/ + while (spip->ssp->SSP_SR & SR_RNE) + (void) spip->ssp->SSP_DR; + spip->ssp->SSP_ICR = ICR_RT | ICR_ROR; + spip->ssp->SSP_CR0 = spip->config->cr0; + spip->ssp->SSP_CPSR = spip->config->cpsr; + spip->ssp->SSP_CR1 = CR1_SSE; +} + +/** + * @brief Deactivates the SPI peripheral. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_stop(SPIDriver *spip) { + + if (spip->state != SPI_STOP) { + spip->ssp->SSP_CR1 = 0; + spip->ssp->SSP_CR0 = 0; + spip->ssp->SSP_CPSR = 0; +#if LPC214x_SPI_USE_SSP + if (&SPID1 == spip) { + PCONP = (PCONP & PCALL) & ~PCSPI1; + VICIntEnClear = INTMASK(SOURCE_SPI1); + } +#endif + } +} + +/** + * @brief Asserts the slave select signal and prepares for transfers. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_select(SPIDriver *spip) { + + palClearPad(spip->config->ssport, spip->config->sspad); +} + +/** + * @brief Deasserts the slave select signal. + * @details The previously selected peripheral is unselected. + * + * @param[in] spip pointer to the @p SPIDriver object + * + * @notapi + */ +void spi_lld_unselect(SPIDriver *spip) { + + palSetPad(spip->config->ssport, spip->config->sspad); +} + +/** + * @brief Ignores data on the SPI bus. + * @details This function transmits a series of idle words on the SPI bus and + * ignores the received data. This function can be invoked even + * when a slave select signal has not been yet asserted. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be ignored + * + * @notapi + */ +void spi_lld_ignore(SPIDriver *spip, size_t n) { + + spip->rxptr = NULL; + spip->txptr = NULL; + spip->rxcnt = spip->txcnt = n; + ssp_fifo_preload(spip); + spip->ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX; +} + +/** + * @brief Exchanges data on the SPI bus. + * @details This asynchronous function starts a simultaneous transmit/receive + * operation. + * @post At the end of the operation the configured callback is invoked. + * @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] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * @param[in] txbuf the pointer to the transmit buffer + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf) { + + spip->rxptr = rxbuf; + spip->txptr = txbuf; + spip->rxcnt = spip->txcnt = n; + ssp_fifo_preload(spip); + spip->ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX; +} + +/** + * @brief Sends data over the SPI bus. + * @details This asynchronous function starts a transmit operation. + * @post At the end of the operation the configured callback is invoked. + * @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] spip pointer to the @p SPIDriver object + * @param[in] n number of words to send + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { + + spip->rxptr = NULL; + spip->txptr = txbuf; + spip->rxcnt = spip->txcnt = n; + ssp_fifo_preload(spip); + spip->ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX; +} + +/** + * @brief Receives data from the SPI bus. + * @details This asynchronous function starts a receive operation. + * @post At the end of the operation the configured callback is invoked. + * @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] spip pointer to the @p SPIDriver object + * @param[in] n number of words to receive + * @param[out] rxbuf the pointer to the receive buffer + * + * @notapi + */ +void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { + + spip->rxptr = rxbuf; + spip->txptr = NULL; + spip->rxcnt = spip->txcnt = n; + ssp_fifo_preload(spip); + spip->ssp->SSP_IMSC = IMSC_ROR | IMSC_RT | IMSC_TX | IMSC_RX; +} + +/** + * @brief Exchanges one frame using a polled wait. + * @details This synchronous function exchanges one frame using a polled + * synchronization method. This function is useful when exchanging + * small amount of data on high speed channels, usually in this + * situation is much more efficient just wait for completion using + * polling than suspending the thread waiting for an interrupt. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] frame the data frame to send over the SPI bus + * @return The received data frame from the SPI bus. + */ +uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) { + + spip->ssp->SSP_DR = (uint32_t)frame; + while ((spip->ssp->SSP_SR & SR_RNE) == 0) + ; + return (uint16_t)spip->ssp->SSP_DR; +} + +#endif /* HAL_USE_SPI */ + +/** @} */ diff --git a/os/hal/ports/LPC/LPC214x/spi_lld.h b/os/hal/ports/LPC/LPC214x/spi_lld.h new file mode 100644 index 000000000..c6713ecc6 --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/spi_lld.h @@ -0,0 +1,207 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/spi_lld.h + * @brief LPC214x low level SPI driver header. + * + * @addtogroup SPI + * @{ + */ + +#ifndef _SPI_LLD_H_ +#define _SPI_LLD_H_ + +#if HAL_USE_SPI || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Hardware FIFO depth. + */ +#define LPC214x_SSP_FIFO_DEPTH 8 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief SPI1 driver enable switch. + * @details If set to @p TRUE the support for SSP is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC214x_SPI_USE_SSP) || defined(__DOXYGEN__) +#define LPC214x_SPI_USE_SSP TRUE +#endif + +/** + * @brief SSP interrupt priority level setting. + */ +#if !defined(LPC214x_SPI_SSP_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC214x_SPI_SSP_IRQ_PRIORITY 4 +#endif + +/** + * @brief Overflow error hook. + * @details The default action is to stop the system. + */ +#if !defined(LPC214x_SPI_SSP_ERROR_HOOK) || defined(__DOXYGEN__) +#define LPC214x_SPI_SSP_ERROR_HOOK() chSysHalt() +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !LPC214x_SPI_USE_SSP +#error "SPI driver activated but no SPI peripheral assigned" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an SPI driver. + */ +typedef struct SPIDriver SPIDriver; + +/** + * @brief SPI notification callback type. + * + * @param[in] spip pointer to the @p SPIDriver object triggering the + * callback + */ +typedef void (*spicallback_t)(SPIDriver *spip); + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief Operation complete callback or @p NULL. + */ + spicallback_t end_cb; + /* End of the mandatory fields.*/ + /** + * @brief The chip select line port. + */ + ioportid_t ssport; + /** + * @brief The chip select line pad number. + */ + uint16_t sspad; + /** + * @brief SSP CR0 initialization data. + */ + uint16_t cr0; + /** + * @brief SSP CPSR initialization data. + */ + uint32_t cpsr; +} SPIConfig; + +/** + * @brief Structure representing a SPI driver. + */ +struct SPIDriver { + /** + * @brief Driver state. + */ + spistate_t state; + /** + * @brief Current configuration data. + */ + const SPIConfig *config; +#if SPI_USE_WAIT || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + Thread *thread; +#endif /* SPI_USE_WAIT */ +#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) +#if CH_USE_MUTEXES || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the bus. + */ + Mutex mutex; +#elif CH_USE_SEMAPHORES + Semaphore semaphore; +#endif +#endif /* SPI_USE_MUTUAL_EXCLUSION */ +#if defined(SPI_DRIVER_EXT_FIELDS) + SPI_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the SSP registers block. + */ + SSP *ssp; + /** + * @brief Number of bytes yet to be received. + */ + uint32_t rxcnt; + /** + * @brief Receive pointer or @p NULL. + */ + void *rxptr; + /** + * @brief Number of bytes yet to be transmitted. + */ + uint32_t txcnt; + /** + * @brief Transmit pointer or @p NULL. + */ + const void *txptr; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if LPC214x_SPI_USE_SSP && !defined(__DOXYGEN__) +extern SPIDriver SPID1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void spi_lld_init(void); + void spi_lld_start(SPIDriver *spip); + void spi_lld_stop(SPIDriver *spip); + void spi_lld_select(SPIDriver *spip); + void spi_lld_unselect(SPIDriver *spip); + void spi_lld_ignore(SPIDriver *spip, size_t n); + void spi_lld_exchange(SPIDriver *spip, size_t n, + const void *txbuf, void *rxbuf); + void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf); + void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf); + uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SPI */ + +#endif /* _SPI_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/LPC/LPC214x/vic.c b/os/hal/ports/LPC/LPC214x/vic.c new file mode 100644 index 000000000..18bb795b4 --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/vic.c @@ -0,0 +1,64 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/vic.c + * @brief LPC214x VIC peripheral support code. + * + * @addtogroup LPC214x_VIC + * @{ + */ + +#include "hal.h" + +/** + * @brief VIC Initialization. + * @note Better reset everything in the VIC, it is a HUGE source of trouble. + * + * @notapi + */ +void vic_init(void) { + int i; + + VIC *vic = VICBase; + vic->VIC_IntSelect = 0; /* All sources assigned to IRQ. */ + vic->VIC_SoftIntClear = ALLINTMASK; /* No interrupts enforced */ + vic->VIC_IntEnClear = ALLINTMASK; /* All sources disabled. */ + for (i = 0; i < 16; i++) { + vic->VIC_VectCntls[i] = 0; + vic->VIC_VectAddrs[i] = 0; + vic->VIC_VectAddr = 0; + } +} + +/** + * @brief Initializes a VIC vector. + * @details Set a vector for an interrupt source and enables it. + * + * @param[in] handler the pointer to the IRQ service routine + * @param[in] vector the vector number + * @param[in] source the IRQ source to be associated to the vector + * + * @api + */ +void SetVICVector(void *handler, int vector, int source) { + + VIC *vicp = VICBase; + vicp->VIC_VectAddrs[vector] = (IOREG32)handler; + vicp->VIC_VectCntls[vector] = (IOREG32)(source | 0x20); +} + +/** @} */ diff --git a/os/hal/ports/LPC/LPC214x/vic.h b/os/hal/ports/LPC/LPC214x/vic.h new file mode 100644 index 000000000..1e713ddb9 --- /dev/null +++ b/os/hal/ports/LPC/LPC214x/vic.h @@ -0,0 +1,39 @@ +/* + ChibiOS - Copyright (C) 2006-2014 Giovanni Di Sirio + + 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 LPC214x/vic.h + * @brief LPC214x VIC peripheral support header. + * + * @addtogroup LPC214x_VIC + * @{ + */ + +#ifndef _VIC_H_ +#define _VIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + void vic_init(void); + void SetVICVector(void *handler, int vector, int source); +#ifdef __cplusplus +} +#endif + +#endif /* _VIC_H_ */ + +/** @} */ -- cgit v1.2.3