lovyan03 / LovyanGFX

SPI LCD graphics library for ESP32 (ESP-IDF/ArduinoESP32) / ESP8266 (ArduinoESP8266) / SAMD51(Seeed ArduinoSAMD51)
Other
1.03k stars 189 forks source link

Multiple spi touch screen + rfid reader #420

Closed Mechalicious closed 9 months ago

Mechalicious commented 10 months ago

Hi,

I connected both touch screen and rfid reader to an esp32 Both are working separately but i can't make them work together I might have troubles configuring spi in lgfx My config:

#pragma once

#define LGFX_USE_V1

#include <LovyanGFX.hpp>
#include <driver/i2c.h>
#include <SPI.h>

#define LANDSCAPE

#ifdef LANDSCAPE
extern const uint16_t screenWidth = 480;
extern const uint16_t screenHeight = 320;
#else
static const uint16_t screenWidth = 320;
static const uint16_t screenHeight = 480;
#endif

class LGFX : public lgfx::LGFX_Device
{
    lgfx::Panel_ILI9488  _panel_instance;
    lgfx::Bus_SPI       _bus_instance;
    lgfx::Light_PWM     _light_instance;
    lgfx::Touch_GT911   _touch_instance;
  public:
    LGFX(void)
    {
      {
        auto cfg = _bus_instance.config();
        cfg.spi_host         = SPI3_HOST;
        cfg.spi_mode         = 0;
        cfg.freq_write       = 40000000;
        cfg.freq_read        = 16000000;
        cfg.spi_3wire        = true;
        cfg.use_lock         = true;
        cfg.dma_channel      = SPI_DMA_CH_AUTO;
        cfg.pin_sclk         = 12;
        cfg.pin_mosi         = 11;
        cfg.pin_miso         = 13;
        cfg.pin_dc           =  16;

        _bus_instance.config(cfg);
        _panel_instance.setBus(&_bus_instance);
      }

      {
        auto cfg = _panel_instance.config();

        cfg.pin_cs           =    15;
        cfg.pin_rst          =    -1;
        cfg.pin_busy         =    -1;

        cfg.panel_width      =   320;
        cfg.panel_height     =   480;
        cfg.offset_x         =     0;
        cfg.offset_y         =     0;
        cfg.offset_rotation  =     0;
        cfg.dummy_read_pixel =     8;
        cfg.dummy_read_bits  =     1;
        cfg.readable         =  true;
        cfg.invert           = false;
        cfg.rgb_order        = false;
        cfg.dlen_16bit       = false;
        cfg.bus_shared       = false;

        _panel_instance.config(cfg);
      }

      {
        auto cfg = _light_instance.config();

        cfg.pin_bl = 21;
        cfg.invert = false;
        cfg.freq   = 44100;
        cfg.pwm_channel = 7;

        _light_instance.config(cfg);
        _panel_instance.setLight(&_light_instance);
      }

      {
        auto cfg = _touch_instance.config();
        cfg.pin_scl  = GPIO_NUM_35;
        cfg.pin_sda  = GPIO_NUM_36;
        cfg.pin_int  = GPIO_NUM_37;
        cfg.i2c_addr = 0x5D;
        cfg.i2c_port = I2C_NUM_0;
        cfg.freq     = 400000;
        cfg.x_min    =  14;
        cfg.x_max    = 310;
        cfg.y_min    =   5;
        cfg.y_max    = 448;
        cfg.offset_rotation = 0;
        cfg.bus_shared = false;

        _touch_instance.config(cfg);
        _panel_instance.setTouch(&_touch_instance);
      }

      setPanel(&_panel_instance);
    }
};

Below, in the initRfid if i uncomment SPI.Begin(); the reader works well but no more screen. The opposite happens if i comment SPI.begin();

void initRfid() {
  //SPI.begin(12, 13, 11, 5);
  rfid.PCD_Init();
   delay(4);
  rfid.PCD_DumpVersionToSerial();
  Serial.println("RFID Initialized");
}

void setup() {
  Serial.begin(115200);

// INIT LGFX

  initLvglLgfx();

  // INIT RFID
  //SPI.begin(12, 13, 11, 5);

  initRfid();

  Serial.println("Initialized LVGL - LGFX");

  // INIT WIFI
 // initWifi();
  // VIEW

  ESP_LOGI(TAG, "Ready to start a demo. Tap a button on screen. Reset the board with the reset button or Ctrl+T Ctrl+R to pick a new one.");
}

void loop()
{
    lv_timer_handler();
    vTaskDelay(pdMS_TO_TICKS(TASK_SLEEP_PERIOD_MS));

  unsigned long currentMillis = millis();

  unsigned long elapsedMillis = currentMillis - StartOfInterval;
  //Serial.println("elapsedmillis: " + elapsedMillis);
  if (elapsedMillis >= ResetInterval)
  {
    StartOfInterval = currentMillis;
    elapsedMillis = 0;
    rfid.PCD_Reset();
    initRfid();
    Serial.println("Resetting reader");
  }

  if (spiState) {
    digitalWrite(15, LOW);
    digitalWrite(5, HIGH);
    rfidCheck();
  } else {
    digitalWrite(15, HIGH);
    digitalWrite(5, LOW);
  }
  spiState = !spiState;
}

