LED_shit/main/led_driver.c
2025-11-22 00:13:32 +00:00

132 lines
3.0 KiB
C

#include "led_driver.h"
#include "driver/rmt_tx.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <string.h>
#define LED_PIN 18 // <-- CERTIFICA-TE disto
#define RMT_RESOLUTION_HZ 10000000 // 10 MHz (1 tick = 0.1us)
typedef struct {
uint8_t r,g,b;
} led_color_t;
static led_color_t leds[LED_COUNT];
static rmt_channel_handle_t rmt_chan = NULL;
static rmt_encoder_handle_t encoder = NULL;
static rmt_transmit_config_t tx_config = {
.loop_count = 0
};
void led_driver_init(void)
{
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
rmt_tx_channel_config_t chan_cfg = {
.gpio_num = LED_PIN,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = RMT_RESOLUTION_HZ,
.mem_block_symbols = 64,
.trans_queue_depth = 1,
};
ESP_ERROR_CHECK(rmt_new_tx_channel(&chan_cfg, &rmt_chan));
ESP_ERROR_CHECK(rmt_enable(rmt_chan));
// WS2812B timings (EXATOS)
rmt_bytes_encoder_config_t enc_cfg = {
.bit0 = {
.duration0 = 4, .level0 = 1, // 0.4us HIGH
.duration1 = 9, .level1 = 0 // 0.9us LOW
},
.bit1 = {
.duration0 = 9, .level0 = 1, // 0.9us HIGH
.duration1 = 4, .level1 = 0 // 0.4us LOW
},
.flags.msb_first = 1
};
ESP_ERROR_CHECK(rmt_new_bytes_encoder(&enc_cfg, &encoder));
memset(leds, 0, sizeof(leds));
led_show();
}
void led_set_pixel(int index, uint8_t r, uint8_t g, uint8_t b)
{
if (index < 0 || index >= LED_COUNT) return;
leds[index].r = r;
leds[index].g = g;
leds[index].b = b;
}
void led_clear(void)
{
memset(leds, 0, sizeof(leds));
}
static void hw_update(void)
{
uint8_t buf[LED_COUNT * 3];
// MOST common format is GRB
for (int i = 0; i < LED_COUNT; i++) {
buf[i*3 + 0] = leds[i].g;
buf[i*3 + 1] = leds[i].r;
buf[i*3 + 2] = leds[i].b;
}
ESP_ERROR_CHECK(rmt_transmit(rmt_chan, encoder, buf, sizeof(buf), &tx_config));
rmt_tx_wait_all_done(rmt_chan, -1);
// Reset time > 50us
esp_rom_delay_us(60);
}
void led_show(void)
{
hw_update();
}
int led_get_count(void)
{
return LED_COUNT;
}
void led_spin_to(uint16_t target, int min_spins, int max_spins, int base_delay_ms)
{
int n = LED_COUNT;
if (min_spins < 1) min_spins = 1;
if (max_spins < min_spins) max_spins = min_spins;
int extra = 0;
if (max_spins > min_spins)
extra = rand() % (max_spins - min_spins + 1);
int total_steps = (min_spins + extra) * n + (target % n);
int delay = base_delay_ms;
for (int step = 0; step <= total_steps; step++) {
int pos = step % n;
for (int i = 0; i < n; i++) {
if (i == pos)
led_set_pixel(i, 0, 40, 0); // verde fraco no cursor
else
led_set_pixel(i, 0, 0, 0);
}
led_show();
if (step < total_steps / 3 && delay > 3)
delay--;
else if (step > (2 * total_steps) / 3)
delay++;
vTaskDelay(pdMS_TO_TICKS(delay));
}
}