jgromes / RadioLib

Universal wireless communication library for embedded devices
https://jgromes.github.io/RadioLib/
MIT License
1.41k stars 355 forks source link

Radiolib blocking other SPI devices #827

Closed koattila closed 9 months ago

koattila commented 9 months ago

Controller: ESP32 Radio module: CC1101 Lib version: 5.3.0

I was using radiolib for controlling CC1101 modul (e07 400m10s), and it is working without a problem.

What I tried to do next is, to get SPI inputs from XPT2046 chip (gives touch outputs from touch screen), when I call "radio.begin();", the touch controller stops receiving inputs from SPI bus. The Radiolib is still working, so only the TFT_Touch.h actions are blocked. Can you please advice how can I use the library with other SPI devices ?

Both devices have differenct CSN pins.

#include <TFT_Touch.h>
#include <SPI.h>
#include <TFT_eWidget.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <RadioLib.h>

#define CC1101CSNPIN 0
#define GDO0PIN 39
// These are the pins used to interface between the 2046 touch controller and Arduino Mega
#define DOUT 23  /* Data out pin (T_DO) of touch screen */
#define DIN  19  /* Data in pin (T_DIN) of touch screen */
#define DCS  5  /* Chip select pin (T_CS) of touch screen */
#define DCLK 18  /* Clock pin (T_CLK) of touch screen */

// These are the default min and maximum values, set to 0 and 4095 to test the screen
#define HMIN 0
#define HMAX 4095
#define VMIN 0
#define VMAX 4095
#define XYSWAP 0 // 0 or 1

// This is the screen size for the raw to coordinate transformation
// width and height specified for landscape orientation
#define HRES 480 /* Default screen resulution for X axis */
#define VRES 320 /* Default screen resulution for Y axis */

/* Create an instance of the touch screen library */
TFT_Touch touch = TFT_Touch(DCS, DCLK, DIN, DOUT);

TFT_eSPI tft = TFT_eSPI();

CC1101 radio = new Module(CC1101CSNPIN,GDO0PIN, RADIOLIB_NC);

unsigned long timeDisplay;

void setup()
{
  unsigned long currTime = millis();
  timeDisplay = currTime;
  Serial.begin(115200);

  int state = radio.begin();

  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
  }
  radio.standby();
  tft.init();

  tft.setRotation(1);
  touch.setCal(HMIN, HMAX, VMIN, VMAX, HRES, VRES, XYSWAP); // Raw xmin, xmax, ymin, ymax, width, height
  touch.setRotation(1);
}

/* Main program */
void loop()
{
  //Serial.println(digitalRead(CSNPIN));
  //Serial.println(digitalRead(0));
  unsigned int X_Raw;
  unsigned int Y_Raw;

  /* Check if the touch screen is currently pressed*/
  // Raw and coordinate values are stored within library at this instant
  // for later retrieval by GetRaw and GetCoord functions.
  // This avoids getting duff values returned
  if (touch.Pressed()) // Note this function updates coordinates stored within library variables
  {
    /* Read the current X and Y axis as raw co-ordinates at the last touch time*/
    // The values returned were captured when Pressed() was called!

    X_Raw = touch.RawX();
    Y_Raw = touch.RawY();

    /* Output the results to the serial port */
    Serial.print("Raw x,y = ");
    Serial.print(X_Raw);
    Serial.print(",");
    Serial.println(Y_Raw);
    delay(10);
  }
  delay(10);

  if(timeDisplay + 1000 < millis()){
      // Draw some random circles
    for (int i = 0; i < 40; i++)
    {
      int rx = random(60);
      int ry = random(60);
      int x = rx + random(480 - rx - rx);
      int y = ry + random(320 - ry - ry);
      tft.fillEllipse(x, y, rx, ry, random(0xFFFF));
    }

    for (int i = 0; i < 40; i++)
    {
      int rx = random(60);
      int ry = random(60);
      int x = rx + random(480 - rx - rx);
      int y = ry + random(320 - ry - ry);
      tft.drawEllipse(x, y, rx, ry, random(0xFFFF));
    }
    timeDisplay = millis();
  }
}

Thank you in advance!

jgromes commented 9 months ago

There's nothing in RadioLib that could "block other SPI devices" - all SPI accesses are wrapped in begin/endTransaction, as they should be.

Instead I would guess that the TFT library is attempting to init SPI with SPI::begin. And because you are using the default SPI bus, RadioLib will attempt to initialize it too. I don't know what happens when SPI::begin gets called twice on ESP32.

You can use a non-default SPI setup to let RadioLib know it should not automatically initalize the bus, see this wiki page: https://github.com/jgromes/RadioLib/wiki/Basics

Also, looking at its source, the TFT_Touch library seems to be doing very strange things with the SPI bus, such as directly changing the pin states as opposed to using the SPI peripheral. So I'm not sure why do you believe this is a problem in RadioLib.

Also also, out of experience, some SPI devices just plain ignore the state of the CS pin, so sometimes there is no other way but to use a different SPI bus. Keep in mind that even if everything works, it's not a good idea to put the communication module on the same bus as the control input - while the radio is writing/reading a packet, you will not get any traffic to/from the display and vice versa.

koattila commented 9 months ago

I'm kind of short of pins, so it would be hard to use separate buses. Is it possible to daisy chain these devices, or strip the CS pins to low, so the slaves on the separate buses are always enabled ?

jgromes commented 9 months ago

I'm kind of short of pins, so it would be hard to use separate buses

You don't have to use a different SPI bus, you just have to explicitly specify it (even if it the same), so that RadioLib does not attempt to initialize it. You can do the following even if HSPI happens to be the default SPI bus.

SPIClass spi(HSPI);
SPISettings spiSettings(2000000, MSBFIRST, SPI_MODE0);
CC1101 radio = new Module(cs, irq, RADIOLIB_NC, RADIOLIB_NC, spi, spiSettings);

or strip the CS pins to low, so the slaves on the separate buses are always enabled

Don't understand what you mean by that, sorry.

jgromes commented 9 months ago

Closing as stale - feel free to reopen later if more information becomes available (though I remain convinced this is not an issue in RadioLib).

irl-ops commented 5 months ago

I don't really have anything helpful to add other than that I have a similar issue. I am using the Adafruit ILI9341 display library to control a display via SPI. The display works great unit RadioLib starts up, then goes unresponsive. I have tried calling the endWrite() function from the Adafruit library after accessing the display which should call SPI.endTransaction() but that doesn't seem to help either. I don't really have time to investigate further, as jgromes said, it could even be a hardware bug.