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 of the timers and places an upper limit on the number of oneshot
timers that you can use. 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 config STM32L4_TIM1_PWM
bool "TIM1 PWM" bool "TIM1 PWM"
default n default n
@@ -114,4 +114,12 @@
#define LPTIM_CR_SNGSTRT (1 << 1) /* Bit 1: Single Mode */ #define LPTIM_CR_SNGSTRT (1 << 1) /* Bit 1: Single Mode */
#define LPTIM_CR_CNTSTRT (1 << 2) /* Bit 2: Continuous 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 */ #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_OR2_OFFSET 0x0050 /* Timer option register 2 */
#define STM32L4_ATIM_OR3_OFFSET 0x0050 /* Timer option register 3 */ #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 ***************************************************************/ /* Register Addresses ***************************************************************/
/* Advanced Timers - TIM1 and TIM8 */ /* 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 * Pre-processor Definitions
************************************************************************************/ ************************************************************************************/
/* Configuration ********************************************************************/ /* Configuration ********************************************************************/
/* Timer devices may be used for different purposes. One special purpose is /* 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 * to generate modulated outputs for such things as motor control. If
* is defined then the CONFIG_STM32L4_TIMn_PWM must also be defined to indicate that * CONFIG_STM32L4_TIMn is defined then the CONFIG_STM32L4_TIMn_PWM must also be
* timer "n" is intended to be used for pulsed output signal generation. * defined to indicate that timer "n" is intended to be used for pulsed output
* signal generation.
*/ */
#ifndef CONFIG_STM32L4_TIM1 #ifndef CONFIG_STM32L4_TIM1
@@ -101,10 +104,12 @@
defined(CONFIG_STM32L4_TIM3_PWM) || defined(CONFIG_STM32L4_TIM4_PWM) || \ defined(CONFIG_STM32L4_TIM3_PWM) || defined(CONFIG_STM32L4_TIM4_PWM) || \
defined(CONFIG_STM32L4_TIM5_PWM) || defined(CONFIG_STM32L4_TIM8_PWM) || \ defined(CONFIG_STM32L4_TIM5_PWM) || defined(CONFIG_STM32L4_TIM8_PWM) || \
defined(CONFIG_STM32L4_TIM15_PWM) || defined(CONFIG_STM32L4_TIM16_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 <arch/board/board.h>
#include "hardware/stm32l4_tim.h" #include "hardware/stm32l4_tim.h"
#include "hardware/stm32l4_lptim.h"
#ifdef CONFIG_PWM_MULTICHAN #ifdef CONFIG_PWM_MULTICHAN
@@ -677,6 +682,40 @@
# endif # endif
#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 #define PWM_NCHANNELS 1
#endif #endif
@@ -723,6 +762,25 @@ extern "C"
FAR struct pwm_lowerhalf_s *stm32l4_pwminitialize(int timer); 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 #undef EXTERN
#if defined(__cplusplus) #if defined(__cplusplus)
} }
@@ -261,6 +261,9 @@
#define GPIO_TIM1_CH2OUT GPIO_TIM1_CH2OUT_1 #define GPIO_TIM1_CH2OUT GPIO_TIM1_CH2OUT_1
#define GPIO_TIM1_CH2NOUT GPIO_TIM1_CH2N_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 * Public Data
****************************************************************************/ ****************************************************************************/
@@ -202,8 +202,9 @@
* DFSDM * DFSDM
*/ */
/* prescaler common to all PLL inputs; will be 1 (XXX source is implicitly /* Prescaler common to all PLL inputs; will be 1 (XXX source is implicitly
as per comment above HSI) */ * as per comment above HSI) .
*/
#define STM32L4_PLLCFG_PLLM RCC_PLLCFG_PLLM(1) #define STM32L4_PLLCFG_PLLM RCC_PLLCFG_PLLM(1)
@@ -271,24 +272,26 @@
/* APB1 clock (PCLK1) is HCLK/1 (80MHz) */ /* APB1 clock (PCLK1) is HCLK/1 (80MHz) */
#define STM32L4_RCC_CFGR_PPRE1 RCC_CFGR_PPRE1_HCLK /* PCLK1 = HCLK / 1 */ #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 */ /* Timers driven from APB1 will be twice PCLK1 */
/* REVISIT : this can be configured */ /* REVISIT : this can be configured */
#define STM32L4_APB1_TIM2_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_TIM3_CLKIN (2 * STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM4_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_TIM5_CLKIN (2 * STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM6_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_TIM7_CLKIN (2 * STM32L4_PCLK1_FREQUENCY)
/* APB2 clock (PCLK2) is HCLK (80MHz) */ /* APB2 clock (PCLK2) is HCLK (80MHz) */
#define STM32L4_RCC_CFGR_PPRE2 RCC_CFGR_PPRE2_HCLK /* PCLK2 = HCLK / 1 */ #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 */ /* Timers driven from APB2 will be twice PCLK2 */
/* REVISIT : this can be configured */ /* REVISIT : this can be configured */
#define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY) #define STM32L4_APB2_TIM1_CLKIN (2*STM32L4_PCLK2_FREQUENCY)
@@ -301,6 +304,7 @@
* otherwise frequency is 2xAPBx. * otherwise frequency is 2xAPBx.
* Note: TIM1,8,15,16,17 are on APB2, others on APB1 * Note: TIM1,8,15,16,17 are on APB2, others on APB1
*/ */
/* REVISIT : this can be configured */ /* REVISIT : this can be configured */
/* TODO SDMMC */ /* TODO SDMMC */
@@ -488,8 +492,8 @@
#define BOARD_TIM15_FREQUENCY STM32L4_HCLK_FREQUENCY #define BOARD_TIM15_FREQUENCY STM32L4_HCLK_FREQUENCY
#define BOARD_TIM16_FREQUENCY STM32L4_HCLK_FREQUENCY #define BOARD_TIM16_FREQUENCY STM32L4_HCLK_FREQUENCY
#define BOARD_TIM17_FREQUENCY STM32L4_HCLK_FREQUENCY #define BOARD_TIM17_FREQUENCY STM32L4_HCLK_FREQUENCY
#define BOARD_LPTIM1_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) #define STM32L4_LPTIM1_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2)
#define BOARD_LPTIM2_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2) #define STM32L4_LPTIM2_FREQUENCY (STM32L4_HCLK_FREQUENCY / 2)
/**************************************************************************** /****************************************************************************
* Public Data * Public Data
@@ -42,6 +42,7 @@
#include <nuttx/config.h> #include <nuttx/config.h>
#include <sys/types.h>
#include <errno.h> #include <errno.h>
#include <debug.h> #include <debug.h>
@@ -262,6 +263,43 @@ int stm32l4_pwm_setup(void)
return ret; return ret;
} }
#endif #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 */ /* Now we are initialized */
initialized = true; initialized = true;