v1.6: Add support for 1000 LEDS, Add "dirty" support to remove update flicker.
This commit is contained in:
parent
606abe7887
commit
6b817ad23e
@ -21,3 +21,8 @@ This application has three submenu items:
|
|||||||
|
|
||||||
# About
|
# About
|
||||||
The "About" menu item contains information about the application.
|
The "About" menu item contains information about the application.
|
||||||
|
|
||||||
|
# Updates
|
||||||
|
- Version 1.6
|
||||||
|
- Added support for up to 1000 LEDs (max set in led_driver.h)
|
||||||
|
- Added "dirty flag" to get rid of flicker when not updating the LEDs
|
||||||
|
@ -52,6 +52,7 @@ typedef struct {
|
|||||||
Widget* widget_about; // The about screen
|
Widget* widget_about; // The about screen
|
||||||
FuriTimer* timer; // Timer for automatic updating the LEDs
|
FuriTimer* timer; // Timer for automatic updating the LEDs
|
||||||
LedTesterModel* model; // The model
|
LedTesterModel* model; // The model
|
||||||
|
LedDriver* led_driver; // The LED driver
|
||||||
} LedTesterApp;
|
} LedTesterApp;
|
||||||
|
|
||||||
// Hack so that we can access the application object from a variable_item_list on_enter/exit callback.
|
// Hack so that we can access the application object from a variable_item_list on_enter/exit callback.
|
||||||
@ -170,7 +171,7 @@ static const char* setting_led_count_config_label = "LED Count";
|
|||||||
static uint16_t setting_led_count_values[] =
|
static uint16_t setting_led_count_values[] =
|
||||||
{1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256, 512, 1024};
|
{1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256, 512, 1024};
|
||||||
static char* setting_led_count_names[] =
|
static char* setting_led_count_names[] =
|
||||||
{"1", "2", "3", "4", "5", "6", "7", "8", "16", "32", "64", "128", "256"};
|
{"1", "2", "3", "4", "5", "6", "7", "8", "16", "32", "64", "128", "256", "512", "1024"};
|
||||||
static uint8_t setting_led_count_default_index = 3; // 4 LEDs
|
static uint8_t setting_led_count_default_index = 3; // 4 LEDs
|
||||||
static void led_tester_setting_led_count_change(VariableItem* item) {
|
static void led_tester_setting_led_count_change(VariableItem* item) {
|
||||||
LedTesterApp* app = variable_item_get_context(item);
|
LedTesterApp* app = variable_item_get_context(item);
|
||||||
@ -334,20 +335,14 @@ static bool led_tester_custom_event_callback(void* context, uint32_t event) {
|
|||||||
((rgb[i] & 0xFF) * app->model->led_max_brightness / 100);
|
((rgb[i] & 0xFF) * app->model->led_max_brightness / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
LedDriver* led_driver = led_driver_alloc(256, pin);
|
led_driver_set_pin(app->led_driver, pin);
|
||||||
|
|
||||||
// Set all LEDs to off
|
|
||||||
for(size_t i = 0; i < 256; i++) {
|
|
||||||
led_driver_set_led(led_driver, i, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the LEDs to the pattern
|
// Set the LEDs to the pattern
|
||||||
for(size_t i = 0; i < app->model->led_count; i++) {
|
for(size_t i = 0; i < app->model->led_count; i++) {
|
||||||
led_driver_set_led(led_driver, i, rgb[i % 4]);
|
led_driver_set_led(app->led_driver, i, rgb[i % 4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
led_driver_transmit(led_driver);
|
led_driver_transmit(app->led_driver, false);
|
||||||
led_driver_free(led_driver);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -437,6 +432,8 @@ static LedTesterApp* led_tester_app_alloc() {
|
|||||||
variable_item_set_current_value_index(item, setting_led_pin_index);
|
variable_item_set_current_value_index(item, setting_led_pin_index);
|
||||||
variable_item_set_current_value_text(item, setting_led_pin_names[setting_led_pin_index]);
|
variable_item_set_current_value_text(item, setting_led_pin_names[setting_led_pin_index]);
|
||||||
app->model->led_pin_index = setting_led_pin_index;
|
app->model->led_pin_index = setting_led_pin_index;
|
||||||
|
app->led_driver =
|
||||||
|
led_driver_alloc(MAX_LED_COUNT, setting_led_pin_values[setting_led_pin_index]);
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
item = variable_item_list_add(
|
item = variable_item_list_add(
|
||||||
@ -518,7 +515,7 @@ static LedTesterApp* led_tester_app_alloc() {
|
|||||||
0,
|
0,
|
||||||
128,
|
128,
|
||||||
64,
|
64,
|
||||||
"This is a WS2812B LED tester\nVersion 1.5\nConnect WS2812B LED data\nwire to GPIO pin on Flipper.\n\nThe 3V3 pin has a 1200mA\nmax current (~4 watts). The\n5V pin has a 1000mA max\ncurrent (5 watts).\n\nauthors: @codeallnight and\nZ3BRO!\n\nhttps://discord.com/invite/NsjCvqwPAd\nhttps://youtube.com/@MrDerekJamison\n\n");
|
"This is a WS2812B LED tester\nVersion 1.6\nConnect WS2812B LED data\nwire to GPIO pin on Flipper.\n\nThe 3V3 pin has a 1200mA\nmax current (~4 watts). The\n5V pin has a 1000mA max\ncurrent (5 watts).\n\nauthors: @codeallnight and\nZ3BRO!\n\nhttps://discord.com/invite/NsjCvqwPAd\nhttps://youtube.com/@MrDerekJamison\n\n");
|
||||||
view_set_previous_callback(
|
view_set_previous_callback(
|
||||||
widget_get_view(app->widget_about), led_tester_navigation_submenu_callback);
|
widget_get_view(app->widget_about), led_tester_navigation_submenu_callback);
|
||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
@ -533,6 +530,7 @@ static LedTesterApp* led_tester_app_alloc() {
|
|||||||
* @param app The led tester application object.
|
* @param app The led tester application object.
|
||||||
*/
|
*/
|
||||||
static void led_tester_app_free(LedTesterApp* app) {
|
static void led_tester_app_free(LedTesterApp* app) {
|
||||||
|
led_driver_free(app->led_driver);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, LedTesterViewAbout);
|
view_dispatcher_remove_view(app->view_dispatcher, LedTesterViewAbout);
|
||||||
widget_free(app->widget_about);
|
widget_free(app->widget_about);
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, LedTesterViewLeds);
|
view_dispatcher_remove_view(app->view_dispatcher, LedTesterViewLeds);
|
||||||
|
@ -3,7 +3,7 @@ App(
|
|||||||
name="WS2812B LED Tester App",
|
name="WS2812B LED Tester App",
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
apptype=FlipperAppType.EXTERNAL,
|
||||||
entry_point="ws2812b_led_tester_app",
|
entry_point="ws2812b_led_tester_app",
|
||||||
fap_version=(1, 5),
|
fap_version=(1, 6),
|
||||||
stack_size=4 * 1024,
|
stack_size=4 * 1024,
|
||||||
requires=[
|
requires=[
|
||||||
"gui",
|
"gui",
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "led_driver.h"
|
#include "led_driver.h"
|
||||||
|
|
||||||
#define MAX_LED_COUNT 256
|
|
||||||
// We store the HIGH/LOW durations (2 values) for each color bit (24 bits per LED)
|
// We store the HIGH/LOW durations (2 values) for each color bit (24 bits per LED)
|
||||||
#define LED_DRIVER_BUFFER_SIZE (MAX_LED_COUNT * 2 * 24)
|
#define LED_DRIVER_BUFFER_SIZE (MAX_LED_COUNT * 2 * 24)
|
||||||
// We use a setinel value to figure out when the timer is complete.
|
// We use a setinel value to figure out when the timer is complete.
|
||||||
@ -37,6 +36,7 @@ struct LedDriver {
|
|||||||
uint8_t timer_buffer[LED_DRIVER_BUFFER_SIZE + 2];
|
uint8_t timer_buffer[LED_DRIVER_BUFFER_SIZE + 2];
|
||||||
uint32_t write_pos;
|
uint32_t write_pos;
|
||||||
uint32_t read_pos;
|
uint32_t read_pos;
|
||||||
|
bool dirty;
|
||||||
|
|
||||||
uint32_t count_leds;
|
uint32_t count_leds;
|
||||||
uint32_t* led_data;
|
uint32_t* led_data;
|
||||||
@ -91,6 +91,7 @@ LedDriver* led_driver_alloc(int count_leds, const GpioPin* gpio) {
|
|||||||
led_driver_init_dma_gpio_update(led_driver, gpio);
|
led_driver_init_dma_gpio_update(led_driver, gpio);
|
||||||
led_driver_init_dma_led_transition_timer(led_driver);
|
led_driver_init_dma_led_transition_timer(led_driver);
|
||||||
led_driver->led_data = malloc(MAX_LED_COUNT * sizeof(uint32_t));
|
led_driver->led_data = malloc(MAX_LED_COUNT * sizeof(uint32_t));
|
||||||
|
led_driver->dirty = true;
|
||||||
|
|
||||||
led_driver->count_leds = count_leds;
|
led_driver->count_leds = count_leds;
|
||||||
|
|
||||||
@ -104,6 +105,15 @@ void led_driver_free(LedDriver* led_driver) {
|
|||||||
free(led_driver);
|
free(led_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void led_driver_set_pin(LedDriver* led_driver, const GpioPin* gpio) {
|
||||||
|
if(led_driver->gpio == gpio) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
led_driver_init_dma_gpio_update(led_driver, gpio);
|
||||||
|
led_driver->dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t led_driver_set_led(LedDriver* led_driver, uint32_t index, uint32_t rrggbb) {
|
uint32_t led_driver_set_led(LedDriver* led_driver, uint32_t index, uint32_t rrggbb) {
|
||||||
furi_assert(led_driver);
|
furi_assert(led_driver);
|
||||||
if(index >= led_driver->count_leds) {
|
if(index >= led_driver->count_leds) {
|
||||||
@ -112,6 +122,8 @@ uint32_t led_driver_set_led(LedDriver* led_driver, uint32_t index, uint32_t rrgg
|
|||||||
|
|
||||||
uint32_t previous = led_driver->led_data[index];
|
uint32_t previous = led_driver->led_data[index];
|
||||||
led_driver->led_data[index] = rrggbb;
|
led_driver->led_data[index] = rrggbb;
|
||||||
|
led_driver->dirty |= previous != rrggbb;
|
||||||
|
|
||||||
return previous;
|
return previous;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,12 +231,18 @@ static void led_driver_add_color(LedDriver* led_driver, uint32_t rrggbb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_driver_transmit(LedDriver* led_driver) {
|
void led_driver_transmit(LedDriver* led_driver, bool transmit_if_clean) {
|
||||||
furi_assert(led_driver);
|
furi_assert(led_driver);
|
||||||
|
|
||||||
furi_assert(!led_driver->read_pos);
|
furi_assert(!led_driver->read_pos);
|
||||||
furi_assert(!led_driver->write_pos);
|
furi_assert(!led_driver->write_pos);
|
||||||
|
|
||||||
|
if(!transmit_if_clean && !led_driver->dirty) {
|
||||||
|
FURI_LOG_D("LED_DRIVER", "Skipping transmit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FURI_LOG_D("LED_DRIVER", "Transmit");
|
||||||
|
|
||||||
furi_hal_gpio_init(led_driver->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
furi_hal_gpio_init(led_driver->gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
||||||
furi_hal_gpio_write(led_driver->gpio, false);
|
furi_hal_gpio_write(led_driver->gpio, false);
|
||||||
|
|
||||||
@ -258,59 +276,5 @@ void led_driver_transmit(LedDriver* led_driver) {
|
|||||||
memset(led_driver->timer_buffer, LED_DRIVER_TIMER_SETINEL, LED_DRIVER_BUFFER_SIZE);
|
memset(led_driver->timer_buffer, LED_DRIVER_TIMER_SETINEL, LED_DRIVER_BUFFER_SIZE);
|
||||||
led_driver->read_pos = 0;
|
led_driver->read_pos = 0;
|
||||||
led_driver->write_pos = 0;
|
led_driver->write_pos = 0;
|
||||||
|
led_driver->dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
int32_t main_led_test(void* _p) {
|
|
||||||
UNUSED(_p);
|
|
||||||
|
|
||||||
uint16_t num_leds = MAX_LED_COUNT;
|
|
||||||
LedDriver* led_driver = led_driver_alloc(num_leds, &gpio_ext_pc3);
|
|
||||||
|
|
||||||
uint32_t* data[80];
|
|
||||||
for(int i = 0; i < 80; i++) {
|
|
||||||
data[i] = malloc(16 * 16 * sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int j = 0; j < num_leds; j++) {
|
|
||||||
uint8_t red = rand() % 2;
|
|
||||||
uint8_t green = rand() % 4;
|
|
||||||
uint8_t blue = rand() % 4;
|
|
||||||
data[0][j] = red << 16 | green << 8 | blue;
|
|
||||||
}
|
|
||||||
data[0][0] = 0x000F00;
|
|
||||||
|
|
||||||
for(int i = 1; i < 80; i++) {
|
|
||||||
for(int j = 1; j < num_leds; j++) {
|
|
||||||
uint8_t red = rand() % 2;
|
|
||||||
uint8_t green = rand() % 4;
|
|
||||||
uint8_t blue = rand() % 4;
|
|
||||||
data[i][j] = red << 16 | green << 8 | blue;
|
|
||||||
data[i][j] = data[i - 1][j - 1];
|
|
||||||
}
|
|
||||||
data[i][0] = data[i - 1][num_leds - 1];
|
|
||||||
// for(int j = 0; j < num_leds; j++) {
|
|
||||||
// if(data[i - 1][j] == 0x000F00) {
|
|
||||||
// data[i][j] = 0x000F00;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
data[i][rand() % num_leds] = 0x000F00;
|
|
||||||
}
|
|
||||||
|
|
||||||
int counter = 0;
|
|
||||||
while(true) {
|
|
||||||
uint32_t i = counter++ % 80;
|
|
||||||
for(int j = 0; j < num_leds; j++) {
|
|
||||||
led_driver_set_led(led_driver, j, data[i][j]);
|
|
||||||
}
|
|
||||||
led_driver_transmit(led_driver);
|
|
||||||
furi_delay_ms(20);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < 80; i++) {
|
|
||||||
free(data[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*/
|
|
@ -1,10 +1,13 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
|
|
||||||
|
#define MAX_LED_COUNT 1024
|
||||||
|
|
||||||
typedef struct LedDriver LedDriver;
|
typedef struct LedDriver LedDriver;
|
||||||
|
|
||||||
LedDriver* led_driver_alloc(int count_leds, const GpioPin* gpio);
|
LedDriver* led_driver_alloc(int count_leds, const GpioPin* gpio);
|
||||||
void led_driver_free(LedDriver* led_driver);
|
void led_driver_free(LedDriver* led_driver);
|
||||||
|
void led_driver_set_pin(LedDriver* led_driver, const GpioPin* gpio);
|
||||||
uint32_t led_driver_set_led(LedDriver* led_driver, uint32_t index, uint32_t rrggbb);
|
uint32_t led_driver_set_led(LedDriver* led_driver, uint32_t index, uint32_t rrggbb);
|
||||||
uint32_t led_driver_get_led(LedDriver* led_driver, uint32_t index);
|
uint32_t led_driver_get_led(LedDriver* led_driver, uint32_t index);
|
||||||
void led_driver_transmit(LedDriver* led_driver);
|
void led_driver_transmit(LedDriver* led_driver, bool transmit_if_clean);
|
||||||
|
Loading…
Reference in New Issue
Block a user