Skip to content

Commit 79b1bbb

Browse files
committed
LEDs: Add support for JetFleet F6 v1 AUX pin (C9)
Feature: Add support for driving LEDs via the JetFleet F6 v1 AUX pin (C9)
1 parent 972ba0b commit 79b1bbb

4 files changed

Lines changed: 138 additions & 104 deletions

File tree

src/conf/datatypes.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ typedef enum {
4242

4343
typedef enum {
4444
LED_PIN_B6 = 0,
45-
LED_PIN_B7
45+
LED_PIN_B7,
46+
LED_PIN_C9,
47+
LED_PIN_LAST = LED_PIN_C9
4648
} LedPin;
4749

4850
typedef enum {

src/conf/settings.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3611,7 +3611,8 @@ p, li { white-space: pre-wrap; }
36113611
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The pin to which the LEDs are connected on the VESC.</p>
36123612
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
36133613
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PPM/Servo pin: Little FOCer v3.x, Tronic 250R, Ubox V2 75V/100V (pin B6)</li>
3614-
<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dedicated LED pin: Little FOCer v4.x, Thor 300 (pin B7)</li></ul>
3614+
<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dedicated LED pin: Little FOCer v4.x, Thor 300/301/400 (pin B7)</li></ul>
3615+
<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">JetFleet F6 v1 AUX pin (pin C9)</li></ul>
36153616
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
36163617
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Board restart required for changes to take effect.</p>
36173618
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
@@ -3620,6 +3621,7 @@ p, li { white-space: pre-wrap; }
36203621
<valInt>1</valInt>
36213622
<enumNames>PPM/Servo pin</enumNames>
36223623
<enumNames>Dedicated LED pin</enumNames>
3624+
<enumNames>JetFleet F6 v1 pin</enumNames>
36233625
</hardware.leds.pin>
36243626
<hardware.leds.pin_config>
36253627
<longName>LED Pin Configuration</longName>

src/led_driver.c

Lines changed: 114 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
#include "led_driver.h"
2020

21-
#include "st_types.h"
22-
2321
#include "utils.h"
2422

2523
#include "vesc_c_if.h"
@@ -31,133 +29,141 @@
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

163169
inline static uint8_t color_order_bits(LedColorOrder order) {
@@ -182,6 +188,12 @@ void led_driver_init(LedDriver *driver) {
182188
bool 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

302314
void 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;

src/led_driver.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,31 @@
2121
#include "conf/datatypes.h"
2222
#include "led_strip.h"
2323

24+
#include "st_types.h"
25+
2426
#include <stdbool.h>
2527
#include <stdint.h>
2628

29+
typedef struct {
30+
void *pin_port;
31+
TIM_TypeDef *timer;
32+
uint32_t ccr_address;
33+
uint32_t rcc_apb1_periph;
34+
volatile uint32_t *timer_ccmr;
35+
DMA_Stream_TypeDef *dma_stream;
36+
uint32_t dma_channel;
37+
uint16_t dma_source;
38+
uint8_t dma_if_shift;
39+
uint8_t timer_ccmr_shift;
40+
uint8_t timer_ccer_shift;
41+
uint8_t pin_nr;
42+
} PinHwConfig;
43+
2744
typedef struct {
2845
uint16_t *bitbuffer;
2946
uint32_t bitbuffer_length;
3047
LedPin pin;
48+
const PinHwConfig *pin_hw_config;
3149
const LedStrip *strips[STRIP_COUNT];
3250
uint16_t *strip_bitbuffs[STRIP_COUNT];
3351
} LedDriver;

0 commit comments

Comments
 (0)