add: add RGBW LED strip control

This commit is contained in:
King Kévin 2022-06-03 10:10:16 +02:00
parent beb6d33f85
commit 0250d81862
1 changed files with 197 additions and 0 deletions

View File

@ -102,6 +102,18 @@ static volatile uint32_t dial_steps = 0; /**< set to drv8825_steps when dial is
static uint8_t rgbmatrix_data[RGBMATRIX_HEIGHT / 2][RGBMATRIX_WIDTH * 2]; /**< data to be sent to RGB matrix (one byte includes upper and lower half values, each byte has 2 clock edges) */
#define RGBMATRIX_TIMER 3 /**< timer to update lines */
// RGBW LED strips
#define STRIP_TIMER 4 /**< timer used for the PWM */
#define STRIP_R_PIN PB9 /**< pin used to drive gate for red channel */
#define STRIP_R_CH 4 /**< channel used for the red channel */
#define STRIP_G_PIN PB8 /**< pin used to drive gate for green channel */
#define STRIP_G_CH 3 /**< channel used for the green channel */
#define STRIP_B_PIN PB7 /**< pin used to drive gate for blue channel */
#define STRIP_B_CH 2 /**< channel used for the blue channel */
#define STRIP_W_PIN PB6 /**< pin used to drive gate for white channel */
#define STRIP_W_CH 1 /**< channel used for the white channel */
#define STRIP_AF GPIO_AF2 /**< alternate function for pin to be used as timer channel */
/** set motor speed and direction
* @param[in] speed speed (in Hz) and direction (sign)
*/
@ -552,6 +564,88 @@ static void command_matrix(void* argument)
rgbmatrix_set(2, 3, false, false, true);
}
/** set intensity of LED strip
* @param[in] red red intensity (0-0xffff), -1 to leave
* @param[in] green green intensity (0-0xffff), -1 to leave
* @param[in] blue blue intensity (0-0xffff), -1 to leave
* @param[in] white white intensity (0-0xffff), -1 to leave
*/
static void strip_rgbw(int32_t red, int32_t green, int32_t blue, int32_t white)
{
if (red >= 0 && red <= 0xffff) {
timer_set_oc_value(TIM(STRIP_TIMER), TIM_OC(STRIP_R_CH), red);
}
if (green >= 0 && green <= 0xffff) {
timer_set_oc_value(TIM(STRIP_TIMER), TIM_OC(STRIP_G_CH), green);
}
if (blue >= 0 && blue <= 0xffff) {
timer_set_oc_value(TIM(STRIP_TIMER), TIM_OC(STRIP_B_CH), blue);
}
if (white >= 0 && white <= 0xffff) {
timer_set_oc_value(TIM(STRIP_TIMER), TIM_OC(STRIP_W_CH), white);
}
}
static void command_strip_red(void* argument)
{
if (!argument) {
printf("argument required\n");
return;
}
uint16_t set = *(uint32_t*)argument; // get provide value
if (set > 100) {
set = 100; // enforce maximum
}
strip_rgbw(0xffff * set / 100, -1, -1, -1); // set light intensity
printf("red channel set to %u%%\n", set);
}
static void command_strip_green(void* argument)
{
if (!argument) {
printf("argument required\n");
return;
}
uint16_t set = *(uint32_t*)argument; // get provide value
if (set > 100) {
set = 100; // enforce maximum
}
strip_rgbw(-1, 0xffff * set / 100, -1, -1); // set light intensity
printf("green channel set to %u%%\n", set);
}
static void command_strip_blue(void* argument)
{
if (!argument) {
printf("argument required\n");
return;
}
uint16_t set = *(uint32_t*)argument; // get provide value
if (set > 100) {
set = 100; // enforce maximum
}
strip_rgbw(-1, -1, 0xffff * set / 100, -1); // set light intensity
printf("blue channel set to %u%%\n", set);
}
static void command_strip_white(void* argument)
{
if (!argument) {
printf("argument required\n");
return;
}
uint16_t set = *(uint32_t*)argument; // get provide value
if (set > 100) {
set = 100; // enforce maximum
}
strip_rgbw(-1, -1, -1, 0xffff * set / 100); // set light intensity
printf("white channel set to %u%%\n", set);
}
/** list of all supported commands */
static const struct menu_command_t menu_commands[] = {
{
@ -634,6 +728,38 @@ static const struct menu_command_t menu_commands[] = {
.argument_description = NULL,
.command_handler = &command_matrix,
},
{
.shortcut = 'r',
.name = "strip_red",
.command_description = "set LED strip red intensity",
.argument = MENU_ARGUMENT_UNSIGNED,
.argument_description = "%",
.command_handler = &command_strip_red,
},
{
.shortcut = 'g',
.name = "strip_green",
.command_description = "set LED strip green intensity",
.argument = MENU_ARGUMENT_UNSIGNED,
.argument_description = "%",
.command_handler = &command_strip_green,
},
{
.shortcut = 'b',
.name = "strip_blue",
.command_description = "set LED strip blue intensity",
.argument = MENU_ARGUMENT_UNSIGNED,
.argument_description = "%",
.command_handler = &command_strip_blue,
},
{
.shortcut = 'w',
.name = "strip_white",
.command_description = "set LED strip white intensity",
.argument = MENU_ARGUMENT_UNSIGNED,
.argument_description = "%",
.command_handler = &command_strip_white,
},
};
static void command_help(void* argument)
@ -865,6 +991,76 @@ void main(void)
puts_debug("OK\n");
// setup LED strips
puts_debug("setup RGBW LED strips: ");
// configure pins
// red channel
rcc_periph_clock_enable(GPIO_RCC(STRIP_R_PIN)); // enable clock for GPIO port peripheral
gpio_clear(GPIO_PORT(STRIP_R_PIN), GPIO_PIN(STRIP_R_PIN)); // switch off light
gpio_set_output_options(GPIO_PORT(STRIP_R_PIN), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN(STRIP_R_PIN)); // set slow edge
gpio_set_af(GPIO_PORT(STRIP_R_PIN), STRIP_AF, GPIO_PIN(STRIP_R_PIN)); // set alternate function to
gpio_mode_setup(GPIO_PORT(STRIP_R_PIN), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(STRIP_R_PIN)); // set pin to alternate timer channel
// green channel
rcc_periph_clock_enable(GPIO_RCC(STRIP_G_PIN)); // enable clock for GPIO port peripheral
gpio_clear(GPIO_PORT(STRIP_G_PIN), GPIO_PIN(STRIP_G_PIN)); // switch off light
gpio_set_output_options(GPIO_PORT(STRIP_G_PIN), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN(STRIP_G_PIN)); // set slow edge
gpio_set_af(GPIO_PORT(STRIP_G_PIN), STRIP_AF, GPIO_PIN(STRIP_G_PIN)); // set alternate function to
gpio_mode_setup(GPIO_PORT(STRIP_G_PIN), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(STRIP_G_PIN)); // set pin as output
// blue channel
rcc_periph_clock_enable(GPIO_RCC(STRIP_B_PIN)); // enable clock for GPIO port peripheral
gpio_clear(GPIO_PORT(STRIP_B_PIN), GPIO_PIN(STRIP_B_PIN)); // switch off light
gpio_set_output_options(GPIO_PORT(STRIP_B_PIN), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN(STRIP_B_PIN)); // set slow edge
gpio_set_af(GPIO_PORT(STRIP_B_PIN), STRIP_AF, GPIO_PIN(STRIP_B_PIN)); // set alternate function to
gpio_mode_setup(GPIO_PORT(STRIP_B_PIN), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(STRIP_B_PIN)); // set pin as output
// white channel
rcc_periph_clock_enable(GPIO_RCC(STRIP_W_PIN)); // enable clock for GPIO port peripheral
gpio_clear(GPIO_PORT(STRIP_W_PIN), GPIO_PIN(STRIP_W_PIN)); // switch off light
gpio_set_output_options(GPIO_PORT(STRIP_W_PIN), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN(STRIP_W_PIN)); // set slow edge
gpio_set_af(GPIO_PORT(STRIP_W_PIN), STRIP_AF, GPIO_PIN(STRIP_W_PIN)); // set alternate function to
gpio_mode_setup(GPIO_PORT(STRIP_W_PIN), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(STRIP_W_PIN)); // set pin as output
// configure timer to generate PWM
rcc_periph_clock_enable(RCC_TIM(STRIP_TIMER)); // enable clock for timer peripheral
rcc_periph_reset_pulse(RST_TIM(STRIP_TIMER)); // reset timer state
timer_disable_counter(TIM(STRIP_TIMER)); // disable timer to configure it
timer_set_mode(TIM(STRIP_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler(TIM(STRIP_TIMER), 10 - 1); // set presecaler for fast enough for LED PWM and less stress on MOSFET gate ( (84E6/(10 * 2**16))=1281 Hz )
// red channel
timer_set_oc_mode(TIM(STRIP_TIMER), TIM_OC(STRIP_R_CH), TIM_OCM_PWM1); // set output to PWM mode
timer_enable_oc_output(TIM(STRIP_TIMER), TIM_OC(STRIP_R_CH)); // enable PWM output
timer_set_oc_value(TIM(STRIP_TIMER), TIM_OC(STRIP_R_CH), 0); // disable light
// green channel
timer_set_oc_mode(TIM(STRIP_TIMER), TIM_OC(STRIP_G_CH), TIM_OCM_PWM1); // set output to PWM mode
timer_enable_oc_output(TIM(STRIP_TIMER), TIM_OC(STRIP_G_CH)); // enable PWM output
timer_set_oc_value(TIM(STRIP_TIMER), TIM_OC(STRIP_G_CH), 0); // disable light
// blue channel
timer_set_oc_mode(TIM(STRIP_TIMER), TIM_OC(STRIP_B_CH), TIM_OCM_PWM1); // set output to PWM mode
timer_enable_oc_output(TIM(STRIP_TIMER), TIM_OC(STRIP_B_CH)); // enable PWM output
timer_set_oc_value(TIM(STRIP_TIMER), TIM_OC(STRIP_B_CH), 0); // disable light
// white channel
timer_set_oc_mode(TIM(STRIP_TIMER), TIM_OC(STRIP_W_CH), TIM_OCM_PWM1); // set output to PWM mode
timer_enable_oc_output(TIM(STRIP_TIMER), TIM_OC(STRIP_W_CH)); // enable PWM output
timer_set_oc_value(TIM(STRIP_TIMER), TIM_OC(STRIP_W_CH), 0); // disable light
timer_enable_counter(TIM(STRIP_TIMER)); // enable timer to generate PWM
/*
// use comparator to time signal (without using the output), starting at slot start
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC1IF); // clear flag
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC1, 1 * (rcc_ahb_frequency / 1000000) - 1); // use compare function to time master pulling low when reading (1 < Tlowr < 15)
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC2IF); // clear flag
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC2, 7 * (rcc_ahb_frequency / 1000000) - 1); // use compare function to read or write 0 or 1 (1 < Trw < 15)
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC3IF); // clear flag
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC3, 62 * (rcc_ahb_frequency / 1000000) - 1); // use compare function to end time slot (60 < Tslot < 120), this will be followed by a recovery time (end of timer)
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_CC4IF); // clear flag
timer_set_oc_value(TIM(ONEWIRE_MASTER_TIMER), TIM_OC4, (70 - 10) * (rcc_ahb_frequency / 1000000) - 1); // use compare function to detect slave presence (15 < Tpdh < 60 + 60 < Tpdl < 240), with hand tuning
timer_clear_flag(TIM(ONEWIRE_MASTER_TIMER), TIM_SR_UIF); // clear update (overflow) flag
timer_update_on_overflow(TIM(ONEWIRE_MASTER_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout)
timer_enable_irq(TIM(ONEWIRE_MASTER_TIMER), TIM_DIER_UIE); // enable update interrupt for overflow
*/
puts_debug("OK\n");
// setup terminal
terminal_prefix = ""; // set default prefix
terminal_process = &process_command; // set central function to process commands
@ -904,6 +1100,7 @@ void main(void)
} else {
scroll_pos -= 1;
}
strip_rgbw(0, 0, 0, (64 - scroll_pos) * 100);
}
if (second_flag) { // one second passed
second_flag = false; // clear flag