diff --git a/main/gpio.h b/main/gpio.h index 07e1b52..27e4ae8 100644 --- a/main/gpio.h +++ b/main/gpio.h @@ -68,5 +68,7 @@ void gpio_output_enable(void); #define GPIO_YELLOWLED 26 #define GPIO_REDLED 27 +#define GPIO_NULL 5 + #endif diff --git a/main/led.c b/main/led.c index b96f62d..61a3186 100644 --- a/main/led.c +++ b/main/led.c @@ -24,19 +24,126 @@ #include #include "driver/gpio.h" +#include "driver/ledc.h" #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_log.h" #include "esp_system.h" #include "esp_spi_flash.h" #include "led.h" #include "gpio.h" -/* global variables for tasks handles */ -TaskHandle_t t_green, t_blue, t_yellow, t_red; +/* defines */ +#define TAG "LED" + +/* global variables for tasks handles */ +TaskHandle_t t_irq, t_green, t_blue, t_yellow, t_red; + +static ledc_timer_config_t ledc_timer = { + .duty_resolution = LEDC_TIMER_12_BIT, // resolution of PWM duty + .freq_hz = 4000, // frequency of PWM signal + .speed_mode = LEDC_HIGH_SPEED_MODE, // timer mode + .timer_num = LEDC_TIMER_0, // timer index + .clk_cfg = LEDC_AUTO_CLK, // Auto select the source clock +}; + +/* + * LEDC channels configuration + * channel number is: GPIO number - 20. This allow to get the hardware + * channel number from the hardware GPIO number + * example: GREEN = GPIO 21 = CHANNEL 21 - 20 = CHANNEL 1 + * others channels are set to an unused GPIO pin (5) but not registered + */ + +static ledc_channel_config_t ledc_channel[] = { + { + .channel = LEDC_CHANNEL_0, + .duty = 0, + .gpio_num = GPIO_NULL, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .hpoint = 0, + .timer_sel = LEDC_TIMER_0, + }, + { + .channel = LEDC_CHANNEL_1, + .duty = 0, + .gpio_num = GPIO_GREENLED, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .hpoint = 0, + .timer_sel = LEDC_TIMER_0, + }, + { + .channel = LEDC_CHANNEL_2, + .duty = 0, + .gpio_num = GPIO_NULL, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .hpoint = 0, + .timer_sel = LEDC_TIMER_0, + }, + { + .channel = LEDC_CHANNEL_3, + .duty = 0, + .gpio_num = GPIO_NULL, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .hpoint = 0, + .timer_sel = LEDC_TIMER_0, + }, + { + .channel = LEDC_CHANNEL_4, + .duty = 0, + .gpio_num = GPIO_NULL, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .hpoint = 0, + .timer_sel = LEDC_TIMER_0, + }, + { + .channel = LEDC_CHANNEL_5, + .duty = 0, + .gpio_num = GPIO_BLUELED, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .hpoint = 0, + .timer_sel = LEDC_TIMER_0, + }, + { + .channel = LEDC_CHANNEL_6, + .duty = 0, + .gpio_num = GPIO_YELLOWLED, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .hpoint = 0, + .timer_sel = LEDC_TIMER_0, + }, + { + .channel = LEDC_CHANNEL_7, + .duty = 0, + .gpio_num = GPIO_REDLED, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .hpoint = 0, + .timer_sel = LEDC_TIMER_0, + } +}; + +/* could be inside led_init but just used to allocate IRQs to CPU 1 instead of 0 */ +void led_dispatch(void *pvParameters) +{ + ledc_fade_func_install(0); + + /* avoit cur duty + target spam on console */ + esp_log_level_set("ledc", ESP_LOG_INFO); + + xTaskCreatePinnedToCore(led_task, "GREEN", 2 * 1024, (void *) GPIO_GREENLED, tskIDLE_PRIORITY, &t_green, 1); + xTaskCreatePinnedToCore(led_task, "BLUE", 2 * 1024, (void *) GPIO_BLUELED, tskIDLE_PRIORITY, &t_blue, 1); + xTaskCreatePinnedToCore(led_task, "YELLOW", 2 * 1024, (void *) GPIO_YELLOWLED, tskIDLE_PRIORITY, &t_yellow, 1); + xTaskCreatePinnedToCore(led_task, "RED", 2 * 1024, (void *) GPIO_REDLED, tskIDLE_PRIORITY, &t_red, 1); + + /* blink green led fast (we are booting...) */ + xTaskNotify(t_green, LED_FAST, eSetValueWithOverwrite); + + ESP_LOGI(TAG, "led_dispatch suspending itself on core %d", xPortGetCoreID()); + vTaskSuspend(NULL); +} -/* init all leds, blink everything once and start background tasks */ void led_init(void) { /* blink allds LEDs once */ gpio_set_level(GPIO_GREENLED, 1); @@ -49,13 +156,12 @@ void led_init(void) { gpio_set_level(GPIO_YELLOWLED, 0); gpio_set_level(GPIO_REDLED, 0); - xTaskCreate(led_task, "GREEN", 1024, (void *) GPIO_GREENLED, tskIDLE_PRIORITY, &t_green); - xTaskCreate(led_task, "BLUE", 1024, (void *) GPIO_BLUELED, tskIDLE_PRIORITY, &t_blue); - xTaskCreate(led_task, "YELLOW", 1024, (void *) GPIO_YELLOWLED, tskIDLE_PRIORITY, &t_yellow); - xTaskCreate(led_task, "RED", 1024, (void *) GPIO_REDLED, tskIDLE_PRIORITY, &t_red); - - /* blink green led fast (we are booting...) */ - xTaskNotify(t_green, LED_FAST, eSetValueWithOverwrite); + ledc_timer_config(&ledc_timer); + ledc_channel_config(&ledc_channel[GPIO_GREENLED - 20]); + ledc_channel_config(&ledc_channel[GPIO_BLUELED - 20]); + ledc_channel_config(&ledc_channel[GPIO_YELLOWLED - 20]); + ledc_channel_config(&ledc_channel[GPIO_REDLED - 20]); + xTaskCreatePinnedToCore(led_dispatch, "DISPATCH", 2 * 1024, NULL, tskIDLE_PRIORITY, &t_irq, 1); } void led_task(void *pvParameters) { @@ -66,34 +172,44 @@ void led_task(void *pvParameters) { /* start only if there is a led specified */ configASSERT(((uint32_t) pvParameters) > 0); + ESP_LOGI(TAG, "led task %i started on core %d", color, xPortGetCoreID()); + while (1) { xTaskNotifyWait(0, 0, &mode, wait); switch (mode) { case LED_OFF: - gpio_set_level(color, 0); + ledc_set_duty(LED_SPEED(color), LED_CHANNEL(color), 0); + ledc_update_duty(LED_SPEED(color), LED_CHANNEL(color)); wait = portMAX_DELAY; break; case LED_ON: - gpio_set_level(color, 1); + ledc_set_duty(LED_SPEED(color), LED_CHANNEL(color), LED_DUTY); + ledc_update_duty(LED_SPEED(color), LED_CHANNEL(color)); wait = portMAX_DELAY; break; case LED_ONCE: - gpio_set_level(color, 1); + ledc_set_duty(LED_SPEED(color), LED_CHANNEL(color), LED_DUTY); + ledc_update_duty(LED_SPEED(color), LED_CHANNEL(color)); vTaskDelay(40 / portTICK_PERIOD_MS); - gpio_set_level(color, 0); + ledc_set_duty(LED_SPEED(color), LED_CHANNEL(color), 0); + ledc_update_duty(LED_SPEED(color), LED_CHANNEL(color)); wait = portMAX_DELAY; break; case LED_FAST: - gpio_set_level(color, 1); + ledc_set_duty(LED_SPEED(color), LED_CHANNEL(color), LED_DUTY); + ledc_update_duty(LED_SPEED(color), LED_CHANNEL(color)); vTaskDelay(40 / portTICK_PERIOD_MS); - gpio_set_level(color, 0); + ledc_set_duty(LED_SPEED(color), LED_CHANNEL(color), 0); + ledc_update_duty(LED_SPEED(color), LED_CHANNEL(color)); wait = 40 / portTICK_PERIOD_MS; break; case LED_SLOW: - gpio_set_level(color, 1); + ledc_set_fade_with_time(LED_SPEED(color), LED_CHANNEL(color), LED_DUTY, 400); + ledc_fade_start(LED_SPEED(color), LED_CHANNEL(color), LEDC_FADE_NO_WAIT); vTaskDelay(500 / portTICK_PERIOD_MS); - gpio_set_level(color, 0); + ledc_set_fade_with_time(LED_SPEED(color), LED_CHANNEL(color), 0, 400); + ledc_fade_start(LED_SPEED(color), LED_CHANNEL(color), LEDC_FADE_NO_WAIT); wait = 500 / portTICK_PERIOD_MS; break; default: diff --git a/main/led.h b/main/led.h index 8405bc2..e21cac7 100644 --- a/main/led.h +++ b/main/led.h @@ -26,6 +26,7 @@ #define LED_H /* prototypes */ +void led_dispatch(void *pvParameters); void led_init(void); void led_task(void *pvParameters); @@ -36,5 +37,10 @@ void led_task(void *pvParameters); #define LED_SLOW (1 << 3) #define LED_FAST (1 << 4) +#define LED_DUTY 4096 + +#define LED_CHANNEL(c) ledc_channel[c - 20].channel +#define LED_SPEED(c) ledc_channel[c - 20].speed_mode + #endif diff --git a/main/main.c b/main/main.c index 3e14041..5b186b6 100644 --- a/main/main.c +++ b/main/main.c @@ -77,7 +77,7 @@ void app_main(void) /* put LED error ON if no inputs (/BTOFF and no /ADBSRC) */ if (gpio_get_level(GPIO_BTOFF) == 0 && gpio_get_level(GPIO_ADBSRC) == 1) { - ESP_LOGE(TAG, "Bluetooth is off and ADB is in device mode!"); + ESP_LOGE(TAG, "Bluetooth is off and ADB is NOT in host mode!"); xTaskNotify(t_red, LED_ON, eSetValueWithOverwrite); } }