Rotary encoder problem with interruption

akon13014
Posts: 3
Joined: Tue May 29, 2018 8:48 am

Rotary encoder problem with interruption

Postby akon13014 » Thu Jul 19, 2018 7:20 am

Hi,
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);
	 }
 }
But I encounter a problem, when I turn in a direction, the interruption is random, once it will be on the signal A, once on the signal B (see screen below) whereas we should have only the A signal that goes into interruption. Yet when I look at the signals on the oscilloscope, I still have signal A before signal B
Capture2.PNG
Can you help me on the subject please?

ESP_Sprite
Posts: 9708
Joined: Thu Nov 26, 2015 4:08 am

Re: Rotary encoder problem with interruption

Postby ESP_Sprite » Fri Jul 20, 2018 10:50 am

Your image doesn't seem to work for me. Also, note that we have a pulse counter peripheral which can be programmed to handle rotary encoders entirely in hardware.

Who is online

Users browsing this forum: No registered users and 96 guests