app: improve/fix RGB panel control
This commit is contained in:
parent
884f007d19
commit
34d44c2a88
@ -2,7 +2,7 @@
|
||||
* @file
|
||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* @date 2016-2021
|
||||
* @date 2016-2022
|
||||
*/
|
||||
|
||||
/* standard libraries */
|
||||
@ -77,21 +77,28 @@ static volatile uint32_t dial_steps = 0; /**< set to drv8825_steps when dial is
|
||||
|
||||
// RGB matrix pins
|
||||
#define RGBMATRIX_OE_PIN PB10 /**< pin to enable output (active low) */
|
||||
// A-B: PB0-PB3
|
||||
// CLK: PA0
|
||||
// LAT: PA1
|
||||
// RGB1: PA2-PA4
|
||||
// RGB2: PA5-PA7
|
||||
#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 2 /**< number of rows in the RGB matrix */
|
||||
#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 (encodes the PA values) */
|
||||
static volatile uint8_t rgbmatrix_line = 0; /**< line currently being displayed */
|
||||
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) */
|
||||
|
||||
/** set motor speed and direction
|
||||
* @param[in] speed speed (in Hz) and direction (sign)
|
||||
@ -120,26 +127,16 @@ static void drv8825_speed(int16_t speed)
|
||||
}
|
||||
}
|
||||
|
||||
/** transfer all data to RGB matrix */
|
||||
static void rgbmatrix_update(void)
|
||||
{
|
||||
while (DMA_SCR(RGBMATRIX_DMA, RGBMATRIX_STREAM) & DMA_SxCR_EN); // wait until current transfer is finished
|
||||
rgbmatrix_line = 0; // restart from line 0
|
||||
dma_enable_stream(RGBMATRIX_DMA, RGBMATRIX_STREAM); // start sending line (the ISR will send the others)
|
||||
}
|
||||
|
||||
/** 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] = 1; // clock rising edge
|
||||
rgbmatrix_data[i][j + 1] = 0; // clock falling edge
|
||||
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]) - 2] |= (1 << 1); // latch data (if will also latch the current data, but we don't do it here because write RGB value would remove this latch information)
|
||||
rgbmatrix_data[i][LENGTH(rgbmatrix_data[0]) - 1] |= (1 << 1); // latch data (next line will remove the latch)
|
||||
}
|
||||
rgbmatrix_update(); // send data to matrix
|
||||
}
|
||||
|
||||
/** set color of the LED on the RGB matrix
|
||||
@ -158,8 +155,11 @@ static void rgbmatrix_set(uint8_t x, uint8_t y, bool r, bool g, bool b)
|
||||
if (y >= RGBMATRIX_HEIGHT) {
|
||||
return;
|
||||
}
|
||||
uint8_t data = 0x1; // set clock high
|
||||
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);
|
||||
}
|
||||
@ -170,6 +170,7 @@ static void rgbmatrix_set(uint8_t x, uint8_t y, bool r, bool g, bool b)
|
||||
data |= (1 << 4);
|
||||
}
|
||||
} else {
|
||||
data = rgbmatrix_data[row][col] & 0x1c; // keep upper line colors
|
||||
if (r) {
|
||||
data |= (1 << 5);
|
||||
}
|
||||
@ -180,7 +181,12 @@ static void rgbmatrix_set(uint8_t x, uint8_t y, bool r, bool g, bool b)
|
||||
data |= (1 << 7);
|
||||
}
|
||||
}
|
||||
rgbmatrix_data[y % LENGTH(rgbmatrix_data)][x * 2] = data; // set the LED data
|
||||
// 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
|
||||
}
|
||||
|
||||
size_t putc(char c)
|
||||
@ -569,7 +575,7 @@ static void command_help(void* argument)
|
||||
static void process_command(char* str)
|
||||
{
|
||||
// ensure actions are available
|
||||
if (NULL == menu_commands || 0 == LENGTH(menu_commands)) {
|
||||
if (0 == LENGTH(menu_commands)) {
|
||||
return;
|
||||
}
|
||||
// don't handle empty lines
|
||||
@ -739,10 +745,12 @@ void main(void)
|
||||
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
|
||||
rcc_periph_clock_enable(RCC_GPIOA); // enable clock for GPIO port peripheral
|
||||
gpio_clear(RCC_GPIOA, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO4 | GPIO5 | GPIO6 | GPIO7); // disable LEDs
|
||||
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO4 | GPIO5 | GPIO6 | GPIO7); // set fast edge
|
||||
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO4 | GPIO5 | GPIO6 | GPIO7); // set pin as output
|
||||
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
|
||||
@ -768,6 +776,7 @@ void main(void)
|
||||
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
|
||||
dma_enable_stream(RGBMATRIX_DMA, RGBMATRIX_STREAM); // start DMA to continuously send data
|
||||
puts_debug("OK\n");
|
||||
|
||||
// setup terminal
|
||||
@ -799,11 +808,10 @@ void main(void)
|
||||
if (second_flag) { // one second passed
|
||||
second_flag = false; // clear flag
|
||||
led_toggle(); // toggle LED to indicate if main function is stuck
|
||||
rgbmatrix_set(matrix_led % RGBMATRIX_WIDTH, 1, false, false, false);
|
||||
matrix_led++;
|
||||
GPIOB_ODR = (GPIOB_ODR & 0xfff0) + ((matrix_led / RGBMATRIX_WIDTH) % RGBMATRIX_HEIGHT);
|
||||
rgbmatrix_set(matrix_led % RGBMATRIX_WIDTH, 1, true, false, false);
|
||||
rgbmatrix_update(); // send data to matrix
|
||||
rgbmatrix_set(matrix_led % RGBMATRIX_WIDTH, matrix_led / RGBMATRIX_WIDTH, false, false, false); // disable current LED
|
||||
matrix_led += 4; // go to next LED
|
||||
//GPIOB_ODR = (GPIOB_ODR & 0xfff0) + ((matrix_led / RGBMATRIX_WIDTH) % RGBMATRIX_HEIGHT);
|
||||
rgbmatrix_set(matrix_led % RGBMATRIX_WIDTH, matrix_led / RGBMATRIX_WIDTH, true, false, false); // enable next LED
|
||||
}
|
||||
if (0 == gpio_get(GPIO_PORT(DRV8825_FAULT_PIN), GPIO_PIN(DRV8825_FAULT_PIN))) { // DRV8825 stepper motor error reports error
|
||||
gpio_set(GPIO_PORT(DRV8825_ENABLE_PIN), GPIO_PIN(DRV8825_ENABLE_PIN)); // disable motor
|
||||
@ -871,12 +879,26 @@ void GPIO_EXTI_ISR(DIAL_SWITCH_PIN)(void)
|
||||
*/
|
||||
void RGBMATRIX_ISR(void)
|
||||
{
|
||||
static uint8_t rgbmatrix_line = 0; // line being transferred
|
||||
if (dma_get_interrupt_flag(RGBMATRIX_DMA, RGBMATRIX_STREAM, DMA_TCIF)) {
|
||||
dma_clear_interrupt_flags(RGBMATRIX_DMA, RGBMATRIX_STREAM, DMA_TCIF);
|
||||
if (rgbmatrix_line < (RGBMATRIX_HEIGHT / 2)) { // there are still other lines to update (we update 2 lines per transfer)
|
||||
rgbmatrix_line++; // go to next line
|
||||
GPIOB_ODR = (GPIOB_ODR & 0xfff0) + (rgbmatrix_line % (RGBMATRIX_HEIGHT / 2)); // select line
|
||||
dma_enable_stream(RGBMATRIX_DMA, RGBMATRIX_STREAM); // start sending next line
|
||||
}
|
||||
rgbmatrix_line = (rgbmatrix_line + 1) % (RGBMATRIX_HEIGHT / 2); // go to next line (two lines are updated at once)
|
||||
// data already latched by last pixel
|
||||
//gpio_set(GPIO_PORT(RGBMATRIX_LAT_PIN), GPIO_PIN(RGBMATRIX_LAT_PIN)); // latch data on rising edge
|
||||
//gpio_clear(GPIO_PORT(RGBMATRIX_LAT_PIN), GPIO_PIN(RGBMATRIX_LAT_PIN)); // release latch
|
||||
for (volatile uint32_t i = 0; i < 4000; i++);
|
||||
GPIOB_ODR = (GPIOB_ODR & 0xfff0) + rgbmatrix_line; // select line (line on lower and upper half are updated at once)
|
||||
dma_set_peripheral_address(RGBMATRIX_DMA, RGBMATRIX_STREAM, (uint32_t)&rgbmatrix_data[rgbmatrix_line]); // set memory containing line data to be transferred
|
||||
dma_enable_stream(RGBMATRIX_DMA, RGBMATRIX_STREAM); // start sending next line
|
||||
}
|
||||
}
|
||||
|
||||
/* I don't why, but I have a ghosting issue between the lines.
|
||||
- it only affects the configured number of lines (e.g. it does not appear when I only use 2 lines)
|
||||
- in affects both halves independently
|
||||
- having the latch on the last - 1 or last + 1 row clock does not solve the issue
|
||||
- I see no ringing in the lines selection signal, and all LEDs in the line are affected the same way
|
||||
- the voltage level does not seem to be the issue (3.3V signal vs 5V panel): each LED color is set correctly, and lowering the panel voltage does not change the ghosting
|
||||
- the LED brightness is different across the lines, but identical across the line
|
||||
- adding sleep time between line selections decreases the effect a bit
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user