From 51af0586c9634da8dfb35c6c71e0726392c1fbb3 Mon Sep 17 00:00:00 2001 From: theshed Date: Sat, 1 Jun 2013 22:00:28 +0000 Subject: More LPC122x drivers from Marcin J. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@5794 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/LPC122x/ext_lld.c | 234 +++++++++++++++++ os/hal/platforms/LPC122x/ext_lld.h | 172 +++++++++++++ os/hal/platforms/LPC122x/ext_lld_isr.c | 159 ++++++++++++ os/hal/platforms/LPC122x/ext_lld_isr.h | 103 ++++++++ os/hal/platforms/LPC122x/i2c_lld.c | 438 +++++++++++++++++++++++++++++++ os/hal/platforms/LPC122x/i2c_lld.h | 228 +++++++++++++++++ os/hal/platforms/LPC122x/platform.mk | 5 + os/hal/platforms/LPC122x/pwm_lld.c | 446 ++++++++++++++++++++++++++++++++ os/hal/platforms/LPC122x/pwm_lld.h | 455 +++++++++++++++++++++++++++++++++ os/hal/platforms/LPC122x/rtc_lld.c | 259 +++++++++++++++++++ os/hal/platforms/LPC122x/rtc_lld.h | 236 +++++++++++++++++ 11 files changed, 2735 insertions(+) create mode 100644 os/hal/platforms/LPC122x/ext_lld.c create mode 100644 os/hal/platforms/LPC122x/ext_lld.h create mode 100644 os/hal/platforms/LPC122x/ext_lld_isr.c create mode 100644 os/hal/platforms/LPC122x/ext_lld_isr.h create mode 100644 os/hal/platforms/LPC122x/i2c_lld.c create mode 100644 os/hal/platforms/LPC122x/i2c_lld.h create mode 100644 os/hal/platforms/LPC122x/pwm_lld.c create mode 100644 os/hal/platforms/LPC122x/pwm_lld.h create mode 100644 os/hal/platforms/LPC122x/rtc_lld.c create mode 100644 os/hal/platforms/LPC122x/rtc_lld.h (limited to 'os/hal') diff --git a/os/hal/platforms/LPC122x/ext_lld.c b/os/hal/platforms/LPC122x/ext_lld.c new file mode 100644 index 000000000..553ae9b5c --- /dev/null +++ b/os/hal/platforms/LPC122x/ext_lld.c @@ -0,0 +1,234 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x EXT driver - Copyright (C) 2013 Marcin Jokel + + 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 LPC122x/ext_lld.c + * @brief LPC122x EXT subsystem low level driver source. + * + * @addtogroup EXT + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_EXT || defined(__DOXYGEN__) + +#include "ext_lld_isr.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief EXTD0 driver identifier. + */ +#if LPC122x_EXT_USE_EXT0 || defined(__DOXYGEN__) +EXTDriver EXTD0; +#endif + +/** + * @brief EXTD1 driver identifier. + */ +#if LPC122x_EXT_USE_EXT1 || defined(__DOXYGEN__) +EXTDriver EXTD1; +#endif + +/** + * @brief EXTD2 driver identifier. + */ +#if LPC122x_EXT_USE_EXT2 || defined(__DOXYGEN__) +EXTDriver EXTD2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level EXT driver initialization. + * + * @notapi + */ +void ext_lld_init(void) { + + /* Driver initialization.*/ +#if LPC122x_EXT_USE_EXT0 + extObjectInit(&EXTD0); + EXTD0.gpio = LPC_GPIO0; +#endif + +#if LPC122x_EXT_USE_EXT1 + extObjectInit(&EXTD1); + EXTD1.gpio = LPC_GPIO1; +#endif + +#if LPC122x_EXT_USE_EXT2 + extObjectInit(&EXTD2); + EXTD2.gpio = LPC_GPIO2; +#endif +} + +/** + * @brief Configures and activates the EXT peripheral. + * + * @param[in] extp pointer to the @p EXTDriver object + * + * @notapi + */ +void ext_lld_start(EXTDriver *extp) { + int i; + + /* Configure all pins as edge sensitive */ +#if LPC122x_EXT_USE_EXT0 + if (extp == &EXTD0) { + LPC_GPIO0->IS = 0; + ext_lld_exti_irq_enable(EXTI0_IRQ); + } +#endif + +#if LPC122x_EXT_USE_EXT1 + if (extp == &EXTD1) { + LPC_GPIO1->IS = 0; + ext_lld_exti_irq_enable(EXTI1_IRQ); + } +#endif + +#if LPC122x_EXT_USE_EXT2 + if (extp == &EXTD2) { + LPC_GPIO2->IS = 0; + ext_lld_exti_irq_enable(EXTI2_IRQ); + } +#endif + + /* Configuration of autostart channels.*/ + for (i = 0; i < EXT_MAX_CHANNELS; i++) + if (extp->config->channels[i].mode & EXT_CH_MODE_AUTOSTART) + ext_lld_channel_enable(extp, i); + else + ext_lld_channel_disable(extp, i); +} + +/** + * @brief Deactivates the EXT peripheral. + * + * @param[in] extp pointer to the @p EXTDriver object + * + * @notapi + */ +void ext_lld_stop(EXTDriver *extp) { + + LPC_GPIO_Type * gp = extp->gpio; + + if (extp->state == EXT_ACTIVE) { +#if LPC122x_EXT_USE_EXT0 + if (extp == &EXTD0) { + ext_lld_exti_irq_disable(EXTI0_IRQ); + } +#endif + +#if LPC122x_EXT_USE_EXT1 + if (extp == &EXTD1) { + ext_lld_exti_irq_disable(EXTI1_IRQ); + } +#endif + +#if LPC122x_EXT_USE_EXT2 + if (extp == &EXTD2) { + ext_lld_exti_irq_disable(EXTI2_IRQ); + } +#endif + } + + gp->IE = 0; + gp->IC = 0xFFFFFFFF; + __NOP(); + __NOP(); +} + +/** + * @brief Enables an EXT channel. + * + * @param[in] extp pointer to the @p EXTDriver object + * @param[in] channel channel to be enabled + * + * @notapi + */ +void ext_lld_channel_enable(EXTDriver *extp, expchannel_t channel) { + + LPC_GPIO_Type * gp; + + gp = extp->gpio; + + /* Programming edge irq enables */ + if (extp->config->channels[channel].mode & EXT_CH_MODE_BOTH_EDGES) + gp->IBE |= (1 << channel); + else { + gp->IBE &= ~(1 << channel); + if (extp->config->channels[channel].mode & EXT_CH_MODE_RISING_EDGE) + gp->IEV |= (1 << channel); + else + gp->IEV &= (1 << channel); + } + + gp->IC = (1 << channel); /* Clear interrupt on selected channel */ + __NOP(); + __NOP(); + + gp->IE |= (1 << channel); /* Interrupt on selected channel + is not masked */ +} + +/** + * @brief Disables an EXT channel. + * + * @param[in] extp pointer to the @p EXTDriver object + * @param[in] channel channel to be disabled + * + * @notapi + */ +void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel) { + + LPC_GPIO_Type * gp; + + gp = extp->gpio; + + gp->IE &= ~(1 << channel); /* Mask interrupt on selected channel */ + gp->IC = (1 << channel); /* Clear interrupt on selected channel */ + __NOP(); + __NOP(); +} + +#endif /* HAL_USE_EXT */ + +/** @} */ diff --git a/os/hal/platforms/LPC122x/ext_lld.h b/os/hal/platforms/LPC122x/ext_lld.h new file mode 100644 index 000000000..89e720494 --- /dev/null +++ b/os/hal/platforms/LPC122x/ext_lld.h @@ -0,0 +1,172 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x EXT driver - Copyright (C) 2013 Marcin Jokel + + 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 LPC122x/ext_lld.h + * @brief LPC122x EXT subsystem low level driver header. + * + * @addtogroup EXT + * @{ + */ + +#ifndef _EXT_LLD_H_ +#define _EXT_LLD_H_ + +#if HAL_USE_EXT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Available number of EXT channels. + */ +#define EXT_MAX_CHANNELS 32 + + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @brief EXT0 driver enable switch. + * @details If set to @p TRUE the support for EXT1 is included. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_EXT_USE_EXT0) || defined(__DOXYGEN__) +#define LPC122x_EXT_USE_EXT0 FALSE +#endif + +/** + * @brief EXT1 driver enable switch. + * @details If set to @p TRUE the support for EXT1 is included. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_EXT_USE_EXT1) || defined(__DOXYGEN__) +#define LPC122x_EXT_USE_EXT1 FALSE +#endif + +/** + * @brief EXT2 driver enable switch. + * @details If set to @p TRUE the support for EXT1 is included. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_EXT_USE_EXT2) || defined(__DOXYGEN__) +#define LPC122x_EXT_USE_EXT2 FALSE +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief EXT channel identifier. + */ +typedef uint32_t expchannel_t; + +/** + * @brief Type of an EXT generic notification callback. + * + * @param[in] extp pointer to the @p EXPDriver object triggering the + * callback + */ +typedef void (*extcallback_t)(EXTDriver *extp, expchannel_t channel); + +/** + * @brief Channel configuration structure. + */ +typedef struct { + /** + * @brief Channel mode. + */ + uint8_t mode; + + /** + * @brief Channel callback. + */ + extcallback_t cb; +} EXTChannelConfig; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Channel configurations. + */ + EXTChannelConfig channels[EXT_MAX_CHANNELS]; + /* End of the mandatory fields.*/ +} EXTConfig; + +/** + * @brief Structure representing an EXT driver. + */ +struct EXTDriver { + /** + * @brief Driver state. + */ + extstate_t state; + /** + * @brief Current configuration data. + */ + const EXTConfig *config; + /* End of the mandatory fields.*/ + LPC_GPIO_Type *gpio; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if LPC122x_EXT_USE_EXT0 || !defined(__DOXYGEN__) +extern EXTDriver EXTD0; +#endif + +#if LPC122x_EXT_USE_EXT1 || !defined(__DOXYGEN__) +extern EXTDriver EXTD1; +#endif + +#if LPC122x_EXT_USE_EXT2 || !defined(__DOXYGEN__) +extern EXTDriver EXTD2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void ext_lld_init(void); + void ext_lld_start(EXTDriver *extp); + void ext_lld_stop(EXTDriver *extp); + void ext_lld_channel_enable(EXTDriver *extp, expchannel_t channel); + void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_EXT */ + +#endif /* _EXT_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC122x/ext_lld_isr.c b/os/hal/platforms/LPC122x/ext_lld_isr.c new file mode 100644 index 000000000..e8ad6f841 --- /dev/null +++ b/os/hal/platforms/LPC122x/ext_lld_isr.c @@ -0,0 +1,159 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x EXT driver - Copyright (C) 2013 Marcin Jokel + + 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 LPC122x/ext_lld_isr.c + * @brief LPC122x EXT subsystem low level driver ISR code. + * + * @addtogroup EXT + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_EXT || defined(__DOXYGEN__) + +#include "ext_lld_isr.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if LPC122x_EXT_USE_EXT0 || LPC122x_EXT_USE_EXT1 || LPC122x_EXT_USE_EXT2 || \ + defined(__DOXYGEN__) +/** + * @brief I2C error handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void ext_lld_serve_interrupt(EXTDriver *extp) { + uint32_t port_stat; + uint8_t i; + + port_stat = extp->gpio->MIS; /* Read interrupt status */ + extp->gpio->IC = port_stat; /* Clear interrupt flags */ + + for (i = 0; i < EXT_MAX_CHANNELS; i++) { + if (port_stat & 0x01) { + extp->config->channels[i].cb(extp, i); + } + port_stat = port_stat >> 1; + } +} +#endif +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if LPC122x_EXT_USE_EXT0 || defined(__DOXYGEN__) +/** + * @brief PIO0 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(VectorA4) { + + CH_IRQ_PROLOGUE(); + ext_lld_serve_interrupt(&EXTD0); + CH_IRQ_EPILOGUE(); +} +#endif + +#if LPC122x_EXT_USE_EXT1 || defined(__DOXYGEN__) +/** + * @brief PIO1 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(VectorA8) { + + CH_IRQ_PROLOGUE(); + ext_lld_serve_interrupt(&EXTD1); + CH_IRQ_EPILOGUE(); +} +#endif + +#if LPC122x_EXT_USE_EXT2 || defined(__DOXYGEN__) +/** + * @brief PIO2 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(VectorAC) { + + CH_IRQ_PROLOGUE(); + ext_lld_serve_interrupt(&EXTD2); + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Enables EXTI IRQ sources. + * + * @notapi + */ +void ext_lld_exti_irq_enable(extirq_t irqn) { + + uint32_t pmask; + + switch (irqn) { + case EXTI0_IRQ: + pmask = LPC122x_EXT_EXTI0_IRQ_PRIORITY; + break; + case EXTI1_IRQ: + pmask = LPC122x_EXT_EXTI1_IRQ_PRIORITY; + break; + case EXTI2_IRQ: + pmask = LPC122x_EXT_EXTI2_IRQ_PRIORITY; + break; + } + nvicEnableVector(EINT0_IRQn + irqn, CORTEX_PRIORITY_MASK(pmask)); + +} + +/** + * @brief Disables EXTI IRQ sources. + * + * @notapi + */ +void ext_lld_exti_irq_disable(extirq_t irqn) { + + nvicDisableVector(EINT0_IRQn + irqn); +} + +#endif /* HAL_USE_EXT */ + +/** @} */ diff --git a/os/hal/platforms/LPC122x/ext_lld_isr.h b/os/hal/platforms/LPC122x/ext_lld_isr.h new file mode 100644 index 000000000..a201cce9b --- /dev/null +++ b/os/hal/platforms/LPC122x/ext_lld_isr.h @@ -0,0 +1,103 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x EXT driver - Copyright (C) 2013 Marcin Jokel + + 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 LPC122x/ext_lld_isr.h + * @brief LPC122x EXT subsystem low level driver ISR header. + * + * @addtogroup EXT + * @{ + */ + +#ifndef _EXT_LLD_ISR_H_ +#define _EXT_LLD_ISR_H_ + +#if HAL_USE_EXT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define EXTI0_IRQ 0 +#define EXTI1_IRQ 1 +#define EXTI2_IRQ 2 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief EXTI0 interrupt priority level setting. + */ +#if !defined(LPC122x_EXT_EXTI0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC122x_EXT_EXTI0_IRQ_PRIORITY 3 +#endif + +/** + * @brief EXTI1 interrupt priority level setting. + */ +#if !defined(LPC122x_EXT_EXTI1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC122x_EXT_EXTI1_IRQ_PRIORITY 3 +#endif + +/** + * @brief EXTI2 interrupt priority level setting. + */ +#if !defined(LPC122x_EXT_EXTI2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC122x_EXT_EXTI2_IRQ_PRIORITY 3 +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief EXT irq port identifier. + */ +typedef uint32_t extirq_t; +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void ext_lld_exti_irq_enable(extirq_t irqn); + void ext_lld_exti_irq_disable(extirq_t irqn); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_EXT */ + +#endif /* _EXT_LLD_ISR_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC122x/i2c_lld.c b/os/hal/platforms/LPC122x/i2c_lld.c new file mode 100644 index 000000000..32055d4c2 --- /dev/null +++ b/os/hal/platforms/LPC122x/i2c_lld.c @@ -0,0 +1,438 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x I2C driver - Copyright (C) 2013 Marcin Jokel + + 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. +*/ + +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + + +/** + * @file LPC122x/i2c_lld.h + * @brief LPC122x I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief I2C1 driver identifier.*/ +I2CDriver I2CD1; + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Wakes up the waiting thread. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] msg wakeup message + * + * @notapi + */ +#define wakeup_isr(i2cp, msg) { \ + chSysLockFromIsr(); \ + if ((i2cp)->thread != NULL) { \ + Thread *tp = (i2cp)->thread; \ + (i2cp)->thread = NULL; \ + tp->p_u.rdymsg = (msg); \ + chSchReadyI(tp); \ + } \ + chSysUnlockFromIsr(); \ +} + +/** + * @brief Handling of stalled I2C transactions. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_safety_timeout(void *p) { + I2CDriver *i2cp = (I2CDriver *)p; + + chSysLockFromIsr(); + if (i2cp->thread) { + Thread *tp = i2cp->thread; + i2cp->thread = NULL; + tp->p_u.rdymsg = RDY_TIMEOUT; + chSchReadyI(tp); + } + chSysUnlockFromIsr(); +} + +/** + * @brief I2C error handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t status) { + i2cflags_t error = 0; + + switch (status) { + case I2C_STATE_ARB_LOST: + error = I2CD_ARBITRATION_LOST; + break; + case I2C_STATE_BUS_ERROR: + error = I2CD_BUS_ERROR; + break; + case I2C_STATE_MS_SLAR_NACK: + case I2C_STATE_MS_TDAT_NACK: + case I2C_STATE_MS_SLAW_NACK: + error = I2CD_ACK_FAILURE ; + break; + } + + /* If some error has been identified then sends wakes the waiting thread.*/ + i2cp->errors = error; + wakeup_isr(i2cp, RDY_RESET); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ +/** + * @brief I2C1 event interrupt handler. + * + * @notapi + */ +CH_IRQ_HANDLER(Vector70) { + uint32_t status; + + CH_IRQ_PROLOGUE(); + status = LPC_I2C->STAT; + switch(status) { + case I2C_STATE_MS_START: /* A START condition has been transmitted. */ + if (I2CD1.txbytes > 0) { + LPC_I2C->DAT = I2CD1.addr; /* Write slave address with WR bit. */ + } + else { + LPC_I2C->DAT = I2CD1.addr | I2C_RD_BIT; /* Write slave address with RD bit. */ + } + + LPC_I2C->CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_SIC; /* Clear START and SI bit. */ + break; + + case I2C_STATE_MS_SLAR_NACK: /* NOT ACK has been received, Master will be transmitted STOP. */ + case I2C_STATE_MS_TDAT_NACK: /* NOT ACK has been received, Master will be transmitted STOP. */ + case I2C_STATE_MS_SLAW_NACK: /* NOT ACK has been received, Master will be transmitted STOP. */ + LPC_I2C->CONSET = I2C_CONSET_STO; /* Set STOP bit. */ + LPC_I2C->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + i2c_lld_serve_error_interrupt(&I2CD1, status); + break; + + case I2C_STATE_MS_SLAW_ACK: /* SLA + W has been transmitted, ACK has been received. */ + case I2C_STATE_MS_TDAT_ACK: /* Data byte has been transmitted, ACK has been received. */ + if (I2CD1.txbytes > 0) { + LPC_I2C->DAT = *I2CD1.txbuf++; /* Write data. */ + I2CD1.txbytes--; + } + else { + if (I2CD1.rxbytes > 0) { + LPC_I2C->CONSET = I2C_CONSET_STO | I2C_CONSET_STA; /* Set START and STOP bit. */ + } /* STOP bit will be transmit, then START bit. */ + else { + LPC_I2C->CONSET = I2C_CONSET_STO; /* Set STOP bit. */ + wakeup_isr(&I2CD1, RDY_OK); + } + } + LPC_I2C->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + break; + + case I2C_STATE_MS_SLAR_ACK: /* SLA + R has been transmitted, ACK has been received. */ + case I2C_STATE_MS_RDAT_ACK: /* Data byte has been received, ACK has been returned. */ + if (status == I2C_STATE_MS_RDAT_ACK) { + *I2CD1.rxbuf++ = LPC_I2C->DAT; /* Read data */ + I2CD1.rxbytes--; + } + if (I2CD1.rxbytes == 1) { + LPC_I2C->CONCLR = I2C_CONCLR_SIC | I2C_CONCLR_AAC; /* Clear SI and ACK bit. */ + } + else { + LPC_I2C->CONSET = I2C_CONSET_AA; /* Set ACK bit. */ + LPC_I2C->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + } + break; + + case I2C_STATE_MS_RDAT_NACK: /* Data byte has been received, NOT ACK has been returned. */ + *I2CD1.rxbuf++ = LPC_I2C->DAT; /* Read data. */ + I2CD1.rxbytes--; + LPC_I2C->CONSET = I2C_CONSET_STO; /* Set STOP bit. */ + LPC_I2C->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + wakeup_isr(&I2CD1, RDY_OK); + break; + + case I2C_STATE_BUS_ERROR: /* Bus error. */ + case I2C_STATE_ARB_LOST: /* Arbitration lost. */ + LPC_I2C->CONCLR = I2C_CONCLR_SIC; /* Clear SI bit. */ + i2c_lld_serve_error_interrupt(&I2CD1, status); + break; + + } + + CH_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2C driver initialization. + * + * @notapi + */ +void i2c_lld_init(void) { + + i2cObjectInit(&I2CD1); + I2CD1.thread = NULL; + I2CD1.i2c = LPC_I2C; + + LPC_IOCON->PIO0_10 = 0x0482; /* Set I2C SCL pin function */ + LPC_IOCON->PIO0_11 = 0x0482; /* Set I2C SDA pin function */ +} + +/** + * @brief Configures and activates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_start(I2CDriver *i2cp) { + uint32_t i2cscl; + uint32_t mulh, mull, div; + LPC_I2C_Type *dp = i2cp->i2c; + + /* Make sure I2C peripheral is disabled */ + dp->CONCLR = I2C_CONCLR_ENC; + + /* If in stopped state then enables the I2C clock. */ + if (i2cp->state == I2C_STOP) { + + if (&I2CD1 == i2cp) { + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 5); /* Enable clock. */ + LPC_SYSCON->PRESETCTRL &= ~(1 << 1); /* Reset I2C peripheral.*/ + __NOP(); + LPC_SYSCON->PRESETCTRL |= (1 << 1); + nvicEnableVector(I2C_IRQn, + CORTEX_PRIORITY_MASK(LPC122x_I2C_IRQ_PRIORITY)); + } + + } + + /* Setup I2C clock parameters.*/ + i2cscl = (LPC122x_SYSCLK/(i2cp->config->clock_timing)); + if (i2cp->config->mode == I2C_FAST_MODE) { + div = 19; + mull = 13; + mulh = 6; + } else if (i2cp->config->mode == I2C_FAST_MODE_PLUS) { + div = 3; + mull = 2; + mulh = 1; + } else { /* i2cp->config->mode == I2C_STANDARD_MODE */ + div = 2; + mull = 1; + mulh = 1; + } + + dp->SCLH = (mulh * i2cscl) / div; + dp->SCLL = (mull *i2cscl) / div; + + /* Enable I2C.*/ + dp->CONSET |= I2C_CONSET_EN; +} + +/** + * @brief Deactivates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_stop(I2CDriver *i2cp) { + + /* If not in stopped state then disables the I2C clock.*/ + if (i2cp->state != I2C_STOP) { + + /* I2C disable.*/ + i2cp->i2c->CONCLR = I2C_CONCLR_ENC; + + if (&I2CD1 == i2cp) { + nvicDisableVector(I2C_IRQn); + LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 5); + } + } +} + +/** + * @brief Receives data via the I2C bus as master. + * @details Number of receiving bytes must be more than 1 on STM32F1x. This is + * hardware restriction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval RDY_OK if the function succeeded. + * @retval RDY_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval RDY_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout) { + LPC_I2C_Type *dp = i2cp->i2c; + VirtualTimer vt; + + i2cp->addr = addr << 1; + /* Global timeout for the whole operation.*/ + if (timeout != TIME_INFINITE) + chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); + + /* Releases the lock from high level driver.*/ + chSysUnlock(); + + /* Initializes driver fields */ + i2cp->errors = 0; + i2cp->rxbuf = rxbuf; + i2cp->rxbytes = rxbytes; + + /* This lock will be released in high level driver.*/ + chSysLock(); + + /* Atomic check on the timer in order to make sure that a timeout didn't + happen outside the critical zone.*/ + if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) + return RDY_TIMEOUT; + + /* Starts the operation.*/ + dp->CONSET = I2C_CONSET_STA; + + /* Waits for the operation completion or a timeout.*/ + i2cp->thread = chThdSelf(); + chSchGoSleepS(THD_STATE_SUSPENDED); + if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) + chVTResetI(&vt); + + return chThdSelf()->p_u.rdymsg; +} + +/** + * @brief Transmits data via the I2C bus as master. + * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x. + * This is hardware restriction. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[in] txbuf pointer to the transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval RDY_OK if the function succeeded. + * @retval RDY_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval RDY_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout) { + LPC_I2C_Type *dp = i2cp->i2c; + VirtualTimer vt; + + i2cp->addr = addr << 1; + /* Global timeout for the whole operation.*/ + if (timeout != TIME_INFINITE) + chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); + + /* Releases the lock from high level driver.*/ + chSysUnlock(); + + /* Initializes driver fields */ + i2cp->errors = 0; + i2cp->txbuf = txbuf; + i2cp->txbytes = txbytes; + i2cp->rxbuf = rxbuf; + i2cp->rxbytes = rxbytes; + + /* This lock will be released in high level driver.*/ + chSysLock(); + + /* Atomic check on the timer in order to make sure that a timeout didn't + happen outside the critical zone.*/ + if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) + return RDY_TIMEOUT; + + /* Starts the operation.*/ + dp->CONSET = I2C_CONSET_STA; + + /* Waits for the operation completion or a timeout.*/ + i2cp->thread = chThdSelf(); + chSchGoSleepS(THD_STATE_SUSPENDED); + + if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) + chVTResetI(&vt); + + return chThdSelf()->p_u.rdymsg; +} + +#endif /* HAL_USE_I2C */ + +/** @} */ diff --git a/os/hal/platforms/LPC122x/i2c_lld.h b/os/hal/platforms/LPC122x/i2c_lld.h new file mode 100644 index 000000000..edff13a95 --- /dev/null +++ b/os/hal/platforms/LPC122x/i2c_lld.h @@ -0,0 +1,228 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x I2C driver - Copyright (C) 2013 Marcin Jokel + + 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file LPC122x/i2c_lld.h + * @brief LPC122x I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#ifndef _I2C_LLD_H_ +#define _I2C_LLD_H_ + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define I2C_CONSET_AA 0x04 /* Assert acknowledge flag. */ +#define I2C_CONSET_SI 0x08 /* I2C interrupt flag. */ +#define I2C_CONSET_STO 0x10 /* STOP flag. */ +#define I2C_CONSET_STA 0x20 /* START flag. */ +#define I2C_CONSET_EN 0x40 /* I2C interface enable. */ + +#define I2C_CONCLR_AAC 0x04 /* Assert acknowledge Clear bit. */ +#define I2C_CONCLR_SIC 0x08 /* I2C interrupt Clear bit. */ +#define I2C_CONCLR_STAC 0x20 /* START flag Clear bit. */ +#define I2C_CONCLR_ENC 0x40 /* I2C interface Disable bit. */ + +#define I2C_WR_BIT 0x00 +#define I2C_RD_BIT 0x01 + +#define I2C_STATE_MS_START 0x08 +#define I2C_STATE_MS_RSTART 0x10 +#define I2C_STATE_MS_SLAW_ACK 0x18 +#define I2C_STATE_MS_SLAW_NACK 0x20 +#define I2C_STATE_MS_TDAT_ACK 0x28 +#define I2C_STATE_MS_TDAT_NACK 0x30 +#define I2C_STATE_ARB_LOST 0x38 + +#define I2C_STATE_MS_SLAR_ACK 0x40 +#define I2C_STATE_MS_SLAR_NACK 0x48 +#define I2C_STATE_MS_RDAT_ACK 0x50 +#define I2C_STATE_MS_RDAT_NACK 0x58 + +#define I2C_STATE_BUS_ERROR 0x00 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ +/** + * @name Configuration options + * @{ + */ + +/** + * @brief I2C interrupt priority level setting. + */ +#if !defined(LPC122x_I2C_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC122x_I2C_IRQ_PRIORITY 3 +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type representing I2C address. + */ +typedef uint16_t i2caddr_t; + +/** + * @brief I2C Driver condition flags type. + */ +typedef uint32_t i2cflags_t; +/** + * @brief Supported modes for the I2C bus. + */ +typedef enum { + I2C_STANDARD_MODE = 1, + I2C_FAST_MODE = 2, + I2C_FAST_MODE_PLUS = 3 +} i2cmode_t; + +/** + * @brief Driver configuration structure. + */ +typedef struct { + i2cmode_t mode; /**< @brief Specifies the I2C mode. */ + uint32_t clock_timing; /**< @brief Specifies the clock timing */ +} I2CConfig; + +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct I2CDriver I2CDriver; + +/** + * @brief Structure representing an I2C driver. + */ +struct I2CDriver { + /** + * @brief Driver state. + */ + i2cstate_t state; + /** + * @brief Current configuration data. + */ + const I2CConfig *config; + /** + * @brief Error flags. + */ + i2cflags_t errors; +#if I2C_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 /* I2C_USE_MUTUAL_EXCLUSION */ +#if defined(I2C_DRIVER_EXT_FIELDS) + I2C_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion. + */ + Thread *thread; + /** + * @brief Current slave address without R/W bit. + */ + i2caddr_t addr; + /** + * @brief Pointer to the transmit buffer. + */ + const uint8_t *txbuf; + /** + * @brief Number of bytes to transmit. + */ + size_t txbytes; + /** + * @brief Pointer to the receive buffer. + */ + uint8_t *rxbuf; + /** + * @brief Number of bytes to receive. + */ + size_t rxbytes; + /** + * @brief Pointer to the I2C registers block. + */ + LPC_I2C_Type *i2c; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Get errors from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_errors(i2cp) ((i2cp)->errors) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern I2CDriver I2CD1; +#endif + +#endif /* !defined(__DOXYGEN__) */ + +#ifdef __cplusplus +extern "C" { +#endif + void i2c_lld_init(void); + void i2c_lld_start(I2CDriver *i2cp); + void i2c_lld_stop(I2CDriver *i2cp); + msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout); + msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout); +#ifdef __cplusplus +} +#endif + + + +#endif /* _I2C_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC122x/platform.mk b/os/hal/platforms/LPC122x/platform.mk index dbf5aaf48..9a9853fbd 100644 --- a/os/hal/platforms/LPC122x/platform.mk +++ b/os/hal/platforms/LPC122x/platform.mk @@ -2,6 +2,11 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/LPC122x/hal_lld.c \ ${CHIBIOS}/os/hal/platforms/LPC122x/gpt_lld.c \ ${CHIBIOS}/os/hal/platforms/LPC122x/pal_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC122x/ext_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC122x/ext_lld_isr.c \ + ${CHIBIOS}/os/hal/platforms/LPC122x/pwm_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC122x/i2c_lld.c \ + ${CHIBIOS}/os/hal/platforms/LPC122x/rtc_lld.c \ ${CHIBIOS}/os/hal/platforms/LPC122x/serial_lld.c \ ${CHIBIOS}/os/hal/platforms/LPC122x/spi_lld.c diff --git a/os/hal/platforms/LPC122x/pwm_lld.c b/os/hal/platforms/LPC122x/pwm_lld.c new file mode 100644 index 000000000..24e5b2639 --- /dev/null +++ b/os/hal/platforms/LPC122x/pwm_lld.c @@ -0,0 +1,446 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x PWM driver - Copyright (C) 2013 Marcin Jokel + + 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 LPC122x/pwm_lld.c + * @brief LPC122x PWM subsystem low level driver header. + * + * @addtogroup PWM + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_PWM || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief PWMD1 driver identifier. + * @note The driver PWMD1 allocates the complex timer TIM1 when enabled. + */ +#if LPC122x_PWM_USE_CT16B0 || defined(__DOXYGEN__) +PWMDriver PWMD1; +#endif + +/** + * @brief PWMD2 driver identifier. + * @note The driver PWMD2 allocates the timer TIM2 when enabled. + */ +#if LPC122x_PWM_USE_CT16B1 || defined(__DOXYGEN__) +PWMDriver PWMD2; +#endif + +/** + * @brief PWMD3 driver identifier. + * @note The driver PWMD3 allocates the timer TIM3 when enabled. + */ +#if LPC122x_PWM_USE_CT32B0 || defined(__DOXYGEN__) +PWMDriver PWMD3; +#endif + +/** + * @brief PWMD4 driver identifier. + * @note The driver PWMD4 allocates the timer TIM4 when enabled. + */ +#if LPC122x_PWM_USE_CT32B1 || defined(__DOXYGEN__) +PWMDriver PWMD4; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if LPC122x_PWM_USE_CT16B0 || LPC122x_PWM_USE_CT16B1 || \ + LPC122x_PWM_USE_CT32B0 || LPC122x_PWM_USE_CT32B1 || defined(__DOXYGEN__) +/** + * @brief Common TIM2...TIM5 IRQ handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @param[in] pwmp pointer to a @p PWMDriver object + */ +static void pwm_lld_serve_interrupt(PWMDriver *pwmp) { + uint16_t sr; + + sr = pwmp->tim->IR; + pwmp->tim->IR = sr; + if ((sr & IR_MR0INT) != 0) + pwmp->config->channels[0].callback(pwmp); + if ((sr & IR_MR1INT) != 0) + pwmp->config->channels[1].callback(pwmp); + if ((sr & IR_MR3INT) != 0) + pwmp->config->callback(pwmp); +} +#endif + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if LPC122x_PWM_USE_CT16B0 || defined(__DOXYGEN__) +/** + * @brief CT16B0 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector74) { + + CH_IRQ_PROLOGUE(); + pwm_lld_serve_interrupt(&PWMD1); + CH_IRQ_EPILOGUE(); +} + +#endif /* STM32_PWM_USE_TIM1 */ + +#if LPC122x_PWM_USE_CT16B1 || defined(__DOXYGEN__) +/** + * @brief CT16B1 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector78) { + + CH_IRQ_PROLOGUE(); + pwm_lld_serve_interrupt(&PWMD2); + CH_IRQ_EPILOGUE(); +} +#endif /* LPC122x_PWM_USE_CT16B1 */ + +#if LPC122x_PWM_USE_CT32B0 || defined(__DOXYGEN__) +/** + * @brief CT32B0 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector7C) { + + CH_IRQ_PROLOGUE(); + pwm_lld_serve_interrupt(&PWMD3); + CH_IRQ_EPILOGUE(); +} +#endif /* LPC122x_PWM_USE_CT32B0 */ + +#if LPC122x_PWM_USE_CT32B1 || defined(__DOXYGEN__) +/** + * @brief CT32B1 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(Vector80) { + + CH_IRQ_PROLOGUE(); + pwm_lld_serve_interrupt(&PWMD4); + CH_IRQ_EPILOGUE(); +} +#endif /* LPC122x_PWM_USE_CT32B1 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level PWM driver initialization. + * + * @notapi + */ +void pwm_lld_init(void) { + +#if LPC122x_PWM_USE_CT16B0 + /* Driver initialization.*/ + pwmObjectInit(&PWMD1); + PWMD1.tim = LPC_CT16B0; + +#if LPC122x_PWM_USE_CT16B0_CH0 +#if LPC122x_PWM_CT16B0_CH0_SELECTOR == PWM_CT16B0_CH0_IS_PIO0_11 + LPC_IOCON->PIO0_11 = 0x84; +#elif LPC122x_PWM_CT16B0_CH0_SELECTOR == PWM_CT16B0_CH0_IS_PIO0_28 + LPC_IOCON->PIO0_28 = 0x84; +#else /* LPC122x_PWM_CT16B0_CH0_SELECTOR == PWM_CT16B0_CH0_IS_PIO2_0 */ + LPC_IOCON->PIO2_0 = 0x84; +#endif +#endif + +#if LPC122x_PWM_USE_CT16B0_CH1 +#if LPC122x_PWM_CT16B0_CH1_SELECTOR == PWM_CT16B0_CH1_IS_PIO0_12 + LPC_IOCON->PIO0_12 = 0x84; +#elif LPC122x_PWM_CT16B0_CH1_SELECTOR == PWM_CT16B0_CH1_IS_PIO0_29 + LPC_IOCON->PIO0_29 = 0x84; +#else /* LPC122x_PWM_CT16B0_CH1_SELECTOR == PWM_CT16B0_CH1_IS_PIO2_1 */ + LPC_IOCON->PIO2_1 = 0x83; +#endif +#endif +#endif + +#if LPC122x_PWM_USE_CT16B1 + /* Driver initialization.*/ + pwmObjectInit(&PWMD2); + PWMD2.tim = LPC_CT16B1; + +#if LPC122x_PWM_USE_CT16B1_CH0 +#if LPC122x_PWM_CT16B1_CH0_SELECTOR == PWM_CT16B1_CH0_IS_PIO0_15 + LPC_IOCON->PIO0_15 = 0x84; +#elif LPC122x_PWM_CT16B1_CH0_SELECTOR == PWM_CT16B1_CH0_IS_PIO1_5 + LPC_IOCON->PIO1_5 = 0x83; +#else /* LPC122x_PWM_CT16B1_CH0_SELECTOR == PWM_CT16B1_CH0_IS_PIO2_2 */ + LPC_IOCON->PIO2_2 = 0x83; +#endif +#endif + +#if LPC122x_PWM_USE_CT16B1_CH1 +#if LPC122x_PWM_CT16B1_CH1_SELECTOR == PWM_CT16B1_CH1_IS_PIO0_16 + LPC_IOCON->PIO0_16 = 0x84; +#elif LPC122x_PWM_CT16B1_CH1_SELECTOR == PWM_CT16B1_CH1_IS_PIO1_6 + LPC_IOCON->PIO1_6 = 0x82; +#else /* LPC122x_PWM_CT16B1_CH1_SELECTOR == PWM_CT16B1_CH1_IS_PIO2_3 */ + LPC_IOCON->PIO2_3 = 0x83; +#endif +#endif +#endif + +#if LPC122x_PWM_USE_CT32B0 + /* Driver initialization.*/ + pwmObjectInit(&PWMD3); + PWMD3.tim = LPC_CT32B0; + +#if LPC122x_PWM_USE_CT32B0_CH0 +#if LPC122x_PWM_CT32B0_CH0_SELECTOR == PWM_CT32B0_CH0_IS_PIO0_1 + LPC_IOCON->PIO0_1 = 0x84; +#elif LPC122x_PWM_CT32B0_CH0_SELECTOR == PWM_CT32B0_CH0_IS_PIO0_18 + LPC_IOCON->PIO0_18 = 0x84; +#else /* LPC122x_PWM_CT32B0_CH0_SELECTOR == PWM_CT32B0_CH0_IS_PIO2_4 */ + LPC_IOCON->PIO2_4 = 0x83; +#endif +#endif + +#if LPC122x_PWM_USE_CT32B0_CH1 +#if LPC122x_PWM_CT32B0_CH1_SELECTOR == PWM_CT32B0_CH1_IS_PIO0_2 + LPC_IOCON->PIO0_2 = 0x84; +#elif LPC122x_PWM_CT32B0_CH1_SELECTOR == PWM_CT32B0_CH1_IS_PIO0_19 + LPC_IOCON->PIO0_19 = 0x84; +#else /* LPC122x_PWM_CT32B0_CH1_SELECTOR == PWM_CT32B0_CH1_IS_PIO2_5 */ + LPC_IOCON->PIO2_5 = 0x83; +#endif +#endif +#endif + +#if LPC122x_PWM_USE_CT32B1 + /* Driver initialization.*/ + pwmObjectInit(&PWMD4); + PWMD4.tim = LPC_CT32B1; + +#if LPC122x_PWM_USE_CT32B1_CH0 +#if LPC122x_PWM_CT32B1_CH0_SELECTOR == PWM_CT32B1_CH0_IS_PIO0_6 + LPC_IOCON->PIO0_6 = 0x84; +#elif LPC122x_PWM_CT32B1_CH0_SELECTOR == PWM_CT32B1_CH0_IS_PIO0_23 + LPC_IOCON->PIO0_23 = 0x84; +#else /* LPC122x_PWM_CT32B1_CH0_SELECTOR == PWM_CT32B1_CH0_IS_PIO2_8 */ + LPC_IOCON->PIO2_8 = 0x83; +#endif +#endif + +#if LPC122x_PWM_USE_CT32B1_CH1 +#if LPC122x_PWM_CT32B1_CH1_SELECTOR == PWM_CT32B1_CH1_IS_PIO0_7 + LPC_IOCON->PIO0_7 = 0x84; +#elif LPC122x_PWM_CT32B1_CH1_SELECTOR == PWM_CT32B1_CH1_IS_PIO0_24 + LPC_IOCON->PIO0_24 = 0x84; +#else /* LPC122x_PWM_CT32B1_CH1_SELECTOR == PWM_CT32B1_CH1_IS_PIO2_9 */ + LPC_IOCON->PIO2_9 = 0x83; +#endif +#endif +#endif +} + +/** + * @brief Configures and activates the PWM peripheral. + * @note Starting a driver that is already in the @p PWM_READY state + * disables all the active channels. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @notapi + */ +void pwm_lld_start(PWMDriver *pwmp) { + uint32_t pr; + + if (pwmp->state == PWM_STOP) { + /* Clock activation and timer reset.*/ +#if LPC122x_PWM_USE_CT16B0 + if (&PWMD1 == pwmp) { + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 7); + nvicEnableVector(TIMER_16_0_IRQn, LPC122x_PWM_CT16B0_IRQ_PRIORITY); + } +#endif +#if LPC122x_PWM_USE_CT16B1 + if (&PWMD2 == pwmp) { + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 8); + nvicEnableVector(TIMER_16_1_IRQn, LPC122x_PWM_CT16B1_IRQ_PRIORITY); + } +#endif +#if LPC122x_PWM_USE_CT32B0 + if (&PWMD3 == pwmp) { + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 9); + nvicEnableVector(TIMER_32_0_IRQn, LPC122x_PWM_CT32B0_IRQ_PRIORITY); + } +#endif +#if LPC122x_PWM_USE_CT32B1 + if (&PWMD4 == pwmp) { + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 10); + nvicEnableVector(TIMER_32_1_IRQn, LPC122x_PWM_CT32B1_IRQ_PRIORITY); + } +#endif + } + else { + /* Driver re-configuration scenario, it must be stopped first.*/ + pwmp->tim->TCR = 0; + } + + /* Output enables and polarities setup.*/ + if(pwmp->config->channels[0].mode == PWM_OUTPUT_ACTIVE_LOW) + pwmp->tim->PWMC = (1 << 0); + + if(pwmp->config->channels[1].mode == PWM_OUTPUT_ACTIVE_LOW) + pwmp->tim->PWMC |= (1 << 1); + + /* Timer configured and started.*/ + pr = (uint16_t)((LPC122x_SYSCLK / pwmp->config->frequency) - 1); + chDbgAssert(((uint32_t)(pr + 1) * pwmp->config->frequency) == LPC122x_SYSCLK, + "pwm_lld_start(), #1", "invalid frequency"); + + pwmp->tim->TC = 0; + pwmp->tim->PR = pr; + pwmp->tim->IR = 0xFF; + pwmp->tim->MCR = MCR_MR3R; /* Reset on Match3 */ + pwmp->tim->MR3 = pwmp->config->period; + + if (pwmp->config->callback != NULL) + pwmp->tim->MCR |= MCR_MR3I; + + pwmp->tim->TCR = 1; /* Timer start */ +} + +/** + * @brief Deactivates the PWM peripheral. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * + * @notapi + */ +void pwm_lld_stop(PWMDriver *pwmp) { + + /* If in ready state then disables the PWM clock.*/ + if (pwmp->state == PWM_READY) { + pwmp->tim->TCR = 0; /* Timer disabled. */ + pwmp->tim->MCR = 0; /* All IRQs disabled. */ + pwmp->tim->IR = 0xFF; /* Clear eventual pending IRQs. */ + pwmp->tim->PWMC = 0; /* PWM outputs disable */ + +#if LPC122x_PWM_USE_CT16B0 + if (&PWMD1 == pwmp) { + nvicDisableVector(TIMER_16_0_IRQn); + LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 7); + } +#endif +#if LPC122x_PWM_USE_CT16B1 + if (&PWMD2 == pwmp) { + nvicDisableVector(TIMER_16_1_IRQn); + LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 8); + } +#endif +#if LPC122x_PWM_USE_CT32B0 + if (&PWMD3 == pwmp) { + nvicDisableVector(TIMER_32_0_IRQn); + LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 9); + } +#endif +#if LPC122x_PWM_USE_CT32B1 + if (&PWMD4 == pwmp) { + nvicDisableVector(TIMER_32_1_IRQn); + LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 10); + } +#endif + } +} + +/** + * @brief Enables a PWM channel. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @post The channel is active using the specified configuration. + * @note The function has effect at the next cycle start. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) + * @param[in] width PWM pulse width as clock pulses number + * + * @notapi + */ +void pwm_lld_enable_channel(PWMDriver *pwmp, + pwmchannel_t channel, + pwmcnt_t width) { + + pwmp->tim->MCR &= ~(7 << (channel * 3)); + + if ( channel == 0) + pwmp->tim->MR0 = width; /* New duty cycle. */ + else + pwmp->tim->MR1 = width; /* New duty cycle. */ + /* If there is a callback defined for the channel then the associated + interrupt must be enabled.*/ + if (pwmp->config->channels[channel].callback != NULL) { + pwmp->tim->IR = (1 << channel); /* Clear interrupt flag*/ + pwmp->tim->MCR |= (1 << (channel * 3)); /* Set interrupt on selected channel */ + } + +} + +/** + * @brief Disables a PWM channel. + * @pre The PWM unit must have been activated using @p pwmStart(). + * @post The channel is disabled and its output line returned to the + * idle state. + * @note The function has effect at the next cycle start. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) + * + * @notapi + */ +void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) { + + if ( channel == 0) + pwmp->tim->MR0 = 0; + else + pwmp->tim->MR1 = 0; + pwmp->tim->MCR &= ~(7 << (channel * 3)); + pwmp->tim->IR = (1 << channel); +} + +#endif /* HAL_USE_PWM */ + +/** @} */ diff --git a/os/hal/platforms/LPC122x/pwm_lld.h b/os/hal/platforms/LPC122x/pwm_lld.h new file mode 100644 index 000000000..d0d54d234 --- /dev/null +++ b/os/hal/platforms/LPC122x/pwm_lld.h @@ -0,0 +1,455 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x PWM driver - Copyright (C) 2013 Marcin Jokel + + 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 LPC122x/pwm_lld.h + * @brief LPC122x PWM subsystem low level driver header. + * + * @addtogroup PWM + * @{ + */ + +#ifndef _PWM_LLD_H_ +#define _PWM_LLD_H_ + +#if HAL_USE_PWM || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Unsupported modes and specific modes */ +/*===========================================================================*/ +#undef PWM_OUTPUT_ACTIVE_HIGH + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define IR_MR0INT (1 << 0) +#define IR_MR1INT (1 << 1) +#define IR_MR2INT (1 << 2) +#define IR_MR3INT (1 << 3) +#define IR_CR0INT (1 << 4) +#define IR_CR1INT (1 << 5) +#define IR_CR2INT (1 << 6) +#define IR_CR3INT (1 << 7) + +#define MCR_MR3I (1 << 9) +#define MCR_MR3R (1 << 10) +#define MCR_MR3S (1 << 11) + +/** + * @brief Number of PWM channels per PWM driver. + */ +#define PWM_CHANNELS 2 + +#define PWM_CT16B0_CH0_IS_PIO0_11 0 +#define PWM_CT16B0_CH0_IS_PIO0_28 1 +#define PWM_CT16B0_CH0_IS_PIO2_0 2 + +#define PWM_CT16B0_CH1_IS_PIO0_12 0 +#define PWM_CT16B0_CH1_IS_PIO0_29 1 +#define PWM_CT16B0_CH1_IS_PIO2_1 2 + +#define PWM_CT16B1_CH0_IS_PIO0_15 0 +#define PWM_CT16B1_CH0_IS_PIO1_5 1 +#define PWM_CT16B1_CH0_IS_PIO2_2 2 + +#define PWM_CT16B1_CH1_IS_PIO0_16 0 +#define PWM_CT16B1_CH1_IS_PIO1_6 1 +#define PWM_CT16B1_CH1_IS_PIO2_3 2 + + +#define PWM_CT32B0_CH0_IS_PIO0_1 0 +#define PWM_CT32B0_CH0_IS_PIO0_18 1 +#define PWM_CT32B0_CH0_IS_PIO2_4 2 + +#define PWM_CT32B0_CH1_IS_PIO0_2 0 +#define PWM_CT32B0_CH1_IS_PIO0_19 1 +#define PWM_CT32B0_CH1_IS_PIO2_5 2 + + +#define PWM_CT32B1_CH0_IS_PIO0_6 0 +#define PWM_CT32B1_CH0_IS_PIO0_23 1 +#define PWM_CT32B1_CH0_IS_PIO2_8 2 + +#define PWM_CT32B1_CH1_IS_PIO0_7 0 +#define PWM_CT32B1_CH1_IS_PIO0_24 1 +#define PWM_CT32B1_CH1_IS_PIO2_9 2 + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ + +/** + * @brief PWMD1 driver enable switch. + * @details If set to @p TRUE the support for PWMD1 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC122x_PWM_USE_CT16B0) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT16B0 FALSE +#endif + +/** + * @brief PWMD2 driver enable switch. + * @details If set to @p TRUE the support for PWMD2 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC122x_PWM_USE_CT16B1) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT16B1 FALSE +#endif + +/** + * @brief PWMD3 driver enable switch. + * @details If set to @p TRUE the support for PWMD3 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC122x_PWM_USE_CT32B0) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT32B0 FALSE +#endif + +/** + * @brief PWMD4 driver enable switch. + * @details If set to @p TRUE the support for PWMD4 is included. + * @note The default is @p TRUE. + */ +#if !defined(LPC122x_PWM_USE_CT32B1) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT32B1 FALSE +#endif + +/** + * @brief PWMD1 Channel 0 driver enable switch. + * @details If set to @p TRUE PWMD1 Channel 0 is enabled. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_PWM_USE_CT16B0_CH0) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT16B0_CH0 FALSE +#endif + +/** + * @brief PWMD1 Channel 1 driver enable switch. + * @details If set to @p TRUE PWMD1 Channel 1 is enabled. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_PWM_USE_CT16B0_CH1) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT16B0_CH1 FALSE +#endif + +/** + * @brief PWMD2 Channel 0 driver enable switch. + * @details If set to @p TRUE PWMD2 Channel 0 is enabled. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_PWM_USE_CT16B1_CH0) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT16B1_CH0 FALSE +#endif + +/** + * @brief PWMD2 Channel 1 driver enable switch. + * @details If set to @p TRUE PWMD2 Channel 1 is enabled. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_PWM_USE_CT16B1_CH1) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT16B1_CH1 FALSE +#endif + +/** + * @brief PWMD3 Channel 0 driver enable switch. + * @details If set to @p TRUE PWMD3 Channel 0 is enabled. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_PWM_USE_CT32B0_CH0) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT32B0_CH0 FALSE +#endif + +/** + * @brief PWMD3 Channel 1 driver enable switch. + * @details If set to @p TRUE PWMD3 Channel 1 is enabled. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_PWM_USE_CT32B0_CH1) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT32B0_CH1 FALSE +#endif + +/** + * @brief PWMD4 Channel 0 driver enable switch. + * @details If set to @p TRUE PWMD4 Channel 0 is enabled. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_PWM_USE_CT32B1_CH0) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT32B1_CH0 FALSE +#endif + +/** + * @brief PWMD4 Channel 1 driver enable switch. + * @details If set to @p TRUE PWMD4 Channel 1 is enabled. + * @note The default is @p FALSE. + */ +#if !defined(LPC122x_PWM_USE_CT32B1_CH1) || defined(__DOXYGEN__) +#define LPC122x_PWM_USE_CT32B1_CH1 FALSE +#endif +/** + * @brief PWMD1 interrupt priority level setting. + */ +#if !defined(LPC122x_PWM_CT16B0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT16B0_IRQ_PRIORITY 3 +#endif + +/** + * @brief PWMD2 interrupt priority level setting. + */ +#if !defined(LPC122x_PWM_CT16B1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT16B1_IRQ_PRIORITY 3 +#endif + +/** + * @brief PWMD3 interrupt priority level setting. + */ +#if !defined(LPC122x_PWM_CT32B0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT32B0_IRQ_PRIORITY 3 +#endif + +/** + * @brief PWMD4 interrupt priority level setting. + */ +#if !defined(LPC122x_PWM_CT32B1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT32B1_IRQ_PRIORITY 3 +#endif + +/** + * @brief PWM_CT16B0_CH0 signal selector. + */ +#if !defined(LPC122x_PWM_CT16B0_CH0_SELECTOR) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT16B0_CH0_SELECTOR PWM_CT16B0_CH0_IS_PIO0_11 +#endif + +/** + * @brief PWM_CT16B0_CH1 signal selector. + */ +#if !defined(LPC122x_PWM_CT16B0_CH1_SELECTOR) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT16B0_CH1_SELECTOR PWM_CT16B0_CH1_IS_PIO0_12 +#endif + +/** + * @brief PWM_CT16B1_CH0 signal selector. + */ +#if !defined(LPC122x_PWM_CT16B1_CH0_SELECTOR) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT16B1_CH0_SELECTOR PWM_CT16B1_CH0_IS_PIO0_15 +#endif + +/** + * @brief PWM_CT16B1_CH1 signal selector. + */ +#if !defined(LPC122x_PWM_CT16B1_CH1_SELECTOR) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT16B1_CH1_SELECTOR PWM_CT16B1_CH1_IS_PIO0_16 +#endif + +/** + * @brief PWM_CT32B0_CH0 signal selector. + */ +#if !defined(LPC122x_PWM_CT32B0_CH0_SELECTOR) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT32B0_CH0_SELECTOR PWM_CT32B0_CH0_IS_PIO0_1 +#endif + +/** + * @brief PWM_CT32B0_CH1 signal selector. + */ +#if !defined(LPC122x_PWM_CT32B0_CH1_SELECTOR) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT32B0_CH1_SELECTOR PWM_CT32B0_CH1_IS_PIO0_2 +#endif + +/** + * @brief PWM_CT32B1_CH0 signal selector. + */ +#if !defined(LPC122x_PWM_CT32B1_CH0_SELECTOR) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT32B1_CH0_SELECTOR PWM_CT32B1_CH0_IS_PIO0_6 +#endif + +/** + * @brief PWM_CT32B1_CH1 signal selector. + */ +#if !defined(LPC122x_PWM_CT32B1_CH1_SELECTOR) || defined(__DOXYGEN__) +#define LPC122x_PWM_CT32B1_CH1_SELECTOR PWM_CT32B1_CH1_IS_PIO0_7 +#endif + +/*===========================================================================*/ +/* Configuration checks. */ +/*===========================================================================*/ + + + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief PWM mode type. + */ +typedef uint32_t pwmmode_t; + +/** + * @brief PWM channel type. + */ +typedef uint8_t pwmchannel_t; + +/** + * @brief PWM counter type. + */ +typedef uint16_t pwmcnt_t; + +/** + * @brief PWM driver channel configuration structure. + */ +typedef struct { + /** + * @brief Channel active logic level. + */ + pwmmode_t mode; + /** + * @brief Channel callback pointer. + * @note This callback is invoked on the channel compare event. If set to + * @p NULL then the callback is disabled. + */ + pwmcallback_t callback; + /* End of the mandatory fields.*/ +} PWMChannelConfig; + +/** + * @brief PWM driver configuration structure. + */ +typedef struct { + /** + * @brief Timer clock in Hz. + * @note The low level can use assertions in order to catch invalid + * frequency specifications. + */ + uint32_t frequency; + /** + * @brief PWM period in ticks. + * @note The low level can use assertions in order to catch invalid + * period specifications. + */ + pwmcnt_t period; + /** + * @brief Periodic callback pointer. + * @note This callback is invoked on PWM counter reset. If set to + * @p NULL then the callback is disabled. + */ + pwmcallback_t callback; + /** + * @brief Channels configurations. + */ + PWMChannelConfig channels[PWM_CHANNELS]; + /* End of the mandatory fields.*/ + +} PWMConfig; + +/** + * @brief Structure representing a PWM driver. + */ +struct PWMDriver { + /** + * @brief Driver state. + */ + pwmstate_t state; + /** + * @brief Current driver configuration data. + */ + const PWMConfig *config; + /** + * @brief Current PWM period in ticks. + */ + pwmcnt_t period; +#if defined(PWM_DRIVER_EXT_FIELDS) + PWM_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Timer base clock. + */ + uint32_t clock; + /** + * @brief Pointer to the TIMx registers block. + */ + LPC_CTxxBx_Type *tim; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Changes the period the PWM peripheral. + * @details This function changes the period of a PWM unit that has already + * been activated using @p pwmStart(). + * @pre The PWM unit must have been activated using @p pwmStart(). + * @post The PWM unit period is changed to the new value. + * @note The function has effect at the next cycle start. + * @note If a period is specified that is shorter than the pulse width + * programmed in one of the channels then the behavior is not + * guaranteed. + * + * @param[in] pwmp pointer to a @p PWMDriver object + * @param[in] period new cycle time in ticks + * + * @notapi + */ +#define pwm_lld_change_period(pwmp, period) \ + ((pwmp)->tim->MR3 = (period)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if LPC122x_PWM_USE_CT16B0 && !defined(__DOXYGEN__) +extern PWMDriver PWMD1; +#endif + +#if LPC122x_PWM_USE_CT16B1 && !defined(__DOXYGEN__) +extern PWMDriver PWMD2; +#endif + +#if LPC122x_PWM_USE_CT32B0 && !defined(__DOXYGEN__) +extern PWMDriver PWMD3; +#endif + +#if LPC122x_PWM_USE_CT32B1 && !defined(__DOXYGEN__) +extern PWMDriver PWMD4; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void pwm_lld_init(void); + void pwm_lld_start(PWMDriver *pwmp); + void pwm_lld_stop(PWMDriver *pwmp); + void pwm_lld_enable_channel(PWMDriver *pwmp, + pwmchannel_t channel, + pwmcnt_t width); + void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_PWM */ + +#endif /* _PWM_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/LPC122x/rtc_lld.c b/os/hal/platforms/LPC122x/rtc_lld.c new file mode 100644 index 000000000..ad1a15f80 --- /dev/null +++ b/os/hal/platforms/LPC122x/rtc_lld.c @@ -0,0 +1,259 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x RTC driver - Copyright (C) 2013 Marcin Jokel + + 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file LPC122x/rtc_lld.c + * @brief LPC122x RTC low level driver. + * + * @addtogroup RTC + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief RTC driver identifier. + */ +RTCDriver RTCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief RTC interrupt handler. + * + * @isr + */ + +#if LPC122x_RTC_USE_ALARM || defined(__DOXYGEN__) +CH_IRQ_HANDLER(VectorB8) { + uint32_t flag; + + CH_IRQ_PROLOGUE(); + + flag = LPC_RTC->RIS; + LPC_RTC->ICR = flag; /* Clear interrupt flag */ + + if ((flag & RIS_RTCRIS) && (RTCD1.callback != NULL)) + RTCD1.callback(&RTCD1, RTC_EVENT_ALARM); + + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Enable access to registers. + * + * @api + */ +void rtc_lld_init(void) { + uint32_t temp[2]; + + if(LPC_SYSCON->SYSRESSTAT & 0x1) { /* POR detected */ + + LPC_SYSCON->SYSAHBCLKCTRL &= ~(1UL << 19); /* Disable clock for RTC */ + LPC_PMU->SYSCFG &= ~(0x0FUL << 11); /* Clear RTC clock source */ + LPC_SYSCON->RTCCLKDIV = LPC122x_RTC_CLKDIV; + LPC_PMU->SYSCFG |= (LPC122x_RTCCLK << 11); /* Set RTC clock source */ + LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 19); /* Enable clock for RTC registers*/ + LPC_RTC->ICR = 0x01; /* Clear interrupt flag */ + LPC_RTC->CR= 1; /* Enable RTC start */ + LPC_SYSCON->SYSRESSTAT = 0x1; /* Clear POR flag */ + + while(LPC_RTC->DR <3 ) { /* Wait, data read not valid */ + __NOP(); + } + } + else { + + LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 19); /* Enable clock for RTC registers*/ + + do { + temp[0] = LPC_RTC->DR; + temp[1] = LPC_RTC->DR; + } while(temp[0] == temp[1]); + +#if LPC122x_RTC_USE_ALARM + if (temp[1] >= LPC_RTC->MR) { /* Check for match event in software, handle if found */ + CH_IRQ_HANDLER(VectorB8); /* Manually invoke ISR */ + } +#endif + + } + +#if LPC122x_RTC_USE_ALARM + nvicEnableVector(RTC_IRQn, CORTEX_PRIORITY_MASK(LPC122x_RTC_IRQ_PRIORITY)); +#endif + return; +} + +/** + * @brief Set current time. + * @note Fractional part will be silently ignored. There is no possibility + * to set it on STM32 platform. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] timespec pointer to a @p RTCTime structure + * + * @api + */ +void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) { + (void)rtcp; + + LPC_RTC->LR = timespec->tv_sec; +} + +/** + * @brief Get current time. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[out] timespec pointer to a @p RTCTime structure + * + * @api + */ +void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec) { + (void)rtcp; + + timespec->tv_sec = LPC_RTC->DR; +} + +/** + * @brief Set alarm time. + * + * @note Default value after BKP domain reset for both comparators is 0. + * @note Function does not performs any checks of alarm time validity. + * + * @param[in] rtcp Pointer to RTC driver structure. + * @param[in] alarm Alarm identifier. Can be 1 or 2. + * @param[in] alarmspec Pointer to a @p RTCAlarm structure. + * + * @api + */ +void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec) { + (void)rtcp; + (void)alarm; + LPC_RTC->MR = alarmspec->tv_sec; + +} + +/** + * @brief Get alarm time. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] alarm alarm identifier + * @param[out] alarmspec pointer to a @p RTCAlarm structure + * + * @api + */ +void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec) { + (void)rtcp; + (void)alarm; + alarmspec->tv_sec = LPC_RTC->MR; + +} + +/** + * @brief Enables or disables RTC callbacks. + * @details This function enables or disables callbacks, use a @p NULL pointer + * in order to disable a callback. + * + * @param[in] rtcp pointer to RTC driver structure + * @param[in] callback callback function pointer or @p NULL + * + * @notapi + */ +void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) { + + LPC_RTC->ICR = 0x01; /* Clear interrupt flag */ + + if (callback != NULL) { + + /* IRQ sources enabled only after setting up the callback.*/ + rtcp->callback = callback; + LPC_RTC->ICSC = ICSC_RTCCIC; /* Enable RTC interrupt */ + } + else { + + LPC_RTC->ICSC = 0; /* Disable RTC interrupt */ + + /* Callback set to NULL only after disabling the IRQ sources.*/ + rtcp->callback = NULL; + } +} + +#include "chrtclib.h" + +/** + * @brief Get current time in format suitable for usage in FatFS. + * + * @param[in] rtcp pointer to RTC driver structure + * @return FAT time value. + * + * @api + */ +uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp) { + uint32_t fattime; + struct tm timp; + + rtcGetTimeTm(rtcp, &timp); + + fattime = (timp.tm_sec) >> 1; + fattime |= (timp.tm_min) << 5; + fattime |= (timp.tm_hour) << 11; + fattime |= (timp.tm_mday) << 16; + fattime |= (timp.tm_mon + 1) << 21; + fattime |= (timp.tm_year - 80) << 25; + + return fattime; +} + +#endif /* HAL_USE_RTC */ + +/** @} */ diff --git a/os/hal/platforms/LPC122x/rtc_lld.h b/os/hal/platforms/LPC122x/rtc_lld.h new file mode 100644 index 000000000..b3d3b48ff --- /dev/null +++ b/os/hal/platforms/LPC122x/rtc_lld.h @@ -0,0 +1,236 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + LPC122x RTC driver - Copyright (C) 2013 Marcin Jokel + + 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. +*/ +/* + Concepts and parts of this file have been contributed by Uladzimir Pylinsky + aka barthess. + */ + +/** + * @file LPC122x/rtc_lld.h + * @brief LPC122x RTC low level driver header. + * + * @addtogroup RTC + * @{ + */ + +#ifndef _RTC_LLD_H_ +#define _RTC_LLD_H_ + +#if HAL_USE_RTC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define CR_RTCSTART 1 +#define ICSC_RTCCIC 1 +#define RIS_RTCRIS 1 +#define MIS_RTCMIS 1 +#define ICR_RTCICR 1 + +/** + * @brief This RTC implementation supports callbacks. + */ +#define RTC_SUPPORTS_CALLBACKS TRUE + +/** + * @brief One alarm comparator available. + */ +#define RTC_ALARMS 1 + +/** + * @brief RTC Clock source type + */ +#define SYSCFG_RTCCLK_1Hz 0 /* 1 Hz clock */ +#define SYSCFG_RTCCLK_DEL_1Hz 1 /* delayed 1 Hz clock */ +#define SYSCFG_RTCCLK_1kHz 10 /* 1 kHz clock */ +#define SYSCFG_RTCCLK_PCLK 4 /* Main clock source divided by RTC */ + /* clock divider */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/* + * RTC driver system settings. + */ + +/** + * @brief RTC PCLK divider. + */ +#if !defined(LPC122x_RTC_CLKDIV) || defined(__DOXYGEN__) +#define LPC122x_RTC_CLKDIV 0 +#endif + +/** + * @brief RTC CLK Source + */ +#if !defined(LPC122x_RTCCLK) || defined(__DOXYGEN__) +#define LPC122x_RTCCLK SYSCFG_RTCCLK_1Hz +#endif + +/** + * @brief RTC Alarm enable. + */ +#if !defined(LPC122x_RTC_USE_ALARM) || defined(__DOXYGEN__) +#define LPC122x_RTC_USE_ALARM FALSE +#endif + +/** + * @brief RTC IRQ Priority. + */ +#if !defined(LPC122x_RTC_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define LPC122x_RTC_IRQ_PRIORITY 3 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !(LPC122x_RTCCLK == SYSCFG_RTCCLK_1Hz) && \ + !(LPC122x_RTCCLK == SYSCFG_RTCCLK_DEL_1Hz) && \ + !(LPC122x_RTCCLK == SYSCFG_RTCCLK_1kHz) && \ + !(LPC122x_RTCCLK == SYSCFG_RTCCLK_PCLK) +#error "Invalid source selected for RTC clock" +#endif + +#if LPC122x_RTCCLK == SYSCFG_RTCCLK_1kHz +#error "1 kHz RTC clock not supported" +#endif + +#if LPC122x_RTCCLK == SYSCFG_RTCCLK_PCLK +#if (LPC122x_MAINCLK/LPC122x_RTC_CLKDIV) != 1 +#error "RTC clock is not 1 Hz" +#endif +#endif +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an RTC alarm time stamp. + */ +typedef struct RTCAlarm RTCAlarm; + +/** + * @brief Type of a structure representing an RTC wakeup period. + */ +typedef struct RTCWakeup RTCWakeup; + +/** + * @brief Type of a structure representing an RTC callbacks config. + */ +typedef struct RTCCallbackConfig RTCCallbackConfig; + +/** + * @brief Type of an RTC alarm. + * @details Meaningful on platforms with more than 1 alarm comparator. + */ +typedef uint32_t rtcalarm_t; + +/** + * @brief Type of an RTC event. + */ +typedef enum { + RTC_EVENT_ALARM = 0 /** Triggered on alarm. */ +} rtcevent_t; + +/** + * @brief Type of a generic RTC callback. + */ +typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event); + +/** + * @brief Structure representing an RTC callbacks config. + */ +struct RTCCallbackConfig{ + /** + * @brief Generic RTC callback pointer. + */ + rtccb_t callback; +}; + +/** + * @brief Structure representing an RTC time stamp. + */ +struct RTCTime { + /** + * @brief Seconds since UNIX epoch. + */ + uint32_t tv_sec; +}; + +/** + * @brief Structure representing an RTC alarm time stamp. + */ +struct RTCAlarm { + /** + * @brief Seconds since UNIX epoch. + */ + uint32_t tv_sec; +}; + +/** + * @brief Structure representing an RTC driver. + */ +struct RTCDriver{ + /** + * @brief Callback pointer. + */ + rtccb_t callback; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern RTCDriver RTCD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void rtc_lld_init(void); + void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec); + void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec); + void rtc_lld_set_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + const RTCAlarm *alarmspec); + void rtc_lld_get_alarm(RTCDriver *rtcp, + rtcalarm_t alarm, + RTCAlarm *alarmspec); + void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback); + uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_RTC */ + +#endif /* _RTC_LLD_H_ */ + +/** @} */ -- cgit v1.2.3