11
11
#include <zephyr/drivers/reset.h>
12
12
#include <zephyr/irq.h>
13
13
#include <zephyr/sys/atomic.h>
14
+ #include <zephyr/drivers/pinctrl.h>
14
15
15
16
#include <stm32_ll_tim.h>
16
17
#include <stm32_ll_rcc.h>
@@ -53,6 +54,12 @@ static uint32_t(*const get_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *) = {
53
54
LL_TIM_OC_GetCompareCH3 , LL_TIM_OC_GetCompareCH4 ,
54
55
};
55
56
#endif
57
+ #ifdef CONFIG_COUNTER_CAPTURE
58
+ static uint32_t (* const get_timer_capture [TIMER_MAX_CH ])(const TIM_TypeDef * ) = {
59
+ LL_TIM_IC_GetCaptureCH1 , LL_TIM_IC_GetCaptureCH2 ,
60
+ LL_TIM_IC_GetCaptureCH3 , LL_TIM_IC_GetCaptureCH4 ,
61
+ };
62
+ #endif /* CONFIG_COUNTER_CAPTURE */
56
63
/** Channel to interrupt enable function mapping. */
57
64
static void (* const enable_it [TIMER_MAX_CH ])(TIM_TypeDef * ) = {
58
65
LL_TIM_EnableIT_CC1 , LL_TIM_EnableIT_CC2 ,
@@ -96,6 +103,9 @@ struct counter_stm32_data {
96
103
97
104
struct counter_stm32_ch_data {
98
105
counter_alarm_callback_t callback ;
106
+ #ifdef CONFIG_COUNTER_CAPTURE
107
+ counter_capture_cb_t capture ;
108
+ #endif /* CONFIG_COUNTER_CAPTURE */
99
109
void * user_data ;
100
110
};
101
111
@@ -109,6 +119,9 @@ struct counter_stm32_config {
109
119
uint32_t irqn ;
110
120
/* Reset controller device configuration */
111
121
const struct reset_dt_spec reset ;
122
+ #ifdef CONFIG_COUNTER_CAPTURE
123
+ const struct pinctrl_dev_config * pcfg ;
124
+ #endif /* CONFIG_COUNTER_CAPTURE */
112
125
113
126
LOG_INSTANCE_PTR_DECLARE (log );
114
127
};
@@ -497,6 +510,14 @@ static int counter_stm32_init_timer(const struct device *dev)
497
510
/* config/enable IRQ */
498
511
cfg -> irq_config_func (dev );
499
512
513
+ #ifdef CONFIG_COUNTER_CAPTURE
514
+ r = pinctrl_apply_state (cfg -> pcfg , PINCTRL_STATE_DEFAULT );
515
+ if (r < 0 ) {
516
+ LOG_ERR ("%s: Counter Capture pinctrl setup failed (%d)" , dev -> name , r );
517
+ return r ;
518
+ }
519
+ #endif /* CONFIG_COUNTER_CAPTURE */
520
+
500
521
/* initialize timer */
501
522
LL_TIM_StructInit (& init );
502
523
@@ -570,28 +591,119 @@ static void counter_stm32_top_irq_handle(const struct device *dev)
570
591
cb (dev , data -> top_user_data );
571
592
}
572
593
573
- static void counter_stm32_alarm_irq_handle (const struct device * dev , uint32_t id )
594
+ static void counter_stm32_irq_handle (const struct device * dev , uint32_t id )
574
595
{
575
596
const struct counter_stm32_config * config = dev -> config ;
576
597
struct counter_stm32_data * data = dev -> data ;
577
598
TIM_TypeDef * timer = config -> timer ;
578
599
579
600
struct counter_stm32_ch_data * chdata ;
580
- counter_alarm_callback_t cb ;
581
601
582
602
atomic_and (& data -> cc_int_pending , ~BIT (id ));
583
- disable_it [id ](timer );
584
603
585
604
chdata = & config -> ch_data [id ];
586
- cb = chdata -> callback ;
587
- chdata -> callback = NULL ;
605
+ #ifdef CONFIG_COUNTER_CAPTURE
606
+ /* With Counter Capture, we need to check which mode it was configured for */
607
+ if (LL_TIM_IC_GetActiveInput (timer , LL_TIM_CHANNEL_CH1 << (4 * id )) ==
608
+ LL_TIM_ACTIVEINPUT_DIRECTTI ) {
609
+ counter_capture_cb_t cb ;
610
+
611
+ cb = chdata -> capture ;
612
+
613
+ /* TODO: check overcapture flag, then print error?
614
+ * CC1OF is also set if at least two consecutive captures
615
+ * occurred whereas the flag was not cleared
616
+ */
617
+
618
+ if (cb ) {
619
+ uint32_t cc_val = get_timer_capture [id ](timer );
620
+ uint32_t pol = LL_TIM_IC_GetPolarity (timer , LL_TIM_CHANNEL_CH1 << (4 * id ));
621
+ uint32_t flags = 0 ;
622
+
623
+ /* translate stm32 flags to zephyr flags */
624
+ if (pol == LL_TIM_IC_POLARITY_RISING ) {
625
+ flags = COUNTER_CAPTURE_RISING_EDGE ;
626
+ } else if (pol == LL_TIM_IC_POLARITY_FALLING ) {
627
+ flags = COUNTER_CAPTURE_FALLING_EDGE ;
628
+ } else if (pol == LL_TIM_IC_POLARITY_BOTHEDGE ) {
629
+ flags = COUNTER_CAPTURE_BOTH_EDGES ;
630
+ }
631
+
632
+ cb (dev , id , flags , cc_val , chdata -> user_data );
633
+ }
634
+ } else {
635
+ #endif
636
+ counter_alarm_callback_t cb ;
637
+ /* Alarm is One-Shot, so disable the Interrupt */
638
+ disable_it [id ](timer );
639
+
640
+ cb = chdata -> callback ;
641
+ chdata -> callback = NULL ;
642
+
643
+ if (cb ) {
644
+ uint32_t cc_val = get_timer_compare [id ](timer );
645
+
646
+ cb (dev , id , cc_val , chdata -> user_data );
647
+ }
648
+ #ifdef CONFIG_COUNTER_CAPTURE
649
+ }
650
+ #endif
651
+ }
652
+ #ifdef CONFIG_COUNTER_CAPTURE
653
+ static int counter_stm32_capture_enable (const struct device * dev , uint8_t chan )
654
+ {
655
+ const struct counter_stm32_config * config = dev -> config ;
656
+ TIM_TypeDef * timer = config -> timer ;
657
+
658
+ LL_TIM_CC_EnableChannel (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ));
588
659
589
- if (cb ) {
590
- uint32_t cc_val = get_timer_compare [id ](timer );
660
+ return 0 ;
661
+ }
662
+
663
+ static int counter_stm32_capture_disable (const struct device * dev , uint8_t chan )
664
+ {
665
+ const struct counter_stm32_config * config = dev -> config ;
666
+ TIM_TypeDef * timer = config -> timer ;
591
667
592
- cb (dev , id , cc_val , chdata -> user_data );
668
+ LL_TIM_CC_DisableChannel (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ));
669
+
670
+ return 0 ;
671
+ }
672
+
673
+ static int counter_stm32_capture_callback_set (const struct device * dev , uint8_t chan ,
674
+ uint32_t flags , counter_capture_cb_t cb ,
675
+ void * user_data )
676
+ {
677
+ const struct counter_stm32_config * config = dev -> config ;
678
+ struct counter_stm32_ch_data * chdata = & config -> ch_data [chan ];
679
+ TIM_TypeDef * timer = config -> timer ;
680
+ uint32_t config_flags = LL_TIM_ACTIVEINPUT_DIRECTTI ;
681
+
682
+ chdata -> capture = cb ;
683
+ chdata -> user_data = user_data ;
684
+
685
+ if ((flags & COUNTER_CAPTURE_BOTH_EDGES ) == COUNTER_CAPTURE_BOTH_EDGES ) {
686
+ config_flags |= LL_TIM_IC_POLARITY_BOTHEDGE ;
687
+ } else if (flags & COUNTER_CAPTURE_FALLING_EDGE ) {
688
+ config_flags |= LL_TIM_IC_POLARITY_FALLING ;
689
+ } else if (flags & COUNTER_CAPTURE_RISING_EDGE ) {
690
+ config_flags |= LL_TIM_IC_POLARITY_RISING ;
593
691
}
692
+ /* TODO: add 'vendor' config flags for filter, prescaler div */
693
+ config_flags |= (LL_TIM_ICPSC_DIV1 | LL_TIM_IC_FILTER_FDIV1 );
694
+
695
+ /* Config is only writable when it is off */
696
+ LL_TIM_CC_DisableChannel (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ));
697
+
698
+ LL_TIM_IC_Config (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ), config_flags );
699
+
700
+ LL_TIM_CC_EnableChannel (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ));
701
+ /* enable interrupt */
702
+ enable_it [chan ](timer );
703
+
704
+ return 0 ;
594
705
}
706
+ #endif
595
707
596
708
static DEVICE_API (counter , counter_stm32_driver_api ) = {
597
709
.start = counter_stm32_start ,
@@ -607,6 +719,11 @@ static DEVICE_API(counter, counter_stm32_driver_api) = {
607
719
.get_freq = counter_stm32_get_freq ,
608
720
.reset = counter_stm32_reset_timer ,
609
721
.set_value = counter_stm32_set_value ,
722
+ #ifdef CONFIG_COUNTER_CAPTURE
723
+ .capture_enable = counter_stm32_capture_enable ,
724
+ .capture_disable = counter_stm32_capture_disable ,
725
+ .capture_callback_set = counter_stm32_capture_callback_set ,
726
+ #endif
610
727
};
611
728
612
729
#define TIM_IRQ_HANDLE_CC (timx , cc ) \
@@ -617,7 +734,7 @@ static DEVICE_API(counter, counter_stm32_driver_api) = {
617
734
if (hw_irq) { \
618
735
LL_TIM_ClearFlag_CC##cc(timer); \
619
736
} \
620
- counter_stm32_alarm_irq_handle (dev, cc - 1U); \
737
+ counter_stm32_irq_handle (dev, cc - 1U); \
621
738
} \
622
739
} while (0)
623
740
@@ -660,6 +777,8 @@ void counter_stm32_irq_handler(const struct device *dev)
660
777
BUILD_ASSERT(NUM_CH(TIM(idx)) <= TIMER_MAX_CH, \
661
778
"TIMER too many channels"); \
662
779
\
780
+ IF_ENABLED(CONFIG_COUNTER_CAPTURE, \
781
+ (PINCTRL_DT_INST_DEFINE(idx);)) \
663
782
static struct counter_stm32_data counter##idx##_data; \
664
783
static struct counter_stm32_ch_data counter##idx##_ch_data[TIMER_MAX_CH]; \
665
784
\
@@ -691,6 +810,8 @@ void counter_stm32_irq_handler(const struct device *dev)
691
810
.irq_config_func = counter_##idx##_stm32_irq_config, \
692
811
.irqn = DT_IRQN(TIMER(idx)), \
693
812
.reset = RESET_DT_SPEC_GET(TIMER(idx)), \
813
+ IF_ENABLED(CONFIG_COUNTER_CAPTURE, \
814
+ (.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx),)) \
694
815
}; \
695
816
\
696
817
DEVICE_DT_INST_DEFINE(idx, \
0 commit comments