You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/01/14 14:47:44 UTC
[incubator-nuttx] 01/07: Low level operation support for STM32L4
PWM driver (Based on STM32 PWM driver).
This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch pr98
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 8c84d91819578db00a039fdeb5b5f8f800c4bbc1
Author: Daniel P. Carvalho <da...@gmail.com>
AuthorDate: Mon Jan 13 16:54:57 2020 -0300
Low level operation support for STM32L4 PWM driver (Based on STM32 PWM driver).
---
arch/arm/src/stm32l4/Kconfig | 1467 +++++++-
arch/arm/src/stm32l4/stm32l4_pwm.c | 3790 ++++++++++++++------
arch/arm/src/stm32l4/stm32l4_pwm.h | 369 +-
.../stm32l4/nucleo-l432kc/include/nucleo-l432kc.h | 15 +-
4 files changed, 4435 insertions(+), 1206 deletions(-)
diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig
index 3d37219..d5e5bda 100644
--- a/arch/arm/src/stm32l4/Kconfig
+++ b/arch/arm/src/stm32l4/Kconfig
@@ -1878,6 +1878,12 @@ endchoice
endif # STM32L4_LPTIM2_PWM
+config STM32L4_PWM_LL_OPS
+ bool "PWM low-level operations"
+ default n
+ ---help---
+ Enable low-level PWM ops.
+
config STM32L4_TIM1_PWM
bool "TIM1 PWM"
default n
@@ -1901,6 +1907,27 @@ config STM32L4_TIM1_MODE
---help---
Specifies the timer mode.
+config STM32L4_TIM1_LOCK
+ int "TIM1 Lock Level Configuration"
+ default 0
+ range 0 3
+ ---help---
+ Timer 1 lock level configuration
+
+config STM32L4_TIM1_TDTS
+ int "TIM1 t_DTS Division"
+ default 0
+ range 0 2
+ ---help---
+ Timer 1 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM1_DEADTIME
+ int "TIM1 Initial Dead-time"
+ default 0
+ range 0 255
+ ---help---
+ Timer 1 initial dead-time
+
if STM32L4_PWM_MULTICHAN
config STM32L4_TIM1_CHANNEL1
@@ -1913,10 +1940,10 @@ if STM32L4_TIM1_CHANNEL1
config STM32L4_TIM1_CH1MODE
int "TIM1 Channel 1 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM1_CH1OUT
bool "TIM1 Channel 1 Output"
@@ -1943,10 +1970,10 @@ if STM32L4_TIM1_CHANNEL2
config STM32L4_TIM1_CH2MODE
int "TIM1 Channel 2 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM1_CH2OUT
bool "TIM1 Channel 2 Output"
@@ -1973,10 +2000,10 @@ if STM32L4_TIM1_CHANNEL3
config STM32L4_TIM1_CH3MODE
int "TIM1 Channel 3 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM1_CH3OUT
bool "TIM1 Channel 3 Output"
@@ -2003,10 +2030,10 @@ if STM32L4_TIM1_CHANNEL4
config STM32L4_TIM1_CH4MODE
int "TIM1 Channel 4 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM1_CH4OUT
bool "TIM1 Channel 4 Output"
@@ -2028,12 +2055,70 @@ config STM32L4_TIM1_CHANNEL
If TIM1 is enabled for PWM usage, you also need specifies the timer output
channel {1,..,4}
+if STM32L4_TIM1_CHANNEL = 1
+
+config STM32L4_TIM1_CH1OUT
+ bool "TIM1 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+config STM32L4_TIM1_CH1NOUT
+ bool "TIM1 Channel 1 Complementary Output"
+ default n
+ ---help---
+ Enables channel 1 Complementary Output.
+
+endif # STM32L4_TIM1_CHANNEL = 1
+
+if STM32L4_TIM1_CHANNEL = 2
+
+config STM32L4_TIM1_CH2OUT
+ bool "TIM1 Channel 2 Output"
+ default n
+ ---help---
+ Enables channel 2 output.
+
+config STM32L4_TIM1_CH2NOUT
+ bool "TIM1 Channel 2 Complementary Output"
+ default n
+ ---help---
+ Enables channel 2 Complementary Output.
+
+endif # STM32L4_TIM1_CHANNEL = 2
+
+if STM32L4_TIM1_CHANNEL = 3
+
+config STM32L4_TIM1_CH3OUT
+ bool "TIM1 Channel 3 Output"
+ default n
+ ---help---
+ Enables channel 3 output.
+
+config STM32L4_TIM1_CH3NOUT
+ bool "TIM1 Channel 3 Complementary Output"
+ default n
+ ---help---
+ Enables channel 3 Complementary Output.
+
+endif # STM32L4_TIM1_CHANNEL = 3
+
+if STM32L4_TIM1_CHANNEL = 4
+
+config STM32L4_TIM1_CH4OUT
+ bool "TIM1 Channel 4 Output"
+ default n
+ ---help---
+ Enables channel 4 output.
+
+endif # STM32L4_TIM1_CHANNEL = 4
+
config STM32L4_TIM1_CHMODE
int "TIM1 Channel Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
endif # !STM32L4_PWM_MULTICHAN
@@ -2074,10 +2159,10 @@ if STM32L4_TIM2_CHANNEL1
config STM32L4_TIM2_CH1MODE
int "TIM2 Channel 1 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM2_CH1OUT
bool "TIM2 Channel 1 Output"
@@ -2097,10 +2182,10 @@ if STM32L4_TIM2_CHANNEL2
config STM32L4_TIM2_CH2MODE
int "TIM2 Channel 2 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM2_CH2OUT
bool "TIM2 Channel 2 Output"
@@ -2120,10 +2205,10 @@ if STM32L4_TIM2_CHANNEL3
config STM32L4_TIM2_CH3MODE
int "TIM2 Channel 3 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM2_CH3OUT
bool "TIM2 Channel 3 Output"
@@ -2143,10 +2228,10 @@ if STM32L4_TIM2_CHANNEL4
config STM32L4_TIM2_CH4MODE
int "TIM2 Channel 4 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM2_CH4OUT
bool "TIM2 Channel 4 Output"
@@ -2168,12 +2253,52 @@ config STM32L4_TIM2_CHANNEL
If TIM2 is enabled for PWM usage, you also need specifies the timer output
channel {1,..,4}
+if STM32L4_TIM2_CHANNEL = 1
+
+config STM32L4_TIM2_CH1OUT
+ bool "TIM2 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+endif # STM32L4_TIM2_CHANNEL = 1
+
+if STM32L4_TIM2_CHANNEL = 2
+
+config STM32L4_TIM2_CH2OUT
+ bool "TIM2 Channel 2 Output"
+ default n
+ ---help---
+ Enables channel 2 output.
+
+endif # STM32L4_TIM2_CHANNEL = 2
+
+if STM32L4_TIM2_CHANNEL = 3
+
+config STM32L4_TIM2_CH3OUT
+ bool "TIM2 Channel 3 Output"
+ default n
+ ---help---
+ Enables channel 3 output.
+
+endif # STM32L4_TIM2_CHANNEL = 3
+
+if STM32L4_TIM2_CHANNEL = 4
+
+config STM32L4_TIM2_CH4OUT
+ bool "TIM2 Channel 4 Output"
+ default n
+ ---help---
+ Enables channel 4 output.
+
+endif # STM32L4_TIM2_CHANNEL = 4
+
config STM32L4_TIM2_CHMODE
int "TIM2 Channel Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
endif # !STM32L4_PWM_MULTICHAN
@@ -2214,10 +2339,10 @@ if STM32L4_TIM3_CHANNEL1
config STM32L4_TIM3_CH1MODE
int "TIM3 Channel 1 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM3_CH1OUT
bool "TIM3 Channel 1 Output"
@@ -2237,10 +2362,10 @@ if STM32L4_TIM3_CHANNEL2
config STM32L4_TIM3_CH2MODE
int "TIM3 Channel 2 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM3_CH2OUT
bool "TIM3 Channel 2 Output"
@@ -2260,10 +2385,10 @@ if STM32L4_TIM3_CHANNEL3
config STM32L4_TIM3_CH3MODE
int "TIM3 Channel 3 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM3_CH3OUT
bool "TIM3 Channel 3 Output"
@@ -2283,10 +2408,10 @@ if STM32L4_TIM3_CHANNEL4
config STM32L4_TIM3_CH4MODE
int "TIM3 Channel 4 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM3_CH4OUT
bool "TIM3 Channel 4 Output"
@@ -2308,12 +2433,52 @@ config STM32L4_TIM3_CHANNEL
If TIM3 is enabled for PWM usage, you also need specifies the timer output
channel {1,..,4}
+if STM32L4_TIM3_CHANNEL = 1
+
+config STM32L4_TIM3_CH1OUT
+ bool "TIM3 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+endif # STM32L4_TIM3_CHANNEL = 1
+
+if STM32L4_TIM3_CHANNEL = 2
+
+config STM32L4_TIM3_CH2OUT
+ bool "TIM3 Channel 2 Output"
+ default n
+ ---help---
+ Enables channel 2 output.
+
+endif # STM32L4_TIM3_CHANNEL = 2
+
+if STM32L4_TIM3_CHANNEL = 3
+
+config STM32L4_TIM3_CH3OUT
+ bool "TIM3 Channel 3 Output"
+ default n
+ ---help---
+ Enables channel 3 output.
+
+endif # STM32L4_TIM3_CHANNEL = 3
+
+if STM32L4_TIM3_CHANNEL = 4
+
+config STM32L4_TIM3_CH4OUT
+ bool "TIM3 Channel 4 Output"
+ default n
+ ---help---
+ Enables channel 4 output.
+
+endif # STM32L4_TIM3_CHANNEL = 4
+
config STM32L4_TIM3_CHMODE
int "TIM3 Channel Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
endif # !STM32L4_PWM_MULTICHAN
@@ -2354,10 +2519,10 @@ if STM32L4_TIM4_CHANNEL1
config STM32L4_TIM4_CH1MODE
int "TIM4 Channel 1 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM4_CH1OUT
bool "TIM4 Channel 1 Output"
@@ -2377,10 +2542,10 @@ if STM32L4_TIM4_CHANNEL2
config STM32L4_TIM4_CH2MODE
int "TIM4 Channel 2 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM4_CH2OUT
bool "TIM4 Channel 2 Output"
@@ -2400,10 +2565,10 @@ if STM32L4_TIM4_CHANNEL3
config STM32L4_TIM4_CH3MODE
int "TIM4 Channel 3 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM4_CH3OUT
bool "TIM4 Channel 3 Output"
@@ -2423,10 +2588,10 @@ if STM32L4_TIM4_CHANNEL4
config STM32L4_TIM4_CH4MODE
int "TIM4 Channel 4 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM4_CH4OUT
bool "TIM4 Channel 4 Output"
@@ -2448,12 +2613,52 @@ config STM32L4_TIM4_CHANNEL
If TIM4 is enabled for PWM usage, you also need specifies the timer output
channel {1,..,4}
+if STM32L4_TIM4_CHANNEL = 1
+
+config STM32L4_TIM4_CH1OUT
+ bool "TIM4 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+endif # STM32L4_TIM4_CHANNEL = 1
+
+if STM32L4_TIM4_CHANNEL = 2
+
+config STM32L4_TIM4_CH2OUT
+ bool "TIM4 Channel 2 Output"
+ default n
+ ---help---
+ Enables channel 2 output.
+
+endif # STM32L4_TIM4_CHANNEL = 2
+
+if STM32L4_TIM4_CHANNEL = 3
+
+config STM32L4_TIM4_CH3OUT
+ bool "TIM4 Channel 3 Output"
+ default n
+ ---help---
+ Enables channel 3 output.
+
+endif # STM32L4_TIM4_CHANNEL = 3
+
+if STM32L4_TIM4_CHANNEL = 4
+
+config STM32L4_TIM4_CH4OUT
+ bool "TIM4 Channel 4 Output"
+ default n
+ ---help---
+ Enables channel 4 output.
+
+endif # STM32L4_TIM4_CHANNEL = 4
+
config STM32L4_TIM4_CHMODE
int "TIM4 Channel Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
endif # !STM32L4_PWM_MULTICHAN
@@ -2494,10 +2699,10 @@ if STM32L4_TIM5_CHANNEL1
config STM32L4_TIM5_CH1MODE
int "TIM5 Channel 1 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM5_CH1OUT
bool "TIM5 Channel 1 Output"
@@ -2517,10 +2722,10 @@ if STM32L4_TIM5_CHANNEL2
config STM32L4_TIM5_CH2MODE
int "TIM5 Channel 2 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM5_CH2OUT
bool "TIM5 Channel 2 Output"
@@ -2540,10 +2745,10 @@ if STM32L4_TIM5_CHANNEL3
config STM32L4_TIM5_CH3MODE
int "TIM5 Channel 3 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM5_CH3OUT
bool "TIM5 Channel 3 Output"
@@ -2563,10 +2768,10 @@ if STM32L4_TIM5_CHANNEL4
config STM32L4_TIM5_CH4MODE
int "TIM5 Channel 4 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM5_CH4OUT
bool "TIM5 Channel 4 Output"
@@ -2588,12 +2793,52 @@ config STM32L4_TIM5_CHANNEL
If TIM5 is enabled for PWM usage, you also need specifies the timer output
channel {1,..,4}
+if STM32L4_TIM5_CHANNEL = 1
+
+config STM32L4_TIM5_CH1OUT
+ bool "TIM5 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+endif # STM32L4_TIM5_CHANNEL = 1
+
+if STM32L4_TIM5_CHANNEL = 2
+
+config STM32L4_TIM5_CH2OUT
+ bool "TIM5 Channel 2 Output"
+ default n
+ ---help---
+ Enables channel 2 output.
+
+endif # STM32L4_TIM5_CHANNEL = 2
+
+if STM32L4_TIM5_CHANNEL = 3
+
+config STM32L4_TIM5_CH3OUT
+ bool "TIM5 Channel 3 Output"
+ default n
+ ---help---
+ Enables channel 3 output.
+
+endif # STM32L4_TIM5_CHANNEL = 3
+
+if STM32L4_TIM5_CHANNEL = 4
+
+config STM32L4_TIM5_CH4OUT
+ bool "TIM5 Channel 4 Output"
+ default n
+ ---help---
+ Enables channel 4 output.
+
+endif # STM32L4_TIM5_CHANNEL = 4
+
config STM32L4_TIM5_CHMODE
int "TIM5 Channel Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
endif # !STM32L4_PWM_MULTICHAN
@@ -2622,6 +2867,27 @@ config STM32L4_TIM8_MODE
---help---
Specifies the timer mode.
+config STM32L4_TIM8_LOCK
+ int "TIM1 Lock Level Configuration"
+ default 0
+ range 0 3
+ ---help---
+ Timer 8 lock level configuration
+
+config STM32L4_TIM8_TDTS
+ int "TIM8 t_DTS Division"
+ default 0
+ range 0 2
+ ---help---
+ Timer 8 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM8_DEADTIME
+ int "TIM8 Initial Dead-time"
+ default 0
+ range 0 255
+ ---help---
+ Timer 8 initial dead-time
+
if STM32L4_PWM_MULTICHAN
config STM32L4_TIM8_CHANNEL1
@@ -2634,10 +2900,10 @@ if STM32L4_TIM8_CHANNEL1
config STM32L4_TIM8_CH1MODE
int "TIM8 Channel 1 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM8_CH1OUT
bool "TIM8 Channel 1 Output"
@@ -2664,10 +2930,10 @@ if STM32L4_TIM8_CHANNEL2
config STM32L4_TIM8_CH2MODE
int "TIM8 Channel 2 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM8_CH2OUT
bool "TIM8 Channel 2 Output"
@@ -2694,10 +2960,10 @@ if STM32L4_TIM8_CHANNEL3
config STM32L4_TIM8_CH3MODE
int "TIM8 Channel 3 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM8_CH3OUT
bool "TIM8 Channel 3 Output"
@@ -2724,10 +2990,10 @@ if STM32L4_TIM8_CHANNEL4
config STM32L4_TIM8_CH4MODE
int "TIM8 Channel 4 Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM8_CH4OUT
bool "TIM8 Channel 4 Output"
@@ -2749,12 +3015,70 @@ config STM32L4_TIM8_CHANNEL
If TIM8 is enabled for PWM usage, you also need specifies the timer output
channel {1,..,4}
-config STM32L4_TIM8_CHMODE
+if STM32L4_TIM8_CHANNEL = 1
+
+config STM32L4_TIM8_CH1OUT
+ bool "TIM8 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+config STM32L4_TIM8_CH1NOUT
+ bool "TIM8 Channel 1 Complementary Output"
+ default n
+ ---help---
+ Enables channel 1 Complementary Output.
+
+endif # STM32L4_TIM8_CHANNEL = 1
+
+if STM32L4_TIM8_CHANNEL = 2
+
+config STM32L4_TIM8_CH2OUT
+ bool "TIM8 Channel 2 Output"
+ default n
+ ---help---
+ Enables channel 2 output.
+
+config STM32L4_TIM8_CH2NOUT
+ bool "TIM8 Channel 2 Complementary Output"
+ default n
+ ---help---
+ Enables channel 2 Complementary Output.
+
+endif # STM32L4_TIM8_CHANNEL = 2
+
+if STM32L4_TIM8_CHANNEL = 3
+
+config STM32L4_TIM8_CH3OUT
+ bool "TIM8 Channel 3 Output"
+ default n
+ ---help---
+ Enables channel 3 output.
+
+config STM32L4_TIM8_CH3NOUT
+ bool "TIM8 Channel 3 Complementary Output"
+ default n
+ ---help---
+ Enables channel 3 Complementary Output.
+
+endif # STM32L4_TIM8_CHANNEL = 3
+
+if STM32L4_TIM8_CHANNEL = 4
+
+config STM32L4_TIM8_CH4OUT
+ bool "TIM8 Channel 4 Output"
+ default n
+ ---help---
+ Enables channel 4 output.
+
+endif # STM32L4_TIM8_CHANNEL = 4
+
+config STM32L4_TIM8_CHMODE
int "TIM8 Channel Mode"
- default 0
- range 0 5
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
endif # !STM32L4_PWM_MULTICHAN
@@ -2775,6 +3099,27 @@ config STM32L4_TIM15_PWM
if STM32L4_TIM15_PWM
+config STM32L4_TIM15_LOCK
+ int "TIM15 Lock Level Configuration"
+ default 0
+ range 0 3
+ ---help---
+ Timer 15 lock level configuration
+
+config STM32L4_TIM15_TDTS
+ int "TIM15 t_DTS Division"
+ default 0
+ range 0 2
+ ---help---
+ Timer 15 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM15_DEADTIME
+ int "TIM15 Initial Dead-time"
+ default 0
+ range 0 255
+ ---help---
+ Timer 15 initial dead-time
+
if STM32L4_PWM_MULTICHAN
config STM32L4_TIM15_CHANNEL1
@@ -2787,10 +3132,10 @@ if STM32L4_TIM15_CHANNEL1
config STM32L4_TIM15_CH1MODE
int "TIM15 Channel 1 Mode"
- default 0
- range 0 3
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM15_CH1OUT
bool "TIM15 Channel 1 Output"
@@ -2817,10 +3162,10 @@ if STM32L4_TIM15_CHANNEL2
config STM32L4_TIM15_CH2MODE
int "TIM15 Channel 2 Mode"
- default 0
- range 0 3
+ default 6
+ range 0 11
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM15_CH2OUT
bool "TIM15 Channel 2 Output"
@@ -2842,12 +3187,44 @@ config STM32L4_TIM15_CHANNEL
If TIM15 is enabled for PWM usage, you also need specifies the timer output
channel {1,2}
+if STM32L4_TIM15_CHANNEL = 1
+
+config STM32L4_TIM15_CH1OUT
+ bool "TIM15 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+config STM32L4_TIM15_CH1NOUT
+ bool "TIM15 Channel 1 Complementary Output"
+ default n
+ ---help---
+ Enables channel 1 Complementary Output.
+
+endif # STM32L4_TIM15_CHANNEL = 1
+
+if STM32L4_TIM15_CHANNEL = 2
+
+config STM32L4_TIM15_CH2OUT
+ bool "TIM15 Channel 2 Output"
+ default n
+ ---help---
+ Enables channel 2 output.
+
+config STM32L4_TIM15_CH2NOUT
+ bool "TIM15 Channel 2 Complementary Output"
+ default n
+ ---help---
+ Enables channel 2 Complementary Output.
+
+endif # STM32L4_TIM15_CHANNEL = 2
+
config STM32L4_TIM15_CHMODE
int "TIM15 Channel Mode"
- default 0
- range 0 3
+ default 6
+ range 0 9
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
endif # !STM32L4_PWM_MULTICHAN
@@ -2868,6 +3245,27 @@ config STM32L4_TIM16_PWM
if STM32L4_TIM16_PWM
+config STM32L4_TIM16_LOCK
+ int "TIM16 Lock Level Configuration"
+ default 0
+ range 0 3
+ ---help---
+ Timer 16 lock level configuration
+
+config STM32L4_TIM16_TDTS
+ int "TIM16 t_DTS Division"
+ default 0
+ range 0 2
+ ---help---
+ Timer 16 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM16_DEADTIME
+ int "TIM16 Initial Dead-time"
+ default 0
+ range 0 255
+ ---help---
+ Timer 16 initial dead-time
+
if STM32L4_PWM_MULTICHAN
config STM32L4_TIM16_CHANNEL1
@@ -2880,10 +3278,10 @@ if STM32L4_TIM16_CHANNEL1
config STM32L4_TIM16_CH1MODE
int "TIM16 Channel 1 Mode"
- default 0
- range 0 1
+ default 6
+ range 0 7
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM16_CH1OUT
bool "TIM16 Channel 1 Output"
@@ -2912,12 +3310,22 @@ config STM32L4_TIM16_CHANNEL
If TIM16 is enabled for PWM usage, you also need specifies the timer output
channel {1}
+if STM32L4_TIM16_CHANNEL = 1
+
+config STM32L4_TIM16_CH1OUT
+ bool "TIM16 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+endif # STM32L4_TIM16_CHANNEL = 1
+
config STM32L4_TIM16_CHMODE
int "TIM16 Channel Mode"
- default 0
- range 0 1
+ default 6
+ range 0 7
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
endif # !STM32L4_PWM_MULTICHAN
@@ -2938,6 +3346,27 @@ config STM32L4_TIM17_PWM
if STM32L4_TIM17_PWM
+config STM32L4_TIM17_LOCK
+ int "TIM17 Lock Level Configuration"
+ default 0
+ range 0 3
+ ---help---
+ Timer 17 lock level configuration
+
+config STM32L4_TIM17_TDTS
+ int "TIM17 t_DTS Division"
+ default 0
+ range 0 2
+ ---help---
+ Timer 17 dead-time and sampling clock (t_DTS) division
+
+config STM32L4_TIM17_DEADTIME
+ int "TIM17 Initial Dead-time"
+ default 0
+ range 0 255
+ ---help---
+ Timer 17 initial dead-time
+
if STM32L4_PWM_MULTICHAN
config STM32L4_TIM17_CHANNEL1
@@ -2950,10 +3379,10 @@ if STM32L4_TIM17_CHANNEL1
config STM32L4_TIM17_CH1MODE
int "TIM17 Channel 1 Mode"
- default 0
- range 0 1
+ default 6
+ range 0 7
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
config STM32L4_TIM17_CH1OUT
bool "TIM17 Channel 1 Output"
@@ -2982,12 +3411,22 @@ config STM32L4_TIM17_CHANNEL
If TIM17 is enabled for PWM usage, you also need specifies the timer output
channel {1}
+if STM32_TIM17_CHANNEL = 1
+
+config STM32L4_TIM17_CH1OUT
+ bool "TIM17 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+endif # STM32L4_TIM17_CHANNEL = 1
+
config STM32L4_TIM17_CHMODE
int "TIM17 Channel Mode"
- default 0
- range 0 1
+ default 6
+ range 0 7
---help---
- Specifies the channel mode.
+ Specifies the channel mode. See enum stm32l4_pwm_chanmode_e in stm32l4_pwm.h.
endif # !STM32L4_PWM_MULTICHAN
@@ -3032,6 +3471,22 @@ config STM32L4_LPTIM1_CHANNEL
If LPTIM1 is enabled for PWM usage, you also need specifies the timer output
channel {1}
+if STM32L4_LPTIM1_CHANNEL = 1
+
+config STM32L4_LPTIM1_CH1OUT
+ bool "LPTIM1 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+config STM32L4_LPTIM1_CH1NOUT
+ bool "LPTIM1 Channel 1 Complementary Output"
+ default n
+ ---help---
+ Enables channel 1 Complementary Output.
+
+endif # STM32L4_LPTIM1_CHANNEL = 1
+
endif # !STM32L4_PWM_MULTICHAN
endif # STM32L4_LPTIM1_PWM
@@ -3075,6 +3530,22 @@ config STM32L4_LPTIM2_CHANNEL
If LPTIM2 is enabled for PWM usage, you also need specifies the timer output
channel {1}
+if STM32L4_LPTIM2_CHANNEL = 1
+
+config STM32L4_LPTIM2_CH1OUT
+ bool "LPTIM2 Channel 1 Output"
+ default n
+ ---help---
+ Enables channel 1 output.
+
+config STM32L4_LPTIM2_CH1NOUT
+ bool "LPTIM2 Channel 1 Complementary Output"
+ default n
+ ---help---
+ Enables channel 1 Complementary Output.
+
+endif # STM32L4_LPTIM2_CHANNEL = 1
+
endif # !STM32L4_PWM_MULTICHAN
endif # STM32L4_LPTIM2_PWM
@@ -3744,6 +4215,778 @@ config STM32L4_TIM8_CAP
Timer devices may be used for different purposes. One special purpose is
to capture input.
+menu "STM32L4 TIMx Outputs Configuration"
+
+config STM32L4_TIM1_CH1POL
+ int "TIM1 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH1OUT
+ ---help---
+ TIM1 Channel 1 output polarity
+
+config STM32L4_TIM1_CH1IDLE
+ int "TIM1 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH1OUT
+ ---help---
+ TIM1 Channel 1 output IDLE
+
+config STM32L4_TIM1_CH1NPOL
+ int "TIM1 Channel 1 Complementary Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH1NOUT
+ ---help---
+ TIM1 Channel 1 Complementary Output polarity
+
+config STM32L4_TIM1_CH1NIDLE
+ int "TIM1 Channel 1 Complementary Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH1NOUT
+ ---help---
+ TIM1 Channel 1 Complementary Output IDLE
+
+config STM32L4_TIM1_CH2POL
+ int "TIM1 Channel 2 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH2OUT
+ ---help---
+ TIM1 Channel 2 output polarity
+
+config STM32L4_TIM1_CH2IDLE
+ int "TIM1 Channel 2 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH2OUT
+ ---help---
+ TIM1 Channel 2 output IDLE
+
+config STM32L4_TIM1_CH2NPOL
+ int "TIM1 Channel 2 Complementary Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH2NOUT
+ ---help---
+ TIM1 Channel 2 Complementary Output polarity
+
+config STM32L4_TIM1_CH2NIDLE
+ int "TIM1 Channel 2 Complementary Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH2NOUT
+ ---help---
+ TIM1 Channel 2 Complementary Output IDLE
+
+config STM32L4_TIM1_CH3POL
+ int "TIM1 Channel 3 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH3OUT
+ ---help---
+ TIM1 Channel 3 output polarity
+
+config STM32L4_TIM1_CH3IDLE
+ int "TIM1 Channel 3 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH3OUT
+ ---help---
+ TIM1 Channel 3 output IDLE
+
+config STM32L4_TIM1_CH3NPOL
+ int "TIM1 Channel 3 Complementary Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH3NOUT
+ ---help---
+ TIM1 Channel 3 Complementary Output polarity
+
+config STM32L4_TIM1_CH3NIDLE
+ int "TIM1 Channel 3 Complementary Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH3NOUT
+ ---help---
+ TIM1 Channel 3 Complementary Output IDLE
+
+config STM32L4_TIM1_CH4POL
+ int "TIM1 Channel 4 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH4OUT
+ ---help---
+ TIM1 Channel 4 output polarity
+
+config STM32L4_TIM1_CH4IDLE
+ int "TIM1 Channel 4 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH4OUT
+ ---help---
+ TIM1 Channel 4 output IDLE
+
+config STM32L4_TIM1_CH5POL
+ int "TIM1 Channel 5 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH5OUT
+ ---help---
+ TIM1 Channel 5 output polarity
+
+config STM32L4_TIM1_CH5IDLE
+ int "TIM1 Channel 5 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH5OUT
+ ---help---
+ TIM1 Channel 5 output IDLE
+
+config STM32L4_TIM1_CH6POL
+ int "TIM1 Channel 6 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH6OUT
+ ---help---
+ TIM1 Channel 6 output polarity
+
+config STM32L4_TIM1_CH6IDLE
+ int "TIM1 Channel 6 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM1_CH6OUT
+ ---help---
+ TIM1 Channel 6 output IDLE
+
+config STM32L4_TIM2_CH1POL
+ int "TIM2 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM2_CH1OUT
+ ---help---
+ TIM2 Channel 1 output polarity
+
+config STM32L4_TIM2_CH1IDLE
+ int "TIM2 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM2_CH1OUT
+ ---help---
+ TIM2 Channel 1 output IDLE
+
+config STM32L4_TIM2_CH2POL
+ int "TIM2 Channel 2 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM2_CH2OUT
+ ---help---
+ TIM2 Channel 2 output polarity
+
+config STM32L4_TIM2_CH2IDLE
+ int "TIM2 Channel 2 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM2_CH2OUT
+ ---help---
+ TIM2 Channel 2 output IDLE
+
+config STM32L4_TIM2_CH3POL
+ int "TIM2 Channel 3 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM2_CH3OUT
+ ---help---
+ TIM2 Channel 3 output polarity
+
+config STM32L4_TIM2_CH3IDLE
+ int "TIM2 Channel 3 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM2_CH3OUT
+ ---help---
+ TIM2 Channel 3 output IDLE
+
+config STM32L4_TIM2_CH4POL
+ int "TIM2 Channel 4 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM2_CH4OUT
+ ---help---
+ TIM2 Channel 4 output polarity
+
+config STM32L4_TIM2_CH4IDLE
+ int "TIM2 Channel 4 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM2_CH4OUT
+ ---help---
+ TIM2 Channel 4 output IDLE
+
+config STM32L4_TIM3_CH1POL
+ int "TIM3 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM3_CH1OUT
+ ---help---
+ TIM3 Channel 1 output polarity
+
+config STM32L4_TIM3_CH1IDLE
+ int "TIM3 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM3_CH1OUT
+ ---help---
+ TIM3 Channel 1 output IDLE
+
+config STM32L4_TIM3_CH2POL
+ int "TIM3 Channel 2 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM3_CH2OUT
+ ---help---
+ TIM3 Channel 2 output polarity
+
+config STM32L4_TIM3_CH2IDLE
+ int "TIM3 Channel 2 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM3_CH2OUT
+ ---help---
+ TIM3 Channel 2 output IDLE
+
+config STM32L4_TIM3_CH3POL
+ int "TIM3 Channel 3 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM3_CH3OUT
+ ---help---
+ TIM3 Channel 3 output polarity
+
+config STM32L4_TIM3_CH3IDLE
+ int "TIM3 Channel 3 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM3_CH3OUT
+ ---help---
+ TIM3 Channel 3 output IDLE
+
+config STM32L4_TIM3_CH4POL
+ int "TIM3 Channel 4 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM3_CH4OUT
+ ---help---
+ TIM3 Channel 4 output polarity
+
+config STM32L4_TIM3_CH4IDLE
+ int "TIM3 Channel 4 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM3_CH4OUT
+ ---help---
+ TIM3 Channel 4 output IDLE
+
+config STM32L4_TIM4_CH1POL
+ int "TIM4 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM4_CH1OUT
+ ---help---
+ TIM4 Channel 1 output polarity
+
+config STM32L4_TIM4_CH1IDLE
+ int "TIM4 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM4_CH1OUT
+ ---help---
+ TIM4 Channel 1 output IDLE
+
+config STM32L4_TIM4_CH2POL
+ int "TIM4 Channel 2 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM4_CH2OUT
+ ---help---
+ TIM4 Channel 2 output polarity
+
+config STM32L4_TIM4_CH2IDLE
+ int "TIM4 Channel 2 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM4_CH2OUT
+ ---help---
+ TIM4 Channel 2 output IDLE
+
+config STM32L4_TIM4_CH3POL
+ int "TIM4 Channel 3 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM4_CH3OUT
+ ---help---
+ TIM4 Channel 3 output polarity
+
+config STM32L4_TIM4_CH3IDLE
+ int "TIM4 Channel 3 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM4_CH3OUT
+ ---help---
+ TIM4 Channel 3 output IDLE
+
+config STM32L4_TIM4_CH4POL
+ int "TIM4 Channel 4 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM4_CH4OUT
+ ---help---
+ TIM4 Channel 4 output polarity
+
+config STM32L4_TIM4_CH4IDLE
+ int "TIM4 Channel 4 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM4_CH4OUT
+ ---help---
+ TIM4 Channel 4 output IDLE
+
+config STM32L4_TIM5_CH1POL
+ int "TIM5 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM5_CH1OUT
+ ---help---
+ TIM5 Channel 1 output polarity
+
+config STM32L4_TIM5_CH1IDLE
+ int "TIM5 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM5_CH1OUT
+ ---help---
+ TIM5 Channel 1 output IDLE
+
+config STM32L4_TIM5_CH2POL
+ int "TIM5 Channel 2 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM5_CH2OUT
+ ---help---
+ TIM5 Channel 2 output polarity
+
+config STM32L4_TIM5_CH2IDLE
+ int "TIM5 Channel 2 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM5_CH2OUT
+ ---help---
+ TIM5 Channel 2 output IDLE
+
+config STM32L4_TIM5_CH3POL
+ int "TIM5 Channel 3 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM5_CH3OUT
+ ---help---
+ TIM5 Channel 3 output polarity
+
+config STM32L4_TIM5_CH3IDLE
+ int "TIM5 Channel 3 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM5_CH3OUT
+ ---help---
+ TIM5 Channel 3 output IDLE
+
+config STM32L4_TIM5_CH4POL
+ int "TIM5 Channel 4 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM5_CH4OUT
+ ---help---
+ TIM5 Channel 4 output polarity
+
+config STM32L4_TIM5_CH4IDLE
+ int "TIM5 Channel 4 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM5_CH4OUT
+ ---help---
+ TIM5 Channel 4 output IDLE
+
+config STM32L4_TIM8_CH1POL
+ int "TIM8 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH1OUT
+ ---help---
+ TIM8 Channel 1 output polarity
+
+config STM32L4_TIM8_CH1IDLE
+ int "TIM8 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH1OUT
+ ---help---
+ TIM8 Channel 1 output IDLE
+
+config STM32L4_TIM8_CH1NPOL
+ int "TIM8 Channel 1 Complementary Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH1NOUT
+ ---help---
+ TIM8 Channel 1 Complementary Output polarity
+
+config STM32L4_TIM8_CH1NIDLE
+ int "TIM8 Channel 1 Complementary Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH1NOUT
+ ---help---
+ TIM8 Channel 1 Complementary Output IDLE
+
+config STM32L4_TIM8_CH2POL
+ int "TIM8 Channel 2 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH2OUT
+ ---help---
+ TIM8 Channel 2 output polarity
+
+config STM32L4_TIM8_CH2IDLE
+ int "TIM8 Channel 2 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH2OUT
+ ---help---
+ TIM8 Channel 2 output IDLE
+
+config STM32L4_TIM8_CH2NPOL
+ int "TIM8 Channel 2 Complementary Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH2NOUT
+ ---help---
+ TIM8 Channel 2 Complementary Output polarity
+
+config STM32L4_TIM8_CH2NIDLE
+ int "TIM8 Channel 2 Complementary Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH2NOUT
+ ---help---
+ TIM8 Channel 2 Complementary Output IDLE
+
+config STM32L4_TIM8_CH3POL
+ int "TIM8 Channel 3 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH3OUT
+ ---help---
+ TIM8 Channel 3 output polarity
+
+config STM32L4_TIM8_CH3IDLE
+ int "TIM8 Channel 3 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH3OUT
+ ---help---
+ TIM8 Channel 3 output IDLE
+
+config STM32L4_TIM8_CH3NPOL
+ int "TIM8 Channel 3 Complementary Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH3NOUT
+ ---help---
+ TIM8 Channel 3 Complementary Output polarity
+
+config STM32L4_TIM8_CH3NIDLE
+ int "TIM8 Channel 3 Complementary Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH3NOUT
+ ---help---
+ TIM8 Channel 3 Complementary Output IDLE
+
+config STM32L4_TIM8_CH4POL
+ int "TIM8 Channel 4 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH4OUT
+ ---help---
+ TIM8 Channel 4 output polarity
+
+config STM32L4_TIM8_CH4IDLE
+ int "TIM8 Channel 4 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH4OUT
+ ---help---
+ TIM8 Channel 4 output IDLE
+
+config STM32L4_TIM8_CH5POL
+ int "TIM8 Channel 5 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH5OUT
+ ---help---
+ TIM8 Channel 5 output polarity
+
+config STM32L4_TIM8_CH5IDLE
+ int "TIM8 Channel 5 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH5OUT
+ ---help---
+ TIM8 Channel 5 output IDLE
+
+config STM32L4_TIM8_CH6POL
+ int "TIM8 Channel 6 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH6OUT
+ ---help---
+ TIM8 Channel 6 output polarity
+
+config STM32L4_TIM8_CH6IDLE
+ int "TIM8 Channel 6 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM8_CH6OUT
+ ---help---
+ TIM8 Channel 6 output IDLE
+
+config STM32L4_TIM9_CH1POL
+ int "TIM9 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM9_CH1OUT
+ ---help---
+ TIM9 Channel 1 output polarity
+
+config STM32L4_TIM9_CH1IDLE
+ int "TIM9 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM9_CH1OUT
+ ---help---
+ TIM9 Channel 1 output IDLE
+
+config STM32L4_TIM9_CH2POL
+ int "TIM9 Channel 2 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM9_CH2OUT
+ ---help---
+ TIM9 Channel 2 output polarity
+
+config STM32L4_TIM9_CH2IDLE
+ int "TIM9 Channel 2 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM9_CH2OUT
+ ---help---
+ TIM9 Channel 2 output IDLE
+
+config STM32L4_TIM10_CH1POL
+ int "TIM10 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM10_CH1OUT
+ ---help---
+ TIM10 Channel 1 output polarity
+
+config STM32L4_TIM10_CH1IDLE
+ int "TIM10 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM10_CH1OUT
+ ---help---
+ TIM10 Channel 1 output IDLE
+
+config STM32L4_TIM11_CH1POL
+ int "TIM11 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM11_CH1OUT
+ ---help---
+ TIM11 Channel 1 output polarity
+
+config STM32L4_TIM11_CH1IDLE
+ int "TIM11 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM11_CH1OUT
+ ---help---
+ TIM11 Channel 1 output IDLE
+
+config STM32L4_TIM12_CH1POL
+ int "TIM12 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM12_CH1OUT
+ ---help---
+ TIM12 Channel 1 output polarity
+
+config STM32L4_TIM12_CH1IDLE
+ int "TIM12 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM12_CH1OUT
+ ---help---
+ TIM12 Channel 1 output IDLE
+
+config STM32L4_TIM12_CH2POL
+ int "TIM12 Channel 2 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM12_CH2OUT
+ ---help---
+ TIM12 Channel 2 output polarity
+
+config STM32L4_TIM12_CH2IDLE
+ int "TIM12 Channel 2 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM12_CH2OUT
+ ---help---
+ TIM12 Channel 2 output IDLE
+
+config STM32L4_TIM13_CH1POL
+ int "TIM13 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM13_CH1OUT
+ ---help---
+ TIM13 Channel 1 output polarity
+
+config STM32L4_TIM13_CH1IDLE
+ int "TIM13 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM13_CH1OUT
+ ---help---
+ TIM13 Channel 1 output IDLE
+
+config STM32L4_TIM14_CH1POL
+ int "TIM14 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM14_CH1OUT
+ ---help---
+ TIM14 Channel 1 output polarity
+
+config STM32L4_TIM14_CH1IDLE
+ int "TIM14 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM14_CH1OUT
+ ---help---
+ TIM14 Channel 1 output IDLE
+
+config STM32L4_TIM15_CH1POL
+ int "TIM15 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM15_CH1OUT
+ ---help---
+ TIM15 Channel 1 output polarity
+
+config STM32L4_TIM15_CH1IDLE
+ int "TIM15 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM15_CH1OUT
+ ---help---
+ TIM15 Channel 1 output IDLE
+
+config STM32L4_TIM15_CH1NPOL
+ int "TIM15 Channel 1 Complementary Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM15_CH1NOUT
+ ---help---
+ TIM15 Channel 1 Complementary Output polarity
+
+config STM32L4_TIM15_CH1NIDLE
+ int "TIM15 Channel 1 Complementary Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM15_CH1NOUT
+ ---help---
+ TIM15 Channel 1 Complementary Output IDLE
+
+config STM32L4_TIM15_CH2POL
+ int "TIM15 Channel 2 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM15_CH2OUT
+ ---help---
+ TIM15 Channel 2 output polarity
+
+config STM32L4_TIM15_CH2IDLE
+ int "TIM15 Channel 2 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM15_CH2OUT
+ ---help---
+ TIM15 Channel 2 output IDLE
+
+config STM32L4_TIM15_CH2NPOL
+ int "TIM15 Channel 2 Complementary Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM15_CH2NOUT
+ ---help---
+ TIM15 Channel 2 Complementary Output polarity
+
+config STM32L4_TIM15_CH2NIDLE
+ int "TIM15 Channel 2 Complementary Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM15_CH2NOUT
+ ---help---
+ TIM15 Channel 2 Complementary Output IDLE
+
+config STM32L4_TIM16_CH1POL
+ int "TIM16 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM16_CH1OUT
+ ---help---
+ TIM16 Channel 1 output polarity
+
+config STM32L4_TIM16_CH1IDLE
+ int "TIM16 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM16_CH1OUT
+ ---help---
+ TIM16 Channel 1 output IDLE
+
+config STM32L4_TIM17_CH1POL
+ int "TIM17 Channel 1 Output polarity"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM17_CH1OUT
+ ---help---
+ TIM17 Channel 1 output polarity
+
+config STM32L4_TIM17_CH1IDLE
+ int "TIM17 Channel 1 Output IDLE"
+ default 0
+ range 0 1
+ depends on STM32L4_TIM17_CH1OUT
+ ---help---
+ TIM17 Channel 1 output IDLE
+
+endmenu #STM32L4 TIMx Outputs Configuration
+
endmenu # Timer Configuration
menu "ADC Configuration"
diff --git a/arch/arm/src/stm32l4/stm32l4_pwm.c b/arch/arm/src/stm32l4/stm32l4_pwm.c
index 84b36eb..d9d34e9 100644
--- a/arch/arm/src/stm32l4/stm32l4_pwm.c
+++ b/arch/arm/src/stm32l4/stm32l4_pwm.c
@@ -77,12 +77,15 @@
/* 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: TIM3,4 */
-#define TIMTYPE_COUNTUP16 2 /* General 16-bit count-up timers: TIM15-17 */
-#define TIMTYPE_GENERAL32 3 /* General 32-bit timers: TIM2,5 */
-#define TIMTYPE_ADVANCED 4 /* Advanced timers: TIM1,8 */
-#define TIMTYPE_LOWPOWER 5 /* Low Power timers: LPTIM1,2 */
+#define TIMTYPE_BASIC 0 /* Basic timers: TIM6,7 */
+#define TIMTYPE_GENERAL16 1 /* General 16-bit timers: TIM3,4 */
+#define TIMTYPE_COUNTUP16 2 /* General 16-bit count-up timers: TIM15-17 */
+#define TIMTYPE_COUNTUP16_N 3 /* General 16-bit count-up timers with
+ * complementary outptus
+ */
+#define TIMTYPE_GENERAL32 4 /* General 32-bit timers: TIM2,5 */
+#define TIMTYPE_ADVANCED 5 /* Advanced timers: TIM1,8 */
+#define TIMTYPE_LOWPOWER 6 /* Low Power timers: LPTIM1,2 */
#define TIMTYPE_TIM1 TIMTYPE_ADVANCED
#define TIMTYPE_TIM2 TIMTYPE_GENERAL32
@@ -92,12 +95,60 @@
#define TIMTYPE_TIM6 TIMTYPE_BASIC
#define TIMTYPE_TIM7 TIMTYPE_BASIC
#define TIMTYPE_TIM8 TIMTYPE_ADVANCED
-#define TIMTYPE_TIM15 TIMTYPE_COUNTUP16
-#define TIMTYPE_TIM16 TIMTYPE_COUNTUP16
-#define TIMTYPE_TIM17 TIMTYPE_COUNTUP16
+#define TIMTYPE_TIM15 TIMTYPE_COUNTUP16_N /* Treated as ADVTIM */
+#define TIMTYPE_TIM16 TIMTYPE_COUNTUP16_N /* Treated as ADVTIM */
+#define TIMTYPE_TIM17 TIMTYPE_COUNTUP16_N /* Treated as ADVTIM */
#define TIMTYPE_LPTIM1 TIMTYPE_LOWPOWER
#define TIMTYPE_LPTIM2 TIMTYPE_LOWPOWER
+/* Advanced Timer support
+ * NOTE: TIM15-17 are not ADVTIM but they support most of the
+ * ADVTIM functionality. The main difference is the number of
+ * supported capture/compare.
+ */
+
+#if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM) || \
+ defined(CONFIG_STM32L4_TIM15_PWM) || defined(CONFIG_STM32L4_TIM16_PWM) || \
+ defined(CONFIG_STM32L4_TIM17_PWM)
+# define HAVE_ADVTIM
+#else
+# undef HAVE_ADVTIM
+#endif
+
+/* Low power Timer support */
+
+#if defined(CONFIG_STM32L4_LPTIM1_PWM) || defined(CONFIG_STM32L4_LPTIM2_PWM)
+# define HAVE_LPTIM
+#else
+# undef HAVE_LPTIM
+#endif
+
+/* Pulsecount support */
+
+#ifdef CONFIG_PWM_PULSECOUNT
+# ifndef HAVE_ADVTIM
+# error "PWM_PULSECOUNT requires HAVE_ADVTIM"
+# endif
+# if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
+# define HAVE_PWM_INTERRUPT
+# endif
+#endif
+
+/* Synchronisation support */
+
+#ifdef CONFIG_STM32L4_PWM_TRGO
+# define HAVE_TRGO
+#endif
+
+/* Break support */
+
+#if defined(CONFIG_STM32L4_TIM1_BREAK1) || defined(CONFIG_STM32L4_TIM1_BREAK2) || \
+ defined(CONFIG_STM32L4_TIM8_BREAK1) || defined(CONFIG_STM32L4_TIM8_BREAK2) || \
+ defined(CONFIG_STM32L4_TIM15_BREAK1) || defined(CONFIG_STM32L4_TIM16_BREAK1) || \
+ defined(CONFIG_STM32L4_TIM17_BREAK1)
+# defined HAVE_BREAK
+#endif
+
/* Debug ********************************************************************/
#ifdef CONFIG_DEBUG_PWM_INFO
@@ -110,44 +161,56 @@
* Private Types
****************************************************************************/
-enum stm32l4_timmode_e
-{
- STM32L4_TIMMODE_COUNTUP = 0,
- STM32L4_TIMMODE_COUNTDOWN = 1,
- STM32L4_TIMMODE_CENTER1 = 2,
- STM32L4_TIMMODE_CENTER2 = 3,
- STM32L4_TIMMODE_CENTER3 = 4,
-};
+/* PWM output configuration */
-enum stm32l4_chanmode_e
+struct stm32l4_pwm_out_s
{
- STM32L4_CHANMODE_PWM1 = 0,
- STM32L4_CHANMODE_PWM2 = 1,
- STM32L4_CHANMODE_COMBINED1 = 2,
- STM32L4_CHANMODE_COMBINED2 = 3,
- STM32L4_CHANMODE_ASYMMETRIC1 = 4,
- STM32L4_CHANMODE_ASYMMETRIC2 = 5,
+ uint8_t in_use:1; /* Output in use */
+ uint8_t pol:1; /* Polarity. Default: positive */
+ uint8_t idle:1; /* Idle state. Default: inactive */
+ uint8_t _res:5; /* Reserved */
+ uint32_t pincfg; /* Output pin configuration */
};
+/* PWM channel configuration */
+
struct stm32l4_pwmchan_s
{
- uint8_t channel; /* Timer output channel: {1,..4} */
- enum stm32l4_chanmode_e mode;
- uint32_t pincfg; /* Output pin configuration */
- uint32_t npincfg; /* Complementary output pin configuration
- * (only TIM1,8 CH1-3 and TIM15,16,17 CH1)
- */
+ uint8_t channel:4; /* Timer output channel: {1,..4} */
+ uint8_t mode:4; /* PWM channel mode (see stm32l4_pwm_chanmode_e) */
+ struct stm32l4_pwm_out_s out1; /* PWM output configuration */
+#ifdef HAVE_BREAK
+ struct stm32l4_pwm_break_s brk; /* PWM break configuration */
+#endif
+#ifdef HAVE_PWM_COMPLEMENTARY
+ struct stm32l4_pwm_out_s out2; /* PWM complementary output configuration */
+#endif
};
/* This structure represents the state of one PWM timer */
struct stm32l4_pwmtimer_s
{
- FAR const struct pwm_ops_s *ops; /* PWM operations */
- struct stm32l4_pwmchan_s channels[PWM_NCHANNELS];
- uint8_t timid; /* Timer ID {1,...,17} */
- uint8_t timtype; /* See the TIMTYPE_* definitions */
- enum stm32l4_timmode_e mode;
+ FAR const struct pwm_ops_s *ops; /* PWM operations */
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ FAR const struct stm32l4_pwm_ops_s *llops; /* Low-level PWM ops */
+#endif
+ FAR struct stm32l4_pwmchan_s *channels; /* Channels configuration */
+ uint8_t timid:5; /* Timer ID {1,...,17} */
+ uint8_t chan_num:3; /* Number of configured channels */
+ uint8_t timtype:3; /* See the TIMTYPE_* definitions */
+ uint8_t mode:3; /* Timer mode (see stm32l4_pwm_tim_mode_e) */
+ uint8_t lock:2; /* TODO: Lock configuration */
+ uint8_t t_dts:3; /* Clock division for t_DTS */
+ uint8_t _res:5; /* Reserved */
+#ifdef HAVE_PWM_COMPLEMENTARY
+ uint8_t deadtime; /* Dead-time value */
+#endif
+#ifdef HAVE_TRGO
+ uint8_t trgo; /* TRGO configuration:
+ * 4 LSB = TRGO, 4 MSB = TRGO2
+ */
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
uint8_t irq; /* Timer update IRQ */
uint8_t prev; /* The previous value of the RCR (pre-loaded) */
@@ -157,7 +220,7 @@ struct stm32l4_pwmtimer_s
uint32_t frequency; /* Current frequency setting */
#endif
uint32_t base; /* The base address of the timer */
- uint32_t pclk; /* The frequency of the peripheral clock
+ uint32_t pclk; /* Frequency of the peripheral clock
* that drives the timer module. */
#ifdef CONFIG_PWM_PULSECOUNT
FAR void *handle; /* Handle used for upper-half callback */
@@ -170,55 +233,84 @@ struct stm32l4_pwmtimer_s
/* Register access */
-static uint16_t stm32l4pwm_getreg(struct stm32l4_pwmtimer_s *priv,
- int offset);
-static void stm32l4pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
- uint16_t value);
+static uint16_t pwm_getreg(struct stm32l4_pwmtimer_s *priv, int offset);
+static void pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
+ uint16_t value);
+static void pwm_modifyreg(struct stm32l4_pwmtimer_s *priv, uint32_t offset,
+ uint32_t clearbits, uint32_t setbits);
#ifdef CONFIG_DEBUG_PWM_INFO
-static void stm32l4pwm_dumpregs(struct stm32l4_pwmtimer_s *priv,
- const char *msg);
+static void pwm_dumpregs(FAR struct pwm_lowerhalf_s *dev,
+ FAR const char *msg);
#else
-# define stm32l4pwm_dumpregs(priv,msg)
+# define pwm_dumpregs(priv,msg)
#endif
/* Timer management */
-static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
- FAR const struct pwm_info_s *info);
-
-static int stm32l4pwm_lptimer(FAR struct stm32l4_pwmtimer_s *priv,
- FAR const struct pwm_info_s *info);
-
-#if defined(CONFIG_PWM_PULSECOUNT) && (defined(CONFIG_STM32L4_TIM1_PWM) || \
- defined(CONFIG_STM32L4_TIM8_PWM))
-static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv);
-#if defined(CONFIG_STM32L4_TIM1_PWM)
-static int stm32l4pwm_tim1interrupt(int irq, void *context, FAR void *arg);
+#ifdef CONFIG_PWM_PULSECOUNT
+static int pwm_pulsecount_timer(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info);
+#else
+static int pwm_timer(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info);
+# ifdef HAVE_LPTIM
+static int pwm_lptimer(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info);
+# endif
+static int pwm_configure(FAR struct pwm_lowerhalf_s *dev);
+#endif
+static int pwm_soft_break(FAR struct pwm_lowerhalf_s *dev, bool state); /* REVISIT: valid for all timers? */
+static int pwm_ccr_update(FAR struct pwm_lowerhalf_s *dev, uint8_t index,
+ uint32_t ccr);
+static int pwm_mode_configure(FAR struct pwm_lowerhalf_s *dev,
+ uint8_t channel, uint32_t mode);
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+static uint32_t pwm_ccr_get(FAR struct pwm_lowerhalf_s *dev, uint8_t index);
+#endif
+static int pwm_arr_update(FAR struct pwm_lowerhalf_s *dev, uint32_t arr);
+static uint32_t pwm_arr_get(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_outputs_enable(FAR struct pwm_lowerhalf_s *dev,
+ uint16_t outputs, bool state);
+static int pwm_soft_update(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_frequency_update(FAR struct pwm_lowerhalf_s *dev,
+ uint32_t frequency);
+static int pwm_timer_enable(FAR struct pwm_lowerhalf_s *dev, bool state);
+#if defined(HAVE_PWM_COMPLEMENTARY) && defined(CONFIG_STM32L4_PWM_LL_OPS)
+static int pwm_deadtime_update(FAR struct pwm_lowerhalf_s *dev, uint8_t dt);
#endif
-#if defined(CONFIG_STM32L4_TIM8_PWM)
-static int stm32l4pwm_tim8interrupt(int irq, void *context, FAR void *arg);
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+static uint32_t pwm_ccr_get(FAR struct pwm_lowerhalf_s *dev, uint8_t index);
#endif
-static uint8_t stm32l4pwm_pulsecount(uint32_t count);
+
+#ifdef HAVE_PWM_INTERRUPT
+static int pwm_interrupt(FAR struct pwm_lowerhalf_s *dev);
+# ifdef CONFIG_STM32L4_TIM1_PWM
+static int pwm_tim1interrupt(int irq, void *context, FAR void *arg);
+# endif
+# ifdef CONFIG_STM32L4_TIM8_PWM
+static int pwm_tim8interrupt(int irq, void *context, FAR void *arg);
+# endif
+static uint8_t pwm_pulsecount(uint32_t count);
#endif
/* PWM driver methods */
-static int stm32l4pwm_setup(FAR struct pwm_lowerhalf_s *dev);
-static int stm32l4pwm_shutdown(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_setup(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev);
#ifdef CONFIG_PWM_PULSECOUNT
-static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
- FAR const struct pwm_info_s *info,
- FAR void *handle);
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info,
+ FAR void *handle);
#else
-static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
- FAR const struct pwm_info_s *info);
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info);
#endif
-static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev);
-static int stm32l4pwm_ioctl(FAR struct pwm_lowerhalf_s *dev,
- int cmd, unsigned long arg);
+static int pwm_stop(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev,
+ int cmd, unsigned long arg);
/****************************************************************************
* Private Data
@@ -230,416 +322,1032 @@ static int stm32l4pwm_ioctl(FAR struct pwm_lowerhalf_s *dev,
static const struct pwm_ops_s g_pwmops =
{
- .setup = stm32l4pwm_setup,
- .shutdown = stm32l4pwm_shutdown,
- .start = stm32l4pwm_start,
- .stop = stm32l4pwm_stop,
- .ioctl = stm32l4pwm_ioctl,
+ .setup = pwm_setup,
+ .shutdown = pwm_shutdown,
+ .start = pwm_start,
+ .stop = pwm_stop,
+ .ioctl = pwm_ioctl,
+};
+
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+static const struct stm32l4_pwm_ops_s g_llpwmops =
+{
+ .configure = pwm_configure,
+ .soft_break = pwm_soft_break,
+ .ccr_update = pwm_ccr_update,
+ .mode_update = pwm_mode_configure,
+ .ccr_get = pwm_ccr_get,
+ .arr_update = pwm_arr_update,
+ .arr_get = pwm_arr_get,
+ .outputs_enable = pwm_outputs_enable,
+ .soft_update = pwm_soft_update,
+ .freq_update = pwm_frequency_update,
+ .tim_enable = pwm_timer_enable,
+# ifdef CONFIG_DEBUG_PWM_INFO
+ .dump_regs = pwm_dumpregs,
+# endif
+# ifdef HAVE_PWM_COMPLEMENTARY
+ .dt_update = pwm_deadtime_update,
+# endif
};
+#endif
#ifdef CONFIG_STM32L4_TIM1_PWM
-static struct stm32l4_pwmtimer_s g_pwm1dev =
+
+static struct stm32l4_pwmchan_s g_pwm1channels[] =
{
- .ops = &g_pwmops,
- .timid = 1,
- .channels =
- {
+ /* TIM1 has 4 channels, 4 complementary */
+
#ifdef CONFIG_STM32L4_TIM1_CHANNEL1
+ {
+ .channel = 1,
+ .mode = CONFIG_STM32L4_TIM1_CH1MODE,
+#ifdef HAVE_BREAK
+ .brk =
+ {
+#ifdef CONFIG_STM32L4_TIM1_BREAK1
+ .en1 = 1,
+ .pol1 = CONFIG_STM32L4_TIM1_BRK1POL,
+#endif
+#ifdef CONFIG_STM32L4_TIM1_BREAK2
+ .en2 = 1,
+ .pol2 = CONFIG_STM32L4_TIM1_BRK2POL,
+ .flt2 = CONFIG_STM32L4_TIM1_BRK2FLT,
+#endif
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM1_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM1_CH1POL,
+ .idle = CONFIG_STM32L4_TIM1_CH1IDLE,
.pincfg = PWM_TIM1_CH1CFG,
- .mode = CONFIG_STM32L4_TIM1_CH1MODE,
- .npincfg = PWM_TIM1_CH1NCFG,
},
#endif
+#ifdef CONFIG_STM32L4_TIM1_CH1NOUT
+ .out2 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM1_CH1NPOL,
+ .idle = CONFIG_STM32L4_TIM1_CH1NIDLE,
+ .pincfg = PWM_TIM1_CH1NCFG,
+ }
+#endif
+ },
+#endif
#ifdef CONFIG_STM32L4_TIM1_CHANNEL2
+ {
+ .channel = 2,
+ .mode = CONFIG_STM32L4_TIM1_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH2OUT
+ .out1 =
{
- .channel = 2,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM1_CH2POL,
+ .idle = CONFIG_STM32L4_TIM1_CH2IDLE,
.pincfg = PWM_TIM1_CH2CFG,
- .mode = CONFIG_STM32L4_TIM1_CH2MODE,
- .npincfg = PWM_TIM1_CH2NCFG,
},
#endif
+#ifdef CONFIG_STM32L4_TIM1_CH2NOUT
+ .out2 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM1_CH2NPOL,
+ .idle = CONFIG_STM32L4_TIM1_CH2NIDLE,
+ .pincfg = PWM_TIM1_CH2NCFG,
+ }
+#endif
+ },
+#endif
#ifdef CONFIG_STM32L4_TIM1_CHANNEL3
+ {
+ .channel = 3,
+ .mode = CONFIG_STM32L4_TIM1_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH3OUT
+ .out1 =
{
- .channel = 3,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM1_CH3POL,
+ .idle = CONFIG_STM32L4_TIM1_CH3IDLE,
.pincfg = PWM_TIM1_CH3CFG,
- .mode = CONFIG_STM32L4_TIM1_CH3MODE,
- .npincfg = PWM_TIM1_CH3NCFG,
},
#endif
+#ifdef CONFIG_STM32L4_TIM1_CH3NOUT
+ .out2 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM1_CH3NPOL,
+ .idle = CONFIG_STM32L4_TIM1_CH3NIDLE,
+ .pincfg = PWM_TIM1_CH3NCFG,
+ }
+#endif
+ },
+#endif
#ifdef CONFIG_STM32L4_TIM1_CHANNEL4
+ {
+ .channel = 4,
+ .mode = CONFIG_STM32L4_TIM1_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH4OUT
+ .out1 =
{
- .channel = 4,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4L4_TIM1_CH4POL,
+ .idle = CONFIG_STM32L4L4_TIM1_CH4IDLE,
.pincfg = PWM_TIM1_CH4CFG,
- .mode = CONFIG_STM32L4_TIM1_CH4MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM1_CHANNEL5
+ {
+ .channel = 5,
+ .mode = CONFIG_STM32L4_TIM1_CH5MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH5OUT
+ .out1 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM1_CH5POL,
+ .idle = CONFIG_STM32L4_TIM1_CH5IDLE,
+ .pincfg = 0, /* No available externaly */
+ }
#endif
},
+#endif
+#ifdef CONFIG_STM32L4_TIM1_CHANNEL6
+ {
+ .channel = 6,
+ .mode = CONFIG_STM32L4_TIM1_CH6MODE,
+#ifdef CONFIG_STM32L4_TIM1_CH6OUT
+ .out1 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM1_CH6POL,
+ .idle = CONFIG_STM32L4_TIM1_CH6IDLE,
+ .pincfg = 0, /* No available externaly */
+ }
+#endif
+ }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm1dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 1,
+ .chan_num = PWM_TIM1_NCHANNELS,
+ .channels = g_pwm1channels,
.timtype = TIMTYPE_TIM1,
.mode = CONFIG_STM32L4_TIM1_MODE,
+ .lock = CONFIG_STM32L4_TIM1_LOCK,
+ .t_dts = CONFIG_STM32L4_TIM1_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = CONFIG_STM32L4_TIM1_DEADTIME,
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM1_TRGO)
+ .trgo = STM32L4_TIM1_TRGO,
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
.irq = STM32L4_IRQ_TIM1UP,
#endif
.base = STM32L4_TIM1_BASE,
.pclk = STM32L4_APB2_TIM1_CLKIN,
};
-#endif
+#endif /* CONFIG_STM32L4_TIM1_PWM */
#ifdef CONFIG_STM32L4_TIM2_PWM
-static struct stm32l4_pwmtimer_s g_pwm2dev =
+
+static struct stm32l4_pwmchan_s g_pwm2channels[] =
{
- .ops = &g_pwmops,
- .timid = 2,
- .channels =
- {
+ /* TIM2 has 4 channels */
+
#ifdef CONFIG_STM32L4_TIM2_CHANNEL1
+ {
+ .channel = 1,
+ .mode = CONFIG_STM32L4_TIM2_CH1MODE,
+#ifdef CONFIG_STM32L4_TIM2_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM2_CH1POL,
+ .idle = CONFIG_STM32L4_TIM2_CH1IDLE,
.pincfg = PWM_TIM2_CH1CFG,
- .mode = CONFIG_STM32L4_TIM2_CH1MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM2_CHANNEL2
+ {
+ .channel = 2,
+ .mode = CONFIG_STM32L4_TIM2_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM2_CH2OUT
+ .out1 =
{
- .channel = 2,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM2_CH2POL,
+ .idle = CONFIG_STM32L4_TIM2_CH2IDLE,
.pincfg = PWM_TIM2_CH2CFG,
- .mode = CONFIG_STM32L4_TIM2_CH2MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM2_CHANNEL3
+ {
+ .channel = 3,
+ .mode = CONFIG_STM32L4_TIM2_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM2_CH3OUT
+ .out1 =
{
- .channel = 3,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM2_CH3POL,
+ .idle = CONFIG_STM32L4_TIM2_CH3IDLE,
.pincfg = PWM_TIM2_CH3CFG,
- .mode = CONFIG_STM32L4_TIM2_CH3MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM2_CHANNEL4
+ {
+ .channel = 4,
+ .mode = CONFIG_STM32L4_TIM2_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM2_CH4OUT
+ .out1 =
{
- .channel = 4,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM2_CH4POL,
+ .idle = CONFIG_STM32L4_TIM2_CH4IDLE,
.pincfg = PWM_TIM2_CH4CFG,
- .mode = CONFIG_STM32L4_TIM2_CH4MODE,
- .npincfg = 0,
- },
+ }
#endif
- },
+ /* No complementary outputs */
+ }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm2dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 2,
+ .chan_num = PWM_TIM2_NCHANNELS,
+ .channels = g_pwm2channels,
.timtype = TIMTYPE_TIM2,
.mode = CONFIG_STM32L4_TIM2_MODE,
+ .lock = 0, /* No lock */
+ .t_dts = 0, /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = 0, /* No deadtime */
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM2_TRGO)
+ .trgo = STM32L4_TIM2_TRGO,
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
.irq = STM32L4_IRQ_TIM2,
#endif
.base = STM32L4_TIM2_BASE,
.pclk = STM32L4_APB1_TIM2_CLKIN,
};
-#endif
+
+#endif /* CONFIG_STM32L4_TIM2_PWM */
#ifdef CONFIG_STM32L4_TIM3_PWM
-static struct stm32l4_pwmtimer_s g_pwm3dev =
+
+static struct stm32l4_pwmchan_s g_pwm3channels[] =
{
- .ops = &g_pwmops,
- .timid = 3,
- .channels =
- {
+ /* TIM3 has 4 channels */
+
#ifdef CONFIG_STM32L4_TIM3_CHANNEL1
+ {
+ .channel = 1,
+ .mode = CONFIG_STM32L4_TIM3_CH1MODE,
+#ifdef CONFIG_STM32L4_TIM3_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM3_CH1POL,
+ .idle = CONFIG_STM32L4_TIM3_CH1IDLE,
.pincfg = PWM_TIM3_CH1CFG,
- .mode = CONFIG_STM32L4_TIM3_CH1MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM3_CHANNEL2
+ {
+ .channel = 2,
+ .mode = CONFIG_STM32L4_TIM3_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM3_CH2OUT
+ .out1 =
{
- .channel = 2,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM3_CH2POL,
+ .idle = CONFIG_STM32L4_TIM3_CH2IDLE,
.pincfg = PWM_TIM3_CH2CFG,
- .mode = CONFIG_STM32L4_TIM3_CH2MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM3_CHANNEL3
+ {
+ .channel = 3,
+ .mode = CONFIG_STM32L4_TIM3_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM3_CH3OUT
+ .out1 =
{
- .channel = 3,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM3_CH3POL,
+ .idle = CONFIG_STM32L4_TIM3_CH3IDLE,
.pincfg = PWM_TIM3_CH3CFG,
- .mode = CONFIG_STM32L4_TIM3_CH3MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM3_CHANNEL4
+ {
+ .channel = 4,
+ .mode = CONFIG_STM32L4_TIM3_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM3_CH4OUT
+ .out1 =
{
- .channel = 4,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM3_CH4POL,
+ .idle = CONFIG_STM32L4_TIM3_CH4IDLE,
.pincfg = PWM_TIM3_CH4CFG,
- .mode = CONFIG_STM32L4_TIM3_CH4MODE,
- .npincfg = 0,
- },
+ }
#endif
- },
+ /* No complementary outputs */
+ }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm3dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 3,
+ .chan_num = PWM_TIM3_NCHANNELS,
+ .channels = g_pwm3channels,
.timtype = TIMTYPE_TIM3,
.mode = CONFIG_STM32L4_TIM3_MODE,
+ .lock = 0, /* No lock */
+ .t_dts = 0, /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = 0, /* No deadtime */
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM3_TRGO)
+ .trgo = STM32L4_TIM3_TRGO,
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
.irq = STM32L4_IRQ_TIM3,
#endif
.base = STM32L4_TIM3_BASE,
.pclk = STM32L4_APB1_TIM3_CLKIN,
};
-#endif
+#endif /* CONFIG_STM32L4_TIM3_PWM */
#ifdef CONFIG_STM32L4_TIM4_PWM
-static struct stm32l4_pwmtimer_s g_pwm4dev =
+
+static struct stm32l4_pwmchan_s g_pwm4channels[] =
{
- .ops = &g_pwmops,
- .timid = 4,
- .channels =
- {
+ /* TIM4 has 4 channels */
+
#ifdef CONFIG_STM32L4_TIM4_CHANNEL1
+ {
+ .channel = 1,
+ .mode = CONFIG_STM32L4_TIM4_CH1MODE,
+#ifdef CONFIG_STM32L4_TIM4_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM4_CH1POL,
+ .idle = CONFIG_STM32L4_TIM4_CH1IDLE,
.pincfg = PWM_TIM4_CH1CFG,
- .mode = CONFIG_STM32L4_TIM4_CH1MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM4_CHANNEL2
+ {
+ .channel = 2,
+ .mode = CONFIG_STM32L4_TIM4_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM4_CH2OUT
+ .out1 =
{
- .channel = 2,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM4_CH2POL,
+ .idle = CONFIG_STM32L4_TIM4_CH2IDLE,
.pincfg = PWM_TIM4_CH2CFG,
- .mode = CONFIG_STM32L4_TIM4_CH2MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM4_CHANNEL3
+ {
+ .channel = 3,
+ .mode = CONFIG_STM32L4_TIM4_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM4_CH3OUT
+ .out1 =
{
- .channel = 3,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM4_CH3POL,
+ .idle = CONFIG_STM32L4_TIM4_CH3IDLE,
.pincfg = PWM_TIM4_CH3CFG,
- .mode = CONFIG_STM32L4_TIM4_CH3MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM4_CHANNEL4
+ {
+ .channel = 4,
+ .mode = CONFIG_STM32L4_TIM4_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM4_CH4OUT
+ .out1 =
{
- .channel = 4,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM4_CH4POL,
+ .idle = CONFIG_STM32L4_TIM4_CH4IDLE,
.pincfg = PWM_TIM4_CH4CFG,
- .mode = CONFIG_STM32L4_TIM4_CH4MODE,
- .npincfg = 0,
- },
+ }
#endif
- },
+ /* No complementary outputs */
+ }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm4dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 4,
+ .chan_num = PWM_TIM4_NCHANNELS,
+ .channels = g_pwm4channels,
.timtype = TIMTYPE_TIM4,
.mode = CONFIG_STM32L4_TIM4_MODE,
+ .lock = 0, /* No lock */
+ .t_dts = 0, /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = 0, /* No deadtime */
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM4_TRGO)
+ .trgo = STM32L4_TIM4_TRGO,
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
.irq = STM32L4_IRQ_TIM4,
#endif
.base = STM32L4_TIM4_BASE,
.pclk = STM32L4_APB1_TIM4_CLKIN,
};
-#endif
+#endif /* CONFIG_STM32L4_TIM4_PWM */
#ifdef CONFIG_STM32L4_TIM5_PWM
-static struct stm32l4_pwmtimer_s g_pwm5dev =
+
+static struct stm32l4_pwmchan_s g_pwm5channels[] =
{
- .ops = &g_pwmops,
- .timid = 5,
- .channels =
- {
+ /* TIM5 has 4 channels */
+
#ifdef CONFIG_STM32L4_TIM5_CHANNEL1
+ {
+ .channel = 1,
+ .mode = CONFIG_STM32L4_TIM5_CH1MODE,
+#ifdef CONFIG_STM32L4_TIM5_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM5_CH1POL,
+ .idle = CONFIG_STM32L4_TIM5_CH1IDLE,
.pincfg = PWM_TIM5_CH1CFG,
- .mode = CONFIG_STM32L4_TIM5_CH1MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM5_CHANNEL2
+ {
+ .channel = 2,
+ .mode = CONFIG_STM32L4_TIM5_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM5_CH2OUT
+ .out1 =
{
- .channel = 2,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM5_CH2POL,
+ .idle = CONFIG_STM32L4_TIM5_CH2IDLE,
.pincfg = PWM_TIM5_CH2CFG,
- .mode = CONFIG_STM32L4_TIM5_CH2MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ /* No complementary outputs */
+ },
#endif
#ifdef CONFIG_STM32L4_TIM5_CHANNEL3
+ {
+ .channel = 3,
+ .mode = CONFIG_STM32L4_TIM5_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM5_CH3OUT
+ .out1 =
{
- .channel = 3,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM5_CH3POL,
+ .idle = CONFIG_STM32L4_TIM5_CH3IDLE,
.pincfg = PWM_TIM5_CH3CFG,
- .mode = CONFIG_STM32L4_TIM5_CH3MODE,
- .npincfg = 0,
- },
+ }
+#endif
+ },
#endif
#ifdef CONFIG_STM32L4_TIM5_CHANNEL4
+ {
+ .channel = 4,
+ .mode = CONFIG_STM32L4_TIM5_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM5_CH4OUT
+ .out1 =
{
- .channel = 4,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM5_CH4POL,
+ .idle = CONFIG_STM32L4_TIM5_CH4IDLE,
.pincfg = PWM_TIM5_CH4CFG,
- .mode = CONFIG_STM32L4_TIM5_CH4MODE,
- .npincfg = 0,
- },
+ }
#endif
},
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm5dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 5,
+ .chan_num = PWM_TIM5_NCHANNELS,
+ .channels = g_pwm5channels,
.timtype = TIMTYPE_TIM5,
.mode = CONFIG_STM32L4_TIM5_MODE,
+ .lock = 0, /* No lock */
+ .t_dts = 0, /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = 0, /* No deadtime */
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM5_TRGO)
+ .trgo = STM32L4_TIM5_TRGO
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
.irq = STM32L4_IRQ_TIM5,
#endif
.base = STM32L4_TIM5_BASE,
.pclk = STM32L4_APB1_TIM5_CLKIN,
};
-#endif
+#endif /* CONFIG_STM32L4_TIM5_PWM */
#ifdef CONFIG_STM32L4_TIM8_PWM
-static struct stm32l4_pwmtimer_s g_pwm8dev =
+
+static struct stm32l4_pwmchan_s g_pwm8channels[] =
{
- .ops = &g_pwmops,
- .timid = 8,
- .channels =
- {
+ /* TIM8 has 4 channels, 4 complementary */
+
#ifdef CONFIG_STM32L4_TIM8_CHANNEL1
+ {
+ .channel = 1,
+ .mode = CONFIG_STM32L4_TIM8_CH1MODE,
+#ifdef HAVE_BREAK
+ .brk =
{
- .channel = 1,
- .pincfg = PWM_TIM8_CH1CFG,
- .mode = CONFIG_STM32L4_TIM8_CH1MODE,
- .npincfg = PWM_TIM8_CH1NCFG,
- },
+#ifdef CONFIG_STM32L4_TIM8_BREAK1
+ .en1 = 1,
+ .pol1 = CONFIG_STM32L4_TIM8_BRK1POL,
+#endif
+#ifdef CONFIG_STM32L4_TIM8_BREAK2
+ .en2 = 1,
+ .pol2 = CONFIG_STM32L4_TIM8_BRK2POL,
+ .flt2 = CONFIG_STM32L4_TIM8_BRK2FLT,
#endif
-#ifdef CONFIG_STM32L4_TIM8_CHANNEL2
- {
- .channel = 2,
- .pincfg = PWM_TIM8_CH2CFG,
- .mode = CONFIG_STM32L4_TIM8_CH2MODE,
- .npincfg = PWM_TIM8_CH2NCFG,
},
#endif
-#ifdef CONFIG_STM32L4_TIM8_CHANNEL3
+#ifdef CONFIG_STM32L4_TIM8_CH1OUT
+ .out1 =
{
- .channel = 3,
- .pincfg = PWM_TIM8_CH3CFG,
- .mode = CONFIG_STM32L4_TIM8_CH3MODE,
- .npincfg = PWM_TIM8_CH3NCFG,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM8_CH1POL,
+ .idle = CONFIG_STM32L4_TIM8_CH1IDLE,
+ .pincfg = PWM_TIM8_CH1CFG,
},
#endif
-#ifdef CONFIG_STM32L4_TIM8_CHANNEL4
+#ifdef CONFIG_STM32L4_TIM8_CH1NOUT
+ .out2 =
{
- .channel = 4,
- .pincfg = PWM_TIM8_CH4CFG,
- .mode = CONFIG_STM32L4_TIM8_CH4MODE,
- .npincfg = 0,
- },
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM8_CH1NPOL,
+ .idle = CONFIG_STM32L4_TIM8_CH1NIDLE,
+ .pincfg = PWM_TIM8_CH1NCFG,
+ }
#endif
},
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL2
+ {
+ .channel = 2,
+ .mode = CONFIG_STM32L4_TIM8_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH2OUT
+ .out1 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM8_CH2POL,
+ .idle = CONFIG_STM32L4_TIM8_CH2IDLE,
+ .pincfg = PWM_TIM8_CH2CFG,
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CH2NOUT
+ .out2 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM8_CH2NPOL,
+ .idle = CONFIG_STM32L4_TIM8_CH2NIDLE,
+ .pincfg = PWM_TIM8_CH2NCFG,
+ }
+#endif
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL3
+ {
+ .channel = 3,
+ .mode = CONFIG_STM32L4_TIM8_CH3MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH3OUT
+ .out1 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM8_CH3POL,
+ .idle = CONFIG_STM32L4_TIM8_CH3IDLE,
+ .pincfg = PWM_TIM8_CH3CFG,
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CH3NOUT
+ .out2 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM8_CH3NPOL,
+ .idle = CONFIG_STM32L4_TIM8_CH3NIDLE,
+ .pincfg = PWM_TIM8_CH3NCFG,
+ }
+#endif
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL4
+ {
+ .channel = 4,
+ .mode = CONFIG_STM32L4_TIM8_CH4MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH4OUT
+ .out1 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM8_CH4POL,
+ .idle = CONFIG_STM32L4_TIM8_CH4IDLE,
+ .pincfg = PWM_TIM8_CH4CFG,
+ }
+#endif
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL5
+ {
+ .channel = 5,
+ .mode = CONFIG_STM32L4_TIM8_CH5MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH5OUT
+ .out1 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM8_CH5POL,
+ .idle = CONFIG_STM32L4_TIM8_CH5IDLE,
+ .pincfg = 0, /* No available externaly */
+ }
+#endif
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM8_CHANNEL6
+ {
+ .channel = 6,
+ .mode = CONFIG_STM32L4_TIM8_CH6MODE,
+#ifdef CONFIG_STM32L4_TIM8_CH6OUT
+ .out1 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM8_CH6POL,
+ .idle = CONFIG_STM32L4_TIM8_CH6IDLE,
+ .pincfg = 0, /* No available externaly */
+ }
+#endif
+ }
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm8dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 8,
+ .chan_num = PWM_TIM8_NCHANNELS,
+ .channels = g_pwm8channels,
.timtype = TIMTYPE_TIM8,
.mode = CONFIG_STM32L4_TIM8_MODE,
+ .lock = CONFIG_STM32L4_TIM8_LOCK,
+ .t_dts = CONFIG_STM32L4_TIM8_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = CONFIG_STM32L4_TIM8_DEADTIME,
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM8_TRGO)
+ .trgo = STM32L4_TIM8_TRGO,
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
.irq = STM32L4_IRQ_TIM8UP,
#endif
.base = STM32L4_TIM8_BASE,
.pclk = STM32L4_APB2_TIM8_CLKIN,
};
-#endif
+#endif /* CONFIG_STM32L4_TIM8_PWM */
#ifdef CONFIG_STM32L4_TIM15_PWM
-static struct stm32l4_pwmtimer_s g_pwm15dev =
+
+static struct stm32l4_pwmchan_s g_pwm15channels[] =
{
- .ops = &g_pwmops,
- .timid = 15,
- .channels =
- {
+ /* TIM15 has 2 channels, 1 complementary */
+
#ifdef CONFIG_STM32L4_TIM15_CHANNEL1
+ {
+ .channel = 1,
+ .mode = CONFIG_STM32L4_TIM15_CH1MODE,
+#ifdef HAVE_BREAK
+ .brk =
+ {
+#ifdef CONFIG_STM32L4_TIM15_BREAK1
+ .en1 = 1,
+ .pol1 = CONFIG_STM32L4_TIM15_BRK1POL,
+#endif
+ /* No BREAK2 */
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM15_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM15_CH1POL,
+ .idle = CONFIG_STM32L4_TIM15_CH1IDLE,
.pincfg = PWM_TIM15_CH1CFG,
- .mode = CONFIG_STM32L4_TIM15_CH1MODE,
- .npincfg = PWM_TIM15_CH1NCFG,
},
#endif
+#ifdef CONFIG_STM32L4_TIM15_CH1NOUT
+ .out2 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM15_CH1NPOL,
+ .idle = CONFIG_STM32L4_TIM15_CH1NIDLE,
+ .pincfg = PWM_TIM15_CH2CFG,
+ }
+#endif
+ },
+#endif
#ifdef CONFIG_STM32L4_TIM15_CHANNEL2
+ {
+ .channel = 2,
+ .mode = CONFIG_STM32L4_TIM15_CH2MODE,
+#ifdef CONFIG_STM32L4_TIM12_CH2OUT
+ .out1 =
{
- .channel = 2,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM15_CH2POL,
+ .idle = CONFIG_STM32L4_TIM15_CH2IDLE,
.pincfg = PWM_TIM15_CH2CFG,
- .mode = CONFIG_STM32L4_TIM15_CH2MODE,
- .npincfg = 0,
- },
+ }
#endif
+ /* No complementary outputs */
},
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm15dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 15,
+ .chan_num = PWM_TIM15_NCHANNELS,
+ .channels = g_pwm15channels,
.timtype = TIMTYPE_TIM15,
.mode = STM32L4_TIMMODE_COUNTUP,
+ .lock = CONFIG_STM32L4_TIM15_LOCK,
+ .t_dts = CONFIG_STM32L4_TIM15_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = CONFIG_STM32L4_TIM15_DEADTIME,
+#endif
+#if defined(HAVE_TRGO) && defined(STM32L4_TIM15_TRGO)
+ .trgo = STM32L4_TIM15_TRGO,
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
.irq = STM32L4_IRQ_TIM15,
#endif
.base = STM32L4_TIM15_BASE,
.pclk = STM32L4_APB2_TIM15_CLKIN,
};
-#endif
+#endif /* CONFIG_STM32L4_TIM15_PWM */
#ifdef CONFIG_STM32L4_TIM16_PWM
-static struct stm32l4_pwmtimer_s g_pwm16dev =
+
+static struct stm32l4_pwmchan_s g_pwm16channels[] =
{
- .ops = &g_pwmops,
- .timid = 16,
- .channels =
- {
+ /* TIM16 has 1 channel, 1 complementary */
+
#ifdef CONFIG_STM32L4_TIM16_CHANNEL1
+ {
+ .channel = 1,
+ .mode = CONFIG_STM32L4_TIM16_CH1MODE,
+#ifdef HAVE_BREAK
+ .brk =
+ {
+#ifdef CONFIG_STM32L4_TIM16_BREAK1
+ .en1 = 1,
+ .pol1 = CONFIG_STM32L4_TIM16_BRK1POL,
+#endif
+ /* No BREAK2 */
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM16_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM16_CH1POL,
+ .idle = CONFIG_STM32L4_TIM16_CH1IDLE,
.pincfg = PWM_TIM16_CH1CFG,
- .mode = CONFIG_STM32L4_TIM16_CH1MODE,
- .npincfg = PWM_TIM16_CH1NCFG,
},
#endif
+#ifdef CONFIG_STM32L4_TIM16_CH1NOUT
+ .out2 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM16_CH1NPOL,
+ .idle = CONFIG_STM32L4_TIM16_CH1NIDLE,
+ .pincfg = PWM_TIM16_CH2CFG,
+ }
+#endif
},
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm16dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 16,
+ .chan_num = PWM_TIM16_NCHANNELS,
+ .channels = g_pwm16channels,
.timtype = TIMTYPE_TIM16,
.mode = STM32L4_TIMMODE_COUNTUP,
+ .lock = CONFIG_STM32L4_TIM16_LOCK,
+ .t_dts = CONFIG_STM32L4_TIM16_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = CONFIG_STM32L4_TIM16_DEADTIME,
+#endif
+#if defined(HAVE_TRGO)
+ .trgo = 0, /* TRGO not supported for TIM16 */
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
.irq = STM32L4_IRQ_TIM16,
#endif
.base = STM32L4_TIM16_BASE,
.pclk = STM32L4_APB2_TIM16_CLKIN,
};
-#endif
+#endif /* CONFIG_STM32L4_TIM16_PWM */
#ifdef CONFIG_STM32L4_TIM17_PWM
-static struct stm32l4_pwmtimer_s g_pwm17dev =
+
+static struct stm32l4_pwmchan_s g_pwm17channels[] =
{
- .ops = &g_pwmops,
- .timid = 17,
- .channels =
- {
+ /* TIM17 has 1 channel, 1 complementary */
+
#ifdef CONFIG_STM32L4_TIM17_CHANNEL1
+ {
+ .channel = 1,
+ .mode = CONFIG_STM32L4_TIM17_CH1MODE,
+#ifdef HAVE_BREAK
+ .brk =
+ {
+#ifdef CONFIG_STM32L4_TIM17_BREAK1
+ .en1 = 1,
+ .pol1 = CONFIG_STM32L4_TIM17_BRK1POL,
+#endif
+ /* No BREAK2 */
+ },
+#endif
+#ifdef CONFIG_STM32L4_TIM17_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM17_CH1POL,
+ .idle = CONFIG_STM32L4_TIM17_CH1IDLE,
.pincfg = PWM_TIM17_CH1CFG,
- .mode = CONFIG_STM32L4_TIM17_CH1MODE,
- .npincfg = PWM_TIM17_CH1NCFG,
},
#endif
+#ifdef CONFIG_STM32L4_TIM17_CH1NOUT
+ .out2 =
+ {
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_TIM17_CH1NPOL,
+ .idle = CONFIG_STM32L4_TIM17_CH1NIDLE,
+ .pincfg = PWM_TIM17_CH2CFG,
+ }
+#endif
},
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwm17dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 17,
+ .chan_num = PWM_TIM17_NCHANNELS,
+ .channels = g_pwm17channels,
.timtype = TIMTYPE_TIM17,
.mode = STM32L4_TIMMODE_COUNTUP,
+ .lock = CONFIG_STM32L4_TIM17_LOCK,
+ .t_dts = CONFIG_STM32L4_TIM17_TDTS,
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = CONFIG_STM32L4_TIM17_DEADTIME,
+#endif
+#if defined(HAVE_TRGO)
+ .trgo = 0, /* TRGO not supported for TIM17 */
+#endif
#ifdef CONFIG_PWM_PULSECOUNT
.irq = STM32L4_IRQ_TIM17,
#endif
.base = STM32L4_TIM17_BASE,
.pclk = STM32L4_APB2_TIM17_CLKIN,
};
-#endif
+#endif /* CONFIG_STM32L4_TIM17_PWM */
#ifdef CONFIG_STM32L4_LPTIM1_PWM
-static struct stm32l4_pwmtimer_s g_pwmlp1dev =
+
+static struct stm32l4_pwmchan_s g_pwmlp1channels[] =
{
- .ops = &g_pwmops,
- .timid = 1,
- .channels =
- {
+ /* LPTIM1 has 1 channel */
+
#ifdef CONFIG_STM32L4_LPTIM1_CHANNEL1
+ {
+ .channel = 1,
+ .mode = 0,
+#ifdef CONFIG_STM32L4_LPTIM1_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = CONFIG_STM32L4_LPTIM1_CH1POL,
+ .idle = 0, /* No idle */
.pincfg = PWM_LPTIM1_CH1CFG,
- .npincfg = PWM_LPTIM1_CH1NCFG,
- },
+ }
#endif
+ /* No complementary outputs */
},
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwmlp1dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 1,
+ .chan_num = PWM_LPTIM1_NCHANNELS,
+ .channels = g_pwmlp1channels,
.timtype = TIMTYPE_LPTIM1,
.mode = STM32L4_TIMMODE_COUNTUP,
+ .lock = 0, /* No lock */
+ .t_dts = 0, /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = 0, /* No deadtime */
+#endif
+#if defined(HAVE_TRGO)
+ .trgo = 0, /* TRGO not supported for LPTIM1 */
+#endif
+#ifdef CONFIG_PWM_PULSECOUNT
+ .irq = STM32L4_IRQ_LPTIM1,
+#endif
.base = STM32L4_LPTIM1_BASE,
#if defined(CONFIG_STM32L4_LPTIM1_CLK_APB1)
.pclk = STM32L4_PCLK1_FREQUENCY,
@@ -651,25 +1359,54 @@ static struct stm32l4_pwmtimer_s g_pwmlp1dev =
.pclk = STM32L4_HSI_FREQUENCY,
#endif
};
-#endif
+#endif /* CONFIG_STM32L4_LPTIM1_PWM */
#ifdef CONFIG_STM32L4_LPTIM2_PWM
-static struct stm32l4_pwmtimer_s g_pwmlp2dev =
+
+static struct stm32l4_pwmchan_s g_pwmlp2channels[] =
{
- .ops = &g_pwmops,
- .timid = 2,
- .channels =
- {
+ /* LPTIM2 has 1 channel */
+
#ifdef CONFIG_STM32L4_LPTIM2_CHANNEL1
+ {
+ .channel = 1,
+ .mode = 0,
+#ifdef CONFIG_STM32L4_LPTIM2_CH1OUT
+ .out1 =
{
- .channel = 1,
+ .in_use = 1,
+ .pol = 0, /* REVISIT: Configure using CONFIG_STM32L4_LPTIM2_CH1POL, */
+ .idle = 0, /* No idle */
.pincfg = PWM_LPTIM2_CH1CFG,
- .npincfg = PWM_LPTIM2_CH1NCFG,
- },
+ }
#endif
+ /* No complementary outputs */
},
+#endif
+};
+
+static struct stm32l4_pwmtimer_s g_pwmlp2dev =
+{
+ .ops = &g_pwmops,
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+ .llops = &g_llpwmops,
+#endif
+ .timid = 2,
+ .chan_num = PWM_LPTIM2_NCHANNELS,
+ .channels = g_pwmlp2channels,
.timtype = TIMTYPE_LPTIM2,
.mode = STM32L4_TIMMODE_COUNTUP,
+ .lock = 0, /* No lock */
+ .t_dts = 0, /* No t_dts */
+#ifdef HAVE_PWM_COMPLEMENTARY
+ .deadtime = 0, /* No deadtime */
+#endif
+#if defined(HAVE_TRGO)
+ .trgo = 0, /* TRGO not supported for LPTIM2 */
+#endif
+#ifdef CONFIG_PWM_PULSECOUNT
+ .irq = STM32L4_IRQ_LPTIM2,
+#endif
.base = STM32L4_LPTIM2_BASE,
#if defined(CONFIG_STM32L4_LPTIM2_CLK_APB1)
.pclk = STM32L4_PCLK1_FREQUENCY,
@@ -681,14 +1418,14 @@ static struct stm32l4_pwmtimer_s g_pwmlp2dev =
.pclk = STM32L4_HSI_FREQUENCY,
#endif
};
-#endif
+#endif /* CONFIG_STM32L4_LPTIM2_PWM */
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
- * Name: stm32l4pwm_getreg
+ * Name: pwm_getreg
*
* Description:
* Read the value of an PWM timer register.
@@ -702,13 +1439,13 @@ static struct stm32l4_pwmtimer_s g_pwmlp2dev =
*
****************************************************************************/
-static uint16_t stm32l4pwm_getreg(struct stm32l4_pwmtimer_s *priv, int offset)
+static uint16_t pwm_getreg(struct stm32l4_pwmtimer_s *priv, int offset)
{
return getreg16(priv->base + offset);
}
/****************************************************************************
- * Name: stm32l4pwm_putreg
+ * Name: pwm_putreg
*
* Description:
* Read the value of an PWM timer register.
@@ -722,7 +1459,7 @@ static uint16_t stm32l4pwm_getreg(struct stm32l4_pwmtimer_s *priv, int offset)
*
****************************************************************************/
-static void stm32l4pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
+static void pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
uint16_t value)
{
if (priv->timtype == TIMTYPE_GENERAL32 &&
@@ -748,7 +1485,50 @@ static void stm32l4pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
}
/****************************************************************************
- * Name: stm32l4pwm_dumpregs
+ * Name: pwm_modifyreg
+ *
+ * Description:
+ * Modify PWM register (32-bit or 16-bit)
+ *
+ * Input Parameters:
+ * priv - A reference to the PWM block status
+ * offset - The offset to the register to read
+ * clrbits - The bits to clear
+ * setbits - The bits to set
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void pwm_modifyreg(struct stm32l4_pwmtimer_s *priv, uint32_t offset,
+ uint32_t clearbits, uint32_t setbits)
+{
+ if (priv->timtype == TIMTYPE_GENERAL32 &&
+ (offset == STM32L4_GTIM_CNT_OFFSET ||
+ offset == STM32L4_GTIM_ARR_OFFSET ||
+ offset == STM32L4_GTIM_CCR1_OFFSET ||
+ offset == STM32L4_GTIM_CCR2_OFFSET ||
+ offset == STM32L4_GTIM_CCR3_OFFSET ||
+ offset == STM32L4_GTIM_CCR4_OFFSET))
+ {
+ /* a 32 bit access is required for a 32 bit register:
+ * if only a 16 bit write would be performed, then the
+ * upper 16 bits of the 32 bit register will be a copy of
+ * the lower 16 bits.
+ */
+
+ modifyreg32(priv->base + offset, clearbits, setbits);
+ }
+ else
+ {
+ modifyreg16(priv->base + offset, (uint16_t)clearbits,
+ (uint16_t)setbits);
+ }
+}
+
+/****************************************************************************
+ * Name: pwm_dumpregs
*
* Description:
* Dump all timer registers.
@@ -762,136 +1542,373 @@ static void stm32l4pwm_putreg(struct stm32l4_pwmtimer_s *priv, int offset,
****************************************************************************/
#ifdef CONFIG_DEBUG_PWM_INFO
-static void stm32l4pwm_dumpregs(struct stm32l4_pwmtimer_s *priv,
- FAR const char *msg)
+static void pwm_dumpregs(FAR struct pwm_lowerhalf_s *dev,
+ FAR const char *msg)
{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
if (priv->timtype == TIMTYPE_LOWPOWER)
{
pwminfo("%s:\n", msg);
pwminfo(" CFGR: %04x CR: %04x CMP: %04x ARR: %04x\n",
- stm32l4pwm_getreg(priv, STM32L4_LPTIM_CFGR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_LPTIM_CMP_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_LPTIM_ARR_OFFSET));
+ pwm_getreg(priv, STM32L4_LPTIM_CFGR_OFFSET),
+ pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET),
+ pwm_getreg(priv, STM32L4_LPTIM_CMP_OFFSET),
+ pwm_getreg(priv, STM32L4_LPTIM_ARR_OFFSET));
pwminfo(" ISR: %04x CNT: %04x\n",
- stm32l4pwm_getreg(priv, STM32L4_LPTIM_ISR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_LPTIM_CNT_OFFSET));
+ pwm_getreg(priv, STM32L4_LPTIM_ISR_OFFSET),
+ pwm_getreg(priv, STM32L4_LPTIM_CNT_OFFSET));
}
else
{
pwminfo("%s:\n", msg);
pwminfo(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n",
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CR2_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_SMCR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_DIER_OFFSET));
+ pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_CR2_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_SMCR_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_DIER_OFFSET));
pwminfo(" SR: %04x EGR: %04x CCMR1: %04x CCMR2: %04x\n",
- stm32l4pwm_getreg(priv, STM32L4_GTIM_SR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_EGR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CCMR1_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CCMR2_OFFSET));
+ pwm_getreg(priv, STM32L4_GTIM_SR_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_EGR_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_CCMR1_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_CCMR2_OFFSET));
pwminfo(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n",
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CNT_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_PSC_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_ARR_OFFSET));
+ pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_CNT_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_PSC_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_ARR_OFFSET));
pwminfo(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n",
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CCR1_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CCR2_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CCR3_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_CCR4_OFFSET));
+ pwm_getreg(priv, STM32L4_GTIM_CCR1_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_CCR2_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_CCR3_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_CCR4_OFFSET));
#if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
if (priv->timtype == TIMTYPE_ADVANCED)
{
pwminfo(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n",
- stm32l4pwm_getreg(priv, STM32L4_ATIM_RCR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_ATIM_DCR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_ATIM_DMAR_OFFSET));
+ pwm_getreg(priv, STM32L4_ATIM_RCR_OFFSET),
+ pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET),
+ pwm_getreg(priv, STM32L4_ATIM_DCR_OFFSET),
+ pwm_getreg(priv, STM32L4_ATIM_DMAR_OFFSET));
}
else
#endif
{
pwminfo(" DCR: %04x DMAR: %04x\n",
- stm32l4pwm_getreg(priv, STM32L4_GTIM_DCR_OFFSET),
- stm32l4pwm_getreg(priv, STM32L4_GTIM_DMAR_OFFSET));
+ pwm_getreg(priv, STM32L4_GTIM_DCR_OFFSET),
+ pwm_getreg(priv, STM32L4_GTIM_DMAR_OFFSET));
}
}
}
#endif
/****************************************************************************
- * Name: stm32l4pwm_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
- *
+ * Name: pwm_ccr_update
****************************************************************************/
-static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
- FAR const struct pwm_info_s *info)
-{
-#ifdef CONFIG_PWM_MULTICHAN
- int i;
-#endif
+static int pwm_ccr_update(FAR struct pwm_lowerhalf_s *dev, uint8_t index,
+ uint32_t ccr)
- /* Calculated values */
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint32_t offset = 0;
- uint32_t prescaler;
- uint32_t timclk;
- uint32_t reload;
- uint32_t ccr;
+#ifdef HAVE_LPTIM
+ if (priv->timtype == TIMTYPE_LOWPOWER)
+ {
+ /* REVISIT: What about index? Is it necessary for LPTIM? */
- /* Register contents */
+ offset = STM32L4_LPTIM_CMP_OFFSET;
+ pwm_putreg(priv, offset, ccr);
- uint16_t cr1;
- uint16_t ccer;
- uint16_t cr2;
- uint32_t ccmr1;
- uint32_t ccmr2;
+ return OK;
+ }
+#endif
- /* New timer register bit settings */
+ /* Only ADV timers have CC5 and CC6 */
- uint16_t ccenable;
- uint16_t ccnenable;
- uint32_t ocmode1;
- uint32_t ocmode2;
+ if (priv->timtype != TIMTYPE_ADVANCED && (index == 5 || index == 6))
+ {
+ pwmerr("ERROR: No such CCR: %u\n", index);
+ return -EINVAL;
+ }
- DEBUGASSERT(priv != NULL && info != NULL);
+ /* REVISIT: start index from 0? */
-#if defined(CONFIG_PWM_MULTICHAN)
- pwminfo("TIM%u frequency: %u\n",
- priv->timid, info->frequency);
-#elif defined(CONFIG_PWM_PULSECOUNT)
- pwminfo("TIM%u channel: %u frequency: %u duty: %08x count: %u\n",
- priv->timid, priv->channels[0].channel, info->frequency,
- info->duty, info->count);
-#else
- pwminfo("TIM%u channel: %u frequency: %u duty: %08x\n",
- priv->timid, priv->channels[0].channel, info->frequency, info->duty);
-#endif
+ switch (index)
+ {
+ case STM32L4_PWM_CHAN1:
+ {
+ offset = STM32L4_GTIM_CCR1_OFFSET;
+ break;
+ }
- DEBUGASSERT(info->frequency > 0);
-#ifndef CONFIG_PWM_MULTICHAN
- DEBUGASSERT(info->duty >= 0 && info->duty < uitoub16(100));
-#endif
+ case STM32L4_PWM_CHAN2:
+ {
+ offset = STM32L4_GTIM_CCR2_OFFSET;
+ break;
+ }
- /* Disable all interrupts and DMA requests, clear all pending status */
+ case STM32L4_PWM_CHAN3:
+ {
+ offset = STM32L4_GTIM_CCR3_OFFSET;
+ break;
+ }
-#ifdef CONFIG_PWM_PULSECOUNT
- stm32l4pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0);
- stm32l4pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
+ case STM32L4_PWM_CHAN4:
+ {
+ offset = STM32L4_GTIM_CCR4_OFFSET;
+ break;
+ }
+
+ case STM32L4_PWM_CHAN5:
+ {
+ offset = STM32L4_ATIM_CCR5_OFFSET;
+ break;
+ }
+
+ case STM32L4_PWM_CHAN6:
+ {
+ offset = STM32L4_ATIM_CCR6_OFFSET;
+ break;
+ }
+
+ default:
+ {
+ pwmerr("ERROR: No such CCR: %u\n", index);
+ return -EINVAL;
+ }
+ }
+
+ /* Update CCR register */
+
+ pwm_putreg(priv, offset, ccr);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_ccr_get
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+static uint32_t pwm_ccr_get(FAR struct pwm_lowerhalf_s *dev, uint8_t index)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint32_t offset = 0;
+
+ switch (index)
+ {
+ case STM32L4_PWM_CHAN1:
+ {
+ offset = STM32L4_GTIM_CCR1_OFFSET;
+ break;
+ }
+
+ case STM32L4_PWM_CHAN2:
+ {
+ offset = STM32L4_GTIM_CCR2_OFFSET;
+ break;
+ }
+
+ case STM32L4_PWM_CHAN3:
+ {
+ offset = STM32L4_GTIM_CCR3_OFFSET;
+ break;
+ }
+
+ case STM32L4_PWM_CHAN4:
+ {
+ offset = STM32L4_GTIM_CCR4_OFFSET;
+ break;
+ }
+
+ case STM32L4_PWM_CHAN5:
+ {
+ offset = STM32L4_ATIM_CCR5_OFFSET;
+ break;
+ }
+
+ case STM32L4_PWM_CHAN6:
+ {
+ offset = STM32L4_ATIM_CCR6_OFFSET;
+ break;
+ }
+
+ default:
+ {
+ pwmerr("ERROR: No such CCR: %u\n", index);
+ return -EINVAL;
+ }
+ }
+
+ /* Return CCR register */
+
+ return pwm_getreg(priv, offset);
+}
+#endif /* CONFIG_STM32L4_PWM_LL_OPS */
+
+/****************************************************************************
+ * Name: pwm_arr_update
+ ****************************************************************************/
+
+static int pwm_arr_update(FAR struct pwm_lowerhalf_s *dev, uint32_t arr)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+ /* Update ARR register */
+
+ if (priv->timtype == TIMTYPE_LOWPOWER)
+ {
+ pwm_putreg(priv, STM32L4_LPTIM_ARR_OFFSET, arr);
+ }
+ else
+ {
+ pwm_putreg(priv, STM32L4_GTIM_ARR_OFFSET, arr);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_arr_get
+ ****************************************************************************/
+
+static uint32_t pwm_arr_get(FAR struct pwm_lowerhalf_s *dev)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+ if (priv->timtype == TIMTYPE_LOWPOWER)
+ {
+ return pwm_getreg(priv, STM32L4_LPTIM_ARR_OFFSET);
+ }
+ else
+ {
+ return pwm_getreg(priv, STM32L4_GTIM_ARR_OFFSET);
+ }
+}
+
+/****************************************************************************
+ * Name: pwm_duty_update
+ *
+ * Description:
+ * Try to change only channel duty
+ *
+ * Input Parameters:
+ * dev - A reference to the lower half PWM driver state structure
+ * channel - Channel to by updated
+ * duty - New duty
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_duty_update(FAR struct pwm_lowerhalf_s *dev, uint8_t channel,
+ ub16_t duty)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint32_t reload = 0;
+ uint32_t ccr = 0;
+
+ /* We don't want compilation warnings if no DEBUGASSERT */
+
+ UNUSED(priv);
+
+ DEBUGASSERT(priv != NULL);
+
+ pwminfo("TIM%u channel: %u duty: %08x\n",
+ priv->timid, channel, duty);
+
+#ifndef CONFIG_STM32L4_PWM_MULTICHAN
+ DEBUGASSERT(channel == priv->channels[0].channel);
+ DEBUGASSERT(duty >= 0 && duty < uitoub16(100));
+#endif
+
+ /* Get the reload values */
+
+ reload = pwm_arr_get(dev);
+
+ /* Duty cycle:
+ *
+ * duty cycle = ccr / reload (fractional value)
+ */
+
+ ccr = b16toi(duty * reload + b16HALF);
+
+ pwminfo("ccr: %u\n", ccr);
+
+ /* Write coresponding CCR register */
+
+ pwm_ccr_update(dev, channel, ccr);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_timer_enable
+ ****************************************************************************/
+
+static int pwm_timer_enable(FAR struct pwm_lowerhalf_s *dev, bool state)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+#ifdef HAVE_LPTIM
+ if (priv->timtype != TIMTYPE_LOWPOWER)
+ {
+#endif
+ if (state == true)
+ {
+ /* Enable timer counter */
+
+ pwm_modifyreg(priv, STM32L4_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN);
+ }
+ else
+ {
+ /* Disable timer counter */
+
+ pwm_modifyreg(priv, STM32L4_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0);
+ }
+#ifdef HAVE_LPTIM
+ }
+ else
+ {
+ if (state == true)
+ {
+ /* Enable timer counter */
+
+ pwm_modifyreg(priv, STM32L4_LPTIM_CR_OFFSET, 0, LPTIM_CR_ENABLE);
+ }
+ else
+ {
+ /* Disable timer counter */
+
+ pwm_modifyreg(priv, STM32L4_LPTIM_CR_OFFSET, LPTIM_CR_ENABLE, 0);
+ }
+ }
#endif
- /* Calculate optimal values for the timer prescaler and for the timer reload
- * register. If 'frequency' is the desired frequency, then
+ return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_frequency_update
+ *
+ * Description:
+ * Update a PWM timer frequency
+ *
+ ****************************************************************************/
+
+static int pwm_frequency_update(FAR struct pwm_lowerhalf_s *dev,
+ uint32_t frequency)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint32_t reload = 0;
+ uint32_t timclk = 0;
+ uint32_t prescaler = 0;
+
+ /* Calculate optimal values for the timer prescaler and for the timer
+ * reload register. If 'frequency' is the desired frequency, then
*
* reload = timclk / frequency
* timclk = pclk / presc
@@ -923,7 +1940,18 @@ static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
* = 60,000
*/
- prescaler = (priv->pclk / info->frequency + 65534) / 65535;
+ /* If timer mode is center aligned the frequency of PWM is the half of
+ * intended so multiply by x2
+ */
+
+ if ((priv->mode == STM32L4_TIMMODE_CENTER1) ||
+ (priv->mode == STM32L4_TIMMODE_CENTER2) ||
+ (priv->mode == STM32L4_TIMMODE_CENTER3))
+ {
+ frequency = frequency * 2;
+ }
+
+ prescaler = (priv->pclk / frequency + 65534) / 65535;
if (prescaler < 1)
{
prescaler = 1;
@@ -935,7 +1963,7 @@ static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
timclk = priv->pclk / prescaler;
- reload = timclk / info->frequency;
+ reload = timclk / frequency;
if (reload < 2)
{
reload = 1;
@@ -950,774 +1978,1387 @@ static int stm32l4pwm_timer(FAR struct stm32l4_pwmtimer_s *priv,
}
pwminfo("TIM%u PCLK: %u frequency: %u TIMCLK: %u prescaler: %u reload: %u\n",
- priv->timid, priv->pclk, info->frequency, timclk, prescaler, reload);
-
- /* Set up the timer CR1 register:
- *
- * 1,8 CKD[1:0] ARPE CMS[1:0] DIR OPM URS UDIS CEN
- * 2-5 CKD[1:0] ARPE CMS DIR OPM URS UDIS CEN
- * 6-7 ARPE OPM URS UDIS CEN
- * 9-14 CKD[1:0] ARPE URS UDIS CEN
- * 15-17 CKD[1:0] ARPE OPM URS UDIS CEN
- */
+ priv->timid, priv->pclk, frequency, timclk, prescaler, reload);
- cr1 = stm32l4pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET);
+ /* Set the reload and prescaler values */
- /* Disable the timer until we get it configured */
+ pwm_arr_update(dev, reload);
+ pwm_putreg(priv, STM32L4_GTIM_PSC_OFFSET, (uint16_t)(prescaler - 1));
- cr1 &= ~GTIM_CR1_CEN;
+ return OK;
+}
- /* Set the counter mode for the advanced timers (1,8) and most general
- * purpose timers (all 2-5, but not 9-17), i.e., all but TIMTYPE_COUNTUP16
- * and TIMTYPE_BASIC
- */
+/****************************************************************************
+ * Name: pwm_lp_frequency_update
+ *
+ * Description:
+ * Update a PWM timer frequency
+ *
+ ****************************************************************************/
-#if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM2_PWM) || \
- defined(CONFIG_STM32L4_TIM3_PWM) || defined(CONFIG_STM32L4_TIM4_PWM) || \
- defined(CONFIG_STM32L4_TIM5_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
+#ifdef HAVE_LPTIM
+static int pwm_lp_frequency_update(FAR struct pwm_lowerhalf_s *dev,
+ uint32_t frequency)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
- if (priv->timtype != TIMTYPE_BASIC && priv->timtype != TIMTYPE_COUNTUP16)
- {
- /* Select the Counter Mode:
- *
- * GTIM_CR1_EDGE: The counter counts up or down depending on the
- * direction bit (DIR).
- * GTIM_CR1_CENTER1, GTIM_CR1_CENTER2, GTIM_CR1_CENTER3: The counter
- * counts up then down.
- * GTIM_CR1_DIR: 0: count up, 1: count down
- */
+ /* Calculated values */
- cr1 &= ~(GTIM_CR1_DIR | GTIM_CR1_CMS_MASK);
+ uint8_t prescaler;
+ uint32_t timclk;
+ uint32_t reload;
- switch (priv->mode)
- {
- case STM32L4_TIMMODE_COUNTUP:
- cr1 |= GTIM_CR1_EDGE;
- break;
+ /* Register contents */
- case STM32L4_TIMMODE_COUNTDOWN:
- cr1 |= GTIM_CR1_EDGE | GTIM_CR1_DIR;
- break;
+ uint32_t cfgr;
- case STM32L4_TIMMODE_CENTER1:
- cr1 |= GTIM_CR1_CENTER1;
- break;
+ /* LPTIM only has 8 possible prescaler values, from /1 to /128
+ * We will attempt to find the lowest prescaler that results
+ * in a maximum reload value which can be represented in 16 bit.
+ * For certain desired frequencies it is possible that the clock
+ * is too high and other one needs to be selected.
+ */
- case STM32L4_TIMMODE_CENTER2:
- cr1 |= GTIM_CR1_CENTER2;
- break;
+ for (prescaler = 0; prescaler < 8; prescaler++)
+ {
+ timclk = priv->pclk / (1 << prescaler);
+ reload = timclk / frequency;
- case STM32L4_TIMMODE_CENTER3:
- cr1 |= GTIM_CR1_CENTER3;
- break;
+ if (reload <= 65535)
+ {
+ /* The reload counter is feasible, go with it */
- default:
- pwmerr("ERROR: No such timer mode: %u\n", (unsigned int)priv->mode);
- return -EINVAL;
+ break;
}
}
-#endif
- /* Set the clock division to zero for all (but the basic timers, but there
- * should be no basic timers in this context
- */
+ if (reload < 2)
+ {
+ reload = 1;
+ }
+ else if (reload > 65535)
+ {
+ reload = 65535;
+ }
- cr1 &= ~GTIM_CR1_CKD_MASK;
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
+ /* TODO: if the desired frequency is not possible this should give an error
+ * and not simply return the feasible frequency without complaining.
+ */
- /* Set the reload and prescaler values */
+ pwminfo("LPTIM%u PCLK: %u frequency: %u TIMCLK: %u prescaler: %u reload: %u\n",
+ priv->timid, priv->pclk, frequency, timclk, prescaler, reload);
- stm32l4pwm_putreg(priv, STM32L4_GTIM_ARR_OFFSET, (uint16_t)reload);
- stm32l4pwm_putreg(priv, STM32L4_GTIM_PSC_OFFSET, (uint16_t)(prescaler - 1));
+ /* Set the reload register value */
- /* Set the advanced timer's repetition counter */
+ pwm_arr_update(dev, reload);
-#if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
- if (priv->timtype == TIMTYPE_ADVANCED)
+ /* Set the prescaler value */
+
+ cfgr = pwm_getreg(priv, STM32L4_LPTIM_CFGR_OFFSET);
+
+ cfgr &= ~LPTIM_CFGR_PRESC_MASK;
+ cfgr |= (prescaler << LPTIM_CFGR_PRESC_SHIFT);
+
+ pwm_putreg(priv, STM32L4_LPTIM_CFGR_OFFSET, cfgr);
+
+ return OK;
+}
+#endif /* HAVE_LPTIM */
+
+/****************************************************************************
+ * Name: pwm_timer_configure
+ *
+ * Description:
+ * Initial configuration for PWM timer
+ *
+ ****************************************************************************/
+
+static int pwm_timer_configure(FAR struct stm32l4_pwmtimer_s *priv)
+{
+ uint16_t cr1 = 0;
+ int ret = OK;
+
+ /* Set up the timer CR1 register:
+ *
+ * 1,8 CKD[1:0] ARPE CMS[1:0] DIR OPM URS UDIS CEN
+ * 2-5 CKD[1:0] ARPE CMS DIR OPM URS UDIS CEN
+ * 6-7 ARPE OPM URS UDIS CEN
+ * 9-14 CKD[1:0] ARPE URS UDIS CEN
+ * 15-17 CKD[1:0] ARPE OPM URS UDIS CEN
+ */
+
+ cr1 = pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET);
+
+ /* Set the counter mode for the advanced timers (1,8) and most general
+ * purpose timers (all 2-5, but not 9-17), i.e., all but TIMTYPE_COUNTUP16
+ * and TIMTYPE_BASIC
+ */
+
+ if (priv->timtype != TIMTYPE_BASIC && priv->timtype != TIMTYPE_COUNTUP16)
{
- /* If a non-zero repetition count has been selected, then set the
- * repitition counter to the count-1 (stm32l4pwm_start() has already
- * assured us that the count value is within range).
+ /* Select the Counter Mode:
+ *
+ * GTIM_CR1_EDGE: The counter counts up or down depending on the
+ * direction bit (DIR).
+ * GTIM_CR1_CENTER1, GTIM_CR1_CENTER2, GTIM_CR1_CENTER3: The counter
+ * counts up then down.
+ * GTIM_CR1_DIR: 0: count up, 1: count down
*/
-#ifdef CONFIG_PWM_PULSECOUNT
- if (info->count > 0)
+ cr1 &= ~(GTIM_CR1_DIR | GTIM_CR1_CMS_MASK);
+
+ switch (priv->mode)
+ {
+ case STM32L4_TIMMODE_COUNTUP:
+ {
+ cr1 |= GTIM_CR1_EDGE;
+ break;
+ }
+
+ case STM32L4_TIMMODE_COUNTDOWN:
+ {
+ cr1 |= GTIM_CR1_EDGE | GTIM_CR1_DIR;
+ break;
+ }
+
+ case STM32L4_TIMMODE_CENTER1:
+ {
+ cr1 |= GTIM_CR1_CENTER1;
+ break;
+ }
+
+ case STM32L4_TIMMODE_CENTER2:
+ {
+ cr1 |= GTIM_CR1_CENTER2;
+ break;
+ }
+
+ case STM32L4_TIMMODE_CENTER3:
+ {
+ cr1 |= GTIM_CR1_CENTER3;
+ break;
+ }
+
+ default:
+ {
+ pwmerr("ERROR: No such timer mode: %u\n",
+ (unsigned int)priv->mode);
+ ret = -EINVAL;
+ goto errout;
+ }
+ }
+ }
+
+ /* Enable ARR Preload
+ * TODO: this should be configurable
+ */
+
+ cr1 |= GTIM_CR1_ARPE;
+
+ /* Write CR1 */
+
+ pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
+
+errout:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: pwm_mode_configure
+ *
+ * Description:
+ * Configure a PWM mode for given channel
+ *
+ ****************************************************************************/
+
+static int pwm_mode_configure(FAR struct pwm_lowerhalf_s *dev,
+ uint8_t channel, uint32_t mode)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint32_t chanmode = 0;
+ uint32_t ocmode = 0;
+ uint32_t ccmr = 0;
+ uint32_t offset = 0;
+ int ret = OK;
+ bool ocmbit = false;
+
+ /* Only advanced timers have channels 5-6 */
+
+ if (channel > 4 && priv->timtype != TIMTYPE_ADVANCED)
+ {
+ pwmerr("ERROR: No such channel: %u\n", channel);
+ ret = -EINVAL;
+ goto errout;
+ }
+
+ /* Get channel mode
+ * TODO: configurable preload for CCxR
+ */
+
+ switch (mode)
+ {
+ case STM32L4_CHANMODE_FRZN:
+ {
+ chanmode = GTIM_CCMR_MODE_FRZN;
+ break;
+ }
+
+ case STM32L4_CHANMODE_CHACT:
+ {
+ chanmode = GTIM_CCMR_MODE_CHACT;
+ break;
+ }
+
+ case STM32L4_CHANMODE_CHINACT:
+ {
+ chanmode = GTIM_CCMR_MODE_CHINACT;
+ break;
+ }
+
+ case STM32L4_CHANMODE_OCREFTOG:
+ {
+ chanmode = GTIM_CCMR_MODE_OCREFTOG;
+ break;
+ }
+
+ case STM32L4_CHANMODE_OCREFLO:
+ {
+ chanmode = GTIM_CCMR_MODE_OCREFLO;
+ break;
+ }
+
+ case STM32L4_CHANMODE_OCREFHI:
+ {
+ chanmode = GTIM_CCMR_MODE_OCREFHI;
+ break;
+ }
+
+ case STM32L4_CHANMODE_PWM1:
+ {
+ chanmode = ATIM_CCMR_MODE_PWM1;
+ break;
+ }
+
+ case STM32L4_CHANMODE_PWM2:
+ {
+ chanmode = ATIM_CCMR_MODE_PWM2;
+ break;
+ }
+
+ case STM32L4_CHANMODE_COMBINED1:
+ {
+ chanmode = ATIM_CCMR_MODE_COMBINED1;
+ ocmbit = true;
+ break;
+ }
+
+ case STM32L4_CHANMODE_COMBINED2:
+ {
+ chanmode = ATIM_CCMR_MODE_COMBINED2;
+ ocmbit = true;
+ break;
+ }
+
+ case STM32L4_CHANMODE_ASYMMETRIC1:
+ {
+ chanmode = ATIM_CCMR_MODE_ASYMMETRIC1;
+ ocmbit = true;
+ break;
+ }
+
+ case STM32L4_CHANMODE_ASYMMETRIC2:
+ {
+ chanmode = ATIM_CCMR_MODE_ASYMMETRIC2;
+ ocmbit = true;
+ break;
+ }
+
+ default:
+ {
+ pwmerr("ERROR: No such mode: %u\n", (unsigned int)mode);
+ ret = -EINVAL;
+ goto errout;
+ }
+ }
+
+ /* PWM mode configuration */
+
+ switch (channel)
+ {
+ /* Get CCMR offset */
+
+ case STM32L4_PWM_CHAN1:
+ case STM32L4_PWM_CHAN2:
+ {
+ offset = STM32L4_GTIM_CCMR1_OFFSET;
+ break;
+ }
+
+ case STM32L4_PWM_CHAN3:
+ case STM32L4_PWM_CHAN4:
+ {
+ offset = STM32L4_GTIM_CCMR2_OFFSET;
+ break;
+ }
+
+ case STM32L4_PWM_CHAN5:
+ case STM32L4_PWM_CHAN6:
+ {
+ offset = STM32L4_ATIM_CCMR3_OFFSET;
+ break;
+ }
+
+ default:
+ {
+ pwmerr("ERROR: No such channel: %u\n", channel);
+ ret = -EINVAL;
+ goto errout;
+ }
+ }
+
+ /* Get current registers */
+
+ ccmr = pwm_getreg(priv, offset);
+
+ /* PWM mode configuration.
+ * NOTE: The CCMRx registers are identical if the channels are outputs.
+ */
+
+ switch (channel)
+ {
+ /* Configure channel 1/3/5 */
+
+ case STM32L4_PWM_CHAN1:
+ case STM32L4_PWM_CHAN3:
+ case STM32L4_PWM_CHAN5:
+ {
+ /* Reset current channel 1/3/5 mode configuration */
+
+ ccmr &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK |
+ ATIM_CCMR1_OC1PE);
+
+ /* Configure CC1/3/5 as output */
+
+ ocmode |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT);
+
+ /* Configure Compare 1/3/5 mode */
+
+ ocmode |= (chanmode << ATIM_CCMR1_OC1M_SHIFT);
+
+ /* Enable CCR1/3/5 preload */
+
+ ocmode |= ATIM_CCMR1_OC1PE;
+
+ /* Reset current OC bit */
+
+ ccmr &= ~(ATIM_CCMR1_OC1M);
+
+ /* Set an additional OC1/3/5M bit */
+
+ if (ocmbit)
+ {
+ ocmode |= ATIM_CCMR1_OC1M;
+ }
+ break;
+ }
+
+ /* Configure channel 2/4/6 */
+
+ case STM32L4_PWM_CHAN2:
+ case STM32L4_PWM_CHAN4:
+ case STM32L4_PWM_CHAN6:
+ {
+ /* Reset current channel 2/4/6 mode configuration */
+
+ ccmr &= ~(ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK |
+ ATIM_CCMR1_OC2PE);
+
+ /* Configure CC2/4/6 as output */
+
+ ocmode |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT);
+
+ /* Configure Compare 2/4/6 mode */
+
+ ocmode |= (chanmode << ATIM_CCMR1_OC2M_SHIFT);
+
+ /* Enable CCR2/4/6 preload */
+
+ ocmode |= ATIM_CCMR1_OC2PE;
+
+ /* Reset current OC bit */
+
+ ccmr &= ~(ATIM_CCMR1_OC2M);
+
+ /* Set an additioneal OC2/4/6M bit */
+
+ if (ocmbit)
+ {
+ ocmode |= ATIM_CCMR1_OC2M;
+ }
+ break;
+ }
+ }
+
+ /* Set the selected output compare mode */
+
+ ccmr |= ocmode;
+
+ /* Write CCMRx registers */
+
+ pwm_putreg(priv, offset, ccmr);
+
+errout:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: pwm_output_configure
+ *
+ * Description:
+ * Configure PWM output for given channel
+ *
+ ****************************************************************************/
+
+static int pwm_output_configure(FAR struct stm32l4_pwmtimer_s *priv,
+ uint8_t channel)
+{
+ uint32_t cr2 = 0;
+ uint32_t ccer = 0;
+
+ /* Get current registers state */
+
+ cr2 = pwm_getreg(priv, STM32L4_GTIM_CR2_OFFSET);
+ ccer = pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET);
+
+ /* | OISx/OISxN | IDLE | for ADVANCED and COUNTUP16 | CR2 register
+ * | CCxP/CCxNP | POL | all PWM timers | CCER register
+ */
+
+ /* Configure output polarity (all PWM timers) */
+
+ if (priv->channels[channel - 1].out1.pol == STM32L4_POL_NEG)
+ {
+ ccer |= (GTIM_CCER_CC1P << ((channel - 1) * 4));
+ }
+ else
+ {
+ ccer &= ~(GTIM_CCER_CC1P << ((channel - 1) * 4));
+ }
+
+#ifdef HAVE_ADVTIM
+ if (priv->timtype == TIMTYPE_ADVANCED ||
+ priv->timtype == TIMTYPE_COUNTUP16_N)
+ {
+ /* Configure output IDLE State */
+
+ if (priv->channels[channel - 1].out1.idle == STM32L4_IDLE_ACTIVE)
+ {
+ cr2 |= (ATIM_CR2_OIS1 << ((channel - 1) * 2));
+ }
+ else
+ {
+ cr2 &= ~(ATIM_CR2_OIS1 << ((channel - 1) * 2));
+ }
+
+#ifdef HAVE_PWM_COMPLEMENTARY
+ /* Configure complementary output IDLE state */
+
+ if (priv->channels[channel - 1].out2.idle == STM32L4_IDLE_ACTIVE)
+ {
+ cr2 |= (ATIM_CR2_OIS1N << ((channel - 1) * 2));
+ }
+ else
{
- /* Save the remaining count and the number of counts that will have
- * elapsed on the first interrupt.
- */
+ cr2 &= ~(ATIM_CR2_OIS1N << ((channel - 1)* 2));
+ }
+
+ /* Configure complementary output polarity */
+
+ if (priv->channels[channel - 1].out2.pol == STM32L4_POL_NEG)
+ {
+ ccer |= (ATIM_CCER_CC1NP << ((channel - 1) * 4));
+ }
+ else
+ {
+ ccer &= ~(ATIM_CCER_CC1NP << ((channel - 1) * 4));
+ }
+#endif /* HAVE_PWM_COMPLEMENTARY */
+
+ /* TODO: OIS5 and OIS6 */
+
+ cr2 &= ~(ATIM_CR2_OIS5 | ATIM_CR2_OIS6);
+
+ /* TODO: CC5P and CC6P */
+
+ ccer &= ~(ATIM_CCER_CC5P | ATIM_CCER_CC6P);
+ }
+#ifdef HAVE_GTIM_CCXNP
+ else
+#endif /* HAVE_GTIM_CCXNP */
+#endif /* HAVE_ADVTIM */
+#ifdef HAVE_GTIM_CCXNP
+ {
+ /* CCxNP must be cleared if not ADVANCED timer.
+ *
+ * REVISIT: not all families have CCxNP bits for GTIM,
+ * which causes an ugly condition above
+ */
+
+ ccer &= ~(GTIM_CCER_CC1NP << ((channel - 1) * 4));
+ }
+#endif /* HAVE_GTIM_CCXNP */
+
+ /* Write registers */
+
+ pwm_modifyreg(priv, STM32L4_GTIM_CR2_OFFSET, 0, cr2);
+ pwm_modifyreg(priv, STM32L4_GTIM_CCER_OFFSET, 0, ccer);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_outputs_enable
+ *
+ * Description:
+ * Enable/disable given timer PWM outputs.
+ *
+ * NOTE: This is bulk operation - we can enable/disable many outputs
+ * at one time
+ *
+ * Input Parameters:
+ * dev - A reference to the lower half PWM driver state structure
+ * outputs - outputs to set (look at enum stm32l4_chan_e in stm32l4_pwm.h)
+ * state - Enable/disable operation
+ *
+ ****************************************************************************/
+
+static int pwm_outputs_enable(FAR struct pwm_lowerhalf_s *dev,
+ uint16_t outputs, bool state)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint32_t ccer = 0;
+ uint32_t regval = 0;
+
+ /* Get curren register state */
- /* If the first interrupt occurs at the end end of the first
- * repetition count, then the count will be the same as the RCR
- * value.
- */
+ ccer = pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET);
- priv->prev = stm32l4pwm_pulsecount(info->count);
- stm32l4pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->prev - 1);
+ /* Get outputs configuration */
- /* Generate an update event to reload the prescaler. This should
- * preload the RCR into active repetition counter.
- */
+ regval |= ((outputs & STM32L4_PWM_OUT1) ? ATIM_CCER_CC1E : 0);
+ regval |= ((outputs & STM32L4_PWM_OUT1N) ? ATIM_CCER_CC1NE : 0);
+ regval |= ((outputs & STM32L4_PWM_OUT2) ? ATIM_CCER_CC2E : 0);
+ regval |= ((outputs & STM32L4_PWM_OUT2N) ? ATIM_CCER_CC2NE : 0);
+ regval |= ((outputs & STM32L4_PWM_OUT3) ? ATIM_CCER_CC3E : 0);
+ regval |= ((outputs & STM32L4_PWM_OUT3N) ? ATIM_CCER_CC3NE : 0);
+ regval |= ((outputs & STM32L4_PWM_OUT4) ? ATIM_CCER_CC4E : 0);
- stm32l4pwm_putreg(priv, STM32L4_GTIM_EGR_OFFSET, ATIM_EGR_UG);
+ /* NOTE: CC4N does not exist, but some docs show configuration bits for it */
- /* Now set the value of the RCR that will be loaded on the next
- * update event.
- */
+ regval |= ((outputs & STM32L4_PWM_OUT5) ? ATIM_CCER_CC5E : 0);
+ regval |= ((outputs & STM32L4_PWM_OUT6) ? ATIM_CCER_CC6E : 0);
- priv->count = info->count;
- priv->curr = stm32l4pwm_pulsecount(info->count - priv->prev);
- stm32l4pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->curr - 1);
+ if (state == true)
+ {
+ /* Enable outpus - set bits */
+
+ ccer |= regval;
+ }
+ else
+ {
+ /* Disable outputs - reset bits */
+
+ ccer &= ~regval;
+ }
+
+ /* Write register */
+
+ pwm_putreg(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
+
+ return OK;
+}
+
+#if defined(HAVE_PWM_COMPLEMENTARY) && defined(CONFIG_STM32L4_PWM_LL_OPS)
+
+/****************************************************************************
+ * Name: pwm_deadtime_update
+ ****************************************************************************/
+
+static int pwm_deadtime_update(FAR struct pwm_lowerhalf_s *dev, uint8_t dt)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint32_t bdtr = 0;
+ int ret = OK;
+
+ /* Check if locked */
+
+ if (priv->lock > 0)
+ {
+ ret = -EACCES;
+ goto errout;
+ }
+
+ /* Get current register state */
+
+ bdtr = pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET);
+
+ /* TODO: check if BDTR not locked */
+
+ /* Update deadtime */
+
+ bdtr &= ~(ATIM_BDTR_DTG_MASK);
+ bdtr |= (dt << ATIM_BDTR_DTG_SHIFT);
+
+ /* Write BDTR register */
+
+ pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, bdtr);
+
+errout:
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: pwm_soft_update
+ *
+ * Description:
+ * Generate an software update event
+ *
+ ****************************************************************************/
+
+static int pwm_soft_update(FAR struct pwm_lowerhalf_s *dev)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+ pwm_putreg(priv, STM32L4_GTIM_EGR_OFFSET, ATIM_EGR_UG);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_soft_break
+ *
+ * Description:
+ * Generate an software break event
+ *
+ * Outputs are enabled if state is false.
+ * Outputs are disabled if state is true.
+ *
+ * NOTE: only timers with complementary outputs have BDTR register and
+ * support software break.
+ *
+ ****************************************************************************/
+
+static int pwm_soft_break(FAR struct pwm_lowerhalf_s *dev, bool state)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+
+ if (state == true)
+ {
+ /* Reset MOE bit */
+
+ pwm_modifyreg(priv, STM32L4_ATIM_BDTR_OFFSET, ATIM_BDTR_MOE, 0);
+ }
+ else
+ {
+ /* Set MOE bit */
+
+ pwm_modifyreg(priv, STM32L4_ATIM_BDTR_OFFSET, 0, ATIM_BDTR_MOE);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_outputs_from_channels
+ *
+ * Description:
+ * Get enabled outputs configuration from the PWM timer state
+ *
+ ****************************************************************************/
+
+static uint16_t pwm_outputs_from_channels(FAR struct stm32l4_pwmtimer_s *priv)
+{
+ uint16_t outputs = 0;
+ uint8_t channel = 0;
+ uint8_t i = 0;
+
+ for (i = 0; i < priv->chan_num; i += 1)
+ {
+ /* Get channel */
+
+ channel = priv->channels[i].channel;
+
+ /* Set outputs if channel configured */
+
+ if (channel != 0)
+ {
+ /* Enable output if confiugred */
+
+ if (priv->channels[i].out1.in_use == 1)
+ {
+ outputs |= (STM32L4_PWM_OUT1 << ((channel - 1) * 2));
+ }
+
+#ifdef HAVE_PWM_COMPLEMENTARY
+ /* Enable complementary output if configured */
+
+ if (priv->channels[i].out2.in_use == 1)
+ {
+ outputs |= (STM32L4_PWM_OUT1N << ((channel - 1) * 2));
+ }
+#endif
}
+ }
+
+ return outputs;
+}
+
+#ifdef HAVE_ADVTIM
+
+/****************************************************************************
+ * Name: pwm_break_dt_configure
+ *
+ * Description:
+ * Configure break and deadtime
+ *
+ * NOTE: we have to configure all BDTR registers at once due to possible
+ * lock configuration
+ *
+ ****************************************************************************/
- /* Otherwise, just clear the repetition counter */
+static int pwm_break_dt_configure(FAR struct stm32l4_pwmtimer_s *priv)
+{
+ uint32_t bdtr = 0;
- else
-#endif
- {
- /* Set the repetition counter to zero */
+ /* Set the clock division to zero for all (but the basic timers, but there
+ * should be no basic timers in this context
+ */
- stm32l4pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, 0);
+ pwm_modifyreg(priv, STM32L4_GTIM_CR1_OFFSET, GTIM_CR1_CKD_MASK,
+ priv->t_dts << GTIM_CR1_CKD_SHIFT);
- /* Generate an update event to reload the prescaler */
+#ifdef HAVE_PWM_COMPLEMENTARY
+ /* Initialize deadtime */
- stm32l4pwm_putreg(priv, STM32L4_GTIM_EGR_OFFSET, ATIM_EGR_UG);
- }
- }
- else
+ bdtr |= (priv->deadtime << ATIM_BDTR_DTG_SHIFT);
#endif
- {
- /* Generate an update event to reload the prescaler (all timers) */
- stm32l4pwm_putreg(priv, STM32L4_GTIM_EGR_OFFSET, ATIM_EGR_UG);
- }
-
- /* Handle channel specific setup */
+#ifdef HAVE_BREAK
+ /* Configure Break 1 */
- ccenable = 0;
- ccnenable = 0;
- ocmode1 = 0;
- ocmode2 = 0;
-
-#ifdef CONFIG_PWM_MULTICHAN
- for (i = 0; i < CONFIG_PWM_NCHANNELS; i++)
-#endif
+ if (priv->brk.en1 == 1)
{
- ub16_t duty;
- uint32_t chanmode;
- uint32_t compout; /* Complementary output config */
- bool ocmbit = false;
- uint8_t channel;
-#ifdef CONFIG_PWM_MULTICHAN
- int j;
-#endif
- enum stm32l4_chanmode_e mode;
-
-#ifdef CONFIG_PWM_MULTICHAN
- duty = info->channels[i].duty;
- channel = info->channels[i].channel;
+ /* Enable Break 1 */
- /* A value of zero means to skip this channel */
-
- if (channel == 0)
- {
- continue;
- }
+ bdtr |= ATIM_BDTR_BKE;
- /* Find the channel */
+ /* Set Break 1 polarity */
- for (j = 0; j < PWM_NCHANNELS; j++)
- {
- if (priv->channels[j].channel == channel)
- {
- mode = priv->channels[j].mode;
- compout = priv->channels[j].npincfg;
- break;
- }
- }
+ bdtr |= (priv->brk.pol1 == STM32L4_POL_NEG ? ATIM_BDTR_BKP : 0);
+ }
- if (j >= PWM_NCHANNELS)
- {
- pwmerr("ERROR: No such channel: %u\n", channel);
- return -EINVAL;
- }
-#else
- duty = info->duty;
- channel = priv->channels[0].channel;
- mode = priv->channels[0].mode;
- compout = priv->channels[0].npincfg;
-#endif
+ /* Configure Break 1 */
- /* Duty cycle:
- *
- * duty cycle = ccr / reload (fractional value)
- */
+ if (priv->brk.en2 == 1)
+ {
+ /* Enable Break 2 */
- ccr = b16toi(duty * reload + b16HALF);
+ bdtr |= ATIM_BDTR_BK2E;
- pwminfo("ccr: %u\n", ccr);
+ /* Set Break 2 polarity */
- switch (mode)
- {
- case STM32L4_CHANMODE_PWM1:
- chanmode = ATIM_CCMR_MODE_PWM1;
- break;
+ bdtr |= (priv->brk.pol2 == STM32L4_POL_NEG ? ATIM_BDTR_BK2P : 0);
- case STM32L4_CHANMODE_PWM2:
- chanmode = ATIM_CCMR_MODE_PWM2;
- break;
+ /* Configure BRK2 filter */
- case STM32L4_CHANMODE_COMBINED1:
- chanmode = ATIM_CCMR_MODE_COMBINED1;
- ocmbit = true;
- break;
+ bdtr |= (priv->brk.flt2 << ATIM_BDTR_BK2F_SHIFT);
+ }
- case STM32L4_CHANMODE_COMBINED2:
- chanmode = ATIM_CCMR_MODE_COMBINED2;
- ocmbit = true;
- break;
+#endif /* HAVE_BREAK */
- case STM32L4_CHANMODE_ASYMMETRIC1:
- chanmode = ATIM_CCMR_MODE_ASYMMETRIC1;
- ocmbit = true;
- break;
+ /* Clear the OSSI and OSSR bits in the BDTR register.
+ *
+ * REVISIT: this should be configurable
+ */
- case STM32L4_CHANMODE_ASYMMETRIC2:
- chanmode = ATIM_CCMR_MODE_ASYMMETRIC2;
- ocmbit = true;
- break;
+ bdtr &= ~(ATIM_BDTR_OSSI | ATIM_BDTR_OSSR);
- default:
- pwmerr("ERROR: No such mode: %u\n", (unsigned int)mode);
- return -EINVAL;
- }
+ /* Configure lock */
- switch (channel)
- {
- case 1: /* PWM Mode configuration: Channel 1 */
- {
- /* Select the CCER enable bit for this channel */
+ bdtr |= priv->lock << ATIM_BDTR_LOCK_SHIFT;
- ccenable |= ATIM_CCER_CC1E;
+ /* Write BDTR register at once */
- /* Conditionally enable the complementary output */
+ pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, bdtr);
- if (compout)
- {
- ccnenable |= ATIM_CCER_CC1NE;
- }
+ return OK;
+}
- /* Set the CCMR1 mode values (leave CCMR2 zero) */
+#endif /* HAVE_ADVTIM */
- ocmode1 |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT) |
- (chanmode << ATIM_CCMR1_OC1M_SHIFT) |
- ATIM_CCMR1_OC1PE;
+/****************************************************************************
+ * Name: pwm_configure
+ *
+ * Description:
+ * Configure PWM timer in normal mode (no PULSECOUNT)
+ *
+ ****************************************************************************/
- if (ocmbit)
- {
- ocmode1 |= ATIM_CCMR1_OC1M;
- }
+static int pwm_configure(FAR struct pwm_lowerhalf_s *dev)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint16_t outputs = 0;
+ uint8_t j = 0;
+ int ret = OK;
- /* Set the duty cycle by writing to the CCR register for this channel */
+ /* NOTE: leave timer counter disabled and all outputs disabled! */
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CCR1_OFFSET, (uint16_t)ccr);
- }
- break;
+ /* Disable the timer until we get it configured */
- case 2: /* PWM Mode configuration: Channel 2 */
- {
- /* Select the CCER enable bit for this channel */
+ pwm_timer_enable(dev, false);
- ccenable |= ATIM_CCER_CC2E;
+ /* Get configured outputs */
- /* Conditionally enable the complementary output */
+ outputs = pwm_outputs_from_channels(priv);
- if (compout)
- {
- ccnenable |= ATIM_CCER_CC2NE;
- }
+ /* Disable outputs */
- /* Set the CCMR1 mode values (leave CCMR2 zero) */
+ ret = pwm_outputs_enable(dev, outputs, false);
+ if (ret < 0)
+ {
+ pwmerr("ERROR on pwm_outputs_enable()\n");
+ goto errout;
+ }
- ocmode1 |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT) |
- (chanmode << ATIM_CCMR1_OC2M_SHIFT) |
- ATIM_CCMR1_OC2PE;
+ /* Initial timer configuration */
- if (ocmbit)
- {
- ocmode1 |= ATIM_CCMR1_OC2M;
- }
+ ret = pwm_timer_configure(priv);
+ if (ret < 0)
+ {
+ pwmerr("ERROR on pwm_timer_configure()\n");
+ goto errout;
+ }
- /* Set the duty cycle by writing to the CCR register for this channel */
+ /* Some special setup for advanced timers */
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CCR2_OFFSET, (uint16_t)ccr);
- }
- break;
+#ifdef HAVE_ADVTIM
+ if (priv->timtype == TIMTYPE_ADVANCED ||
+ priv->timtype == TIMTYPE_COUNTUP16_N)
+ {
+ /* Configure break and deadtime register */
- case 3: /* PWM Mode configuration: Channel 3 */
- {
- /* Select the CCER enable bit for this channel */
+ ret = pwm_break_dt_configure(priv);
+ if (ret < 0)
+ {
+ pwmerr("ERROR on pwm_break_dt_configure()\n");
+ goto errout;
+ }
- ccenable |= ATIM_CCER_CC3E;
+#ifdef HAVE_TRGO
+ /* Configure TRGO/TRGO2 */
- /* Conditionally enable the complementary output */
+ ret = pwm_sync_configure(priv, priv->trgo);
+ if (ret < 0)
+ {
+ pwmerr("ERROR on pwm_sync_configure()\n");
+ goto errout;
+ }
+#endif
+ }
+#endif
- if (compout)
- {
- ccnenable |= ATIM_CCER_CC3NE;
- }
+ /* Configure timer channels */
- /* Set the CCMR2 mode values (leave CCMR1 zero) */
+ for (j = 0; j < priv->chan_num; j++)
+ {
+ /* Skip channle if not in use */
- ocmode2 |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC3S_SHIFT) |
- (chanmode << ATIM_CCMR2_OC3M_SHIFT) |
- ATIM_CCMR2_OC3PE;
+ if (priv->channels[j].channel != 0)
+ {
+ /* Update PWM mode */
- if (ocmbit)
- {
- ocmode2 |= ATIM_CCMR2_OC3M;
- }
+ ret = pwm_mode_configure(dev, priv->channels[j].channel,
+ priv->channels[j].mode);
+ if (ret < 0)
+ {
+ pwmerr("ERROR on pwm_mode_configure()\n");
+ goto errout;
+ }
- /* Set the duty cycle by writing to the CCR register for this channel */
+ /* PWM outputs configuration */
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CCR3_OFFSET, (uint16_t)ccr);
+ ret = pwm_output_configure(priv, priv->channels[j].channel);
+ if (ret < 0)
+ {
+ pwmerr("ERROR on pwm_output_configure()\n");
+ goto errout;
}
- break;
+ }
+ }
- case 4: /* PWM Mode configuration: Channel 4 */
- {
- /* Select the CCER enable bit for this channel */
+ /* Disable software break at the end of the outputs configuration (enablei
+ * outputs).
+ *
+ * NOTE: Only timers with complementary outputs have BDTR register and
+ * support software break.
+ */
- ccenable |= ATIM_CCER_CC4E;
+ if (priv->timtype == TIMTYPE_ADVANCED ||
+ priv->timtype == TIMTYPE_COUNTUP16_N)
+ {
+ pwminfo("pwm_soft_break(dev, false)\n");
+ ret = pwm_soft_break(dev, false);
+ if (ret < 0)
+ {
+ pwmerr("ERROR on pwm_soft_break()\n");
+ goto errout;
+ }
+ }
- /* Set the CCMR2 mode values (leave CCMR1 zero) */
+errout:
+ return ret;
+}
- ocmode2 |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC4S_SHIFT) |
- (chanmode << ATIM_CCMR2_OC4M_SHIFT) |
- ATIM_CCMR2_OC4PE;
+#ifdef CONFIG_PWM_PULSECOUNT
- if (ocmbit)
- {
- ocmode2 |= ATIM_CCMR2_OC4M;
- }
+/****************************************************************************
+ * Name: pwm_pulsecount_timer
+ *
+ * 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
+ *
+ * TODO: PWM_PULSECOUNT should be configurable for each timer instance
+ * TODO: PULSECOUNT doesnt work with MULTICHAN at this moment
+ *
+ ****************************************************************************/
- /* Set the duty cycle by writing to the CCR register for this channel */
+static int pwm_pulsecount_timer(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ ub16_t duty = 0;
+ uint8_t channel = 0;
+ uint16_t outputs = 0;
+ int ret = OK;
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CCR4_OFFSET, (uint16_t)ccr);
- }
- break;
+ /* If we got here it means that timer instance support pulsecount mode! */
- default:
- pwmerr("ERROR: No such channel: %u\n", channel);
- return -EINVAL;
- }
- }
+ DEBUGASSERT(priv != NULL && info != NULL);
- /* Disable the Channel by resetting the CCxE Bit in the CCER register */
+ pwminfo("TIM%u channel: %u frequency: %u duty: %08x count: %u\n",
+ priv->timid, priv->channels[0].channel, info->frequency,
+ info->duty, info->count);
- ccer = stm32l4pwm_getreg(priv, STM32L4_GTIM_CCER_OFFSET);
- ccer &= ~ccenable;
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
+ DEBUGASSERT(info->frequency > 0);
- /* Fetch the CR2, CCMR1, and CCMR2 register (already have cr1 and ccer) */
+ /* Channel specific setup */
- cr2 = stm32l4pwm_getreg(priv, STM32L4_GTIM_CR2_OFFSET);
- ccmr1 = stm32l4pwm_getreg(priv, STM32L4_GTIM_CCMR1_OFFSET);
- ccmr2 = stm32l4pwm_getreg(priv, STM32L4_GTIM_CCMR2_OFFSET);
+ duty = info->duty;
+ channel = priv->channels[0].channel;
- /* Reset the Output Compare Mode Bits and set the select output compare mode */
+ /* Disable all interrupts and DMA requests, clear all pending status */
- ccmr1 &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK | ATIM_CCMR1_OC1PE |
- ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK | ATIM_CCMR1_OC2PE
- | ATIM_CCMR1_OC1M | ATIM_CCMR1_OC2M
- );
- ccmr2 &= ~(ATIM_CCMR2_CC3S_MASK | ATIM_CCMR2_OC3M_MASK | ATIM_CCMR2_OC3PE |
- ATIM_CCMR2_CC4S_MASK | ATIM_CCMR2_OC4M_MASK | ATIM_CCMR2_OC4PE
- | ATIM_CCMR2_OC3M | ATIM_CCMR2_OC4M
- );
- ccmr1 |= ocmode1;
- ccmr2 |= ocmode2;
+ pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0);
+ pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
- /* Reset the output polarity level of all channels (selects high polarity)*/
+ /* Set timer frequency */
- ccer &= ~(ATIM_CCER_CC1P | ATIM_CCER_CC2P | ATIM_CCER_CC3P | ATIM_CCER_CC4P);
+ ret = pwm_frequency_update(dev, info->frequency);
+ if (ret < 0)
+ {
+ goto errout;
+ }
- /* Enable the output state of the selected channels */
+ /* Update duty cycle */
- ccer &= ~(ATIM_CCER_CC1E | ATIM_CCER_CC2E | ATIM_CCER_CC3E | ATIM_CCER_CC4E);
- ccer |= ccenable;
+ ret = pwm_duty_update(dev, channel, duty);
+ if (ret < 0)
+ {
+ goto errout;
+ }
- /* Some special setup for advanced timers */
+ /* If a non-zero repetition count has been selected, then set the
+ * repitition counter to the count-1 (pwm_pulsecount_start() has already
+ * assured us that the count value is within range).
+ */
-#if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM)
- if (priv->timtype == TIMTYPE_ADVANCED)
+ if (info->count > 0)
{
- uint16_t bdtr;
-
- /* Reset output N polarity level, output N state, output compare state,
- * output compare N idle state.
+ /* Save the remaining count and the number of counts that will have
+ * elapsed on the first interrupt.
*/
- ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | ATIM_CCER_CC2NE |
- ATIM_CCER_CC2NP | ATIM_CCER_CC3NE | ATIM_CCER_CC3NP);
+ /* If the first interrupt occurs at the end end of the first
+ * repetition count, then the count will be the same as the RCR
+ * value.
+ */
- ccer |= ccnenable;
+ priv->prev = stm32l4pwm_pulsecount(info->count);
+ pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->prev - 1);
- /* Reset the output compare and output compare N IDLE State */
+ /* Generate an update event to reload the prescaler. This should
+ * preload the RCR into active repetition counter.
+ */
- cr2 &= ~(ATIM_CR2_OIS1 | ATIM_CR2_OIS1N | ATIM_CR2_OIS2 | ATIM_CR2_OIS2N |
- ATIM_CR2_OIS3 | ATIM_CR2_OIS3N | ATIM_CR2_OIS4);
+ pwm_soft_update(dev);
- /* Set the main output enable (MOE) bit and clear the OSSI and OSSR
- * bits in the BDTR register.
+ /* Now set the value of the RCR that will be loaded on the next
+ * update event.
*/
- bdtr = stm32l4pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET);
- bdtr &= ~(ATIM_BDTR_OSSI | ATIM_BDTR_OSSR);
- bdtr |= ATIM_BDTR_MOE;
- stm32l4pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, bdtr);
+ priv->count = info->count;
+ priv->curr = stm32l4pwm_pulsecount(info->count - priv->prev);
+ pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->curr - 1);
}
- else
-#if defined(CONFIG_STM32L4_TIM15_PWM) || defined(CONFIG_STM32L4_TIM16_PWM) || \
- defined(CONFIG_STM32L4_TIM17_PWM)
- if (priv->timtype == TIMTYPE_COUNTUP16)
- {
- /* Reset output N polarity level, output N state, output compare state,
- * output compare N idle state.
- */
- ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP);
- ccer |= ccnenable;
- }
+ /* Otherwise, just clear the repetition counter */
+
else
-#endif
-#endif
{
- ccer &= ~(GTIM_CCER_CC1NP | GTIM_CCER_CC2NP | GTIM_CCER_CC3NP); /* Not sure why? */
+ /* Set the repetition counter to zero */
+
+ pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, 0);
+
+ /* Generate an update event to reload the prescaler */
+
+ pwm_soft_update(dev);
}
- /* Save the modified register values */
+ /* Get configured outputs */
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CR2_OFFSET, cr2);
- putreg32(ccmr1, priv->base + STM32L4_GTIM_CCMR1_OFFSET);
- putreg32(ccmr2, priv->base + STM32L4_GTIM_CCMR2_OFFSET);
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
+ outputs = pwm_outputs_from_channels(priv);
- /* Set the ARR Preload Bit */
+ /* Enable output */
- cr1 = stm32l4pwm_getreg(priv, STM32L4_GTIM_CR1_OFFSET);
- cr1 |= GTIM_CR1_ARPE;
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
+ ret = pwm_outputs_enable(dev, outputs, true);
+ if (ret < 0)
+ {
+ goto errout;
+ }
/* Setup update interrupt. If info->count is > 0, then we can be
- * assured that stm32l4pwm_start() has already verified: (1) that this is an
- * advanced timer, and that (2) the repetition count is within range.
+ * assured that pwm_pulsecount_start() has already verified: (1) that this
+ * is an advanced timer, and that (2) the repetition count is within range.
*/
-#ifdef CONFIG_PWM_PULSECOUNT
if (info->count > 0)
{
/* Clear all pending interrupts and enable the update interrupt. */
- stm32l4pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
- stm32l4pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, ATIM_DIER_UIE);
+ pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
+ pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, ATIM_DIER_UIE);
/* Enable the timer */
- cr1 |= GTIM_CR1_CEN;
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
+ pwm_timer_enable(dev, true);
/* And enable timer interrupts at the NVIC */
up_enable_irq(priv->irq);
}
- else
-#endif
- {
- /* Just enable the timer, leaving all interrupts disabled */
- cr1 |= GTIM_CR1_CEN;
- stm32l4pwm_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
- }
+ pwm_dumpregs(dev, "After starting");
- stm32l4pwm_dumpregs(priv, "After starting");
- return OK;
+errout:
+ return ret;
}
+#else /* !CONFIG_PWM_PULSECOUNT */
+
/****************************************************************************
- * Name: stm32l4pwm_lptimer
+ * Name: pwm_duty_channels_update
*
* Description:
- * (Re-)initialize the low-power 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
+ * Update duty cycle for given channels
*
****************************************************************************/
-static int stm32l4pwm_lptimer(FAR struct stm32l4_pwmtimer_s *priv,
- FAR const struct pwm_info_s *info)
+static int pwm_duty_channels_update(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info)
{
- /* Calculated values */
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint8_t channel = 0;
+ ub16_t duty = 0;
+ int ret = OK;
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
+ int i = 0;
+ int j = 0;
+#endif
- uint8_t prescaler;
- uint32_t timclk;
- uint32_t reload;
- uint32_t ccr;
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
+ for (i = 0; i < CONFIG_PWM_NCHANNELS; i++)
+#endif
+ {
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
+ duty = info->channels[i].duty;
+ channel = info->channels[i].channel;
- /* Register contents */
+ /* A value of zero means to skip this channel */
- uint16_t cr;
- uint32_t cfgr;
+ if (channel != 0)
+ {
+ /* Find the channel */
- DEBUGASSERT(priv != NULL && info != NULL);
+ for (j = 0; j < priv->chan_num; j++)
+ {
+ if (priv->channels[j].channel == channel)
+ {
+ break;
+ }
+ }
- pwminfo("LPTIM%u frequency: %u duty: %08x\n",
-#ifdef CONFIG_PWM_MULTICHAN
- priv->timid, info->frequency, info->channels[0].duty);
+ /* Check range */
+
+ if (j >= priv->chan_num)
+ {
+ pwmerr("ERROR: No such channel: %u\n", channel);
+ ret = -EINVAL;
+ goto errout;
+ }
#else
- priv->timid, info->frequency, info->duty);
+ duty = info->duty;
+ channel = priv->channels[0].channel;
#endif
- DEBUGASSERT(info->frequency > 0);
- DEBUGASSERT(info->duty >= 0 && info->duty < uitoub16(100));
-
- /* LPTIM only has 8 possible prescaler values, from /1 to /128
- * We will attempt to find the lowest prescaler that results
- * in a maximum reload value which can be represented in 16 bit.
- * For certain desired frequencies it is possible that the clock
- * is too high and other one needs to be selected.
- */
-
- for (prescaler = 0; prescaler < 8; prescaler++)
- {
- timclk = priv->pclk / (1 << prescaler);
- reload = timclk / info->frequency;
-
- if (reload <= 65535)
- {
- /* The reload counter is feasible, go with it */
+ /* Update duty cycle */
- break;
+ ret = pwm_duty_update(dev, channel, duty);
+ if (ret < 0)
+ {
+ goto errout;
+ }
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
}
+#endif
}
- if (reload < 2)
- {
- reload = 1;
- }
- else if (reload > 65535)
- {
- reload = 65535;
- }
-
- /* TODO: if the desired frequency is not possible this should give an error and
- * not simply return the feasible frequency without complaining.
- */
-
- pwminfo("LPTIM%u PCLK: %u frequency: %u TIMCLK: %u prescaler: %u reload: %u\n",
- priv->timid, priv->pclk, info->frequency, timclk, prescaler, reload);
-
- /* Disable the timer to set the prescaler */
-
- cr = stm32l4pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET);
+errout:
+ return OK;
+}
- cr &= ~LPTIM_CR_ENABLE;
- stm32l4pwm_putreg(priv, STM32L4_LPTIM_CR_OFFSET, cr);
+/****************************************************************************
+ * Name: pwm_timer
+ *
+ * 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
+ *
+ ****************************************************************************/
- /* We have to way two counter clocks before the clock is actually enabled */
+static int pwm_timer(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info)
+{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint16_t outputs = 0;
+ int ret = OK;
- up_udelay(2 * USEC_PER_SEC / timclk);
+ DEBUGASSERT(priv != NULL && info != NULL);
- /* Set the prescaler value and choose high polarity */
+#if defined(CONFIG_STM32L4_PWM_MULTICHAN)
+ pwminfo("TIM%u frequency: %u\n",
+ priv->timid, info->frequency);
+#else
+ pwminfo("TIM%u channel: %u frequency: %u duty: %08x\n",
+ priv->timid, priv->channels[0].channel,
+ info->frequency, info->duty);
+#endif
- cfgr = getreg32(priv->base + STM32L4_LPTIM_CFGR_OFFSET);
+ DEBUGASSERT(info->frequency > 0);
+#ifndef CONFIG_STM32L4_PWM_MULTICHAN
+ DEBUGASSERT(info->duty >= 0 && info->duty < uitoub16(100));
+#endif
- cfgr &= ~LPTIM_CFGR_PRESC_MASK;
- cfgr |= (prescaler << LPTIM_CFGR_PRESC_SHIFT) | LPTIM_CFGR_WAVPOL;
+ /* TODO: what if we have pwm running and we want disable some channels ? */
- putreg32(cfgr, priv->base + STM32L4_LPTIM_CFGR_OFFSET);
+ /* Set timer frequency */
- /* Enable again, ARR and CMP need to be written while enabled */
+ ret = pwm_frequency_update(dev, info->frequency);
+ if (ret < 0)
+ {
+ goto errout;
+ }
- cr |= LPTIM_CR_ENABLE;
- stm32l4pwm_putreg(priv, STM32L4_LPTIM_CR_OFFSET, cr);
+ /* Channel specific configuration */
- /* Compute reload value */
+ ret = pwm_duty_channels_update(dev, info);
+ if (ret < 0)
+ {
+ goto errout;
+ }
-#ifdef CONFIG_PWM_MULTICHAN
- ub16_t duty = info->channels[0].duty;
-#else
- ub16_t duty = info->duty;
-#endif
+ /* Set the advanced timer's repetition counter */
- /* Duty cycle:
- *
- * duty cycle = ccr / reload (fractional value)
- */
+#ifdef HAVE_ADVTIM
+ if (priv->timtype == TIMTYPE_ADVANCED ||
+ priv->timtype == TIMTYPE_COUNTUP16_N)
+ {
+ /* If a non-zero repetition count has been selected, then set the
+ * repitition counter to the count-1 (pwm_start() has already
+ * assured us that the count value is within range).
+ */
- ccr = b16toi(duty * reload + b16HALF);
+ /* Set the repetition counter to zero */
- pwminfo("ccr: %u\n", ccr);
+ pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, 0);
- /* Set reload register */
+ /* Generate an update event to reload the prescaler */
- stm32l4pwm_putreg(priv, STM32L4_LPTIM_ARR_OFFSET, (uint16_t)reload);
+ pwm_soft_update(dev);
+ }
+ else
+#endif
+ {
+ /* Generate an update event to reload the prescaler (all timers) */
- /* Wait for write to complete */
+ pwm_soft_update(dev);
+ }
- while (!(getreg32(priv->base + STM32L4_LPTIM_ISR_OFFSET) & LPTIM_ISR_ARROK));
+ /* Get configured outputs */
- /* Set compare register */
+ outputs = pwm_outputs_from_channels(priv);
- stm32l4pwm_putreg(priv, STM32L4_LPTIM_CMP_OFFSET, (uint16_t)ccr);
+ /* Enable outputs */
- /* Wait for write to complete */
+ ret = pwm_outputs_enable(dev, outputs, true);
+ if (ret < 0)
+ {
+ goto errout;
+ }
- while (!(getreg32(priv->base + STM32L4_LPTIM_ISR_OFFSET) & LPTIM_ISR_CMPOK));
+ /* Just enable the timer, leaving all interrupts disabled */
- /* Start counter */
+ pwm_timer_enable(dev, true);
- cr = stm32l4pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET);
- cr |= LPTIM_CR_CNTSTRT;
- stm32l4pwm_putreg(priv, STM32L4_LPTIM_CR_OFFSET, cr);
+ pwm_dumpregs(dev, "After starting");
- stm32l4pwm_dumpregs(priv, "After starting");
- return OK;
+errout:
+ return ret;
}
-#ifndef CONFIG_PWM_PULSECOUNT
/****************************************************************************
- * Name: stm32l4pwm_update_duty
+ * Name: pwm_lptimer
*
* Description:
- * Try to change only channel duty.
+ * (Re-)initialize the low-power timer resources and start the
+ * pulsed output
*
* Input Parameters:
- * priv - A reference to the lower half PWM driver state structure
- * channel - Channel to by updated
- * duty - New duty.
+ * 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 stm32l4pwm_update_duty(FAR struct stm32l4_pwmtimer_s *priv,
- uint8_t channel, ub16_t duty)
+#ifdef HAVE_LPTIM
+static int pwm_lptimer(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info)
{
- /* Register offset */
-
- int ccr_offset;
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
+ uint16_t cr;
+ int ret = OK;
- /* Calculated values */
+ DEBUGASSERT(priv != NULL && info != NULL);
- uint32_t reload;
- uint32_t ccr;
+#if defined(CONFIG_STM32L4_PWM_MULTICHAN)
+ pwminfo("LPTIM%u frequency: %u\n",
+ priv->timid, info->frequency);
+#else
+ pwminfo("LPTIM%u channel: %u frequency: %u duty: %08x\n",
+ priv->timid, priv->channels[0].channel,
+ info->frequency, info->duty);
+#endif
- DEBUGASSERT(priv != NULL);
+ DEBUGASSERT(info->frequency > 0);
+#ifndef CONFIG_STM32L4_PWM_MULTICHAN
+ DEBUGASSERT(info->duty >= 0 && info->duty < uitoub16(100));
+#endif
- pwminfo("%s%u channel: %u duty: %08x\n",
- priv->timtype == TIMTYPE_LOWPOWER ? "LPTIM" : "TIM",
- priv->timid, channel, duty);
+ /* Enable again, ARR and CMP need to be written while enabled */
-#ifndef CONFIG_PWM_MULTICHAN
- DEBUGASSERT(channel == priv->channels[0].channel);
- DEBUGASSERT(duty >= 0 && duty < uitoub16(100));
-#endif
+ pwm_timer_enable(dev, true);
- /* Get the reload values */
+ /* Set timer frequency */
- if (priv->timtype == TIMTYPE_LOWPOWER)
- {
- reload = stm32l4pwm_getreg(priv, STM32L4_LPTIM_ARR_OFFSET);
- }
- else
+ ret = pwm_lp_frequency_update(dev, info->frequency);
+ if (ret < 0)
{
- reload = stm32l4pwm_getreg(priv, STM32L4_GTIM_ARR_OFFSET);
+ goto errout;
}
- /* Duty cycle:
- *
- * duty cycle = ccr / reload (fractional value)
- */
-
- ccr = b16toi(duty * reload + b16HALF);
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
+ ub16_t duty = info->channels[0].duty;
+#else
+ ub16_t duty = info->duty;
+#endif
- pwminfo("ccr: %u\n", ccr);
+ /* Update duty cycle */
- if (priv->timtype == TIMTYPE_LOWPOWER)
+ ret = pwm_duty_update(dev, priv->channels[0].channel, duty);
+ if (ret < 0)
{
- /* Low-power timers only have a compare register */
-
- ccr_offset = STM32L4_LPTIM_CMP_OFFSET;
+ goto errout;
}
- else
- {
- switch (channel)
- {
- case 1: /* Register offset for Channel 1 */
- ccr_offset = STM32L4_GTIM_CCR1_OFFSET;
- break;
-
- case 2: /* Register offset for Channel 2 */
- ccr_offset = STM32L4_GTIM_CCR2_OFFSET;
- break;
- case 3: /* Register offset for Channel 3 */
- ccr_offset = STM32L4_GTIM_CCR3_OFFSET;
- break;
+ /* Start counter */
- case 4: /* Register offset for Channel 4 */
- ccr_offset = STM32L4_GTIM_CCR4_OFFSET;
- break;
+ cr = pwm_getreg(priv, STM32L4_LPTIM_CR_OFFSET);
+ cr |= LPTIM_CR_CNTSTRT;
+ pwm_putreg(priv, STM32L4_LPTIM_CR_OFFSET, cr);
- default:
- pwmerr("ERROR: No such channel: %u\n", channel);
- return -EINVAL;
- }
- }
+ pwm_dumpregs(dev, "After starting");
- /* Set the duty cycle by writing to the CCR register for this channel */
+errout:
+ return ret;
+}
+#endif /* HAVE_LPTIM */
- stm32l4pwm_putreg(priv, ccr_offset, (uint16_t)ccr);
+#endif /* CONFIG_PWM_PULSECOUNT */
- return OK;
-}
-#endif
+#ifdef HAVE_PWM_INTERRUPT
/****************************************************************************
- * Name: stm32l4pwm_interrupt
+ * Name: pwm_interrupt
*
* Description:
* Handle timer interrupts.
*
* Input Parameters:
- * priv - A reference to the lower half PWM driver state structure
+ * dev - A reference to the lower half PWM driver state structure
*
* Returned Value:
* Zero on success; a negated errno value on failure
*
****************************************************************************/
-#if defined(CONFIG_PWM_PULSECOUNT) && (defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM))
-static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv)
+static int pwm_interrupt(FAR struct pwm_lowerhalf_s *dev)
{
+ FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
uint16_t regval;
/* Verify that this is an update interrupt. Nothing else is expected. */
- regval = stm32l4pwm_getreg(priv, STM32L4_ATIM_SR_OFFSET);
+ regval = pwm_getreg(priv, STM32L4_ATIM_SR_OFFSET);
DEBUGASSERT((regval & ATIM_SR_UIF) != 0);
/* Clear the UIF interrupt bit */
- stm32l4pwm_putreg(priv, STM32L4_ATIM_SR_OFFSET, regval & ~ATIM_SR_UIF);
+ pwm_putreg(priv, STM32L4_ATIM_SR_OFFSET, regval & ~ATIM_SR_UIF);
/* Calculate the new count by subtracting the number of pulses
* since the last interrupt.
@@ -1729,13 +3370,13 @@ static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv)
* quickly as possible.
*/
- regval = stm32l4pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET);
+ regval = pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET);
regval &= ~ATIM_BDTR_MOE;
- stm32l4pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, regval);
+ pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, regval);
/* Disable first interrtups, stop and reset the timer */
- stm32l4pwm_stop((FAR struct pwm_lowerhalf_s *)priv);
+ pwm_stop(dev);
/* Then perform the callback into the upper half driver */
@@ -1762,17 +3403,18 @@ static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv)
priv->prev = priv->curr;
priv->curr = stm32l4pwm_pulsecount(priv->count - priv->prev);
- stm32l4pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->curr - 1);
+ pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->curr - 1);
}
- /* Now all of the time critical stuff is done so we can do some debug output */
+ /* Now all of the time critical stuff is done so we can do some debug
+ * output
+ */
pwminfo("Update interrupt SR: %04x prev: %u curr: %u count: %u\n",
regval, priv->prev, priv->curr, priv->count);
return OK;
}
-#endif
/****************************************************************************
* Name: pwm_tim1/8interrupt
@@ -1788,19 +3430,19 @@ static int stm32l4pwm_interrupt(struct stm32l4_pwmtimer_s *priv)
*
****************************************************************************/
-#if defined(CONFIG_PWM_PULSECOUNT) && defined(CONFIG_STM32L4_TIM1_PWM)
-static int stm32l4pwm_tim1interrupt(int irq, void *context, FAR void *arg)
+#ifdef CONFIG_STM32L4_TIM1_PWM
+static int pwm_tim1interrupt(int irq, void *context, FAR void *arg)
{
- return stm32l4pwm_interrupt(&g_pwm1dev);
+ return pwm_interrupt((FAR struct pwm_lowerhalf_s *)&g_pwm1dev);
}
-#endif
+#endif /* CONFIG_STM32L4_TIM1_PWM */
-#if defined(CONFIG_PWM_PULSECOUNT) && defined(CONFIG_STM32L4_TIM8_PWM)
-static int stm32l4pwm_tim8interrupt(int irq, void *context, FAR void *arg)
+#ifdef CONFIG_STM32L4_TIM8_PWM
+static int pwm_tim8interrupt(int irq, void *context, FAR void *arg)
{
- return stm32l4pwm_interrupt(&g_pwm8dev);
+ return pwm_interrupt((FAR struct pwm_lowerhalf_s *)&g_pwm8dev);
}
-#endif
+#endif /* CONFIG_STM32L4_TIM8_PWM */
/****************************************************************************
* Name: stm32l4pwm_pulsecount
@@ -1816,7 +3458,6 @@ static int stm32l4pwm_tim8interrupt(int irq, void *context, FAR void *arg)
*
****************************************************************************/
-#if defined(CONFIG_PWM_PULSECOUNT) && (defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM))
static uint8_t stm32l4pwm_pulsecount(uint32_t count)
{
/* The the remaining pulse count is less than or equal to the maximum, the
@@ -1825,7 +3466,7 @@ static uint8_t stm32l4pwm_pulsecount(uint32_t count)
if (count <= ATIM_RCR_REP_MAX)
{
- return count;
+ return (uint8_t)count;
}
/* Otherwise, we have to be careful. We do not want a small number of
@@ -1837,17 +3478,17 @@ static uint8_t stm32l4pwm_pulsecount(uint32_t count)
else if (count < (3 * ATIM_RCR_REP_MAX / 2))
{
- return (ATIM_RCR_REP_MAX + 1) >> 1;
+ return (uint8_t)((ATIM_RCR_REP_MAX + 1) >> 1);
}
/* Otherwise, return the maximum. The final count will be 64 or more */
else
{
- return ATIM_RCR_REP_MAX;
+ return (uint8_t)ATIM_RCR_REP_MAX;
}
}
-#endif
+#endif /* HAVE_PWM_INTERRUPT */
/****************************************************************************
* Name: stm32l4pwm_setapbclock
@@ -1861,10 +3502,12 @@ static uint8_t stm32l4pwm_pulsecount(uint32_t count)
*
****************************************************************************/
-static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
+static int stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv,
+ bool on)
{
uint32_t en_bit;
uint32_t regaddr;
+ int ret = OK;
/* Determine which timer to configure */
@@ -1874,60 +3517,91 @@ static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
{
#ifdef CONFIG_STM32L4_TIM1_PWM
case 1:
- regaddr = STM32L4_RCC_APB2ENR;
- en_bit = RCC_APB2ENR_TIM1EN;
- break;
+ {
+ regaddr = STM32L4_RCC_APB2ENR;
+ en_bit = RCC_APB2ENR_TIM1EN;
+ break;
+ }
#endif
+
#ifdef CONFIG_STM32L4_TIM2_PWM
case 2:
- regaddr = STM32L4_RCC_APB1ENR1;
- en_bit = RCC_APB1ENR1_TIM2EN;
- break;
+ {
+ regaddr = STM32L4_RCC_APB1ENR1;
+ en_bit = RCC_APB1ENR1_TIM2EN;
+ break;
+ }
#endif
+
#ifdef CONFIG_STM32L4_TIM3_PWM
case 3:
- regaddr = STM32L4_RCC_APB1ENR1;
- en_bit = RCC_APB1ENR1_TIM3EN;
- break;
+ {
+ regaddr = STM32L4_RCC_APB1ENR1;
+ en_bit = RCC_APB1ENR1_TIM3EN;
+ break;
+ }
#endif
+
#ifdef CONFIG_STM32L4_TIM4_PWM
case 4:
- regaddr = STM32L4_RCC_APB1ENR1;
- en_bit = RCC_APB1ENR1_TIM4EN;
- break;
+ {
+ regaddr = STM32L4_RCC_APB1ENR1;
+ en_bit = RCC_APB1ENR1_TIM4EN;
+ break;
+ }
#endif
+
#ifdef CONFIG_STM32L4_TIM5_PWM
case 5:
- regaddr = STM32L4_RCC_APB1ENR1;
- en_bit = RCC_APB1ENR1_TIM5EN;
- break;
+ {
+ regaddr = STM32L4_RCC_APB1ENR1;
+ en_bit = RCC_APB1ENR1_TIM5EN;
+ break;
+ }
#endif
+
#ifdef CONFIG_STM32L4_TIM8_PWM
case 8:
- regaddr = STM32L4_RCC_APB2ENR;
- en_bit = RCC_APB2ENR_TIM8EN;
- break;
+ {
+ regaddr = STM32L4_RCC_APB2ENR;
+ en_bit = RCC_APB2ENR_TIM8EN;
+ break;
+ }
#endif
+
#ifdef CONFIG_STM32L4_TIM15_PWM
case 15:
- regaddr = STM32L4_RCC_APB2ENR;
- en_bit = RCC_APB2ENR_TIM15EN;
- break;
+ {
+ regaddr = STM32L4_RCC_APB2ENR;
+ en_bit = RCC_APB2ENR_TIM15EN;
+ break;
+ }
#endif
+
#ifdef CONFIG_STM32L4_TIM16_PWM
case 16:
- regaddr = STM32L4_RCC_APB2ENR;
- en_bit = RCC_APB2ENR_TIM16EN;
- break;
+ {
+ regaddr = STM32L4_RCC_APB2ENR;
+ en_bit = RCC_APB2ENR_TIM16EN;
+ break;
+ }
#endif
+
#ifdef CONFIG_STM32L4_TIM17_PWM
case 17:
- regaddr = STM32L4_RCC_APB2ENR;
- en_bit = RCC_APB2ENR_TIM17EN;
- break;
+ {
+ regaddr = STM32L4_RCC_APB2ENR;
+ en_bit = RCC_APB2ENR_TIM17EN;
+ break;
+ }
#endif
+
default:
- return;
+ {
+ pwmerr("ERROR: No such timer configured %d\n", priv->timid);
+ ret = -EINVAL;
+ goto errout;
+ }
}
/* Enable/disable APB 1/2 clock for timer */
@@ -1941,6 +3615,7 @@ static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
modifyreg32(regaddr, en_bit, 0);
}
}
+#ifdef HAVE_LPTIM
else
{
uint32_t clock_bits;
@@ -1949,67 +3624,86 @@ static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
{
#ifdef CONFIG_STM32L4_LPTIM1_PWM
case 1:
+ {
#if defined(CONFIG_STM32L4_LPTIM1_CLK_APB1)
- /* Enable APB clock for LPTIM1 */
-
- if (on)
- {
- modifyreg32(STM32L4_RCC_APB1ENR1, 0, RCC_APB1ENR1_LPTIM1EN);
- }
- else
- {
- modifyreg32(STM32L4_RCC_APB1ENR1, RCC_APB1ENR1_LPTIM1EN, 0);
- }
-
- clock_bits = RCC_CCIPR_LPTIM1SEL_PCLK;
+ /* Enable APB clock for LPTIM1 */
+
+ if (on)
+ {
+ modifyreg32(STM32L4_RCC_APB1ENR1,
+ 0, RCC_APB1ENR1_LPTIM1EN);
+ }
+ else
+ {
+ modifyreg32(STM32L4_RCC_APB1ENR1,
+ RCC_APB1ENR1_LPTIM1EN, 0);
+ }
+
+ clock_bits = RCC_CCIPR_LPTIM1SEL_PCLK;
#elif defined(CONFIG_STM32L4_LPTIM1_CLK_LSI)
- clock_bits = RCC_CCIPR_LPTIM1SEL_LSI;
+ clock_bits = RCC_CCIPR_LPTIM1SEL_LSI;
#elif defined(CONFIG_STM32L4_LPTIM1_CLK_LSE)
- clock_bits = RCC_CCIPR_LPTIM1SEL_LSE;
+ clock_bits = RCC_CCIPR_LPTIM1SEL_LSE;
#elif defined(CONFIG_STM32L4_LPTIM1_CLK_HSI)
- clock_bits = RCC_CCIPR_LPTIM1SEL_HSI;
+ clock_bits = RCC_CCIPR_LPTIM1SEL_HSI;
#endif
- /* Choose which clock will be used for LPTIM1 */
+ /* Choose which clock will be used for LPTIM1 */
- modifyreg32(STM32L4_RCC_CCIPR, RCC_CCIPR_LPTIM1SEL_MASK, clock_bits);
- break;
+ modifyreg32(STM32L4_RCC_CCIPR, RCC_CCIPR_LPTIM1SEL_MASK,
+ clock_bits);
+ break;
+ }
#endif
#ifdef CONFIG_STM32L4_LPTIM2_PWM
case 2:
+ {
#if defined(CONFIG_STM32L4_LPTIM2_CLK_APB1)
- /* Enable APB clock for LPTIM2 */
-
- if (on)
- {
- modifyreg32(STM32L4_RCC_APB1ENR2, 0, RCC_APB1ENR2_LPTIM2EN);
- }
- else
- {
- modifyreg32(STM32L4_RCC_APB1ENR2, RCC_APB1ENR2_LPTIM2EN, 0);
- }
-
- clock_bits = RCC_CCIPR_LPTIM2SEL_PCLK;
+ /* Enable APB clock for LPTIM2 */
+
+ if (on)
+ {
+ modifyreg32(STM32L4_RCC_APB1ENR2,
+ 0, RCC_APB1ENR2_LPTIM2EN);
+ }
+ else
+ {
+ modifyreg32(STM32L4_RCC_APB1ENR2,
+ RCC_APB1ENR2_LPTIM2EN, 0);
+ }
+
+ clock_bits = RCC_CCIPR_LPTIM2SEL_PCLK;
#elif defined(CONFIG_STM32L4_LPTIM2_CLK_LSI)
- clock_bits = RCC_CCIPR_LPTIM2SEL_LSI;
+ clock_bits = RCC_CCIPR_LPTIM2SEL_LSI;
#elif defined(CONFIG_STM32L4_LPTIM2_CLK_LSE)
- clock_bits = RCC_CCIPR_LPTIM2SEL_LSE;
+ clock_bits = RCC_CCIPR_LPTIM2SEL_LSE;
#elif defined(CONFIG_STM32L4_LPTIM2_CLK_HSI)
- clock_bits = RCC_CCIPR_LPTIM2SEL_HSI;
+ clock_bits = RCC_CCIPR_LPTIM2SEL_HSI;
#endif
- /* Choose which clock will be used for LPTIM2 */
+ /* Choose which clock will be used for LPTIM2 */
+
+ modifyreg32(STM32L4_RCC_CCIPR, RCC_CCIPR_LPTIM2SEL_MASK,
+ clock_bits);
+ break;
+ }
- modifyreg32(STM32L4_RCC_CCIPR, RCC_CCIPR_LPTIM2SEL_MASK, clock_bits);
- break;
#endif
default:
- return;
+ {
+ pwmerr("ERROR: No such timer configured %d\n", priv->timid);
+ ret = -EINVAL;
+ goto errout;
+ }
}
}
+
+#endif /* HAVE_LPTIM */
+errout:
+ return ret;
}
/****************************************************************************
- * Name: stm32l4pwm_setup
+ * Name: pwm_setup
*
* Description:
* This method is called when the driver is opened. The lower half driver
@@ -2028,10 +3722,11 @@ static void stm32l4pwm_setapbclock(FAR struct stm32l4_pwmtimer_s *priv, bool on)
*
****************************************************************************/
-static int stm32l4pwm_setup(FAR struct pwm_lowerhalf_s *dev)
+static int pwm_setup(FAR struct pwm_lowerhalf_s *dev)
{
FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
uint32_t pincfg;
+ int ret;
int i;
if (priv->timtype == TIMTYPE_LOWPOWER)
@@ -2043,42 +3738,55 @@ static int stm32l4pwm_setup(FAR struct pwm_lowerhalf_s *dev)
pwminfo("TIM%u\n", priv->timid);
}
- stm32l4pwm_dumpregs(priv, "Initially");
-
/* Enable APB1/2 clocking for timer. */
stm32l4pwm_setapbclock(priv, true);
+ pwm_dumpregs(dev, "Initially");
+
/* Configure the PWM output pins, but do not start the timer yet */
- for (i = 0; i < PWM_NCHANNELS; i++)
+ for (i = 0; i < priv->chan_num; i++)
{
- pincfg = priv->channels[i].pincfg;
- if (pincfg != 0)
+ if (priv->channels[i].out1.in_use == 1)
{
+ pincfg = priv->channels[i].out1.pincfg;
pwminfo("pincfg: %08x\n", pincfg);
stm32l4_configgpio(pincfg);
+ pwm_dumpgpio(pincfg, "PWM setup");
}
- /* Enable complementary channel if available */
-
- pincfg = priv->channels[i].npincfg;
- if (pincfg != 0)
+#ifdef HAVE_PWM_COMPLEMENTARY
+ if (priv->channels[i].out2.in_use == 1)
{
- pwminfo("npincfg: %08x\n", pincfg);
+ pincfg = priv->channels[i].out2.pincfg;
+ pwminfo("pincfg: %08x\n", pincfg);
stm32l4_configgpio(pincfg);
+ pwm_dumpgpio(pincfg, "PWM setup");
}
+#endif
+ }
+
+ /* Configure PWM timer with the selected configuration.
+ *
+ * NOTE: We configure PWM here during setup, but leave timer with disabled
+ * counter, disabled outputs, not configured frequency and duty cycle
+ */
- pwm_dumpgpio(pincfg, "PWM setup");
+ ret = pwm_configure(dev);
+ if (ret < 0)
+ {
+ pwmerr("failed to configure PWM %d\n", priv->timid);
+ return ERROR;
}
return OK;
}
/****************************************************************************
- * Name: stm32l4pwm_shutdown
+ * Name: pwm_shutdown
*
* Description:
* This method is called when the driver is closed. The lower half driver
@@ -2093,27 +3801,39 @@ static int stm32l4pwm_setup(FAR struct pwm_lowerhalf_s *dev)
*
****************************************************************************/
-static int stm32l4pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
+static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
{
FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
- uint32_t pincfg;
- int i;
+ uint32_t pincfg = 0;
+ int i = 0;
+ int ret = OK;
- pwminfo("TIM%u\n", priv->timid);
+ if (priv->timtype == TIMTYPE_LOWPOWER)
+ {
+ pwminfo("LPTIM%u\n", priv->timid);
+ }
+ else
+ {
+ pwminfo("TIM%u\n", priv->timid);
+ }
/* Make sure that the output has been stopped */
- stm32l4pwm_stop(dev);
+ pwm_stop(dev);
/* Disable APB1/2 clocking for timer. */
- stm32l4pwm_setapbclock(priv, false);
+ ret = stm32l4pwm_setapbclock(priv, false);
+ if (ret < 0)
+ {
+ goto errout;
+ }
/* Then put the GPIO pins back to the default state */
- for (i = 0; i < PWM_NCHANNELS; i++)
+ for (i = 0; i < priv->chan_num; i++)
{
- pincfg = priv->channels[i].pincfg;
+ pincfg = priv->channels[i].out1.pincfg;
if (pincfg != 0)
{
pwminfo("pincfg: %08x\n", pincfg);
@@ -2124,23 +3844,26 @@ static int stm32l4pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
stm32l4_configgpio(pincfg);
}
- pincfg = priv->channels[i].npincfg;
+#ifdef HAVE_PWM_COMPLEMENTARY
+ pincfg = priv->channels[i].out2.pincfg;
if (pincfg != 0)
{
- pwminfo("npincfg: %08x\n", pincfg);
+ pwminfo("pincfg: %08x\n", pincfg);
pincfg &= (GPIO_PORT_MASK | GPIO_PIN_MASK);
pincfg |= GPIO_INPUT | GPIO_FLOAT;
stm32l4_configgpio(pincfg);
}
+#endif
}
- return OK;
+errout:
+ return ret;
}
/****************************************************************************
- * Name: stm32l4pwm_start
+ * Name: pwm_start
*
* Description:
* (Re-)initialize the timer resources and start the pulsed output
@@ -2155,7 +3878,7 @@ static int stm32l4pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
****************************************************************************/
#ifdef CONFIG_PWM_PULSECOUNT
-static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
FAR const struct pwm_info_s *info,
FAR void *handle)
{
@@ -2181,17 +3904,11 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
/* Start the time */
- if (priv->timtype == TIMTYPE_LOWPOWER)
- {
- return stm32l4pwm_lptimer(priv, info);
- }
- else
- {
- return stm32l4pwm_timer(priv, info);
- }
+ return pwm_pulsecount_timer(dev, info);
}
-#else
-static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
+#else /* !CONFIG_PWM_PULSECOUNT */
+
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
FAR const struct pwm_info_s *info)
{
int ret = OK;
@@ -2201,7 +3918,7 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
if (info->frequency == priv->frequency)
{
-#ifdef CONFIG_PWM_MULTICHAN
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
int i;
for (i = 0; ret == OK && i < CONFIG_PWM_NCHANNELS; i++)
@@ -2210,25 +3927,26 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
if (info->channels[i].channel != 0)
{
- ret = stm32l4pwm_update_duty(priv, info->channels[i].channel,
- info->channels[i].duty);
+ ret = pwm_duty_update(dev, info->channels[i].channel,
+ info->channels[i].duty);
}
}
-
#else
- ret = stm32l4pwm_update_duty(priv, priv->channels[0].channel, info->duty);
-#endif
+ ret = pwm_duty_update(dev, priv->channels[0].channel, info->duty);
+#endif /* CONFIG_STM32L4_PWM_MULTICHAN */
}
else
{
- if (priv->timtype == TIMTYPE_LOWPOWER)
+ if (priv->timtype != TIMTYPE_LOWPOWER)
{
- ret = stm32l4pwm_lptimer(priv, info);
+ ret = pwm_timer(dev, info);
}
+#ifdef HAVE_LPTIM
else
{
- ret = stm32l4pwm_timer(priv, info);
+ ret = pwm_lptimer(dev, info);
}
+#endif
/* Save current frequency */
@@ -2240,10 +3958,10 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
return ret;
}
-#endif
+#endif /* CONFIG_PWM_PULSECOUNT */
/****************************************************************************
- * Name: stm32l4pwm_stop
+ * Name: pwm_stop
*
* Description:
* Stop the pulsed output and reset the timer resources
@@ -2261,7 +3979,7 @@ static int stm32l4pwm_start(FAR struct pwm_lowerhalf_s *dev,
*
****************************************************************************/
-static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
+static int pwm_stop(FAR struct pwm_lowerhalf_s *dev)
{
FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
uint32_t resetbit = 0;
@@ -2278,21 +3996,6 @@ static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
pwminfo("TIM%u\n", priv->timid);
}
- /* Disable interrupts momentary to stop any ongoing timer processing and
- * to prevent any concurrent access to the reset register.
- */
-
- flags = enter_critical_section();
-
- /* Stopped so frequency is zero */
-
- priv->frequency = 0;
-
- /* Disable further interrupts and stop the timer */
-
- stm32l4pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0);
- stm32l4pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
-
/* Determine which timer to reset */
if (priv->timtype != TIMTYPE_LOWPOWER)
@@ -2367,11 +4070,30 @@ static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
resetbit = RCC_APB1RSTR2_LPTIM2RST;
break;
#endif
+ default:
+ return -EINVAL;
}
}
+ /* Disable interrupts momentary to stop any ongoing timer processing and
+ * to prevent any concurrent access to the reset register.
+ */
+
+ flags = enter_critical_section();
+
+#ifndef CONFIG_PWM_PULSECOUNT
+ /* Stopped so frequency is zero */
+
+ priv->frequency = 0;
+#endif
+
+ /* Disable further interrupts and stop the timer */
+
+ pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0);
+ pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0);
+
/* Reset the timer - stopping the output and putting the timer back
- * into a state where stm32l4pwm_start() can be called.
+ * into a state where pwm_start() can be called.
*/
regval = getreg32(regaddr);
@@ -2383,12 +4105,12 @@ static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
leave_critical_section(flags);
pwminfo("regaddr: %08x resetbit: %08x\n", regaddr, resetbit);
- stm32l4pwm_dumpregs(priv, "After stop");
+ pwm_dumpregs(dev, "After stop");
return OK;
}
/****************************************************************************
- * Name: stm32l4pwm_ioctl
+ * Name: pwm_ioctl
*
* Description:
* Lower-half logic may support platform-specific ioctl commands
@@ -2403,8 +4125,8 @@ static int stm32l4pwm_stop(FAR struct pwm_lowerhalf_s *dev)
*
****************************************************************************/
-static int stm32l4pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd,
- unsigned long arg)
+static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd,
+ unsigned long arg)
{
#ifdef CONFIG_DEBUG_PWM_INFO
FAR struct stm32l4_pwmtimer_s *priv = (FAR struct stm32l4_pwmtimer_s *)dev;
@@ -2538,6 +4260,7 @@ FAR struct pwm_lowerhalf_s *stm32l4_pwminitialize(int timer)
*
****************************************************************************/
+#ifdef HAVE_LPTIM
FAR struct pwm_lowerhalf_s *stm32l4_lp_pwminitialize(int timer)
{
FAR struct stm32l4_pwmtimer_s *lower;
@@ -2565,5 +4288,6 @@ FAR struct pwm_lowerhalf_s *stm32l4_lp_pwminitialize(int timer)
return (FAR struct pwm_lowerhalf_s *)lower;
}
+#endif /* HAVE_LPTIM */
#endif /* CONFIG_STM32L4_TIMn_PWM, n = 1,...,17 */
diff --git a/arch/arm/src/stm32l4/stm32l4_pwm.h b/arch/arm/src/stm32l4/stm32l4_pwm.h
index c7a639d..d359c38 100644
--- a/arch/arm/src/stm32l4/stm32l4_pwm.h
+++ b/arch/arm/src/stm32l4/stm32l4_pwm.h
@@ -1,4 +1,4 @@
-/************************************************************************************
+/****************************************************************************
* arch/arm/src/stm32l4/stm32l4_pwm.h
*
* Copyright (C) 2011, 2015 Gregory Nutt. All rights reserved.
@@ -33,36 +33,36 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
- ************************************************************************************/
+ ****************************************************************************/
#ifndef __ARCH_ARM_SRC_STM32L4_STM32L4_PWM_H
#define __ARCH_ARM_SRC_STM32L4_STM32L4_PWM_H
-/* The STM32L4 does not have dedicated PWM hardware. Rather, pulsed output control
- * is a capability of the STM32L4 timers. The logic in this file implements the
- * lower half of the standard, NuttX PWM interface using the STM32L4 timers. That
- * interface is described in include/nuttx/timers/pwm.h.
+/* The STM32L4 does not have dedicated PWM hardware. Rather, pulsed output
+ * control is a capability of the STM32L4 timers. The logic in this file
+ * implements the lower half of the standard, NuttX PWM interface using the
+ * STM32L4 timers. That interface is described in include/nuttx/timers/pwm.h.
*/
-/************************************************************************************
+/****************************************************************************
* Included Files
- ************************************************************************************/
+ ****************************************************************************/
#include <nuttx/config.h>
#include "chip.h"
-/************************************************************************************
+/****************************************************************************
* Pre-processor Definitions
- ************************************************************************************/
+ ****************************************************************************/
-/* Configuration ********************************************************************/
+/* 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.
+ * 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
@@ -99,7 +99,9 @@
# undef CONFIG_STM32L4_LPTIM2_PWM
#endif
-/* The basic timers (timer 6 and 7) are not capable of generating output pulses */
+/* The basic timers (timer 6 and 7) are not capable of generating output
+ * pulses.
+ */
#undef CONFIG_STM32L4_TIM6_PWM
#undef CONFIG_STM32L4_TIM7_PWM
@@ -117,7 +119,9 @@
#include "hardware/stm32l4_tim.h"
#include "hardware/stm32l4_lptim.h"
-#ifdef CONFIG_PWM_MULTICHAN
+/* PWM driver channels configuration */
+
+#ifdef CONFIG_STM32L4_PWM_MULTICHAN
#ifdef CONFIG_STM32L4_TIM1_CHANNEL1
# ifdef CONFIG_STM32L4_TIM1_CH1OUT
@@ -502,33 +506,19 @@
#endif
#define PWM_LPTIM2_NCHANNELS PWM_LPTIM2_CHANNEL1
-#define PWM_MAX(a, b) ((a) > (b) ? (a) : (b))
-
-#define PWM_NCHANNELS PWM_MAX(PWM_TIM1_NCHANNELS, \
- PWM_MAX(PWM_TIM2_NCHANNELS, \
- PWM_MAX(PWM_TIM3_NCHANNELS, \
- PWM_MAX(PWM_TIM4_NCHANNELS, \
- PWM_MAX(PWM_TIM5_NCHANNELS, \
- PWM_MAX(PWM_TIM8_NCHANNELS, \
- PWM_MAX(PWM_TIM15_NCHANNELS, \
- PWM_MAX(PWM_TIM16_NCHANNELS, \
- PWM_MAX(PWM_TIM17_NCHANNELS, \
- PWM_MAX(PWM_LPTIM1_NCHANNELS, \
- PWM_LPTIM2_NCHANNELS))))))))))
+#else /* !CONFIG_STM32L4_PWM_MULTICHAN */
-#else
-
-/* For each timer that is enabled for PWM usage, we need the following additional
- * configuration settings:
+/* For each timer that is enabled for PWM usage, we need the following
+ * additional configuration settings:
*
* CONFIG_STM32L4_TIMx_CHANNEL - Specifies the timer output channel {1,..,4}
- * PWM_TIMx_CHn - One of the values defined in chip/stm32*_pinmap.h. In the case
- * where there are multiple pin selections, the correct setting must be provided
- * in the arch/board/board.h file.
+ * PWM_TIMx_CHn - One of the values defined in chip/stm32*_pinmap.h. In the
+ * case where there are multiple pin selections, the correct setting must be
+ * provided in the arch/board/board.h file.
*
- * NOTE: The STM32L4 timers are each capable of generating different signals on
- * each of the four channels with different duty cycles. That capability is
- * not supported by this driver: Only one output channel per timer.
+ * NOTE: The STM32L4 timers are each capable of generating different signals
+ * on each of the four channels with different duty cycles. That capability
+ * is not supported by this driver: Only one output channel per timer.
*/
#ifdef CONFIG_STM32L4_TIM1_PWM
@@ -537,25 +527,46 @@
# elif CONFIG_STM32L4_TIM1_CHANNEL == 1
# define CONFIG_STM32L4_TIM1_CHANNEL1 1
# define CONFIG_STM32L4_TIM1_CH1MODE CONFIG_STM32L4_TIM1_CHMODE
-# define PWM_TIM1_CH1CFG GPIO_TIM1_CH1OUT
-# define PWM_TIM1_CH1NCFG 0
+# ifdef CONFIG_STM32L4_TIM1_CH1OUT
+# define PWM_TIM1_CH1CFG GPIO_TIM1_CH1OUT
+# endif
+# ifdef CONFIG_STM32L4_TIM1_CH1NOUT
+# define PWM_TIM1_CH1NCFG GPIO_TIM1_CH1NOUT
+# else
+# define PWM_TIM1_CH1NCFG 0
+# endif
# elif CONFIG_STM32L4_TIM1_CHANNEL == 2
# define CONFIG_STM32L4_TIM1_CHANNEL2 1
# define CONFIG_STM32L4_TIM1_CH2MODE CONFIG_STM32L4_TIM1_CHMODE
-# define PWM_TIM1_CH2CFG GPIO_TIM1_CH2OUT
-# define PWM_TIM1_CH2NCFG 0
+# ifdef CONFIG_STM32L4_TIM1_CH2OUT
+# define PWM_TIM1_CH2CFG GPIO_TIM1_CH2OUT
+# endif
+# ifdef CONFIG_STM32L4_TIM1_CH2NOUT
+# define PWM_TIM1_CH2NCFG GPIO_TIM1_CH2NOUT
+# else
+# define PWM_TIM1_CH2NCFG 0
+# endif
# elif CONFIG_STM32L4_TIM1_CHANNEL == 3
# define CONFIG_STM32L4_TIM1_CHANNEL3 1
# define CONFIG_STM32L4_TIM1_CH3MODE CONFIG_STM32L4_TIM1_CHMODE
-# define PWM_TIM1_CH3CFG GPIO_TIM1_CH3OUT
-# define PWM_TIM1_CH3NCFG 0
+# ifdef CONFIG_STM32L4_TIM1_CH3OUT
+# define PWM_TIM1_CH3CFG GPIO_TIM1_CH3OUT
+# endif
+# ifdef CONFIG_STM32L4_TIM1_CH3NOUT
+# define PWM_TIM1_CH3NCFG GPIO_TIM1_CH3NOUT
+# else
+# define PWM_TIM1_CH3NCFG 0
+# endif
# elif CONFIG_STM32L4_TIM1_CHANNEL == 4
# define CONFIG_STM32L4_TIM1_CHANNEL4 1
# define CONFIG_STM32L4_TIM1_CH4MODE CONFIG_STM32L4_TIM1_CHMODE
-# define PWM_TIM1_CH4CFG GPIO_TIM1_CH4OUT
+# ifdef CONFIG_STM32L4_TIM1_CH4OUT
+# define PWM_TIM1_CH4CFG GPIO_TIM1_CH4OUT
+# endif
# else
# error "Unsupported value of CONFIG_STM32L4_TIM1_CHANNEL"
# endif
+# define PWM_TIM1_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_TIM2_PWM
@@ -580,6 +591,7 @@
# else
# error "Unsupported value of CONFIG_STM32L4_TIM2_CHANNEL"
# endif
+# define PWM_TIM2_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_TIM3_PWM
@@ -604,6 +616,7 @@
# else
# error "Unsupported value of CONFIG_STM32L4_TIM3_CHANNEL"
# endif
+# define PWM_TIM3_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_TIM4_PWM
@@ -628,6 +641,7 @@
# else
# error "Unsupported value of CONFIG_STM32L4_TIM4_CHANNEL"
# endif
+# define PWM_TIM4_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_TIM5_PWM
@@ -652,6 +666,7 @@
# else
# error "Unsupported value of CONFIG_STM32L4_TIM5_CHANNEL"
# endif
+# define PWM_TIM5_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_TIM8_PWM
@@ -679,6 +694,7 @@
# else
# error "Unsupported value of CONFIG_STM32L4_TIM8_CHANNEL"
# endif
+# define PWM_TIM8_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_TIM15_PWM
@@ -696,6 +712,7 @@
# else
# error "Unsupported value of CONFIG_STM32L4_TIM15_CHANNEL"
# endif
+# define PWM_TIM15_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_TIM16_PWM
@@ -709,6 +726,7 @@
# else
# error "Unsupported value of CONFIG_STM32L4_TIM16_CHANNEL"
# endif
+# define PWM_TIM16_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_TIM17_PWM
@@ -722,6 +740,7 @@
# else
# error "Unsupported value of CONFIG_STM32L4_TIM17_CHANNEL"
# endif
+# define PWM_TIM17_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_LPTIM1_PWM
@@ -734,6 +753,7 @@
# else
# error "Unsupported value of CONFIG_STM32L4_LPTIM1_CHANNEL"
# endif
+# define PWM_LPTIM1_NCHANNELS 1
#endif
#ifdef CONFIG_STM32L4_LPTIM2_PWM
@@ -746,19 +766,258 @@
# else
# error "Unsupported value of CONFIG_STM32L4_LPTIM2_CHANNEL"
# endif
+# define PWM_LPTIM2_NCHANNELS 1
+#endif
+
#endif
-#define PWM_NCHANNELS 1
+/* Complementary outputs support */
+#if defined(CONFIG_STM32L4_TIM1_CH1NOUT) || defined(CONFIG_STM32L4_TIM1_CH2NOUT) || \
+ defined(CONFIG_STM32L4_TIM1_CH3NOUT)
+# define HAVE_TIM1_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_TIM8_CH1NOUT) || defined(CONFIG_STM32L4_TIM8_CH2NOUT) || \
+ defined(CONFIG_STM32L4_TIM8_CH3NOUT)
+# define HAVE_TIM8_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_TIM15_CH1NOUT)
+# define HAVE_TIM15_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_TIM16_CH1NOUT)
+# define HAVE_TIM16_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_TIM17_CH1NOUT)
+# define HAVE_TIM17_COMPLEMENTARY
+#endif
+#if defined(CONFIG_STM32L4_LPTIM1_CH1NOUT)
+# define HAVE_LPTIM1_COMPLEMENTARY
#endif
+#if defined(CONFIG_STM32L4_LPTIM2_CH1NOUT)
+# define HAVE_LPTIM2_COMPLEMENTARY
+#endif
+#if defined(HAVE_TIM1_COMPLEMENTARY) || defined(HAVE_TIM8_COMPLEMENTARY) || \
+ defined(HAVE_TIM15_COMPLEMENTARY) || defined(HAVE_TIM16_COMPLEMENTARY) || \
+ defined(HAVE_TIM17_COMPLEMENTARY) || defined(HAVE_LPTIM1_COMPLEMENTARY) || \
+ defined(HAVE_LPTIM2_COMPLEMENTARY)
+# define HAVE_PWM_COMPLEMENTARY
+#endif
+
+/* Low-level ops helpers ************************************************************/
+
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+
+/* NOTE: low-level ops accept pwm_lowerhalf_s as first argument, but llops
+ * access can be found in stm32_pwm_dev_s
+ */
-/************************************************************************************
+#define STM32L4_PWM_SETUP(dev) \
+ (dev)->ops->setup((FAR struct pwm_lowerhalf_s *)dev)
+#define STM32L4_PWM_SHUTDOWN(dev) \
+ (dev)->ops->shutdown((FAR struct pwm_lowerhalf_s *)dev)
+#define STM32L4_PWM_CCR_UPDATE(dev, index, ccr) \
+ (dev)->llops->ccr_update((FAR struct pwm_lowerhalf_s *)dev, index, ccr)
+#define STM32L4_PWM_MODE_UPDATE(dev, index, mode) \
+ (dev)->llops->mode_update((FAR struct pwm_lowerhalf_s *)dev, index, mode)
+#define STM32L4_PWM_CCR_GET(dev, index) \
+ (dev)->llops->ccr_get((FAR struct pwm_lowerhalf_s *)dev, index)
+#define STM32L4_PWM_ARR_UPDATE(dev, arr) \
+ (dev)->llops->arr_update((FAR struct pwm_lowerhalf_s *)dev, arr)
+#define STM32L4_PWM_ARR_GET(dev) \
+ (dev)->llops->arr_get((FAR struct pwm_lowerhalf_s *)dev)
+#define STM32L4_PWM_OUTPUTS_ENABLE(dev, out, state) \
+ (dev)->llops->outputs_enable((FAR struct pwm_lowerhalf_s *)dev, out, state)
+#define STM32L4_PWM_SOFT_UPDATE(dev) \
+ (dev)->llops->soft_update((FAR struct pwm_lowerhalf_s *)dev)
+#define STM32L4_PWM_CONFIGURE(dev) \
+ (dev)->llops->configure((FAR struct pwm_lowerhalf_s *)dev)
+#define STM32L4_PWM_SOFT_BREAK(dev, state) \
+ (dev)->llops->soft_break((FAR struct pwm_lowerhalf_s *)dev, state)
+#define STM32L4_PWM_FREQ_UPDATE(dev, freq) \
+ (dev)->llops->freq_update((FAR struct pwm_lowerhalf_s *)dev, freq)
+#define STM32L4_PWM_TIM_ENABLE(dev, state) \
+ (dev)->llops->tim_enable((FAR struct pwm_lowerhalf_s *)dev, state)
+#ifdef CONFIG_DEBUG_STM32L4_PWM_INFO
+# define STM32L4_PWM_DUMP_REGS(dev, msg) \
+ (dev)->llops->dump_regs((FAR struct pwm_lowerhalf_s *)dev, msg)
+#else
+# define STM32L4_PWM_DUMP_REGS(dev, msg)
+#endif
+#define STM32L4_PWM_DT_UPDATE(dev, dt) \
+ (dev)->llops->dt_update((FAR struct pwm_lowerhalf_s *)dev, dt)
+#endif
+
+/****************************************************************************
* Public Types
- ************************************************************************************/
+ ****************************************************************************/
+
+/* Timer mode */
+
+enum stm32l4_timmode_e
+{
+ STM32L4_TIMMODE_COUNTUP = 0,
+ STM32L4_TIMMODE_COUNTDOWN = 1,
+ STM32L4_TIMMODE_CENTER1 = 2,
+ STM32L4_TIMMODE_CENTER2 = 3,
+ STM32L4_TIMMODE_CENTER3 = 4,
+};
+
+/* Timer output polarity */
+
+enum stm32l4_pwm_pol_e
+{
+ STM32L4_POL_POS = 0,
+ STM32L4_POL_NEG = 1,
+};
+
+/* Timer output IDLE state */
+
+enum stm32l4_pwm_idle_e
+{
+ STM32L4_IDLE_INACTIVE = 0,
+ STM32L4_IDLE_ACTIVE = 1
+};
+
+/* PWM channel mode */
+
+enum stm32l4_chanmode_e
+{
+ STM32L4_CHANMODE_FRZN = 0, /* CCRx matches has no effects on outputs */
+ STM32L4_CHANMODE_CHACT = 1, /* OCxREF active on match */
+ STM32L4_CHANMODE_CHINACT = 2, /* OCxREF inactive on match */
+ STM32L4_CHANMODE_OCREFTOG = 3, /* OCxREF toggles when TIMy_CNT=TIMyCCRx */
+ STM32L4_CHANMODE_OCREFLO = 4, /* OCxREF is forced low */
+ STM32L4_CHANMODE_OCREFHI = 5, /* OCxREF is forced high */
+ STM32L4_CHANMODE_PWM1 = 6, /* PWM mode 1 */
+ STM32L4_CHANMODE_PWM2 = 7, /* PWM mode 2 */
+ STM32L4_CHANMODE_COMBINED1 = 8, /* Combined PWM mode 1 */
+ STM32L4_CHANMODE_COMBINED2 = 9, /* Combined PWM mode 2 */
+ STM32L4_CHANMODE_ASYMMETRIC1 = 10, /* Asymmetric PWM mode 1 */
+ STM32L4_CHANMODE_ASYMMETRIC2 = 11, /* Asymmetric PWM mode 2 */
+};
+
+/* PWM timer channel */
+
+enum stm32l4_pwm_chan_e
+{
+ STM32L4_PWM_CHAN1 = 1,
+ STM32L4_PWM_CHAN2 = 2,
+ STM32L4_PWM_CHAN3 = 3,
+ STM32L4_PWM_CHAN4 = 4,
+ STM32L4_PWM_CHAN5 = 5,
+ STM32L4_PWM_CHAN6 = 6,
+};
+
+/* PWM timer channel output */
+
+enum stm32l4_pwm_output_e
+{
+ STM32L4_PWM_OUT1 = (1 << 0),
+ STM32L4_PWM_OUT1N = (1 << 1),
+ STM32L4_PWM_OUT2 = (1 << 2),
+ STM32L4_PWM_OUT2N = (1 << 3),
+ STM32L4_PWM_OUT3 = (1 << 4),
+ STM32L4_PWM_OUT3N = (1 << 5),
+ STM32L4_PWM_OUT4 = (1 << 6),
+ /* 1 << 7 reserved - no complementary output for CH4 */
+ /* Only available inside micro */
+ STM32L4_PWM_OUT5 = (1 << 8),
+ /* 1 << 9 reserved - no complementary output for CH5 */
+ STM32L4_PWM_OUT6 = (1 << 10),
+ /* 1 << 11 reserved - no complementary output for CH6 */
+};
+
+#ifdef CONFIG_STM32L4_PWM_LL_OPS
+
+/* This structure provides the publicly visable representation of the
+ * "lower-half" PWM driver structure.
+ */
+
+struct stm32_pwm_dev_s
+{
+ /* The first field of this state structure must be a pointer to the PWM
+ * callback structure to be consistent with upper-half PWM driver.
+ */
+
+ FAR const struct pwm_ops_s *ops;
+
+ /* Publicly visible portion of the "lower-half" PWM driver structure */
+
+ FAR const struct stm32l4_pwm_ops_s *llops;
+
+ /* Require cast-compatibility with private "lower-half" PWM strucutre */
+};
+
+/* Low-level operations for PWM */
+
+struct pwm_lowerhalf_s;
+struct stm32l4_pwm_ops_s
+{
+ /* Update CCR register */
+
+ int (*ccr_update)(FAR struct pwm_lowerhalf_s *dev,
+ uint8_t index, uint32_t ccr);
+
+ /* Update PWM mode */
+
+ int (*mode_update)(FAR struct pwm_lowerhalf_s *dev,
+ uint8_t index, uint32_t mode);
+
+ /* Get CCR register */
+
+ uint32_t (*ccr_get)(FAR struct pwm_lowerhalf_s *dev, uint8_t index);
+
+ /* Update ARR register */
+
+ int (*arr_update)(FAR struct pwm_lowerhalf_s *dev, uint32_t arr);
+
+ /* Get ARR register */
+
+ uint32_t (*arr_get)(FAR struct pwm_lowerhalf_s *dev);
+
+ /* Enable outputs */
+
+ int (*outputs_enable)(FAR struct pwm_lowerhalf_s *dev,
+ uint16_t outputs, bool state);
-/************************************************************************************
+ /* Software update */
+
+ int (*soft_update)(FAR struct pwm_lowerhalf_s *dev);
+
+ /* PWM configure */
+
+ int (*configure)(FAR struct pwm_lowerhalf_s *dev);
+
+ /* Software break */
+
+ int (*soft_break)(FAR struct pwm_lowerhalf_s *dev, bool state);
+
+ /* Update frequency */
+
+ int (*freq_update)(FAR struct pwm_lowerhalf_s *dev, uint32_t frequency);
+
+ /* Enable timer counter */
+
+ int (*tim_enable)(FAR struct pwm_lowerhalf_s *dev, bool state);
+
+#ifdef CONFIG_DEBUG_PWM_INFO
+ /* Dump timer registers */
+
+ void (*dump_regs)(FAR struct pwm_lowerhalf_s *dev, FAR const char *msg);
+#endif
+
+#ifdef HAVE_PWM_COMPLEMENTARY
+ /* Deadtime update */
+
+ int (*dt_update)(FAR struct pwm_lowerhalf_s *dev, uint8_t dt);
+#endif
+};
+
+#endif /* CONFIG_STM32L4_PWM_LL_OPS */
+
+/****************************************************************************
* Public Data
- ************************************************************************************/
+ ****************************************************************************/
#ifndef __ASSEMBLY__
@@ -771,11 +1030,11 @@ extern "C"
#define EXTERN extern
#endif
-/************************************************************************************
+/****************************************************************************
* Public Functions
- ************************************************************************************/
+ ****************************************************************************/
-/************************************************************************************
+/****************************************************************************
* Name: stm32l4_pwminitialize
*
* Description:
@@ -790,7 +1049,7 @@ extern "C"
* 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_pwminitialize(int timer);
diff --git a/boards/arm/stm32l4/nucleo-l432kc/include/nucleo-l432kc.h b/boards/arm/stm32l4/nucleo-l432kc/include/nucleo-l432kc.h
index a9819b8..964fffe 100644
--- a/boards/arm/stm32l4/nucleo-l432kc/include/nucleo-l432kc.h
+++ b/boards/arm/stm32l4/nucleo-l432kc/include/nucleo-l432kc.h
@@ -68,7 +68,8 @@
* synced MSI.
*
* System Clock source : PLL (HSI)
- * SYSCLK(Hz) : 80000000 Determined by PLL configuration
+ * SYSCLK(Hz) : 80000000 Determined by PLL
+ * configuration
* HCLK(Hz) : 80000000 (STM32L4_RCC_CFGR_HPRE)
* (Max 80 MHz)
* AHB Prescaler : 1 (STM32L4_RCC_CFGR_HPRE)
@@ -233,9 +234,9 @@
/* 'main' PLL config; we use this to generate our system clock via the R
* output. We set it up as 16 MHz / 1 * 10 / 2 = 80 MHz
*
- * XXX NOTE: currently the main PLL is implicitly turned on and is implicitly
- * the system clock; this should be configurable since not all applications may
- * want things done this way.
+ * XXX NOTE: currently the main PLL is implicitly turned on and is
+ * implicitly the system clock; this should be configurable since not all
+ * applications may want things done this way.
*/
#define STM32L4_PLLCFG_PLLN RCC_PLLCFG_PLLN(10)
@@ -495,6 +496,8 @@
#define STM32L4_APB1_TIM2_CLKIN (STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM6_CLKIN (STM32L4_PCLK1_FREQUENCY)
#define STM32L4_APB1_TIM7_CLKIN (STM32L4_PCLK1_FREQUENCY)
+#define STM32L4_APB1_LPTIM1_CLKIN (STM32L4_PCLK1_FREQUENCY)
+#define STM32L4_APB1_LPTIM2_CLKIN (STM32L4_PCLK1_FREQUENCY)
/* Configure the APB2 prescaler */
@@ -507,8 +510,8 @@
#endif
-/* The timer clock frequencies are automatically defined by hardware.
- * If the APB prescaler equals 1, the timer clock frequencies are set to the same
+/* The timer clock frequencies are automatically defined by hardware. If the
+ * APB prescaler equals 1, the timer clock frequencies are set to the same
* frequency as that of the APB domain. Otherwise they are set to twice.
* Note: TIM1,15,16 are on APB2, others on APB1
*/