diff options
Diffstat (limited to 'nuttx/arch/arm/src/lpc17xx/lpc17_timer.c')
-rw-r--r-- | nuttx/arch/arm/src/lpc17xx/lpc17_timer.c | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_timer.c b/nuttx/arch/arm/src/lpc17xx/lpc17_timer.c new file mode 100644 index 000000000..c1e2112de --- /dev/null +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_timer.c @@ -0,0 +1,667 @@ +/**************************************************************************** + * arch/arm/src/lpc17xx/lpc17_timer.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/pwm.h> +#include <arch/board/board.h> + +#include "up_internal.h" +#include "up_arch.h" + +#include "chip.h" +#include "chip/lpc17_syscon.h" +#include "lpc17_timer.h" +#include "chip/lpc176x_pinconfig.h" +#include "lpc17_gpio.h" +#include "lpc176x_gpio.h" + +/* This module then only compiles if there is at least one enabled timer + * intended for use with the TIMER upper half driver. + */ + +#if defined(CONFIG_LPC17_TMR0) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* PWM/Timer Definitions ****************************************************/ +/* The following definitions are used to identify the various time types */ + +#define TIMTYPE_BASIC 0 /* Basic timers: TIM6-7 */ +#define TIMTYPE_GENERAL16 1 /* General 16-bit timers: TIM2-5 on F1 */ +#define TIMTYPE_COUNTUP16 2 /* General 16-bit count-up timers: TIM9-14 on F4 */ +#define TIMTYPE_GENERAL32 3 /* General 32-bit timers: TIM2-5 on F4 */ +#define TIMTYPE_ADVANCED 4 /* Advanced timers: TIM1-8 */ + +#define TIMTYPE_TIM1 TIMTYPE_ADVANCED + + +/* Debug ********************************************************************/ +/* Non-standard debug that may be enabled just for testing PWM */ + +#ifndef CONFIG_DEBUG +# undef CONFIG_DEBUG_PWM +#endif + +#ifdef CONFIG_DEBUG_PWM +# define pwmdbg dbg +# define pwmlldbg lldbg +# ifdef CONFIG_DEBUG_VERBOSE +# define pwmvdbg vdbg +# define pwmllvdbg llvdbg +# define pwm_dumpgpio(p,m) stm32_dumpgpio(p,m) +# else +# define pwmlldbg(x...) +# define pwmllvdbg(x...) +# define pwm_dumpgpio(p,m) +# endif +#else +# define pwmdbg(x...) +# define pwmlldbg(x...) +# define pwmvdbg(x...) +# define pwmllvdbg(x...) +# define pwm_dumpgpio(p,m) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/* This structure represents the state of one PWM timer */ + +struct lpc17_timer_s +{ + FAR const struct pwm_ops_s *ops; /* PWM operations */ + uint8_t timid; /* Timer ID {0,...,7} */ + uint8_t channel; /* Timer output channel: {1,..4} */ + uint8_t timtype; /* See the TIMTYPE_* definitions */ + uint32_t base; /* The base address of the timer */ + uint32_t pincfg; /* Output pin configuration */ + uint32_t pclk; /* The frequency of the peripheral clock + * that drives the timer module. */ +}; + +/**************************************************************************** + * Static Function Prototypes + ****************************************************************************/ +/* Register access */ + +static uint32_t timer_getreg(struct lpc17_timer_s *priv, int offset); +static void timer_putreg(struct lpc17_timer_s *priv, int offset, uint32_t value); + +#if defined(CONFIG_DEBUG_PWM) && defined(CONFIG_DEBUG_VERBOSE) +static void timer_dumpregs(struct lpc17_timer_s *priv, FAR const char *msg); +#else +# define timer_dumpregs(priv,msg) +#endif + +/* Timer management */ + +static int timer_timer(FAR struct lpc17_timer_s *priv, + FAR const struct pwm_info_s *info); + +/* PWM driver methods */ + +static int timer_setup(FAR struct pwm_lowerhalf_s *dev); +static int timer_shutdown(FAR struct pwm_lowerhalf_s *dev); + +static int timer_start(FAR struct pwm_lowerhalf_s *dev, + FAR const struct pwm_info_s *info); + +static int timer_stop(FAR struct pwm_lowerhalf_s *dev); +static int timer_ioctl(FAR struct pwm_lowerhalf_s *dev, + int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ +/* This is the list of lower half PWM driver methods used by the upper half driver */ + +static const struct pwm_ops_s g_pwmops = +{ + .setup = timer_setup, + .shutdown = timer_shutdown, + .start = timer_start, + .stop = timer_stop, + .ioctl = timer_ioctl, +}; + +#ifdef CONFIG_LPC17_TMR0 +static struct lpc17_timer_s g_pwm1dev = +{ + .ops = &g_pwmops, + .timid = 1, + .channel = CONFIG_LPC17_MAT0_PIN, + .timtype = TIMTYPE_TIM1, + .base = LPC17_TMR1_BASE, + .pincfg = GPIO_MAT0p1_2, + .pclk = (0x1 << 12), +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: timer_getreg + * + * Description: + * Read the value of an PWM timer register. + * + * Input Parameters: + * priv - A reference to the PWM block status + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ****************************************************************************/ + +static uint32_t timer_getreg(struct lpc17_timer_s *priv, int offset) +{ + return getreg32(priv->base + offset); +} + +/**************************************************************************** + * Name: timer_putreg + * + * Description: + * Read the value of an PWM timer register. + * + * Input Parameters: + * priv - A reference to the PWM block status + * offset - The offset to the register to read + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void timer_putreg(struct lpc17_timer_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +/**************************************************************************** + * Name: timer_dumpregs + * + * Description: + * Dump all timer registers. + * + * Input parameters: + * priv - A reference to the PWM block status + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_PWM) && defined(CONFIG_DEBUG_VERBOSE) +static void timer_dumpregs(struct lpc17_timer_s *priv, FAR const char *msg) +{ + pwmdbg("%s:\n", msg); + pwmdbg(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n", + timer_getreg(priv, LPC17_PWM_MR0_OFFSET), + timer_getreg(priv, LPC17_PWM_MR1_OFFSET), + timer_getreg(priv, LPC17_PWM_MR2_OFFSET), + timer_getreg(priv, LPC17_PWM_MR3_OFFSET)); +#if defined(CONFIG_LPC17_TMR0) + if (priv->timtype == TIMTYPE_ADVANCED) + { + pwmdbg(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n", + timer_getreg(priv, LPC17_PWM_MR0_OFFSET), + timer_getreg(priv, LPC17_PWM_MR1_OFFSET), + timer_getreg(priv, LPC17_PWM_MR2_OFFSET), + timer_getreg(priv, LPC17_PWM_MR3_OFFSET)); + } + else +#endif + { + pwmdbg(" DCR: %04x DMAR: %04x\n", + timer_getreg(priv, LPC17_PWM_MR2_OFFSET), + timer_getreg(priv, LPC17_PWM_MR3_OFFSET)); + } +} +#endif + +/**************************************************************************** + * Name: timer_timer + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * Input parameters: + * priv - A reference to the lower half PWM driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int timer_timer(FAR struct lpc17_timer_s *priv, + FAR const struct pwm_info_s *info) +{ + irqstate_t flags; + uint32_t regval; + + flags = irqsave(); + + putreg32(info->frequency, LPC17_TMR0_MR1); /* Set TIMER MR0 = number of counts */ + putreg32(info->frequency, LPC17_TMR1_MR0); /* Set TIMER MR0 = number of counts */ + + putreg32(1, LPC17_TMR0_TCR); /* Start timer0*/ + putreg32(1, LPC17_TMR1_TCR); /* Start timer0*/ + + irqrestore(flags); + timer_dumpregs(priv, "After starting"); + return OK; +} + +#ifdef XXXXX +/**************************************************************************** + * Name: timer_interrupt + * + * Description: + * Handle timer interrupts. + * + * Input parameters: + * priv - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int timer_interrupt(struct lpc17_timer_s *priv) +{ + uint16_t regval; + + /* Verify that this is an update interrupt. Nothing else is expected. */ + + regval = timer_getreg(priv, STM32_ATIM_SR_OFFSET); + DEBUGASSERT((regval & ATIM_SR_UIF) != 0); + + /* Clear the UIF interrupt bit */ + + timer_putreg(priv, STM32_ATIM_SR_OFFSET, regval & ~ATIM_SR_UIF); + + /* Calculate the new count by subtracting the number of pulses + * since the last interrupt. + */ + + return OK; +} + +/**************************************************************************** + * Name: timer_tim1/8interrupt + * + * Description: + * Handle timer 1 and 8 interrupts. + * + * Input parameters: + * Standard NuttX interrupt inputs + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int timer_tim1interrupt(int irq, void *context) +{ + return timer_interrupt(&g_pwm1dev); +} + +/**************************************************************************** + * Name: timer_set_apb_clock + * + * Description: + * Enable or disable APB clock for the timer peripheral + * + * Input parameters: + * dev - A reference to the lower half PWM driver state structure + * on - Enable clock if 'on' is 'true' and disable if 'false' + * + ****************************************************************************/ + +static void timer_set_apb_clock(FAR struct lpc17_timer_s *priv, bool on) +{ + uint32_t en_bit; + uint32_t regaddr; + + /* Determine which timer to configure */ + + switch (priv->timid) + { +#ifdef CONFIG_LPC17_TMR0 + case 1: + regaddr = STM32_RCC_APB2ENR; + en_bit = RCC_APB2ENR_TIM1EN; + break; +#endif + } + + /* Enable/disable APB 1/2 clock for timer */ + + if (on) + { + modifyreg32(regaddr, 0, en_bit); + } + else + { + modifyreg32(regaddr, en_bit, 0); + } +} +#endif /*XXXXX*/ + +/**************************************************************************** + * Name: timer_setup + * + * Description: + * This method is called when the driver is opened. The lower half driver + * should configure and initialize the device so that it is ready for use. + * It should not, however, output pulses until the start method is called. + * + * Input parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * APB1 or 2 clocking for the GPIOs has already been configured by the RCC + * logic at power up. + * + ****************************************************************************/ + +static int timer_setup(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct lpc17_timer_s *priv = (FAR struct lpc17_timer_s *)dev; + irqstate_t flags; + uint32_t regval; + + flags = irqsave(); + + /* Power on the timer peripherals*/ + + regval = getreg32(LPC17_SYSCON_PCONP); + regval |= SYSCON_PCONP_PCTIM0; + regval |= SYSCON_PCONP_PCTIM1; + regval |= SYSCON_PCONP_PCTIM2; + regval |= SYSCON_PCONP_PCTIM3; + putreg32(regval, LPC17_SYSCON_PCONP); + + /* Select clock for the timer peripheral*/ + + regval = getreg32(LPC17_SYSCON_PCLKSEL0); + regval &= ~(0x3 << 2); + regval |= (0x1 << 2); /* PCLK_MC peripheral clk = CCLK = 12.5 MHz */ + regval &= ~(0x3 << 4); + regval |= (0x1 << 4); /* PCLK_MC peripheral clk = CCLK = 12.5 MHz */ + putreg32(regval, LPC17_SYSCON_PCLKSEL0); + regval = getreg32(LPC17_SYSCON_PCLKSEL1); + regval &= ~(0x3 << 12); + regval |= (0x1 << 12); /* PCLK_MC peripheral clk = CCLK = 12.5 MHz */ + regval &= ~(0x3 << 14); + regval |= (0x1 << 14); /* PCLK_MC peripheral clk = CCLK = 12.5 MHz */ + putreg32(regval, LPC17_SYSCON_PCLKSEL1); + priv->pclk = (0x1 << 12) | (0x1 << 4); + + putreg32(500, LPC17_TMR0_MR1); /* Set TIMER0 MR1 = number of counts */ + + putreg32(1, LPC17_TMR0_PR); /* Prescaler count frequency:Fpclk/1 */ + putreg32(~(0x3 << 0), LPC17_TMR0_CCR); /* Prescaler count frequency:Fpclk/1 */ + putreg32(~(0x3 << 0), LPC17_TMR0_CTCR);/* Prescaler count frequency:Fpclk/1 */ + putreg32((2 << 3), LPC17_TMR0_MCR); /* Reset on match register MR1*/ + putreg32(((1 << 1)|(3 << 6)), LPC17_TMR0_EMR); /* Output bit toggle on external match event*/ + putreg32((1 << 0), LPC17_TMR0_TCR); /* Start timer0*/ + + /* Sonfigure the output pins GPIO3.26*/ + + lpc17_configgpio(GPIO_MAT0p1_2); + + putreg32(1000, LPC17_TMR1_MR0); /* Set TIMER1 MR0 = number of counts */ + + putreg32(1, LPC17_TMR1_PR); /* Prescaler count frequency:Fpclk/1 */ + putreg32(~(0x3 << 0), LPC17_TMR1_CCR); /* Prescaler count frequency:Fpclk/1 */ + putreg32(~(0x3 << 0), LPC17_TMR1_CTCR);/* Prescaler count frequency:Fpclk/1 */ + putreg32((2 << 0), LPC17_TMR1_MCR); /* Reset on match register MR0 */ +// putreg32(((1 << 0)|(3 << 4)), LPC17_TMR1_EMR); /* Output bit toggle on external match event MAT0*/ + putreg32((1 << 0), LPC17_TMR1_TCR); /* Start timer1*/ + + /* configure the output pins GPIO3.26 */ +// lpc17_configgpio(GPIO_MAT0p1_2); + + irqrestore(flags); + pwm_dumpgpio(priv->pincfg, "TIMER setup"); + return OK; +} + +/**************************************************************************** + * Name: timer_shutdown + * + * Description: + * This method is called when the driver is closed. The lower half driver + * stop pulsed output, free any resources, disable the timer hardware, and + * put the system into the lowest possible power usage state + * + * Input parameters: + * dev - A reference to the lower half TIMER driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int timer_shutdown(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct lpc17_timer_s *priv = (FAR struct lpc17_timer_s *)dev; + uint32_t pincfg; + + pwmdbg("TIM%d pincfg: %08x\n", priv->timid, priv->pincfg); + + /* Make sure that the output has been stopped */ + + return OK; +} + +/**************************************************************************** + * Name: timer_start + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * Input parameters: + * dev - A reference to the lower half TIMER driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int timer_start(FAR struct pwm_lowerhalf_s *dev, + FAR const struct pwm_info_s *info) +{ + FAR struct lpc17_timer_s *priv = (FAR struct lpc17_timer_s *)dev; + return timer_timer(priv, info); +} + +/**************************************************************************** + * Name: timer_stop + * + * Description: + * Stop the pulsed output and reset the timer resources + * + * Input parameters: + * dev - A reference to the lower half TIMER driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * This function is called to stop the pulsed output at anytime. This + * method is also called from the timer interrupt handler when a repetition + * count expires... automatically stopping the timer. + * + ****************************************************************************/ + +static int timer_stop(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct lpc17_timer_s *priv = (FAR struct lpc17_timer_s *)dev; + uint32_t resetbit; + uint32_t regaddr; + uint32_t regval; + irqstate_t flags; + + pwmdbg("TIM%d\n", priv->timid); + + /* Disable interrupts momentary to stop any ongoing timer processing and + * to prevent any concurrent access to the reset register. + */ + + flags = irqsave(); + + /* Disable further interrupts and stop the timer */ + + /* Determine which timer to reset */ + + switch (priv->timid) + { +#ifdef CONFIG_LPC17_TMR0 + case 1: + break; +#endif + } + + /* Reset the timer - stopping the output and putting the timer back + * into a state where timer_start() can be called. + */ + + irqrestore(flags); + + pwmdbg("regaddr: %08x resetbit: %08x\n", regaddr, resetbit); + timer_dumpregs(priv, "After stop"); + return OK; +} + +/**************************************************************************** + * Name: timer_ioctl + * + * Description: + * Lower-half logic may support platform-specific ioctl commands + * + * Input parameters: + * dev - A reference to the lower half TIMER driver state structure + * cmd - The ioctl command + * arg - The argument accompanying the ioctl command + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int timer_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd, unsigned long arg) +{ +#ifdef CONFIG_DEBUG_TIMER + FAR struct lpc17_timer_s *priv = (FAR struct lpc17_timer_s *)dev; + + /* There are no platform-specific ioctl commands */ + + pwmdbg("TIM%d\n", priv->timid); +#endif + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc17_timerinitialize + * + * Description: + * Initialize one timer for use with the upper_level TIMER driver. + * + * Input Parameters: + * timer - A number identifying the timer use. The number of valid timer + * IDs varies with the STM32 MCU and MCU family but is somewhere in + * the range of {1,..,14}. + * + * Returned Value: + * On success, a pointer to the STM32 lower half TIMER driver is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +FAR struct pwm_lowerhalf_s *lpc17_timerinitialize(int timer) +{ + FAR struct lpc17_timer_s *lower; + + pwmdbg("TIM%d\n", timer); + + switch (timer) + { +#ifdef CONFIG_LPC17_TMR0 + case 0: + lower = &g_pwm1dev; + + /* Attach but disable the TIM1 update interrupt */ + + break; +#endif + + default: + pwmdbg("No such timer configured\n"); + return NULL; + } + + return (FAR struct pwm_lowerhalf_s *)lower; +} + +#endif /* CONFIG_LPC17_TIMn_TIMER, n = 1,...,14 */ |