I am a beginner with the ESP32 and I wish to realize a simple counter which is incremented with each rotation of a Rotary Encoder.
For this I need to interrupt when a rotation is made, I disable the interruption to not return constantly.
Depending on the input (signal A or signal B) that goes first from low to high, you increment or decrement. I have also added a timer function that activates the interrupt for inputs A and B every second. (see code below)
Code: Select all
#include "driver/periph_ctrl.h"
#include "driver/timer.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "timer.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "freertos/event_groups.h"
#define TIMER_INTR_SEL TIMER_INTR_LEVEL /*!< Timer level interrupt */
#define TIMER_GROUP TIMER_GROUP_0 /*!< Test on timer group 0 */
#define TIMER_DIVIDER 64 /*!< Hardware timer clock divider */
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) /*!< used to calculate counter value */
#define TIMER_FINE_ADJ (1.4*(TIMER_BASE_CLK / TIMER_DIVIDER)/1000000) /*!< used to compensate alarm value */
#define TIMER_INTERVAL0_SEC (0.01) /*!< test interval for timer 0 */
#define GPIO_pinA 25
#define GPIO_pinB 17
#define GPIO_pinSW 18
volatile int flagA = 0;
volatile int flagB = 0;
const int MS_BIT = BIT0;
const int SEC_BIT = BIT0;
static void (*s_timer_group_0_timer_0_cb)(void*) = NULL;
volatile int flagTimer = 0;
volatile int f_1s =0;
volatile int f_100ms = 0;
volatile int count_1s = 0;
volatile int F_GPIO_pinA=0;
volatile int F_GPIO_pinB=0;
typedef struct {
int type; /*!< event type */
int group; /*!< timer group */
int idx; /*!< timer number */
uint64_t counter_val; /*!< timer counter value */
int timer_group;
int timer_idx;
uint64_t timer_counter_value;
} timer_event_t;
static QueueHandle_t q1 = NULL;
//EventGroupHandle_t iGroup;
void IRAM_ATTR gpio_isr_handler(void* arg) {
gpio_intr_disable(25);
gpio_intr_disable(17);
uint32_t flag_pin = (uint32_t) arg;
//BaseType_t xHigherPriorityTaskWoken;
if (flag_pin == GPIO_pinA) {
//xEventGroupSetBitsFromISR(interrupt_group, GPIO_SENSE_BIT, NULL);
flagA = 1;
xQueueSendToBackFromISR(q1, &flagA, NULL);
//xQueueSendToBackFromISR(q1, &flagA, NULL);
}
if (flag_pin ==GPIO_pinB) {
//xEventGroupSetBitsFromISR(interrupt_group, GPIO_SENSE_BIT2, NULL);
flagB = 1;
xQueueSendToBackFromISR(q1, &flagB, NULL);
//xQueueSendToBackFromISR(q1, &flagA, NULL);
}
}
/*void IRAM_ATTR gpio_isr_handler2(void* arg2) {
gpio_intr_disable(25);
gpio_intr_disable(17);
uint32_t flag_pinB = (uint32_t) arg2;
if (flag_pinB ==GPIO_pinB) {
//xEventGroupSetBitsFromISR(interrupt_group, GPIO_SENSE_BIT2, NULL);
flagB = 1;
xQueueSendToBackFromISR(q1, &flagB, NULL);
//xQueueSendToBackFromISR(q1, &flagA, NULL);
}
}*/
void IRAM_ATTR timer_group0_isr(void *arg)
{
//GROUP 0, TIMER 0 ISR
//CLEAR INTERRUPT
TIMERG0.int_clr_timers.t0 = 1;
//RESET ALARM
//ESP32 ALARMS ARE ONE SHOT
//NEED TO BE MANUALLY SET EVERY TIME
flagTimer = 1;
//CALL USER CB FUNCTION IF NOT NULL
if(s_timer_group_0_timer_0_cb != NULL)
{
(*s_timer_group_0_timer_0_cb)(NULL);
}
}
/*
* @Chris-timer group0 hardware timer0 init
* Initialize selected timer of the timer group 0
*
* Timer number to initialize
* The timer auto reload on alarm
* The interval of alarm to set
*/
void example_tg0_timer_init(void *arg) {
// Select and initialize basic parameters of the timer
timer_config_t config;
config.alarm_en = TIMER_ALARM_EN;
config.auto_reload = TIMER_AUTORELOAD_EN;
config.counter_dir = TIMER_COUNT_UP;
config.divider = 16;
config.intr_type = TIMER_INTR_SEL;
config.counter_dir = TIMER_COUNT_UP;
config.counter_en = TIMER_PAUSE;
//Configure timer
timer_init(TIMER_GROUP_0, TIMER_0, &config);
//Stop timer counter
timer_pause(TIMER_GROUP_0, TIMER_0);
//Enable timer interrupt
timer_enable_intr(TIMER_GROUP_0, TIMER_0);
//Start timer counter
timer_start(TIMER_GROUP_0, TIMER_0);
//Load counter value
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 10);
//Set Divider
timer_set_divider(TIMER_GROUP_0,TIMER_0,TIMER_DIVIDER);
// Configure the alarm value and the interrupt on alarm.
timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, ((TIMER_SCALE * TIMER_INTERVAL0_SEC)-TIMER_FINE_ADJ));
timer_isr_register(TIMER_GROUP_0, TIMER_0, timer_group0_isr, (void *) TIMER_0, ESP_INTR_FLAG_IRAM, NULL);
printf("INIT TIMER SUCCECED!\n");
//Variables
int count_100ms = 0;
while (1){
if(flagTimer == 1 ){
flagTimer = 0;
timer_set_alarm(TIMER_GROUP_0, TIMER_0, TIMER_ALARM_EN);
if (count_100ms == 10 ){
count_100ms = 0;
f_100ms = 1;
f_100ms = 0;
}
if(count_1s == 100) {
count_1s = 0;
f_1s = 1;
count_1s ++;
count_100ms ++;
}
//printf ("Nothing\n");
vTaskDelay(10/ portTICK_RATE_MS); // sleep 5s
}
vTaskDelete (NULL);
}
void gpio_task(void *pvParameter) {
//EventBits_t bitA;
//EventBits_t bitB;
int counter = 0;
//interrupt_group = xEventGroupCreate();
int etat_pinA = 1;
int etat_pinB = 1;
while (1) {
BaseType_t rc;
//etat_pinA = gpio_get_level(GPIO_pinA);
//etat_pinB = gpio_get_level(GPIO_pinB);
//bitA= xEventGroupWaitBits(interrupt_group, GPIO_SENSE_BIT,pdTRUE, pdFALSE, 1 / portTICK_RATE_MS); // max wait 1ms
//bitB= xEventGroupWaitBits(interrupt_group, GPIO_SENSE_BIT2,pdTRUE, pdFALSE, 1 / portTICK_RATE_MS); // max wait 1ms
if(xQueueReceive(q1, &flagA, 10/portTICK_RATE_MS) == pdTRUE) {
printf("interrupt flag A\n");
flagA = 0;
counter++ ;
}
//bitB= xEventGroupWaitBits(interrupt_group, GPIO_SENSE_BIT2,pdTRUE, pdFALSE, 1 / portTICK_RATE_MS); // max wait 60s
if(xQueueReceive(q1, &flagB, 10/portTICK_RATE_MS) == pdTRUE) {
printf("interrupt flag B\n");
flagB = 0;
//gpio_intr_disable(GPIO_pinA);
//gpio_intr_disable(GPIO_pinB);
counter= counter -1 ;
}
if (f_1s == 1){
f_1s =0;
printf("counter = %d \n", counter );
gpio_intr_enable(GPIO_pinA);
gpio_intr_enable(GPIO_pinB);
xQueueReset(q1);
}
vTaskDelay(10/portTICK_RATE_MS);
}
vTaskDelete(NULL);
}
void init_timer (void){
}
void init_gpio(void) {
gpio_config_t io_conf_pinA;
gpio_config_t io_conf_pinB;
//###################### GPIO INIT ##########################
//interrupt of falling edge
io_conf_pinA.pin_bit_mask =GPIO_SEL_25;
io_conf_pinA.mode = GPIO_MODE_INPUT;
io_conf_pinA.pull_up_en = 1;
io_conf_pinA.pull_down_en = 0;
io_conf_pinA.intr_type = GPIO_INTR_POSEDGE;
gpio_config(&io_conf_pinA);
//interrupt of falling edge
io_conf_pinB.pin_bit_mask = GPIO_SEL_17;
io_conf_pinB.mode = GPIO_MODE_INPUT;
io_conf_pinB.pull_up_en = 1;
io_conf_pinB.pull_down_en = 0;
io_conf_pinB.intr_type = GPIO_INTR_POSEDGE;
gpio_config(&io_conf_pinB);
//install gpio isr service
gpio_install_isr_service(0); // no flags
//hook isr handler for specific gpio pin
gpio_isr_handler_add(GPIO_pinA, gpio_isr_handler, (void*)GPIO_pinA);
gpio_isr_handler_add(GPIO_pinB, gpio_isr_handler, (void*)GPIO_pinB);
printf("INIT ROTARY ENCODER SUCCECED!\n");
}
void app_main()
{
//nvs_flash_init();
//tcpip_adapter_init();
init_gpio();
//init_timer();
//############## QUEUE INIT #############
q1 = xQueueCreate(1, sizeof(int));
//iGroup = xEventGroupCreate();
//xTaskCreate(spi_bus, "BUS SPI", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
xTaskCreate(example_tg0_timer_init, "timer_evt_task", 2048, NULL, 10, NULL);
xTaskCreate(gpio_task, "gpio_task",2048, NULL, 5, NULL);
//vTaskStartScheduler();
while (1){
vTaskDelay(10/portTICK_RATE_MS);
}
}