diff --git a/arch/arm/src/tiva/Make.defs b/arch/arm/src/tiva/Make.defs index 0ba34f6751a..f3eb92fadce 100644 --- a/arch/arm/src/tiva/Make.defs +++ b/arch/arm/src/tiva/Make.defs @@ -101,6 +101,10 @@ ifeq ($(CONFIG_TIVA_I2C),y) CHIP_CSRCS += tiva_i2c.c endif +ifeq ($(CONFIG_TIVA_PWM),y) +CHIP_CSRCS += tiva_pwm.c +endif + ifeq ($(CONFIG_TIVA_TIMER),y) CHIP_CSRCS += tiva_timerlib.c ifeq ($(CONFIG_TIVA_TIMER32_PERIODIC),y) diff --git a/arch/arm/src/tiva/chip/tiva_pwm.h b/arch/arm/src/tiva/chip/tiva_pwm.h new file mode 100644 index 00000000000..f0af47a6696 --- /dev/null +++ b/arch/arm/src/tiva/chip/tiva_pwm.h @@ -0,0 +1,112 @@ +/************************************************************************************ + * arch/arm/src/tiva/chip/tiva_pwm.h + * + * Copyright (C) 2016 Young Mu. All rights reserved. + * Author: Young Mu + * + * 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. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_TIVA_CHIP_TIVA_PWM_H +#define __ARCH_ARM_SRC_TIVA_CHIP_TIVA_PWM_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +#define TIVA_PWM_CTL_OFFSET (0x0) /* PWM Master Control */ +#define TIVA_PWM_SYNC_OFFSET (0x4) /* PWM Time Base Sync */ +#define TIVA_PWM_ENABLE_OFFSET (0x8) /* PWM Output Enable */ +#define TIVA_PWM_INVERT_OFFSET (0xc) /* PWM Output Inversion */ +#define TIVA_PWM_FAULT_OFFSET (0x10) /* PWM Output Fault */ +#define TIVA_PWM_INTEN_OFFSET (0x14) /* PWM Interrupt Enable */ +#define TIVA_PWM_RIS_OFFSET (0x18) /* PWM Raw Interrupt Status */ +#define TIVA_PWM_ISC_OFFSET (0x1c) /* PWM Interrupt Status and Clear */ +#define TIVA_PWM_STATUS_OFFSET (0x20) /* PWM Status */ +#define TIVA_PWM_FAULTVAL_OFFSET (0x24) /* PWM Fault Condition Value */ +#define TIVA_PWM_ENUPD_OFFSET (0x28) /* PWM Enable Update */ + +#define TIVA_PWMn_BASE (0x40) /* PWMn Base */ +#define TIVA_PWMn_INTERVAL (0x40) /* PWMn Interval */ + +#define TIVA_PWMn_CTL_OFFSET (0x0) /* PWMn Control */ +#define TIVA_PWMn_INTEN_OFFSET (0x4) /* PWMn Interrupt and Trigger Enable */ +#define TIVA_PWMn_RIS_OFFSET (0x8) /* PWMn Raw Interrupt Status */ +#define TIVA_PWMn_ISC_OFFSET (0xc) /* PWMn Interrupt Status and Clear */ +#define TIVA_PWMn_LOAD_OFFSET (0x10) /* PWMn Load */ +#define TIVA_PWMn_COUNT_OFFSET (0x14) /* PWMn Counter */ +#define TIVA_PWMn_CMPA_OFFSET (0x18) /* PWMn Compare A */ +#define TIVA_PWMn_CMPB_OFFSET (0x1c) /* PWMn Compare B */ +#define TIVA_PWMn_GENA_OFFSET (0x20) /* PWMn Generator A Control */ +#define TIVA_PWMn_GENB_OFFSET (0x24) /* PWMn Generator B Control */ +#define TIVA_PWMn_DBCTL_OFFSET (0x28) /* PWMn Dead-Band Control */ +#define TIVA_PWMn_DBRISE_OFFSET (0x2c) /* PWMn Dead-Band Rising-Edge-Delay */ +#define TIVA_PWMn_DBFALL_OFFSET (0x30) /* PWMn Dead-Band Falling-Edge-Delay */ +#define TIVA_PWMn_FLTSRC0_OFFSET (0x34) /* PWMn Fault Source 0 */ +#define TIVA_PWMn_FLTSRC1_OFFSET (0x38) /* PWMn Fault Source 1 */ +#define TIVA_PWMn_MINFLTPER_OFFSET (0x3c) /* PWMn Minimum Fault Period */ + +#define TIVA_PWMn_FAULT_BASE (0x800) /* PWMn Fault Base */ +#define TIVA_PWMn_FAULT_INTERVAL (0x80) /* PWMn Fault Interval */ + +#define TIVA_PWMn_FAULT_SEN_OFFSET (0x0) /* PWMn Fault Pin Logic Sense */ +#define TIVA_PWMn_FAULT_STAT0_OFFSET (0x4) /* PWMn Fault Status 0 */ +#define TIVA_PWMn_FAULT_STAT1_OFFSET (0x8) /* PWMn Fault Status 1 */ + +#define TIVA_PWM_PP (0xfc0) /* PWM Peripheral Properties */ +#define TIVA_PWM_CC (0xfc8) /* PWM Clock Configuration */ + +#define TIVA_PWMn_GENx_ACTCMPBD (10) /* (Bit) Action for Comparator B Down */ +#define TIVA_PWMn_GENx_ACTCMPBU (8) /* (Bit) Action for Comparator B Up */ +#define TIVA_PWMn_GENx_ACTCMPAD (6) /* (Bit) Action for Comparator A Down */ +#define TIVA_PWMn_GENx_ACTCMPAU (4) /* (Bit) Action for Comparator A Up */ +#define TIVA_PWMn_GENx_ACTLOAD (2) /* (Bit) Action for Counter equals LOAD */ +#define TIVA_PWMn_GENx_ACTZERO (0) /* (Bit) Action for Counter equals ZERO */ +#define GENx_INVERT (0x1) /* (Value) Invert */ +#define GENx_LOW (0x2) /* (Value) Drive Low */ +#define GENx_HIGH (0x3) /* (Value) Drive High */ + +#define TIVA_PWM_CC_USEPWM (8) /* (Bit) Use PWM Clock Divisor */ +#define TIVA_PWM_CC_PWMDIV (0) /* (Bit) PWM Clock Divider */ +#define CC_USEPWM (0x1) /* (Value) Use PWM divider as clock source */ +#define CC_PWMDIV_2 (0x0) /* (Value) Divided by 2 */ +#define CC_PWMDIV_4 (0x1) /* (Value) Divided by 4 */ +#define CC_PWMDIV_8 (0x2) /* (Value) Divided by 8 */ +#define CC_PWMDIV_16 (0x3) /* (Value) Divided by 16 */ +#define CC_PWMDIV_32 (0x4) /* (Value) Divided by 32 */ +#define CC_PWMDIV_64 (0x5) /* (Value) Divided by 64 */ + +#define TIVA_PWMn_CTL_ENABLE (0) /* (Bit) PWM Block Enable */ +#define CTL_ENABLE (1) /* (Value) Enable */ + +#endif /* __ARCH_ARM_SRC_TIVA_CHIP_TIVA_PWM_H */ diff --git a/arch/arm/src/tiva/chip/tm4c129_syscontrol.h b/arch/arm/src/tiva/chip/tm4c129_syscontrol.h index 928be38e95a..9578313b86b 100644 --- a/arch/arm/src/tiva/chip/tm4c129_syscontrol.h +++ b/arch/arm/src/tiva/chip/tm4c129_syscontrol.h @@ -1895,7 +1895,9 @@ /* PWM Power Control */ -#define SYSCON_PCPWM_P0 (1 << 0) /* Bit 0: PWM Module 0 Power Control */ +#define SYSCON_PCPWM(n) (1 << (n)) /* Bit n: PWM module n Power Control */ +# define SYSCON_PCPWM_P0 (1 << 0) /* Bit 0: PWM Module 0 Power Control */ +# define SYSCON_PCPWM_P1 (1 << 1) /* Bit 1: PWM Module 1 Power Control */ /* QE Interface Power Control */ diff --git a/arch/arm/src/tiva/tiva_pwm.c b/arch/arm/src/tiva/tiva_pwm.c new file mode 100644 index 00000000000..9e1f660be51 --- /dev/null +++ b/arch/arm/src/tiva/tiva_pwm.c @@ -0,0 +1,576 @@ +/************************************************************************************ +* arch/arm/src/tiva/tiva_pwm.c +* +* Copyright (C) 2016 Young Mu. All rights reserved. +* Author: Young Mu +* +* The basic structure of this driver derives in spirit (if nothing more) from the +* NuttX SAM PWM driver which has: +* +* Copyright (C) 2013 Gregory Nutt. All rights reserved. +* Author: Gregory Nutt +* +* 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 +#include + +#include + +#include "up_arch.h" +#include "tiva_gpio.h" +#include "tiva_pwm.h" +#include "tiva_enablepwr.h" +#include "tiva_enableclks.h" + +#include "chip/tiva_pwm.h" +#include "chip/tiva_pinmap.h" +#include "chip/tm4c_memorymap.h" + +/************************************************************************************ +* Pre-processor Definitions +************************************************************************************/ + +#define pwmerr(fmt, args...) printf("%s(%d): " fmt, __FUNCTION__, __LINE__, ##args); + +#ifndef CONFIG_DEBUG +# undef CONFIG_DEBUG_PWM +#endif + +#ifdef CONFIG_DEBUG_PWM +# define pwmdbg dbg +# ifdef CONFIG_DEBUG_VERBOSE +# define pwmvdbg vdbg +# else +# define pwmvdbg(x...) +# endif +#else +# define pwmdbg(x...) +# define pwmvdbg(x...) +#endif + +/************************************************************************************ +* Private Types +************************************************************************************/ + +uint32_t g_pwm_pinset[] = +{ + GPIO_M0_PWM0, + GPIO_M0_PWM1, + GPIO_M0_PWM2, + GPIO_M0_PWM3, + GPIO_M0_PWM4, + GPIO_M0_PWM5, + GPIO_M0_PWM6, + GPIO_M0_PWM7, +}; + +struct tiva_pwm_chan_s +{ + const struct pwm_ops_s *ops; + uint8_t controller_id; + uintptr_t controller_base; + uint8_t generator_id; + uintptr_t generator_base; + uint8_t channel_id; +}; + + +/************************************************************************************ +* Private Function Prototypes +************************************************************************************/ + +static inline void tiva_pwm_putreg(struct tiva_pwm_chan_s *chan, unsigned int offset, uint32_t regval); +static inline uint32_t tiva_pwm_getreg(struct tiva_pwm_chan_s *chan, unsigned int offset); + +static int tiva_pwm_setup(FAR struct pwm_lowerhalf_s *dev); +static int tiva_pwm_shutdown(FAR struct pwm_lowerhalf_s *dev); +static int tiva_pwm_start(FAR struct pwm_lowerhalf_s *dev, + FAR const struct pwm_info_s *info); +static int tiva_pwm_stop(FAR struct pwm_lowerhalf_s *dev); +static int tiva_pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, + int cmd, unsigned long arg); + +/************************************************************************************ +* Private Data +************************************************************************************/ + +uint32_t g_pwm_freq = 15000000; +uint32_t g_pwm_counter = (1 << 16); + +static const struct pwm_ops_s g_pwm_ops = +{ + .setup = tiva_pwm_setup, + .shutdown = tiva_pwm_shutdown, + .start = tiva_pwm_start, + .stop = tiva_pwm_stop, + .ioctl = tiva_pwm_ioctl, +}; + +#ifdef CONFIG_TIVA_PWM0_CHAN0 +static struct tiva_pwm_chan_s g_pwm_chan0 = +{ + .ops = &g_pwm_ops, + .controller_id = 0, + .controller_base = TIVA_PWM0_BASE, + .generator_id = 0, + .generator_base = TIVA_PWM0_BASE + TIVA_PWMn_BASE + TIVA_PWMn_INTERVAL * 0, + .channel_id = 0, +}; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN1 +static struct tiva_pwm_chan_s g_pwm_chan1 = +{ + .ops = &g_pwm_ops, + .controller_id = 0, + .controller_base = TIVA_PWM0_BASE, + .generator_id = 0, + .generator_base = TIVA_PWM0_BASE + TIVA_PWMn_BASE + TIVA_PWMn_INTERVAL * 0, + .channel_id = 1, +}; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN2 +static struct tiva_pwm_chan_s g_pwm_chan2 = +{ + .ops = &g_pwm_ops, + .controller_id = 0, + .controller_base = TIVA_PWM0_BASE, + .generator_id = 1, + .generator_base = TIVA_PWM0_BASE + TIVA_PWMn_BASE + TIVA_PWMn_INTERVAL * 1, + .channel_id = 2, +}; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN3 +static struct tiva_pwm_chan_s g_pwm_chan3 = +{ + .ops = &g_pwm_ops, + .controller_id = 0, + .controller_base = TIVA_PWM0_BASE, + .generator_id = 1, + .generator_base = TIVA_PWM0_BASE + TIVA_PWMn_BASE + TIVA_PWMn_INTERVAL * 1, + .channel_id = 3, +}; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN4 +static struct tiva_pwm_chan_s g_pwm_chan4 = +{ + .ops = &g_pwm_ops, + .controller_id = 0, + .controller_base = TIVA_PWM0_BASE, + .generator_id = 2, + .generator_base = TIVA_PWM0_BASE + TIVA_PWMn_BASE + TIVA_PWMn_INTERVAL * 2, + .channel_id = 4, +}; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN5 +static struct tiva_pwm_chan_s g_pwm_chan5 = +{ + .ops = &g_pwm_ops, + .controller_id = 0, + .controller_base = TIVA_PWM0_BASE, + .generator_id = 2, + .generator_base = TIVA_PWM0_BASE + TIVA_PWMn_BASE + TIVA_PWMn_INTERVAL * 2, + .channel_id = 5, +}; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN6 +static struct tiva_pwm_chan_s g_pwm_chan6 = +{ + .ops = &g_pwm_ops, + .controller_id = 0, + .controller_base = TIVA_PWM0_BASE, + .generator_id = 3, + .generator_base = TIVA_PWM0_BASE + TIVA_PWMn_BASE + TIVA_PWMn_INTERVAL * 3, + .channel_id = 6, +}; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN7 +static struct tiva_pwm_chan_s g_pwm_chan7 = +{ + .ops = &g_pwm_ops, + .controller_id = 0, + .controller_base = TIVA_PWM0_BASE, + .generator_id = 3, + .generator_base = TIVA_PWM0_BASE + TIVA_PWMn_BASE + TIVA_PWMn_INTERVAL * 3, + .channel_id = 7, +}; +#endif + +/************************************************************************************ +* Private Functions +************************************************************************************/ + +/************************************************************************************ +* Name: tiva_pwm_getreg +* +* Description: +* Get a 32-bit register value by offset +* +************************************************************************************/ + +static inline uint32_t tiva_pwm_getreg(struct tiva_pwm_chan_s *chan, unsigned int offset) +{ + uintptr_t regaddr = chan->generator_base + offset; + return getreg32(regaddr); +} + +/************************************************************************************ +* Name: tiva_pwm_putreg +* +* Description: +* Put a 32-bit register value by offset +* +************************************************************************************/ + +static inline void tiva_pwm_putreg(struct tiva_pwm_chan_s *chan, unsigned int offset, uint32_t regval) +{ + uintptr_t regaddr = chan->generator_base + offset; + putreg32(regval, regaddr); +} + +/**************************************************************************** +* Name: pwm_setup +* +* Description: +* This method is called when the driver is opened. The lower half driver +* will be configured and initialized the device so that it is ready for +* use. It will 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 +* +****************************************************************************/ + +static int tiva_pwm_setup(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct tiva_pwm_chan_s *chan = (FAR struct tiva_pwm_chan_s *)dev; + pwmdbg("setup PWM for channel %d\n", chan->channel_id); + + /* Enable GPIO port, GPIO pin type and GPIO alternate function (refer to TM4C1294NC 23.4.2-4) */ + int ret = tiva_configgpio(g_pwm_pinset[chan->channel_id]); + if (ret < 0) + { + pwmerr("tiva_configgpio failed (%x)\n", g_pwm_pinset[chan->channel_id]); + return -1; + } + + return OK; +} + +/**************************************************************************** +* Name: pwm_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 PWM driver state structure +* +* Returned Value: +* Zero on success; a negated errno value on failure +* +****************************************************************************/ + +static int tiva_pwm_shutdown(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct tiva_pwm_chan_s *chan = (FAR struct tiva_pwm_chan_s *)dev; + pwmdbg("shutdown PWM for channel %d\n", chan->channel_id); + + /* Remove unused-variable warning */ + (void)chan; + + /* Ensure the PWM channel has been stopped */ + tiva_pwm_stop(dev); + + return OK; +} + +/**************************************************************************** +* Name: pwm_start +* +* Description: +* (Re-)initialize the timer resources and start the pulsed output +* +* Input parameters: +* dev - 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 tiva_pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_s *info) +{ + FAR struct tiva_pwm_chan_s *chan = (FAR struct tiva_pwm_chan_s *)dev; + pwmdbg("start PWM for channel %d\n", chan->channel_id); + + uint16_t duty = info->duty; + uint32_t frequency = info->frequency; + + /* Configure PWM countdown mode (refer to TM4C1294NC 23.4.6) */ + tiva_pwm_putreg(chan, TIVA_PWMn_CTL_OFFSET, 0); + if (chan->channel_id % 2 == 0) + { + tiva_pwm_putreg(chan, TIVA_PWMn_GENA_OFFSET, + GENx_LOW << TIVA_PWMn_GENx_ACTCMPAD | GENx_HIGH << TIVA_PWMn_GENx_ACTLOAD); + } + else + { + tiva_pwm_putreg(chan, TIVA_PWMn_GENB_OFFSET, + GENx_LOW << TIVA_PWMn_GENx_ACTCMPBD | GENx_HIGH << TIVA_PWMn_GENx_ACTLOAD); + } + + /* Set the PWM period (refer to TM4C1294NC 23.4.7) */ + uint32_t pwm_min_freq = (uint32_t)(g_pwm_freq / g_pwm_counter) + 1; + uint32_t pwm_max_freq = g_pwm_freq; + uint32_t load = (uint32_t)(g_pwm_freq / frequency); + pwmdbg("channel %d: load = %u (%08x)\n", chan->channel_id, load, load); + if (load >= g_pwm_counter || load < 1) + { + pwmerr("frequency should be in [%d, %d] Hz\n", pwm_min_freq, pwm_max_freq); + return -1; + } + tiva_pwm_putreg(chan, TIVA_PWMn_LOAD_OFFSET, load - 1); + + /* Configure PWM duty (refer to TM4C1294NC 23.4.8-9) */ + uint32_t comp = (uint32_t)((1 - (float)duty / g_pwm_counter) * load); + pwmdbg("channel %d: comp = %u (%08x)\n", chan->channel_id, comp, comp); + if (chan->channel_id % 2 == 0) + { + tiva_pwm_putreg(chan, TIVA_PWMn_CMPA_OFFSET, comp - 1); + } + else + { + tiva_pwm_putreg(chan, TIVA_PWMn_CMPB_OFFSET, comp - 1); + } + + /* Enable the PWM generator (refer to TM4C1294NC 23.4.10) */ + tiva_pwm_putreg(chan, TIVA_PWMn_CTL_OFFSET, CTL_ENABLE << TIVA_PWMn_CTL_ENABLE); + + /* Enable PWM channel (refer to TM4C1294NC 23.4.11) */ + putreg32((1 << chan->channel_id), chan->controller_base + TIVA_PWM_ENABLE_OFFSET); + + return OK; +} + +/**************************************************************************** +* Name: pwm_stop +* +* Description: +* Stop the pulsed output and reset the timer resources +* +* 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: +* 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 tiva_pwm_stop(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct tiva_pwm_chan_s *chan = (FAR struct tiva_pwm_chan_s *)dev; + pwmdbg("stop PWM for channel %d\n", chan->channel_id); + + /* Disable PWM channel */ + uint32_t value = getreg32(chan->controller_base + TIVA_PWM_ENABLE_OFFSET); + value &= ~(1 << chan->channel_id); + putreg32(value, chan->controller_base + TIVA_PWM_ENABLE_OFFSET); + + return OK; +} + +/**************************************************************************** +* Name: pwm_ioctl +* +* Description: +* Lower-half logic may support platform-specific ioctl commands +* +* Input parameters: +* dev - A reference to the lower half PWM 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 tiva_pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd, unsigned long arg) +{ + FAR struct tiva_pwm_chan_s *chan = (FAR struct tiva_pwm_chan_s *)dev; + pwmdbg("ioctl PWM for channel %d\n", chan->channel_id); + + /* Remove unused-variable warning */ + (void)chan; + + /* There are no platform-specific ioctl commands */ + + return -1; +} + +/**************************************************************************** +* Public Functions +****************************************************************************/ + +/**************************************************************************** +* Name: tiva_pwm_initialize +* +* Description: +* Initialize one PWM channel for use with the upper_level PWM driver. +* +* Input Parameters: +* channel - A number identifying the PWM channel use. +* +* Returned Value: +* On success, a pointer to the SAMA5 lower half PWM driver is returned. +* NULL is returned on any failure. +* +****************************************************************************/ + +FAR struct pwm_lowerhalf_s *tiva_pwm_initialize(int channel) +{ + assert(channel >= 0 && channel <= 7); + FAR struct tiva_pwm_chan_s *chan; + + switch (channel) + { +#ifdef CONFIG_TIVA_PWM0_CHAN0 + case 0: + chan = &g_pwm_chan0; + break; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN1 + case 1: + chan = &g_pwm_chan1; + break; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN2 + case 2: + chan = &g_pwm_chan2; + break; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN3 + case 3: + chan = &g_pwm_chan3; + break; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN4 + case 4: + chan = &g_pwm_chan4; + break; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN5 + case 5: + chan = &g_pwm_chan5; + break; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN6 + case 6: + chan = &g_pwm_chan6; + break; +#endif + +#ifdef CONFIG_TIVA_PWM0_CHAN7 + case 7: + chan = &g_pwm_chan7; + break; +#endif + + default: + pwmerr("ERROR: invalid channel %d\n", channel); + return NULL; + } + + pwmvdbg("channel %d: channel_id=%d, ", channel, chan->channel_id); + pwmvdbg("controller_id=%d, controller_base=%08x, ", chan->controller_id, chan->controller_base); + pwmvdbg("generator_id=%d, generator_base=%08x\n", chan->generator_id, chan->generator_base); + + /* Enable PWM controller (refer to TM4C1294NC 23.4.1) */ + assert(chan->controller_id == 0); + tiva_pwm_enablepwr(chan->controller_id); + tiva_pwm_enableclk(chan->controller_id); + + /* Configure PWM Clock Configuration (refer to TM4C1294NC 23.4.5) */ + /* on TM4C1294NC, configure the PWM clock source as 15MHz (the system clock 120MHz divided by 8) */ + /* TODO: need an algorithm to choose the best divider and load value combo */ + putreg32(CC_USEPWM << TIVA_PWM_CC_USEPWM | CC_PWMDIV_8 << TIVA_PWM_CC_PWMDIV, + chan->controller_base + TIVA_PWM_CC); + + return (FAR struct pwm_lowerhalf_s *)chan; +} + +/**************************************************************************** +* Name: board_pwm_setup +* +* Description: +* No implementation for now, it's called by PWM tool. +* +* Input Parameters: +* None. +* +* Returned Value: +* Zero on Success. +* +****************************************************************************/ + +int board_pwm_setup(void) +{ + return OK; +} diff --git a/arch/arm/src/tiva/tiva_pwm.h b/arch/arm/src/tiva/tiva_pwm.h new file mode 100644 index 00000000000..d75e704c713 --- /dev/null +++ b/arch/arm/src/tiva/tiva_pwm.h @@ -0,0 +1,54 @@ +/************************************************************************************ + * arch/arm/src/tiva/tiva_pwm.h + * + * Copyright (C) 2016 Young Mu. All rights reserved. + * Author: Young Mu + * + * 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. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_TIVA_TIVA_PWM_H +#define __ARCH_ARM_SRC_TIVA_TIVA_PWM_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +FAR struct pwm_lowerhalf_s *tiva_pwm_initialize(int channel); + +void tm4c_pwm_register(int channel); +int board_pwm_setup(void); + +#endif /* __ARCH_ARM_SRC_TIVA_TIVA_PWM_H */ diff --git a/arch/arm/src/tiva/tiva_timerlow32.c b/arch/arm/src/tiva/tiva_timerlow32.c index 2491e01f634..2fcf9694298 100644 --- a/arch/arm/src/tiva/tiva_timerlow32.c +++ b/arch/arm/src/tiva/tiva_timerlow32.c @@ -511,7 +511,7 @@ static int tiva_ioctl(struct timer_lowerhalf_s *lower, int cmd, { int ret = -ENOTTY; - DEBUGASSERT(priv); + DEBUGASSERT(lower); tmrinfo("Entry: cmd=%d arg=%ld\n", cmd, arg); return ret; diff --git a/configs/tm4c1294-launchpad/src/tm4c_bringup.c b/configs/tm4c1294-launchpad/src/tm4c_bringup.c index 9c8a60f2b43..e19d9e693d9 100644 --- a/configs/tm4c1294-launchpad/src/tm4c_bringup.c +++ b/configs/tm4c1294-launchpad/src/tm4c_bringup.c @@ -37,6 +37,9 @@ * Included Files ****************************************************************************/ +#include +#include + #include #include @@ -45,8 +48,13 @@ #include #include "tiva_i2c.h" +#include "tiva_pwm.h" #include "tm4c1294-launchpad.h" +#define PWM_PATH_FMT "/dev/pwm%d" +#define PWM_PATH_FMTLEN (10) + + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -55,6 +63,10 @@ # define HAVE_TIMER #endif +#ifdef CONFIG_TM4C1294_LAUNCHPAD_PWM +# define HAVE_PWM +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -136,6 +148,82 @@ static void tm4c_i2ctool(void) # define tm4c_i2ctool() #endif +/**************************************************************************** +* Name: tm4c_pwm_register +* +* Description: +* Register a PWM dev file with the upper_level PWM driver. +* +* Input Parameters: +* channel - A number identifying the PWM channel use. +* +* Returned Value: +* None. +* +****************************************************************************/ + +void tm4c_pwm_register(int channel) +{ + FAR struct pwm_lowerhalf_s *dev; + int ret; + char pwm_path[PWM_PATH_FMTLEN]; + + dev = tiva_pwm_initialize(channel); + if (dev == NULL) + { + dbg("ERROR: Failed to get PWM%d interface\n", channel); + } + else + { + snprintf(pwm_path, PWM_PATH_FMTLEN, PWM_PATH_FMT, channel); + ret = pwm_register(pwm_path, dev); + if (ret < 0) + { + dbg("ERROR: Failed to register PWM%d driver: %d\n", channel, ret); + } + } +} + +/**************************************************************************** + * Name: tm4c_pwm + * + * Description: + * Register PWM drivers for the PWM tool. + * + ****************************************************************************/ + +#ifdef HAVE_PWM + +static void tm4c_pwm(void) +{ +#ifdef CONFIG_TIVA_PWM0_CHAN0 + tm4c_pwm_register(0); +#endif +#ifdef CONFIG_TIVA_PWM0_CHAN1 + tm4c_pwm_register(1); +#endif +#ifdef CONFIG_TIVA_PWM0_CHAN2 + tm4c_pwm_register(2); +#endif +#ifdef CONFIG_TIVA_PWM0_CHAN3 + tm4c_pwm_register(3); +#endif +#ifdef CONFIG_TIVA_PWM0_CHAN4 + tm4c_pwm_register(4); +#endif +#ifdef CONFIG_TIVA_PWM0_CHAN5 + tm4c_pwm_register(5); +#endif +#ifdef CONFIG_TIVA_PWM0_CHAN6 + tm4c_pwm_register(6); +#endif +#ifdef CONFIG_TIVA_PWM0_CHAN7 + tm4c_pwm_register(7); +#endif +} + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -158,6 +246,10 @@ int tm4c_bringup(void) tm4c_i2ctool(); + /* Register PWM drivers */ + + tm4c_pwm(); + #ifdef HAVE_TIMER /* Initialize the timer driver */