How can i configure the spi bus to make them work ?

lovyan03 commented 10 months ago

you can use SPI2_HOST.

cfg.spi_host = SPI2_HOST;

Mechalicious commented 10 months ago

Thanks, It's "working" unfortunately i'm having trouble reading data from both spi "at the same time" Changing the cs pin too fast in the loop doesn't work for both It does when i put a long wait time between both periphericals but i want to use cs quite simultaneously Would you know a better way to handle the data ?

lovyan03 commented 10 months ago

Do not manipulate the CS pin outside of the library without permission. If you do so, it is only natural that they will stop working.

Mechalicious commented 10 months ago

How can I use digitalWrite with the lib ? i'm not finding any method or how can I use permissions

lovyan03 commented 10 months ago

Normally, the SPI bus is released after use; assertion and deassertion of the CS pin is automatic. All you have to do is to exclusively control multiple SPI devices so that their communication does not occur at the same time. I don't know how the RFID library is built, but you just need to make sure that it does not communicate with the RFID during the LCD drawing operation.

Mechalicious commented 10 months ago

How would you stop the communication with the display in lgfx in order to communicate with the RFID module ?

lovyan03 commented 10 months ago

No communication unless drawing instructions are used. If you are using LVGL, there should be an instruction to draw to the LCD in the drawing handler you wrote.

Mechalicious commented 10 months ago

Okay thank you very much

lovyan03 commented 10 months ago

If you are using startWrite, the SPI bus is occupied until you use endWrite. In this case, use endWrite before communicating with RFID, and use startWrite after communicating with RFID.

Mechalicious commented 10 months ago

Sorry, i'm Still having troubles making both work Would you mind taking a look at what's wrong ?

The loop

void loop()
{
    lv_timer_handler();
    vTaskDelay(pdMS_TO_TICKS(TASK_SLEEP_PERIOD_MS));

  unsigned long currentMillis = millis();

  unsigned long elapsedMillis = currentMillis - StartOfInterval;
  if (elapsedMillis >= ResetInterval && !spiState)
  {
    StartOfInterval = currentMillis;
    elapsedMillis = 0;
    rfid.PCD_Reset();
    initRfid(); 
    Serial.println("Resetting reader");
  }

  if (!spiState) {
    rfidCheck();
  }

  unsigned long elapsedMillis2 = currentMillis - RfidStartOfInterval;
// 50ms 
  if (elapsedMillis2 >= ScreenRfidResetInterval) {
    elapsedMillis2 = 0;
    RfidStartOfInterval = currentMillis;
    spiState = !spiState;
  }  
}

The rfidcheck :

void rfidCheck() {

 if ( ! rfid.PICC_IsNewCardPresent())
    return;

  // Verify if the NUID has been readed
  if ( ! rfid.PICC_ReadCardSerial())
    return;

  Serial.print(F("PICC type: "));
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  Serial.println(rfid.PICC_GetTypeName(piccType));

  if (rfid.uid.uidByte[0] != nuidPICC[0] || 
    rfid.uid.uidByte[1] != nuidPICC[1] || 
    rfid.uid.uidByte[2] != nuidPICC[2] || 
    rfid.uid.uidByte[3] != nuidPICC[3] ) {
    Serial.println(F("A new card has been detected."));

    // Store NUID into nuidPICC array
    for (byte i = 0; i < 4; i++) {
      nuidPICC[i] = rfid.uid.uidByte[i];
    }

    Serial.println(F("The NUID tag is:"));
    Serial.print(F("In hex: "));
    printHex(rfid.uid.uidByte, rfid.uid.size);
    Serial.println();
    Serial.print(F("In dec: "));
    printDec(rfid.uid.uidByte, rfid.uid.size);
    Serial.println();
    playSound();
  }
  else Serial.println(F("Card read previously."));

  rfid.PICC_HaltA();

  rfid.PCD_StopCrypto1();
}

The display flush:

static void display_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
  #ifdef DISABLE_FLUSH_DURING_BENCHMARK
  if (disable_flush) {
    lv_disp_flush_ready(disp);
    return;
  }
  #endif 

  if (spiState) {
   uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);
    Serial.println("Calling display flush");
    display.startWrite();
    display.setAddrWindow(area->x1, area->y1, w, h);
    display.writePixels((uint16_t *)&color_p->full, w * h, true);
    display.endWrite();
  }
    lv_disp_flush_ready(disp);

}
lovyan03 commented 9 months ago

display_flush関数では必ずフラッシュする必要があると思いますが、 spiStateによって勝手に分岐してデータを破棄すると動作がおかしくなりませんか?

これはLGFXのバグではなくてあなたのプログラムの問題だと思います。私はあなたの便利なデバッガーではありません。 LGFXのバグだというのであれば確実に再現できるコンパクトなプログラムを用意して新しいIssueを作ってください。