TFT display conflict with Rotary Encoder in ESP32 project

Hi Guys
I have problem with Rotary Encoder and TFT display in my ESP32 project.
I have tested this code with only TFT display connected with ESP32, it works fine.

#include <lvgl.h>
#include <Arduino_GFX_Library.h>
#include <ui.h>

/*Don't forget to set Sketchbook location in File/Preferencesto the path of your UI project (the parent foder of this INO file)*/

//GFX Display databus and driver setting
#define GFX_BL DF_GFX_BL // default backlight pin, you may replace DF_GFX_BL to actual backlight pin

/* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */
#if defined(DISPLAY_DEV_KIT)
Arduino_GFX *gfx = create_default_Arduino_GFX();
#else /* !defined(DISPLAY_DEV_KIT) */

/* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */
Arduino_DataBus *bus = new Arduino_ESP32LCD8(
    11 /*DC*/, 12 /*CS*/, 10 /* WR */, 9 /* RST */,
    46 /* D0 */, 3 /* D1 */, 8 /* D2 */, 18 /* D3 */, 17 /* D4 */, 16 /* D5 */, 15 /* D6 */, 7 /* D7 */);

/* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */
Arduino_GFX *gfx = new Arduino_HX8369A(bus, DF_GFX_RST, 1 /* rotation */, false /* IPS */);

#endif /* !defined(DISPLAY_DEV_KIT) */
/*******************************************************************************
 * End of Arduino_GFX setting
 ******************************************************************************/

And then I connected Rotary Encoder with ESP32, with the Pins below

#define ENC_A 9
#define ENC_B 10
#define MaxVolume 100
#define MinVolume 0
volatile int counter = 0;

I used GPIO9 for PinA and GPIO 10 for PinB of Rotary Encoder.
This is the schematic of Rotary Encoder is below

And I tested Rotary Encoder alone, it works fine

#define ENC_A 9
#define ENC_B 10
#define MaxVolume 100
#define MinVolume 0

volatile int counter = 0;

void setup() {

  // Set encoder pins and attach interrupts
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENC_A), read_encoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ENC_B), read_encoder, CHANGE);

  // Start the serial monitor to show output
  Serial.begin(115200); // Change to 9600 for Nano, 115200 for ESP32
  delay(500);           // Wait for serial to start  
  Serial.println("Start");
}

void loop() {
  static int lastCounter = 0;

  // If count has changed print the new value to serial
  if(counter != lastCounter){
    Serial.println(counter);
    lastCounter = counter;
  }
}

void read_encoder() {
  // Encoder interrupt routine for both pins. Updates counter
  // if they are valid and have rotated a full indent
 
  static uint8_t old_AB = 3;  // Lookup table index
  static int8_t encval = 0;   // Encoder value  
  static const int8_t enc_states[]  = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; // Lookup table

  old_AB <<=2;  // Remember previous state

  if (digitalRead(ENC_A)) old_AB |= 0x02; // Add current state of pin A
  if (digitalRead(ENC_B)) old_AB |= 0x01; // Add current state of pin B
  
  encval += enc_states[( old_AB & 0x0f )];

  // Update counter if encoder has rotated a full indent, that is at least 4 steps
  if( encval > 3 ) {        // Four steps forward
    counter++;              // Increase counter
    if (counter > MaxVolume) counter = 100;
    encval = 0;
  }
  else if( encval < -3 ) {  // Four steps backwards
   counter--;               // Decrease counter
   if (counter < MinVolume) counter = 0;
   encval = 0;
  }
}

Then I put the TFT code and Rotary Encoder together. This is the Code

#include <lvgl.h>
#include <Arduino_GFX_Library.h>
#include <ui.h>

/*Don't forget to set Sketchbook location in File/Preferencesto the path of your UI project (the parent foder of this INO file)*/

//GFX Display databus and driver setting
#define GFX_BL DF_GFX_BL // default backlight pin, you may replace DF_GFX_BL to actual backlight pin

/* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */
#if defined(DISPLAY_DEV_KIT)
Arduino_GFX *gfx = create_default_Arduino_GFX();
#else /* !defined(DISPLAY_DEV_KIT) */

/* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */
Arduino_DataBus *bus = new Arduino_ESP32LCD8(
    11 /*DC*/, 12 /*CS*/, 10 /* WR */, 9 /* RST */,
    46 /* D0 */, 3 /* D1 */, 8 /* D2 */, 18 /* D3 */, 17 /* D4 */, 16 /* D5 */, 15 /* D6 */, 7 /* D7 */);

/* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */
Arduino_GFX *gfx = new Arduino_HX8369A(bus, DF_GFX_RST, 1 /* rotation */, false /* IPS */);

#endif /* !defined(DISPLAY_DEV_KIT) */
/*******************************************************************************
 * End of Arduino_GFX setting
 ******************************************************************************/
 
/*Change to your screen resolution*/
//static const uint16_t screenWidth  = 480;
//static const uint16_t screenHeight = 800;
static uint32_t screenWidth;
static uint32_t screenHeight;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t *disp_draw_buf;
static lv_color_t *disp_draw_buf2;
static lv_disp_drv_t disp_drv;

//测试用参数
unsigned long watch_tick = 0;
int VolumePoint[] = {10,60,100,80,30,75,45};
uint8_t VolumePointsCount = 7;
uint8_t VolumePointsIndex = 0;
int VolumeVal = 0;
char VolumeText[16];


//音量旋转编码器参数
#define ENC_A 9
#define ENC_B 10
#define MaxVolume 100
#define MinVolume 0
volatile int counter = 0;

//增加触屏板头文件
#include "touch.h"

#if LV_USE_LOG != 0
/* Serial debugging */
void my_print(const char * buf)
{
    Serial.printf(buf);
    Serial.flush();
}
#endif

/* Display flushing */
void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p )
{
    uint32_t w = ( area->x2 - area->x1 + 1 );
    uint32_t h = ( area->y2 - area->y1 + 1 );

    #if (LV_COLOR_16_SWAP != 0)
      gfx->draw16bitBeRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h);
    #else
      gfx->draw16bitRGBBitmap(area->x1, area->y1, (uint16_t *)&color_p->full, w, h);
    #endif

    lv_disp_flush_ready( disp );
}

/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * indev_driver, lv_indev_data_t * data )
{
   //已更改为GT911驱动所需格式
   if (touch_has_signal())
    {
        if (touch_touched())
        {
            data->state = LV_INDEV_STATE_PR;

            /*Set the coordinates*/
            data->point.x = touch_last_x;
            data->point.y = touch_last_y;
        }
        else if (touch_released())
        {
            data->state = LV_INDEV_STATE_REL;
        }
    }
    else
    {
        data->state = LV_INDEV_STATE_REL;
    }
}

//音量旋转编码器对应的中断例程
void IRAM_ATTR read_encoder() {
  // Encoder interrupt routine for both pins. Updates counter
  // if they are valid and have rotated a full indent
 
  static uint8_t old_AB = 3;  // Lookup table index
  static int8_t encval = 0;   // Encoder value  
  static const int8_t enc_states[]  = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; // Lookup table

  old_AB <<=2;  // Remember previous state

  if (digitalRead(ENC_A)) old_AB |= 0x02; // Add current state of pin A
  if (digitalRead(ENC_B)) old_AB |= 0x01; // Add current state of pin B
  
  encval += enc_states[( old_AB & 0x0f )];

  // Update counter if encoder has rotated a full indent, that is at least 4 steps
  if( encval > 3 ) {        // Four steps forward
    counter++;              // Increase counter
    if (counter > MaxVolume) counter = 100;
    encval = 0;
  }
  else if( encval < -3 ) {  // Four steps backwards
   counter--;               // Decrease counter
   if (counter < MinVolume) counter = 0;
   encval = 0;
  }
}

void setup()
{
    Serial.begin( 115200 ); /* prepare for possible serial debug */
   
    //设置音量旋转编码器对应的GPIO,并关连相应中断
    pinMode(ENC_A, INPUT_PULLUP);
    pinMode(ENC_B, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(ENC_A), read_encoder, CHANGE);
    attachInterrupt(digitalPinToInterrupt(ENC_B), read_encoder, CHANGE);

    String LVGL_Arduino = "Hello Arduino! ";
    LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();

    Serial.println( LVGL_Arduino );
    Serial.println( "I am LVGL_Arduino" );

    #ifdef GFX_PWD
      pinMode(GFX_PWD, OUTPUT);
      digitalWrite(GFX_PWD, HIGH);
    #endif

    // Init Display
    touch_init();//触摸屏初始化
    gfx->begin();
    gfx->fillScreen(BLACK);

    #ifdef GFX_BL
      pinMode(GFX_BL, OUTPUT);
      digitalWrite(GFX_BL, HIGH);
    #endif

    lv_init();

    screenWidth = gfx->width();
    screenHeight = gfx->height();

    #ifdef ESP32
      disp_draw_buf = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * screenWidth * 32, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
      // disp_draw_buf2 = (lv_color_t *)heap_caps_malloc(sizeof(lv_color_t) * screenWidth * 32, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
    #else
      disp_draw_buf = (lv_color_t *)malloc(sizeof(lv_color_t) * screenWidth * 32);
    #endif
    if (!disp_draw_buf)
    {
      Serial.println("LVGL disp_draw_buf allocate failed!");
    }
    else
    {
    
    if (!disp_draw_buf2)
    {
      Serial.println("LVGL disp_draw_buf2 not allocated!");
      lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, NULL, screenWidth * 32);
    }
    else
    {
      lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, disp_draw_buf2, screenWidth * 32);
    }
    
    /*Initialize the display*/
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init( &disp_drv );
    /*Change the following line to your display resolution*/
    disp_drv.hor_res = screenWidth;
    disp_drv.ver_res = screenHeight;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register( &disp_drv );

    /*Initialize the (dummy) input device driver*/
    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init( &indev_drv );
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = my_touchpad_read;
    lv_indev_drv_register( &indev_drv );


    ui_init();

    Serial.println( "Setup done" );
    }
}

void loop()
{
   static int lastCounter = 0;//音量旋转编码器计数状态重置
  
   // If count has changed print the new value to serial
   if(counter != lastCounter){
       Serial.println(counter);
       lastCounter = counter;

   }
   
   if(millis() > (watch_tick + 20))
   {
       //改变显示屏的音量显示数字
       VolumeVal = counter;
       itoa(VolumeVal, VolumeText, 10);
       lv_label_set_text(ui_Label2, VolumeText);
   }

/*
    //改变音量显示数字测试
    int Target_Volume = VolumePoint[VolumePointsIndex];
    char VolumeText[16];

    if(millis() > (watch_tick + 20))
    {
      if(VolumeVal < Target_Volume)
      {
        //音量数字增加
        VolumeVal = VolumeVal + 1;
      }

      if(VolumeVal > Target_Volume)
      {
        //音量数字减小
        VolumeVal = VolumeVal - 1;
      }

      if(VolumeVal == Target_Volume)
      {
        VolumePointsIndex++;

        if(VolumePointsIndex == VolumePointsCount)
        {
          VolumePointsIndex = 0;        
        }
      }

      watch_tick = millis() + 20;

      itoa(VolumeVal, VolumeText, 10);
      lv_label_set_text(ui_Label2, VolumeText);
    }

    Serial.println(VolumeText);
*/    
    lv_timer_handler(); /* let the GUI do its work */
    delay(5);
}


This is the code in Loop() which control the Digit of Lable1 of Screen

   static int lastCounter = 0;//音量旋转编码器计数状态重置
  
   // If count has changed print the new value to serial
   if(counter != lastCounter){
       Serial.println(counter);
       lastCounter = counter;

   }
   
   if(millis() > (watch_tick + 20))
   {
       //改变显示屏的音量显示数字
       VolumeVal = counter;
       itoa(VolumeVal, VolumeText, 10);
       lv_label_set_text(ui_Label2, VolumeText);
   }

When upload the program to ESP32, the screen shows correctly, but if I turned the Rotary Encode. The TFT screen will turn to Black and shows nothing, and will not show anything anymore.

Found the problem. The Pins used for Rotary Encoder

and the Pins used for TFT screen

GPIO9 and GPIO10 are conflict

I changed GPIO6 for PinA and GPIO13 for PinB of Rotary Encoder, everything works fine now. :grinning:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.