arch/arm/src/stm32l4 and boards/arm/stm32l4/nucleo-l476rg: Add support for LPTIM timers on the STM32L4 as PWM outputs.

This commit is contained in:
Matias N
2019-10-27 17:21:32 -06:00
committed by Gregory Nutt
parent 637004e70c
commit fd625eaa89
8 changed files with 791 additions and 219 deletions
+68
View File
@@ -1810,6 +1810,74 @@ config STM32L4_ONESHOT_MAXTIMERS
of the timers and places an upper limit on the number of oneshot
timers that you can use.
config STM32L4_LPTIM1_PWM
bool "LPTIM1 PWM"
default n
depends on STM32L4_LPTIM1
select PWM
---help---
Reserve low-power timer 1 for use by PWM
Timer devices may be used for different purposes. One special purpose is
to generate modulated outputs for such things as motor control. If STM32L4_LPTIM1
is defined then THIS following may also be defined to indicate that
the timer is intended to be used for pulsed output modulation.
if STM32L4_LPTIM1_PWM
choice
prompt "LPTIM1 clock source"
default STM32L4_LPTIM1_CLK_APB1
config STM32L4_LPTIM1_CLK_APB1
bool "Clock LPTIM1 from APB1"
config STM32L4_LPTIM1_CLK_LSE
bool "Clock LPTIM1 from LSE"
config STM32L4_LPTIM1_CLK_LSI
bool "Clock LPTIM1 from LSI"
config STM32L4_LPTIM1_CLK_HSI
bool "Clock LPTIM1 from HSI"
endchoice
endif # STM32L4_LPTIM1_PWM
config STM32L4_LPTIM2_PWM
bool "LPTIM2 PWM"
default n
depends on STM32L4_LPTIM2
select PWM
---help---
Reserve low-power timer 2 for use by PWM
Timer devices may be used for different purposes. One special purpose is
to generate modulated outputs for such things as motor control. If STM32L4_LPTIM2
is defined then THIS following may also be defined to indicate that
the timer is intended to be used for pulsed output modulation.
if STM32L4_LPTIM2_PWM
choice
prompt "LPTIM2 clock source"
default STM32L4_LPTIM2_CLK_APB1
config STM32L4_LPTIM2_CLK_APB1
bool "Clock LPTIM2 from APB1"
config STM32L4_LPTIM2_CLK_LSE
bool "Clock LPTIM2 from LSE"
config STM32L4_LPTIM2_CLK_LSI
bool "Clock LPTIM2 from LSI"
config STM32L4_LPTIM2_CLK_HSI
bool "Clock LPTIM2 from HSI"
endchoice
endif # STM32L4_LPTIM2_PWM
config STM32L4_TIM1_PWM
bool "TIM1 PWM"
default n
@@ -114,4 +114,12 @@
#define LPTIM_CR_SNGSTRT (1 << 1) /* Bit 1: Single Mode */
#define LPTIM_CR_CNTSTRT (1 << 2) /* Bit 2: Continuous Mode */
#define LPTIM_ISR_CMPM (1 << 0) /* Bit 0: Compare match */
#define LPTIM_ISR_ARRM (1 << 1) /* Bit 1: Autoreload match */
#define LPTIM_ISR_EXTTRIG (1 << 2) /* Bit 2: External trigger edge event */
#define LPTIM_ISR_CMPOK (1 << 3) /* Bit 3: Compare register update OK */
#define LPTIM_ISR_ARROK (1 << 4) /* Bit 4: Autoreload register update OK */
#define LPTIM_ISR_UP (1 << 5) /* Bit 5: Counter direction change down to up */
#define LPTIM_ISR_DOWN (1 << 6) /* Bit 6: Counter direction change up to down */
#endif /* __ARCH_ARM_SRC_STM32L4_HARDWARE_STM32L4_LPTIM_H */
@@ -116,18 +116,6 @@
#define STM32L4_ATIM_OR2_OFFSET 0x0050 /* Timer option register 2 */
#define STM32L4_ATIM_OR3_OFFSET 0x0050 /* Timer option register 3 */
/* Low-Power Timers - LPTIM1 and LPTIM2 */
#define STM32L4_LPTIM_ISR_OFFSET 0x0000 /* Interrupt and Status register */
#define STM32L4_LPTIM_ICR_OFFSET 0x0004 /* Interrupt clear register */
#define STM32L4_LPTIM_IER_OFFSET 0x0008 /* Interrupt enable register */
#define STM32L4_LPTIM_CFGR_OFFSET 0x000c /* Configuration register */
#define STM32L4_LPTIM_CR_OFFSET 0x0010 /* Control register */
#define STM32L4_LPTIM_CMP_OFFSET 0x0014 /* Compare register */
#define STM32L4_LPTIM_ARR_OFFSET 0x0018 /* Auto-reloud register (16-bit) */
#define STM32L4_LPTIM_CNT_OFFSET 0x001c /* Counter (16-bit) */
#define STM32L4_LPTIM_OR_OFFSET 0x001c /* Options Register */
/* Register Addresses ***************************************************************/
/* Advanced Timers - TIM1 and TIM8 */
File diff suppressed because it is too large Load Diff
+62 -4
View File
@@ -55,11 +55,14 @@
/************************************************************************************
* Pre-processor Definitions
************************************************************************************/
/* Configuration ********************************************************************/
/* Timer devices may be used for different purposes. One special purpose is
* to generate modulated outputs for such things as motor control. If CONFIG_STM32L4_TIMn
* is defined then the CONFIG_STM32L4_TIMn_PWM must also be defined to indicate that
* timer "n" is intended to be used for pulsed output signal generation.
* to generate modulated outputs for such things as motor control. If
* CONFIG_STM32L4_TIMn is defined then the CONFIG_STM32L4_TIMn_PWM must also be
* defined to indicate that timer "n" is intended to be used for pulsed output
* signal generation.
*/
#ifndef CONFIG_STM32L4_TIM1
@@ -101,10 +104,12 @@
defined(CONFIG_STM32L4_TIM3_PWM) || defined(CONFIG_STM32L4_TIM4_PWM) || \
defined(CONFIG_STM32L4_TIM5_PWM) || defined(CONFIG_STM32L4_TIM8_PWM) || \
defined(CONFIG_STM32L4_TIM15_PWM) || defined(CONFIG_STM32L4_TIM16_PWM) || \
defined(CONFIG_STM32L4_TIM17_PWM)
defined(CONFIG_STM32L4_TIM17_PWM) || defined(CONFIG_STM32L4_LPTIM1_PWM) || \
defined(CONFIG_STM32L4_LPTIM2_PWM)
#include <arch/board/board.h>
#include "hardware/stm32l4_tim.h"
#include "hardware/stm32l4_lptim.h"
#ifdef CONFIG_PWM_MULTICHAN
@@ -677,6 +682,40 @@
# endif
#endif
/* REVISIT: any other LPTIM implementations have more than one channel? */
#define CONFIG_STM32L4_LPTIM1_CHANNEL 1
#ifdef CONFIG_STM32L4_LPTIM1_PWM
# if !defined(CONFIG_STM32L4_LPTIM1_CHANNEL)
# error "CONFIG_STM32L4_LPTIM1_CHANNEL must be provided"
# elif CONFIG_STM32L4_LPTIM1_CHANNEL == 1
# define CONFIG_STM32L4_LPTIM1_CHANNEL1 1
# define CONFIG_STM32L4_LPTIM1_CH1MODE CONFIG_STM32L4_LPTIM1_CHMODE
# define PWM_LPTIM1_CH1CFG GPIO_LPTIM1_CH1OUT
# define PWM_LPTIM1_CH1NCFG 0
# else
# error "Unsupported value of CONFIG_STM32L4_LPTIM1_CHANNEL"
# endif
#endif
/* REVISIT: any other LPTIM implementations have more than one channel? */
#define CONFIG_STM32L4_LPTIM2_CHANNEL 1
#ifdef CONFIG_STM32L4_LPTIM2_PWM
# if !defined(CONFIG_STM32L4_LPTIM2_CHANNEL)
# error "CONFIG_STM32L4_LPTIM2_CHANNEL must be provided"
# elif CONFIG_STM32L4_LPTIM2_CHANNEL == 1
# define CONFIG_STM32L4_LPTIM2_CHANNEL1 1
# define CONFIG_STM32L4_LPTIM2_CH1MODE CONFIG_STM32L4_LPTIM2_CHMODE
# define PWM_LPTIM2_CH1CFG GPIO_LPTIM2_CH1OUT
# define PWM_LPTIM2_CH1NCFG 0
# else
# error "Unsupported value of CONFIG_STM32L4_LPTIM2_CHANNEL"
# endif
#endif
#define PWM_NCHANNELS 1
#endif
@@ -723,6 +762,25 @@ extern "C"
FAR struct pwm_lowerhalf_s *stm32l4_pwminitialize(int timer);
/****************************************************************************
* Name: stm32l4_lp_pwminitialize
*
* Description:
* Initialize one low-power timer for use with the upper_level PWM 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,..,2}.
*
* Returned Value:
* On success, a pointer to the STM32 lower half PWM driver is returned.
* NULL is returned on any failure.
*
****************************************************************************/
FAR struct pwm_lowerhalf_s *stm32l4_lp_pwminitialize(int timer);
#undef EXTERN
#if defined(__cplusplus)
}
@@ -261,6 +261,9 @@
#define GPIO_TIM1_CH2OUT GPIO_TIM1_CH2OUT_1
#define GPIO_TIM1_CH2NOUT GPIO_TIM1_CH2N_1
#define GPIO_LPTIM1_CH1OUT GPIO_LPTIM1_OUT_1
#define GPIO_LPTIM2_CH1OUT GPIO_LPTIM2_OUT_2
/****************************************************************************
* Public Data
****************************************************************************/
@@ -202,8 +202,9 @@
* DFSDM
*/
/* prescaler common to all PLL inputs; will be 1 (XXX source is implicitly
as per comment above HSI) */
/* Prescaler common to all PLL inputs; will be 1 (XXX source is implicitly
* as per comment above HSI) .
*/
#define STM32L4_PLLCFG_PLLM RCC_PLLCFG_PLLM(1)
@@ -271,24 +272,26 @@
/* APB1 clock (PCLK1) is HCLK/1 (80MHz) */
#define STM32L4_RCC_CFGR_PPRE1 RCC_CFGR_PPRE1_HCLK /* PCLK1 = HCLK / 1 */
#define STM32L4_PCLK1_FREQUENCY (STM32L4_HCLK_FREQUENCY/1)
#define STM32L4_PCLK1_FREQUENCY (STM32L4_HCLK_FREQUENCY / 1)
/* Timers driven from APB1 will be twice PCLK1 */
/* REVISIT : this can be configured */
#define STM32L4_APB1_TIM2_CLKIN (2*STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM3_CLKIN (2*STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM4_CLKIN (2*STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM5_CLKIN (2*STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM6_CLKIN (2*STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM7_CLKIN (2*STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM2_CLKIN (2 * STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM3_CLKIN (2 * STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM4_CLKIN (2 * STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM5_CLKIN (2 * STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM6_CLKIN (2 * STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM7_CLKIN (2 * STM32L4_PCLK1_FREQUENCY)
/* APB2 clock (PCLK2) is HCLK (80MHz) */
#define STM32L4_RCC_CFGR_PPRE2 RCC_CFGR_PPRE2_HCLK /* PCLK2 = HCLK / 1 */
#define STM32L4_PCLK2_FREQUENCY (STM32L4_HCLK_FREQUENCY/1)
#define STM32L4_PCLK2_FREQUENCY (STM32L4_HCLK_FREQUENCY / 1)
/* Timers driven from APB2 will be twice PCLK2 */
/* REVISIT : this can be configured */
#define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY)
@@ -301,6 +304,7 @@
* otherwise frequency is 2xAPBx.
* Note: TIM1,8,15,16,17 are on APB2, others on APB1
*/
/* REVISIT : this can be configured */
/* TODO SDMMC */
@@ -488,8 +492,8 @@
#define BOARD_TIM15_FREQUENCY STM32L4_HCLK_FREQUENCY
#define BOARD_TIM16_FREQUENCY STM32L4_HCLK_FREQUENCY
#define BOARD_TIM17_FREQUENCY STM32L4_HCLK_FREQUENCY
#define BOARD_LPTIM1_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2)
#define BOARD_LPTIM2_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2)
#define STM32L4_LPTIM1_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2)
#define STM32L4_LPTIM2_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2)
/****************************************************************************
* Public Data
@@ -42,6 +42,7 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <errno.h>
#include <debug.h>
@@ -262,6 +263,43 @@ int stm32l4_pwm_setup(void)
return ret;
}
#endif
#if defined(CONFIG_STM32L4_LPTIM1_PWM)
pwm = stm32l4_lp_pwminitialize(1);
if (!pwm)
{
aerr("ERROR: Failed to get the STM32L4 PWM lower half\n");
return -ENODEV;
}
/* Register the PWM driver at "/dev/lppwm1" */
ret = pwm_register("/dev/lppwm1", pwm);
if (ret < 0)
{
aerr("ERROR: pwm_register failed: %d\n", ret);
return ret;
}
#endif
#if defined(CONFIG_STM32L4_LPTIM2_PWM)
pwm = stm32l4_lp_pwminitialize(2);
if (!pwm)
{
aerr("ERROR: Failed to get the STM32L4 PWM lower half\n");
return -ENODEV;
}
/* Register the PWM driver at "/dev/lppwm2" */
ret = pwm_register("/dev/lppwm2", pwm);
if (ret < 0)
{
aerr("ERROR: pwm_register failed: %d\n", ret);
return ret;
}
#endif
/* Now we are initialized */
initialized = true;