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
|
||||
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
|
||||
FuriTimer* timer; // Timer for automatic updating the LEDs
|
||||
LedTesterModel* model; // The model
|
||||
LedDriver* led_driver; // The LED driver
|
||||
} LedTesterApp;
|
||||
|
||||
// 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[] =
|
||||
{1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256, 512, 1024};
|
||||
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 void led_tester_setting_led_count_change(VariableItem* 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);
|
||||
}
|
||||
|
||||
LedDriver* led_driver = led_driver_alloc(256, pin);
|
||||
|
||||
// Set all LEDs to off
|
||||
for(size_t i = 0; i < 256; i++) {
|
||||
led_driver_set_led(led_driver, i, 0);
|
||||
}
|
||||
led_driver_set_pin(app->led_driver, pin);
|
||||
|
||||
// Set the LEDs to the pattern
|
||||
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_free(led_driver);
|
||||
led_driver_transmit(app->led_driver, false);
|
||||
|
||||
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_text(item, setting_led_pin_names[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
|
||||
item = variable_item_list_add(
|
||||
@ -518,7 +515,7 @@ static LedTesterApp* led_tester_app_alloc() {
|
||||
0,
|
||||
128,
|
||||
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(
|
||||
widget_get_view(app->widget_about), led_tester_navigation_submenu_callback);
|
||||
view_dispatcher_add_view(
|
||||
@ -533,6 +530,7 @@ static LedTesterApp* led_tester_app_alloc() {
|
||||
* @param app The led tester application object.
|
||||
*/
|
||||
static void led_tester_app_free(LedTesterApp* app) {
|
||||
led_driver_free(app->led_driver);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, LedTesterViewAbout);
|
||||
widget_free(app->widget_about);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, LedTesterViewLeds);
|
||||
|
@ -3,7 +3,7 @@ App(
|
||||
name="WS2812B LED Tester App",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="ws2812b_led_tester_app",
|
||||
fap_version=(1, 5),
|
||||
fap_version=(1, 6),
|
||||
stack_size=4 * 1024,
|
||||
requires=[
|
||||
"gui",
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#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)
|
||||
#define LED_DRIVER_BUFFER_SIZE (MAX_LED_COUNT * 2 * 24)
|
||||
// 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];
|
||||
uint32_t write_pos;
|
||||
uint32_t read_pos;
|
||||
bool dirty;
|
||||
|
||||
uint32_t count_leds;
|
||||
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_led_transition_timer(led_driver);
|
||||
led_driver->led_data = malloc(MAX_LED_COUNT * sizeof(uint32_t));
|
||||
led_driver->dirty = true;
|
||||
|
||||
led_driver->count_leds = count_leds;
|
||||
|
||||
@ -104,6 +105,15 @@ void led_driver_free(LedDriver* 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) {
|
||||
furi_assert(led_driver);
|
||||
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];
|
||||
led_driver->led_data[index] = rrggbb;
|
||||
led_driver->dirty |= previous != rrggbb;
|
||||
|
||||
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->read_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_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);
|
||||
led_driver->read_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_hal.h>
|
||||
|
||||
#define MAX_LED_COUNT 1024
|
||||
|
||||
typedef struct LedDriver LedDriver;
|
||||
|
||||
LedDriver* led_driver_alloc(int count_leds, const GpioPin* gpio);
|
||||
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_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