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,117 @@ 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 )) == LL_TIM_ACTIVEINPUT_DIRECTTI ) {
608
+ counter_capture_cb_t cb ;
609
+
610
+ cb = chdata -> capture ;
611
+
612
+ /* TODO: check overcapture flag, then print error?
613
+ * CC1OF is also set if at least two consecutive captures
614
+ * occurred whereas the flag was not cleared
615
+ */
616
+
617
+ if (cb ) {
618
+ uint32_t cc_val = get_timer_capture [id ](timer );
619
+ uint32_t pol = LL_TIM_IC_GetPolarity (timer , LL_TIM_CHANNEL_CH1 << (4 * id ));
620
+ uint32_t flags = 0 ;
621
+
622
+ /* translate stm32 flags to zephyr flags */
623
+ if (pol == LL_TIM_IC_POLARITY_RISING ) {
624
+ flags = COUNTER_CAPTURE_RISING_EDGE ;
625
+ } else if (pol == LL_TIM_IC_POLARITY_FALLING ) {
626
+ flags = COUNTER_CAPTURE_FALLING_EDGE ;
627
+ } else if (pol == LL_TIM_IC_POLARITY_BOTHEDGE ) {
628
+ flags = COUNTER_CAPTURE_BOTH_EDGES ;
629
+ }
630
+
631
+ cb (dev , id , flags , cc_val , chdata -> user_data );
632
+ }
633
+ } else {
634
+ #endif
635
+ counter_alarm_callback_t cb ;
636
+ /* Alarm is One-Shot, so disable the Interrupt */
637
+ disable_it [id ](timer );
638
+
639
+ cb = chdata -> callback ;
640
+ chdata -> callback = NULL ;
641
+
642
+ if (cb ) {
643
+ uint32_t cc_val = get_timer_compare [id ](timer );
644
+
645
+ cb (dev , id , cc_val , chdata -> user_data );
646
+ }
647
+ #ifdef CONFIG_COUNTER_CAPTURE
648
+ }
649
+ #endif
650
+ }
651
+ #ifdef CONFIG_COUNTER_CAPTURE
652
+ static int counter_stm32_capture_enable (const struct device * dev , uint8_t chan )
653
+ {
654
+ const struct counter_stm32_config * config = dev -> config ;
655
+ TIM_TypeDef * timer = config -> timer ;
588
656
589
- if (cb ) {
590
- uint32_t cc_val = get_timer_compare [id ](timer );
657
+ LL_TIM_CC_EnableChannel (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ));
591
658
592
- cb (dev , id , cc_val , chdata -> user_data );
659
+ return 0 ;
660
+ }
661
+
662
+ static int counter_stm32_capture_disable (const struct device * dev , uint8_t chan )
663
+ {
664
+ const struct counter_stm32_config * config = dev -> config ;
665
+ TIM_TypeDef * timer = config -> timer ;
666
+
667
+ LL_TIM_CC_DisableChannel (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ));
668
+
669
+ return 0 ;
670
+ }
671
+
672
+ static int counter_stm32_capture_callback_set (const struct device * dev , uint8_t chan ,
673
+ uint32_t flags , counter_capture_cb_t cb ,
674
+ void * user_data )
675
+ {
676
+ const struct counter_stm32_config * config = dev -> config ;
677
+ struct counter_stm32_ch_data * chdata = & config -> ch_data [chan ];
678
+ TIM_TypeDef * timer = config -> timer ;
679
+ uint32_t config_flags = LL_TIM_ACTIVEINPUT_DIRECTTI ;
680
+ chdata -> capture = cb ;
681
+ chdata -> user_data = user_data ;
682
+
683
+ if ((flags & COUNTER_CAPTURE_BOTH_EDGES ) == COUNTER_CAPTURE_BOTH_EDGES ) {
684
+ config_flags |= LL_TIM_IC_POLARITY_BOTHEDGE ;
685
+ } else if (flags & COUNTER_CAPTURE_FALLING_EDGE ) {
686
+ config_flags |= LL_TIM_IC_POLARITY_FALLING ;
687
+ } else if (flags & COUNTER_CAPTURE_RISING_EDGE ) {
688
+ config_flags |= LL_TIM_IC_POLARITY_RISING ;
593
689
}
690
+ /* TODO: add 'vendor' config flags for filter, prescaler div */
691
+ config_flags |= (LL_TIM_ICPSC_DIV1 | LL_TIM_IC_FILTER_FDIV1 );
692
+
693
+ /* Config is only writable when it is off */
694
+ LL_TIM_CC_DisableChannel (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ));
695
+
696
+ LL_TIM_IC_Config (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ), config_flags );
697
+
698
+ LL_TIM_CC_EnableChannel (timer , LL_TIM_CHANNEL_CH1 << (4 * chan ));
699
+ /* enable interrupt */
700
+ enable_it [chan ](timer );
701
+
702
+ return 0 ;
594
703
}
704
+ #endif
595
705
596
706
static DEVICE_API (counter , counter_stm32_driver_api ) = {
597
707
.start = counter_stm32_start ,
@@ -607,6 +717,11 @@ static DEVICE_API(counter, counter_stm32_driver_api) = {
607
717
.get_freq = counter_stm32_get_freq ,
608
718
.reset = counter_stm32_reset_timer ,
609
719
.set_value = counter_stm32_set_value ,
720
+ #ifdef CONFIG_COUNTER_CAPTURE
721
+ .capture_enable = counter_stm32_capture_enable ,
722
+ .capture_disable = counter_stm32_capture_disable ,
723
+ .capture_callback_set = counter_stm32_capture_callback_set ,
724
+ #endif
610
725
};
611
726
612
727
#define TIM_IRQ_HANDLE_CC (timx , cc ) \
@@ -617,7 +732,7 @@ static DEVICE_API(counter, counter_stm32_driver_api) = {
617
732
if (hw_irq) { \
618
733
LL_TIM_ClearFlag_CC##cc(timer); \
619
734
} \
620
- counter_stm32_alarm_irq_handle (dev, cc - 1U); \
735
+ counter_stm32_irq_handle (dev, cc - 1U); \
621
736
} \
622
737
} while (0)
623
738
@@ -660,6 +775,8 @@ void counter_stm32_irq_handler(const struct device *dev)
660
775
BUILD_ASSERT(NUM_CH(TIM(idx)) <= TIMER_MAX_CH, \
661
776
"TIMER too many channels"); \
662
777
\
778
+ IF_ENABLED(CONFIG_COUNTER_CAPTURE, \
779
+ (PINCTRL_DT_INST_DEFINE(idx);)) \
663
780
static struct counter_stm32_data counter##idx##_data; \
664
781
static struct counter_stm32_ch_data counter##idx##_ch_data[TIMER_MAX_CH]; \
665
782
\
@@ -691,6 +808,8 @@ void counter_stm32_irq_handler(const struct device *dev)
691
808
.irq_config_func = counter_##idx##_stm32_irq_config, \
692
809
.irqn = DT_IRQN(TIMER(idx)), \
693
810
.reset = RESET_DT_SPEC_GET(TIMER(idx)), \
811
+ IF_ENABLED(CONFIG_COUNTER_CAPTURE, \
812
+ (.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx),)) \
694
813
}; \
695
814
\
696
815
DEVICE_DT_INST_DEFINE(idx, \
0 commit comments