Last active
February 16, 2024 21:48
-
-
Save bonekost/c3ace766878ca3fe8953b3085a102dcf to your computer and use it in GitHub Desktop.
RTOS app for 8 inputs and 8 outputs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "driver/gpio.h" | |
#include "freertos/FreeRTOS.h" | |
#include "freertos/task.h" | |
#include "freertos/semphr.h" | |
#include "esp_intr_alloc.h" | |
#include "esp_log.h" | |
#define NUM_GPIO_INPUTS 8 | |
#define NUM_GPIO_OUTPUTS 8 | |
#define DEBOUNCE_TIME_MS 50 // Debounce time in milliseconds | |
#define SIGNAL_LIGHT_1_IDX 0 // Index for the first signal light input | |
#define SIGNAL_LIGHT_2_IDX 1 // Index for the second signal light input | |
#define SIGNAL_TOGGLE_PERIOD pdMS_TO_TICKS(500) // Toggle period for the signal lights (500 ms) | |
int input_gpios[NUM_GPIO_INPUTS] = {0, 1, 2, 3, 4, 5, 6, 7}; // Example input pins, adjust as needed | |
int output_gpios[NUM_GPIO_OUTPUTS] = {32, 33, 25, 26, 27, 14, 12, 13}; // Example output pins, adjust as needed | |
uint8_t output_states[NUM_GPIO_OUTPUTS] = {0}; | |
int64_t last_interrupt_time[NUM_GPIO_INPUTS] = {0}; | |
volatile bool toggle_signal_light_1 = false; | |
volatile bool toggle_signal_light_2 = false; | |
SemaphoreHandle_t mutex; | |
// GPIO ISR handler | |
static void IRAM_ATTR gpio_isr_handler(void* arg) { | |
int gpio_num = (int)arg; | |
int64_t now = esp_timer_get_time(); | |
for (int i = 0; i < NUM_GPIO_INPUTS; i++) { | |
if (gpio_num == input_gpios[i]) { | |
if (now - last_interrupt_time[i] > DEBOUNCE_TIME_MS * 1000) { | |
// Notify the gpio_task to handle the GPIO change | |
xTaskNotifyFromISR((TaskHandle_t)arg, gpio_num, eSetValueWithOverwrite, NULL); | |
last_interrupt_time[i] = now; | |
} | |
break; | |
} | |
} | |
} | |
// GPIO task to handle GPIO changes outside ISR context | |
static void gpio_task(void* arg) { | |
uint32_t gpio_num; | |
TickType_t last_wake_time = xTaskGetTickCount(); | |
for (;;) { | |
if (xTaskNotifyWait(0x00, ULONG_MAX, &gpio_num, SIGNAL_TOGGLE_PERIOD) == pdPASS) { | |
// Check if the notification is for toggling signal lights | |
if (gpio_num == input_gpios[SIGNAL_LIGHT_1_IDX]) { | |
toggle_signal_light_1 = !toggle_signal_light_1; | |
} else if (gpio_num == input_gpios[SIGNAL_LIGHT_2_IDX]) { | |
toggle_signal_light_2 = !toggle_signal_light_2; | |
} else { | |
// For other inputs, toggle the corresponding output state | |
xSemaphoreTake(mutex, portMAX_DELAY); | |
for (int i = 0; i < NUM_GPIO_INPUTS; i++) { | |
if (gpio_num == input_gpios[i]) { | |
output_states[i] = !output_states[i]; | |
gpio_set_level(output_gpios[i], output_states[i] ? 0 : 1); // Active low | |
break; | |
} | |
} | |
xSemaphoreGive(mutex); | |
} | |
} | |
// Handle the signal lights separately | |
if (toggle_signal_light_1) { | |
gpio_set_level(output_gpios[SIGNAL_LIGHT_1_IDX], !gpio_get_level(output_gpios[SIGNAL_LIGHT_1_IDX])); | |
} | |
if (toggle_signal_light_2) { | |
gpio_set_level(output_gpios[SIGNAL_LIGHT_2_IDX], !gpio_get_level(output_gpios[SIGNAL_LIGHT_2_IDX])); | |
} | |
// Wait for the next cycle | |
vTaskDelayUntil(&last_wake_time, SIGNAL_TOGGLE_PERIOD); | |
} | |
} | |
// Initialize GPIOs for input and output | |
void gpio_init(void) { | |
gpio_config_t io_conf = {}; | |
// Configure output GPIOs as initially HIGH (active low) | |
io_conf.intr_type = GPIO_INTR_DISABLE; | |
io_conf.mode = GPIO_MODE_OUTPUT; | |
io_conf.pin_bit_mask = 0; | |
for (int i = 0; i < NUM_GPIO_OUTPUTS; i++) { | |
io_conf.pin_bit_mask |= (1ULL << output_gpios[i]); | |
} | |
io_conf.pull_down_en = 0; | |
io_conf.pull_up_en = 0; | |
ESP_ERROR_CHECK(gpio_config(&io_conf)); | |
for (int i = 0; i < NUM_GPIO_OUTPUTS; i++) { | |
gpio_set_level(output_gpios[i], 1); // Set outputs HIGH initially | |
} | |
// Configure input GPIOs as pull-up, to be active low | |
io_conf.intr_type = GPIO_INTR_NEGEDGE; // Trigger on falling edge | |
io_conf.mode = GPIO_MODE_INPUT; | |
io_conf.pin_bit_mask = 0; | |
for (int i = 0; i < NUM_GPIO_INPUTS; i++) { | |
io_conf.pin_bit_mask |= (1ULL << input_gpios[i]); | |
} | |
io_conf.pull_up_en = 1; | |
ESP_ERROR_CHECK(gpio_config(&io_conf)); | |
// Install GPIO ISR service | |
ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_IRAM)); | |
// Attach the interrupt service routine | |
for (int i = 0; i < NUM_GPIO_INPUTS; i++) { | |
ESP_ERROR_CHECK(gpio_isr_handler_add(input_gpios[i], gpio_isr_handler, (void*)(intptr_t)i)); | |
} | |
} | |
void app_main(void) { | |
// Initialize the GPIOs | |
gpio_init(); | |
// Create mutex for output state access | |
mutex = xSemaphoreCreateMutex(); | |
if (mutex == NULL) { | |
ESP_LOGE("main", "Failed to create mutex"); | |
return; | |
} | |
// Create a task to handle GPIO input changes safely outside ISR | |
TaskHandle_t task_handle; | |
xTaskCreate(gpio_task, "gpio_task", 2048, NULL, 10, &task_handle); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment