diff --git a/application.c b/application.c index d8fab32..35a8371 100644 --- a/application.c +++ b/application.c @@ -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