Skip to content

Instantly share code, notes, and snippets.

@bonekost
Last active February 16, 2024 21:48
Show Gist options
  • Save bonekost/c3ace766878ca3fe8953b3085a102dcf to your computer and use it in GitHub Desktop.
Save bonekost/c3ace766878ca3fe8953b3085a102dcf to your computer and use it in GitHub Desktop.
RTOS app for 8 inputs and 8 outputs
#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