diff --git a/application.c b/application.c index 19453eb..bd629e0 100644 --- a/application.c +++ b/application.c @@ -35,8 +35,9 @@ #include "terminal.h" // handle the terminal interface #include "menu.h" // menu utilities #include "font.h" // to draw text -#include "radio_esp8266.h" // to receive ARTnet +#include "led_rgbpanel.h" // to control RGB panels #include "led_ws2812b.h" // control WS2812b LEDs +#include "radio_esp8266.h" // to receive ARTnet /** watchdog period in ms */ #define WATCHDOG_PERIOD 10000 @@ -79,32 +80,6 @@ static bool drv8825_reached = false; /**< set when the goal is reached */ #define DIAL_MIDNIGHT_STEPS 6557U /**< number of steps after dial detection for dials to show midnight */ static volatile uint32_t dial_steps = 0; /**< set to drv8825_steps when dial is nearby */ -// RGB matrix pins -#define RGBMATRIX_OE_PIN PB10 /**< pin to enable output (active low) */ -#define RGBMATRIX_A_PIN PB0 /**< pin to select line */ -#define RGBMATRIX_B_PIN PB1 /**< pin to select line */ -#define RGBMATRIX_C_PIN PB2 /**< pin to select line */ -#define RGBMATRIX_D_PIN PB3 /**< pin to select line */ -#define RGBMATRIX_CLK_PIN PA0 /**< pin to generate clock for serial data */ -#define RGBMATRIX_LAT_PIN PA1 /**< pin to latch data on rising edge */ -#define RGBMATRIX_R1_PIN PA2 /**< pin to enable red color on top half */ -#define RGBMATRIX_G1_PIN PA3 /**< pin to enable green color on top half */ -#define RGBMATRIX_B1_PIN PA4 /**< pin to enable blue color on top half */ -#define RGBMATRIX_R2_PIN PA5 /**< pin to enable red color on bottom half */ -#define RGBMATRIX_G2_PIN PA6 /**< pin to enable green color on bottom half */ -#define RGBMATRIX_B2_PIN PA7 /**< pin to enable blue color on bottom half */ - -#define RGBMATRIX_DMA DMA2 /**< DMA used to send data to the RGB matrix (only DMA2 can be used for memory-to-memory transfer) */ -#define RGBMATRIX_RCC_DMA RCC_DMA2 /**< RCC for DMA used for the RGB matrix */ -#define RGBMATRIX_STREAM DMA_STREAM1 /**< stream used to send data to the RGB matrix (any stream can be used for memory-to-memory transfer) */ -#define RGBMATRIX_CHANNEL DMA_SxCR_CHSEL_0 /**< channel used to send data to the RGB matrix (any channel can be used for memory-to-memory transfer) */ -#define RGBMATRIX_IRQ NVIC_DMA2_STREAM1_IRQ /**< IRQ for when a line transfer is complete */ -#define RGBMATRIX_ISR dma2_stream1_isr /**< ISR for when a line transfer is complete */ -#define RGBMATRIX_HEIGHT 32 /**< number of rows in the RGB matrix */ -#define RGBMATRIX_WIDTH 64 /**< number of columns in the RGB matrix */ -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 */ - #define WSMATRIX_HEIGHT (2 * 8) /**< WS2812b panel height, in pixels */ #define WSMATRIX_WIDTH 32 /**< WS2812b panel width, in pixels */ @@ -149,18 +124,6 @@ static void drv8825_speed(int16_t speed) } } -/** switch off all LEDs on the RGB matrix */ -static void rgbmatrix_clear(void) -{ - for (uint8_t i = 0; i < LENGTH(rgbmatrix_data); i++) { // for each line - for (uint8_t j = 0; j < LENGTH(rgbmatrix_data[0]); j += 2) { // for each clock cycle - rgbmatrix_data[i][j + 0] = 0; // create clock falling edge - rgbmatrix_data[i][j + 1] = 1; // create clock rising edge - } - rgbmatrix_data[i][LENGTH(rgbmatrix_data[0]) - 1] |= (1 << 1); // latch data (next line will remove the latch) - } -} - /** set color of the LED on the RGB matrix or WS2812b panel * @param[in] ws false to display on RGB matrix, true on WS2812b panel * @param[in] x horizontal position (0 = left) @@ -171,10 +134,10 @@ static void rgbmatrix_clear(void) */ static void matrix_set(bool ws, int16_t x, int16_t y, bool r, bool g, bool b) { - if (x < 0 || x >= (ws ? WSMATRIX_WIDTH : RGBMATRIX_WIDTH)) { + if (x < 0 || x >= (ws ? WSMATRIX_WIDTH : RGBPANEL_WIDTH)) { return; } - if (y < 0 || y >= (ws ? WSMATRIX_HEIGHT : RGBMATRIX_HEIGHT)) { + if (y < 0 || y >= (ws ? WSMATRIX_HEIGHT : RGBPANEL_HEIGHT)) { return; } if (ws) { @@ -198,38 +161,7 @@ static void matrix_set(bool ws, int16_t x, int16_t y, bool r, bool g, bool b) } led_ws2812b_set_rgb(col * (WSMATRIX_HEIGHT / 2U) + row, g * WSMATRIX_BRIGHTNESS, r * WSMATRIX_BRIGHTNESS, b * WSMATRIX_BRIGHTNESS); } else { - const uint8_t row = y % (RGBMATRIX_HEIGHT / 2); // get the actual line/row - const uint8_t col = x * 2; // get the actual column - uint8_t data = 0; // there we will set the color bits - if (y < (RGBMATRIX_HEIGHT / 2)) { - data = rgbmatrix_data[row][col] & 0xe0; // keep lower line colors - if (r) { - data |= (1 << 2); - } - if (g) { - data |= (1 << 3); - } - if (b) { - data |= (1 << 4); - } - } else { - data = rgbmatrix_data[row][col] & 0x1c; // keep upper line colors - if (r) { - data |= (1 << 5); - } - if (g) { - data |= (1 << 6); - } - if (b) { - data |= (1 << 7); - } - } - // set data on low edge - rgbmatrix_data[row][col + 0] &= 0x3; // clear color data (don't touch clock and latch data) - rgbmatrix_data[row][col + 0] |= data; // set the LED data - // set data on high edge - rgbmatrix_data[row][col + 1] &= 0x3; // clear color data (don't touch clock and latch data) - rgbmatrix_data[row][col + 1] |= data; // set the LED data on clock high edge + rgbpanel_set(x, y, r, g, b); // set LED color } } @@ -252,10 +184,10 @@ static void matrix_putc(bool ws, int16_t x, int16_t y, char c, enum font_name fo if (c < ' ' || c > '~') { return; } - if (x + fonts[font].width < 0 || x >= (ws ? WSMATRIX_WIDTH : RGBMATRIX_WIDTH)) { + if (x + fonts[font].width < 0 || x >= (ws ? WSMATRIX_WIDTH : RGBPANEL_WIDTH)) { return; } - if (y + fonts[font].height < 0 || y >= (ws ? WSMATRIX_HEIGHT : RGBMATRIX_HEIGHT)) { + if (y + fonts[font].height < 0 || y >= (ws ? WSMATRIX_HEIGHT : RGBPANEL_HEIGHT)) { return; } @@ -292,13 +224,13 @@ static void matrix_puts(bool ws, int16_t x, int16_t y, const char* str, enum fon if (font >= FONT_MAX) { return; } - if (y + fonts[font].height < 0 || y >= (ws ? WSMATRIX_HEIGHT : RGBMATRIX_HEIGHT)) { + if (y + fonts[font].height < 0 || y >= (ws ? WSMATRIX_HEIGHT : RGBPANEL_HEIGHT)) { return; } const uint8_t len = strlen(str); for (uint8_t i = 0; i < len; i++) { - if (x >= (ws ? WSMATRIX_WIDTH : RGBMATRIX_WIDTH)) { + if (x >= (ws ? WSMATRIX_WIDTH : RGBPANEL_WIDTH)) { return; } if (x + fonts[font].width >= 0) { @@ -986,56 +918,7 @@ void main(void) puts_debug("OK\n"); puts_debug("setup RGB matrix: "); - // configure pin for output enable - rcc_periph_clock_enable(GPIO_RCC(RGBMATRIX_OE_PIN)); // enable clock for GPIO port peripheral - gpio_set(GPIO_PORT(RGBMATRIX_OE_PIN), GPIO_PIN(RGBMATRIX_OE_PIN)); // disable output - gpio_set_output_options(GPIO_PORT(RGBMATRIX_OE_PIN), GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN(RGBMATRIX_OE_PIN)); // set fast edge - gpio_mode_setup(GPIO_PORT(RGBMATRIX_OE_PIN), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(RGBMATRIX_OE_PIN)); // set pin as output - // configure pins for data and clock lines - const uint32_t rgbmatrix_serial_port = GPIO_PORT(RGBMATRIX_LAT_PIN); // common port for pins controlling the serial data - const uint16_t rgbmatrix_serial_pins = GPIO_PIN(RGBMATRIX_LAT_PIN) | GPIO_PIN(RGBMATRIX_CLK_PIN) | GPIO_PIN(RGBMATRIX_R1_PIN) | GPIO_PIN(RGBMATRIX_G1_PIN) | GPIO_PIN(RGBMATRIX_B1_PIN) | GPIO_PIN(RGBMATRIX_R2_PIN) | GPIO_PIN(RGBMATRIX_G2_PIN) | GPIO_PIN(RGBMATRIX_B2_PIN); // pins controlling the serial data - rcc_periph_clock_enable(GPIO_RCC(RGBMATRIX_LAT_PIN)); // enable clock for GPIO port peripheral - gpio_clear(rgbmatrix_serial_port, rgbmatrix_serial_pins); // disable LEDs - gpio_set_output_options(rgbmatrix_serial_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, rgbmatrix_serial_pins); // set fast edge - gpio_mode_setup(rgbmatrix_serial_port, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, rgbmatrix_serial_pins); // set pin as output - // configure pins for address lines - rcc_periph_clock_enable(RCC_GPIOB); // enable clock for GPIO port peripheral - gpio_clear(RCC_GPIOB, GPIO0 | GPIO1 | GPIO2 | GPIO3); // unselect line - gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO0 | GPIO1 | GPIO2 | GPIO3); // set fast edge - gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0 | GPIO1 | GPIO2 | GPIO3); // set pin as output - // configure DMA to sent line data - // because there is no peripheral request for data, this is a memory to memory transfer - rcc_periph_clock_enable(RGBMATRIX_RCC_DMA); // enable clock for DMA peripheral (any DMA and channel can be used) - dma_disable_stream(RGBMATRIX_DMA, RGBMATRIX_STREAM); // disable stream before re-configuring - while (DMA_SCR(RGBMATRIX_DMA, RGBMATRIX_STREAM) & DMA_SxCR_EN); // wait until transfer is finished before we can reconfigure - dma_stream_reset(RGBMATRIX_DMA, RGBMATRIX_STREAM); // use default values - //dma_set_peripheral_address(RGBMATRIX_DMA, RGBMATRIX_STREAM, (uint32_t)&rgbmatrix_data[0]); // set memory to read from (for memory-to-memory transfer, the source is the peripheral) - dma_set_peripheral_size(RGBMATRIX_DMA, RGBMATRIX_STREAM, DMA_SxCR_PSIZE_8BIT); // we only write the 8 first bit - dma_enable_peripheral_increment_mode(RGBMATRIX_DMA, RGBMATRIX_STREAM); // increment address of memory to read - dma_set_memory_address(RGBMATRIX_DMA, RGBMATRIX_STREAM, (uint32_t) &GPIOA_ODR); // set GPIOA as destination (for memory-to-memory transfer, the destination is the memory) - dma_set_memory_size(RGBMATRIX_DMA, RGBMATRIX_STREAM, DMA_SxCR_MSIZE_8BIT); // read 8 bits for transfer - dma_disable_memory_increment_mode(RGBMATRIX_DMA, RGBMATRIX_STREAM); // don't increment GPIO address - dma_set_number_of_data(RGBMATRIX_DMA, RGBMATRIX_STREAM, LENGTH(rgbmatrix_data[0])); // set transfer size (one line) - dma_channel_select(RGBMATRIX_DMA, RGBMATRIX_STREAM, RGBMATRIX_CHANNEL); // set the channel for this stream - dma_set_transfer_mode(RGBMATRIX_DMA, RGBMATRIX_STREAM, DMA_SxCR_DIR_MEM_TO_MEM); // set transfer from memory to memory - dma_set_priority(RGBMATRIX_DMA, RGBMATRIX_STREAM, DMA_SxCR_PL_LOW); // there is no need to rush - dma_enable_transfer_complete_interrupt(RGBMATRIX_DMA, RGBMATRIX_STREAM); // interrupt when line transfer is complete - nvic_enable_irq(RGBMATRIX_IRQ); // enable interrupt - rgbmatrix_clear(); // clear matrix - gpio_clear(GPIO_PORT(RGBMATRIX_OE_PIN), GPIO_PIN(RGBMATRIX_OE_PIN)); // enable output - - // configure timer to go through rows/lines - rcc_periph_clock_enable(RCC_TIM(RGBMATRIX_TIMER)); // enable clock for timer domain - rcc_periph_reset_pulse(RST_TIM(RGBMATRIX_TIMER)); // reset timer state - timer_set_mode(TIM(RGBMATRIX_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(RGBMATRIX_TIMER), 2 - 1); // hand tuned prescale to minimize inter-line ghosting - timer_set_period(TIM(RGBMATRIX_TIMER), 0x9fff - 1); // hand tuned period to minimize inter-line ghosting - timer_clear_flag(TIM(RGBMATRIX_TIMER), TIM_SR_UIF); // clear update (overflow) flag - timer_update_on_overflow(TIM(RGBMATRIX_TIMER)); // only use counter overflow as UEV source (use overflow as next line update indication) - timer_enable_irq(TIM(RGBMATRIX_TIMER), TIM_DIER_UIE); // enable update interrupt for timer - nvic_enable_irq(NVIC_TIM_IRQ(RGBMATRIX_TIMER)); // catch interrupt in service routine - timer_enable_counter(TIM(RGBMATRIX_TIMER)); // start timer to update RGB matrix - + rgbpanel_setup(); puts_debug("OK\n"); // setup LED strips @@ -1136,7 +1019,7 @@ void main(void) } if (wakeup_flag) { // time to do periodic checks wakeup_flag = false; // clear flag - rgbmatrix_clear(); + rgbpanel_clear(); matrix_puts(false, scroll_pos, 8, scroll_text, FONT_KING14, true, true, true); if (scroll_pos < -1 * (int16_t)strlen(scroll_text) * (fonts[FONT_KING14].width + 1)) { scroll_pos = 64; @@ -1280,7 +1163,7 @@ void TIM_ISR(DRV8825_STEP_TIMER)(void) void GPIO_EXTI_ISR(DIAL_SWITCH_PIN)(void) { exti_reset_request(GPIO_EXTI(DIAL_SWITCH_PIN)); // reset interrupt - // I don't know why, but the RGBMATRIX_ISR does trigger this EXTI + // I don't know why, but the RGBPANEL_ISR does trigger this EXTI if (gpio_get(GPIO_PORT(DIAL_SWITCH_PIN), GPIO_PIN(DIAL_SWITCH_PIN))) { // be sure the pin is actually low return; } @@ -1290,32 +1173,3 @@ void GPIO_EXTI_ISR(DIAL_SWITCH_PIN)(void) } } -static volatile uint8_t rgbmatrix_line = 0; // line being transferred - -/** ISR triggered when the data for the line of the RGB matrix has been transferred - * we switch line just after the data is latched, to reduce ghosting - */ -void RGBMATRIX_ISR(void) -{ - if (dma_get_interrupt_flag(RGBMATRIX_DMA, RGBMATRIX_STREAM, DMA_TCIF)) { - dma_clear_interrupt_flags(RGBMATRIX_DMA, RGBMATRIX_STREAM, DMA_TCIF); - GPIOB_ODR = (GPIOB_ODR & 0xfff0) | (rgbmatrix_line & 0xf); // select line (line on lower and upper half are updated at once) - rgbmatrix_line = (rgbmatrix_line + 1) % (RGBMATRIX_HEIGHT / 2); // go to next line (two lines are updated at once) - } -} - -/** interrupt service routine called to update next line of RGB matrix - * @note ideally the next line should be updated when the current one is complete, but the DMA is too fast. - * @note switching lines too fast causes inter-line ghosting of the LEDs (on the same column), due to capacitance and driver switching limitations - */ -void TIM_ISR(RGBMATRIX_TIMER)(void) -{ - if (timer_get_flag(TIM(RGBMATRIX_TIMER), TIM_SR_UIF)) { // update event happened - timer_clear_flag(TIM(RGBMATRIX_TIMER), TIM_SR_UIF); // clear flag - if (DMA_SCR(RGBMATRIX_DMA, RGBMATRIX_STREAM) & DMA_SxCR_EN) { // DMA is not complete - return; - } - dma_set_peripheral_address(RGBMATRIX_DMA, RGBMATRIX_STREAM, (uint32_t)&rgbmatrix_data[rgbmatrix_line]); // set memory containing line data to be transferred (for memory-to-memory transfer, the source is the peripheral) - dma_enable_stream(RGBMATRIX_DMA, RGBMATRIX_STREAM); // start sending next line - } -}