1818
1919#include "led_driver.h"
2020
21- #include "st_types.h"
22-
2321#include "utils.h"
2422
2523#include "vesc_c_if.h"
3129#define WS2812_ZERO (((uint32_t) TIM_PERIOD) * 0.3)
3230#define WS2812_ONE (((uint32_t) TIM_PERIOD) * 0.7)
3331
34- typedef struct {
35- uint8_t pin_nr ;
36- DMA_Stream_TypeDef * dma_stream ;
37- uint16_t dma_source ;
38- uint32_t ccr_address ;
39- } PinHwConfig ;
40-
41- static PinHwConfig get_pin_hw_config (LedPin pin ) {
42- PinHwConfig cfg ;
43- switch (pin ) {
44- case LED_PIN_B6 :
45- cfg .pin_nr = 6 ;
46- cfg .dma_stream = DMA1_Stream0 ;
47- cfg .dma_source = TIM_DMA_CC1 ;
48- cfg .ccr_address = (uint32_t ) & TIM4 -> CCR1 ;
49- break ;
50- case LED_PIN_B7 :
51- cfg .pin_nr = 7 ;
52- cfg .dma_stream = DMA1_Stream3 ;
53- cfg .dma_source = TIM_DMA_CC2 ;
54- cfg .ccr_address = (uint32_t ) & TIM4 -> CCR2 ;
55- break ;
32+ static const PinHwConfig pin_hw_configs [] = {
33+ {
34+ .pin_port = GPIOB ,
35+ .pin_nr = 6 ,
36+ .timer = TIM4 ,
37+ .ccr_address = (uint32_t ) & TIM4 -> CCR1 ,
38+ .rcc_apb1_periph = RCC_APB1Periph_TIM4 ,
39+ .timer_ccmr = & TIM4 -> CCMR1 ,
40+ .timer_ccmr_shift = 0 ,
41+ .timer_ccer_shift = 0 ,
42+ .dma_stream = DMA1_Stream0 ,
43+ .dma_channel = DMA_Channel_2 ,
44+ .dma_if_shift = 0 ,
45+ .dma_source = TIM_DMA_CC1 ,
46+ },
47+ {
48+ .pin_port = GPIOB ,
49+ .pin_nr = 7 ,
50+ .timer = TIM4 ,
51+ .ccr_address = (uint32_t ) & TIM4 -> CCR2 ,
52+ .rcc_apb1_periph = RCC_APB1Periph_TIM4 ,
53+ .timer_ccmr = & TIM4 -> CCMR1 ,
54+ .timer_ccmr_shift = 8 ,
55+ .timer_ccer_shift = 4 ,
56+ .dma_stream = DMA1_Stream3 ,
57+ .dma_channel = DMA_Channel_2 ,
58+ .dma_if_shift = 22 ,
59+ .dma_source = TIM_DMA_CC2 ,
60+ },
61+ {
62+ .pin_port = GPIOC ,
63+ .pin_nr = 9 ,
64+ .timer = TIM3 ,
65+ .ccr_address = (uint32_t ) & TIM3 -> CCR4 ,
66+ .rcc_apb1_periph = RCC_APB1Periph_TIM3 ,
67+ .timer_ccmr = & TIM3 -> CCMR2 ,
68+ .timer_ccmr_shift = 8 ,
69+ .timer_ccer_shift = 12 ,
70+ .dma_stream = DMA1_Stream2 ,
71+ .dma_channel = DMA_Channel_5 ,
72+ .dma_if_shift = 16 ,
73+ .dma_source = TIM_DMA_CC4 ,
5674 }
75+ };
5776
58- return cfg ;
77+ static void reset_timer (const PinHwConfig * pin_hw_cfg ) {
78+ RCC -> APB1RSTR |= pin_hw_cfg -> rcc_apb1_periph ;
79+ RCC -> APB1RSTR &= ~pin_hw_cfg -> rcc_apb1_periph ;
5980}
6081
61- static void reset_tim4 () {
62- RCC -> APB1RSTR |= RCC_APB1Periph_TIM4 ;
63- RCC -> APB1RSTR &= ~RCC_APB1Periph_TIM4 ;
82+ static void init_timer (const PinHwConfig * pin_hw_cfg ) {
83+ // enable the Low Speed APB (APB1) peripheral clock
84+ // see: RCC_APB1PeriphClockCmd()
85+ RCC -> APB1ENR |= pin_hw_cfg -> rcc_apb1_periph ;
86+
87+ // init timer registers
88+ // see: TIM_TimeBaseInit()
89+ pin_hw_cfg -> timer -> CR1 |= TIM_CounterMode_Up ;
90+ pin_hw_cfg -> timer -> ARR = TIM_PERIOD ;
91+
92+ // see: TIM_OC<N>Init() and TIM_OC<N>PreloadConfig()
93+ * pin_hw_cfg -> timer_ccmr |= TIM_OCMode_PWM1 << pin_hw_cfg -> timer_ccmr_shift ;
94+ pin_hw_cfg -> timer -> CCER |= (TIM_OCPolarity_High | TIM_OutputState_Enable )
95+ << pin_hw_cfg -> timer_ccer_shift ;
96+ * pin_hw_cfg -> timer_ccmr |= TIM_OCPreload_Enable << pin_hw_cfg -> timer_ccmr_shift ;
97+
98+ // enable timer peripheral Preload register on ARR and enable the timer
99+ // see: RCC_APB1PeriphClockCmd()
100+ pin_hw_cfg -> timer -> CR1 |= TIM_CR1_ARPE | TIM_CR1_CEN ;
64101}
65102
66- static void init_tim4 (bool ccr1 ) {
67- // enable the Low Speed APB (APB1) peripheral clock for TIM4
68- RCC -> APB1ENR |= RCC_APB1Periph_TIM4 ;
69-
70- // init TIM4 registers
71- TIM4 -> CR1 |= TIM_CounterMode_Up ;
72- TIM4 -> ARR = TIM_PERIOD ;
73-
74- if (ccr1 ) {
75- TIM4 -> CCMR1 |= TIM_OCMode_PWM1 ;
76- TIM4 -> CCER |= TIM_OCPolarity_High | TIM_OutputState_Enable ;
77- TIM4 -> CCMR1 |= TIM_OCPreload_Enable ;
78- } else {
79- TIM4 -> CCMR1 |= TIM_OCMode_PWM1 << 8 ;
80- TIM4 -> CCER |= TIM_OCPolarity_High << 4 | TIM_OutputState_Enable << 4 ;
81- TIM4 -> CCMR1 |= TIM_OCPreload_Enable << 8 ;
82- }
83-
84- // enable TIM4 peripheral Preload register on ARR and enable TIM4
85- TIM4 -> CR1 |= TIM_CR1_ARPE | TIM_CR1_CEN ;
103+ static void disable_dma_stream (const PinHwConfig * pin_hw_cfg ) {
104+ pin_hw_cfg -> dma_stream -> CR &= ~DMA_SxCR_EN ;
86105}
87106
88- static void disable_dma_stream ( DMA_Stream_TypeDef * dma_stream ) {
89- dma_stream -> CR &= ~ DMA_SxCR_EN ;
107+ static void enable_dma_stream ( const PinHwConfig * pin_hw_cfg ) {
108+ pin_hw_cfg -> dma_stream -> CR |= DMA_SxCR_EN ;
90109}
91110
92- static void enable_dma_stream (DMA_Stream_TypeDef * dma_stream ) {
93- dma_stream -> CR |= DMA_SxCR_EN ;
94- }
95-
96- // Only DMA_Stream0 and DMA_Stream3 supported as of now.
97- static void init_dma_stream (
98- DMA_Stream_TypeDef * dma_stream , uint16_t * buf , uint32_t buf_len , uint32_t ccr_address
99- ) {
111+ static void init_dma_stream (const PinHwConfig * pin_hw_cfg , uint16_t * buf , uint32_t buf_len ) {
100112 // enable the AHB1 peripheral clock for DMA1
113+ // see: RCC_AHB1PeriphClockCmd()
101114 RCC -> AHB1ENR |= RCC_AHB1Periph_DMA1 ;
102115
103- disable_dma_stream (dma_stream );
116+ // see: DMA_Init()
117+ disable_dma_stream (pin_hw_cfg );
104118
105- dma_stream -> M1AR = 0 ;
119+ pin_hw_cfg -> dma_stream -> M1AR = 0 ;
106120
107121 const uint32_t dma_stream0_it_mask =
108122 DMA_LISR_FEIF0 | DMA_LISR_DMEIF0 | DMA_LISR_TEIF0 | DMA_LISR_HTIF0 | DMA_LISR_TCIF0 ;
109- if (dma_stream == DMA1_Stream0 ) {
110- DMA1 -> LIFCR = dma_stream0_it_mask ;
111- } else {
112- DMA1 -> LIFCR = dma_stream0_it_mask << 22 ;
113- }
123+ DMA1 -> LIFCR = dma_stream0_it_mask << pin_hw_cfg -> dma_if_shift ;
114124
115- dma_stream -> CR = DMA_Channel_2 | DMA_DIR_MemoryToPeripheral | DMA_MemoryInc_Enable |
116- DMA_PeripheralDataSize_HalfWord | DMA_MemoryDataSize_HalfWord | DMA_Mode_Normal |
117- DMA_Priority_High | DMA_MemoryBurst_Single | DMA_PeripheralBurst_Single ;
125+ pin_hw_cfg -> dma_stream -> CR = pin_hw_cfg -> dma_channel | DMA_DIR_MemoryToPeripheral |
126+ DMA_MemoryInc_Enable | DMA_PeripheralDataSize_HalfWord | DMA_MemoryDataSize_HalfWord |
127+ DMA_Mode_Normal | DMA_Priority_High | DMA_MemoryBurst_Single | DMA_PeripheralBurst_Single ;
118128
119- dma_stream -> FCR = 0x00000020 | DMA_FIFOThreshold_Full ;
129+ pin_hw_cfg -> dma_stream -> FCR = 0x00000020 | DMA_FIFOThreshold_Full ;
120130
121- dma_stream -> M0AR = (uint32_t ) buf ;
122- dma_stream -> NDTR = buf_len ;
123- dma_stream -> PAR = ccr_address ;
131+ pin_hw_cfg -> dma_stream -> M0AR = (uint32_t ) buf ;
132+ pin_hw_cfg -> dma_stream -> NDTR = buf_len ;
133+ pin_hw_cfg -> dma_stream -> PAR = pin_hw_cfg -> ccr_address ;
124134
125- enable_dma_stream (dma_stream );
135+ enable_dma_stream (pin_hw_cfg );
126136}
127137
128- static void reset_dma_stream_transfer_complete (DMA_Stream_TypeDef * dma_stream ) {
129- if (dma_stream == DMA1_Stream0 ) {
130- DMA1 -> LIFCR |= DMA_LIFCR_CTCIF0 ;
131- } else if (dma_stream == DMA1_Stream3 ) {
132- DMA1 -> LIFCR |= DMA_LIFCR_CTCIF3 ;
133- }
138+ static void reset_dma_stream_transfer_complete (const PinHwConfig * pin_hw_cfg ) {
139+ DMA1 -> LIFCR |= DMA_LIFCR_CTCIF0 << pin_hw_cfg -> dma_if_shift ;
134140}
135141
136- static void disable_tim4_dma ( uint16_t dma_source ) {
137- TIM4 -> DIER &= ~dma_source ;
142+ static void disable_timer_dma ( const PinHwConfig * pin_hw_cfg ) {
143+ pin_hw_cfg -> timer -> DIER &= ~pin_hw_cfg -> dma_source ;
138144}
139145
140- static void enable_tim4_dma ( uint16_t dma_source ) {
141- TIM4 -> DIER |= dma_source ;
146+ static void enable_timer_dma ( const PinHwConfig * pin_hw_cfg ) {
147+ pin_hw_cfg -> timer -> DIER |= pin_hw_cfg -> dma_source ;
142148}
143149
144- static void init_hw (LedPin pin , LedPinConfig pin_config , uint16_t * buffer , uint32_t length ) {
145- PinHwConfig cfg = get_pin_hw_config ( pin );
146-
150+ static void init_hw (
151+ const PinHwConfig * cfg , LedPinConfig pin_config , uint16_t * buffer , uint32_t length
152+ ) {
147153 uint32_t pin_mode = PAL_MODE_ALTERNATE (2 ) | PAL_STM32_OSPEED_MID1 ;
148154 pin_mode |= pin_config == LED_PIN_CFG_PULLUP_TO_5V ? PAL_STM32_OTYPE_OPENDRAIN
149155 : PAL_STM32_OTYPE_PUSHPULL ;
150- VESC_IF -> set_pad_mode (GPIOB , cfg . pin_nr , pin_mode );
156+ VESC_IF -> set_pad_mode (cfg -> pin_port , cfg -> pin_nr , pin_mode );
151157
152- reset_tim4 ( );
153- init_dma_stream (cfg . dma_stream , buffer , length , cfg . ccr_address );
154- init_tim4 (cfg . ccr_address == ( uint32_t ) & TIM4 -> CCR1 );
155- enable_tim4_dma (cfg . dma_source );
158+ reset_timer ( cfg );
159+ init_dma_stream (cfg , buffer , length );
160+ init_timer (cfg );
161+ enable_timer_dma (cfg );
156162}
157163
158- static void deinit_hw (LedPin pin ) {
159- reset_tim4 ( );
160- disable_dma_stream (get_pin_hw_config ( pin ). dma_stream );
164+ static void deinit_hw (const PinHwConfig * cfg ) {
165+ reset_timer ( cfg );
166+ disable_dma_stream (cfg );
161167}
162168
163169inline static uint8_t color_order_bits (LedColorOrder order ) {
@@ -182,6 +188,12 @@ void led_driver_init(LedDriver *driver) {
182188bool led_driver_setup (
183189 LedDriver * driver , LedPin pin , LedPinConfig pin_config , const LedStrip * * led_strips
184190) {
191+ if (pin > LED_PIN_LAST ) {
192+ log_error ("Invalid LED pin configured: %u" , pin );
193+ return false;
194+ }
195+ driver -> pin_hw_config = & pin_hw_configs [pin ];
196+
185197 driver -> bitbuffer_length = 0 ;
186198
187199 size_t offsets [3 ] = {0 };
@@ -219,7 +231,7 @@ bool led_driver_setup(
219231 }
220232 driver -> bitbuffer [driver -> bitbuffer_length - 1 ] = 0 ;
221233
222- init_hw (pin , pin_config , driver -> bitbuffer , driver -> bitbuffer_length );
234+ init_hw (driver -> pin_hw_config , pin_config , driver -> bitbuffer , driver -> bitbuffer_length );
223235 return true;
224236}
225237
@@ -291,18 +303,18 @@ void led_driver_paint(LedDriver *driver) {
291303 }
292304 }
293305
294- PinHwConfig cfg = get_pin_hw_config ( driver -> pin ) ;
295- disable_tim4_dma (cfg . dma_source );
296- disable_dma_stream (cfg . dma_stream );
297- reset_dma_stream_transfer_complete (cfg . dma_stream );
298- enable_dma_stream (cfg . dma_stream );
299- enable_tim4_dma (cfg . dma_source );
306+ const PinHwConfig * cfg = driver -> pin_hw_config ;
307+ disable_timer_dma (cfg );
308+ disable_dma_stream (cfg );
309+ reset_dma_stream_transfer_complete (cfg );
310+ enable_dma_stream (cfg );
311+ enable_timer_dma (cfg );
300312}
301313
302314void led_driver_destroy (LedDriver * driver ) {
303315 if (driver -> bitbuffer ) {
304316 // only touch the timer/DMA if we inited it - something else could be using it
305- deinit_hw (driver -> pin );
317+ deinit_hw (driver -> pin_hw_config );
306318
307319 VESC_IF -> free (driver -> bitbuffer );
308320 driver -> bitbuffer = NULL ;
0 commit comments