dparson55 / NRFLite

nRF24L01+ library with AVR 2 pin support, requiring very little code along with YouTube videos showing all available features. It can be installed via the Arduino IDE Library Manager
MIT License
155 stars 25 forks source link

NRFlite using second SPI hardware bus #58

Closed freetoair closed 3 years ago

freetoair commented 3 years ago

Hi Dave ! Let me explain my problem first, I must have to use 2` SPI on ESP32 because TFT ST7789 has CE pin hardwired on GND, so i can't use shared SPI with nRF24L01. According to the example for ESP32 SPI_Multiple_Buses it is possible to define two objects that use different hardware SPI interfaces (HSPI, VSPI). Is it possible to somehow use a new SPI object in NRFlite, which is previously defined in the void setup (). Obviously I'm not some C/C++ expert, but I tried everything I could. Even the version with SoftSPI would be helpful.

dparson55 commented 3 years ago

Hi man! NRFLite doesn't support SPI objects and just uses the default SPI pins setup by the SPI library, but I think you can use the radio and display on the same SPI bus. The CE pin is not used for SPI communication, it just turns on or enables the device in question. So rather than the CE pin, the chip select/slave select pin is the important one for SPI as it controls which device interacts with the SPI bus. On the nRF24L01+ this pin is labeled CSN while on the TFT ST7789 it is labeled CS. On the ESP32 it seems like the HSPI pins are used as the default SPI pins, so try connecting the ESP32 HSPI pins for MISO, MOSI, and SCK to the associated pins on the radio and display, then use separate pins for the CSN and CS pins on the devices.

I threw this together from some examples I found, maybe it will help.

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#include <NRFLite.h>

// Display
#define TFT_CS     15 // Using 15 because it is the default Slave Select pin for HSPI
#define TFT_DC     9
#define TFT_RST    8  // Reset pin, or set to -1 and connect to Arduino RESET pin

Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
SPIClass * hspi = NULL;

// Radio
const static uint8_t RADIO_ID = 0;
const static uint8_t PIN_RADIO_CE = 4;
const static uint8_t PIN_RADIO_CSN = 5;

NRFLite _radio;

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

    // Setup the SPI bus.
    hspi = new SPIClass(HSPI); // MISO = 12, MOSI = 13, SCLK = 14, SS = 15
    hspi->begin(); 

    tft.init(240, 240, SPI_MODE0); // The radio uses mode 0 so hopefully this mode works with the tft.
    tft.fillScreen(ST77XX_BLACK); // See if the display actually works.

    // Indicate to NRFLite that it should not call SPI.begin() during initialization since it has already been done.
    uint8_t callSpiBegin = 0;

    if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE2MBPS, 100, callSpiBegin))
    {
        Serial.println("Cannot communicate with radio");
        while (1); // Wait here forever.
    }
}

void loop() { }
eriklukas commented 3 years ago

I have a similar issue with STM32F103C8 Bluepill, although I'm not using a display and just want to utilize the second SPI.

#include <SPI.h>
#include <NRFLite.h>

NRFLite _radio;
uint8_t _data;

const static uint8_t RADIO_ID = 0;
const static uint8_t PIN_RADIO_CE = PA8;
const static uint8_t PIN_RADIO_CSN = PB12;

void setup()
{
    Serial.begin(115200);
    while(!Serial)
        ;
    SPIClass SPI_2(PB15,PB14,PB13);
    SPI_2.begin();
    uint8_t callSpiBegin = 0;
    if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE2MBPS, 100, callSpiBegin))
    {
        Serial.println("Cannot communicate with radio");
        while (1); // Wait here forever.
    }
}

void loop()
{
    while (_radio.hasData())
    {
        _radio.readData(&_data);
        Serial.println(_data);
    }

}
freetoair commented 3 years ago

Hi Dave ! Thanks for your prompt response. Looks like we didn't understand , I don't have access to the CE line. It is simply not connected to the display port. Someone who designed the printed board thought it was not necessary and connect it permanently to the GND. That's why I can't use a shared SPI bus, Once you turn on the ST7789 it doesn't release the SPI bus so that some other peripherals can use the same SPI lines. In the meantime, I was able to customize another library (RF24.h) that has the ability for SoftSPI to work with ESP32. There were small problems with setting the parameters for receiving NRFlite format, but I succeeded. Otherwise for those who want to use this library (RF24.h) on ESP32, they should know that it does not work in the original with ESP32 in SoftSPI mode. Since the ESP32 is a very fast controller SoftSPI works satisfactorily fast. Anyway thanks for the effort to help me !

@Lukas1337 NRFlite calls the SPI.xxx functions directly from the SPI driver for a particular controller, and the other connected SPI peripherals do the same, causing a collision on the bus. Although you created a new SPI object for SPI_2 it is never called from NRFlite.

regards, freetoair !

eriklukas commented 3 years ago

Thank you for the reply, how do I set up NRFlite so that it calls the new object? Or is there a better way?

freetoair commented 3 years ago

@Lukas1337 That was my question for @ dparson55. Unfortunately, changing the library seems either impossible or difficult. I'm not good enough at C/C++ to be able to do it myself. Unfortunately !!!

freetoair commented 3 years ago

@Lukas1337 If you use a fast enough controller on the receiving side, then the variant with RF24 and SoftSPI will be enough in most cases.

dparson55 commented 3 years ago

@freetoair I think we are still not on the same page. You mentioned again that you do not have access to the CE pin. This is ok, it is not used for SPI communication. You do not need access to the CE pin for what I was suggesting.

CE = chip enable = not used for SPI CS/CSN/SS = chip select/chip select not/slave select = used for SPI communication

Are you actually saying the display you are using does not expose the CS pin? If you have a picture of the display and the pins it exposes, I could double check for you.

dparson55 commented 3 years ago

@freetoair and @Lukas1337 I started looking into if I could easily update NRFLite to allow providing an SPIClass object in the constructor. I don't have an ESP32 or STM32 to test with so could you test it for me?

The updated code is in the spi branch.

There are 2 ways it should be able to work.

ESP Method

#include <SPI.h>
#include <NRFLite.h>

const static uint8_t RADIO_ID = 0;
const static uint8_t PIN_RADIO_CE = 4;
const static uint8_t PIN_RADIO_CSN = 15; // Change this to either 15 or 5 for either HSPI or VSPI

SPIClass * _spi;
NRFLite _radio(_spi); // Provide the SPI object to NRFLite

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

    // Create the SPI object that will be used by NRFLite using the ESP enumeration
    // HSPI : MISO = 12, MOSI = 13, SCLK = 14, SS = 15
    // VSPI : MISO = 19, MOSI = 23, SCLK = 18, SS = 5
    _spi = new SPIClass(HSPI);

    if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN))
    {
        Serial.println("Cannot communicate with radio");
        while (1); // Wait here forever.
    }
}

void loop() { }

STM Method

#include <SPI.h>
#include <NRFLite.h>

const static uint8_t RADIO_ID = 1;
const static uint8_t PIN_RADIO_CE = 9;
const static uint8_t PIN_RADIO_CSN = 10;

SPIClass * _spi;
NRFLite _radio(_spi);  // Provide the SPI object to NRFLite

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

    // Create the SPI object that will be used by NRFLite using raw pin numbers
    _spi = new SPIClass();
    _spi->begin(13, 12, 11, PIN_RADIO_CSN); // SCK, MISO, MOSI, SS

    // Indicate to NRFLite that it should not call SPI.begin() during initialization since it has already been done.
    uint8_t callSpiBegin = 0;

    if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN, NRFLite::BITRATE2MBPS, 100, callSpiBegin))
    {
        Serial.println("Cannot communicate with radio");
        while (1); // Wait here forever.
    }
}

void loop() { }
eriklukas commented 3 years ago

Wow, thanks for your work. I'll try and test it this weekend!

dparson55 commented 3 years ago

Ok thanks!

freetoair commented 3 years ago

First I apologize for possible spelling mistakes, English is not my native language so I use Google Translate. I have now sent a picture of the display. Yes, that's right, the CE line on the printed board, that holds the display, is not connected. ST7789 pinout

I have ESP32, BluePill (STM32F103C8T6) and DIY MORE (STM32F407VGT6) available. I'll try it on all three boards now, and I'll send you how things are.

regards.

freetoair commented 3 years ago

Yes, I forgot to mention, my first choice for a graphics library is TFT_eSPI. This is because, as @bodmer claims, this library is better suited for 32 bit controllers, and I guess faster. In the meantime, I did it to connect the CE/CS pin on the ST7789 display instead of BLK, and the variant that Dave suggested with Adafruit GFX works great. But the TFT_eSPI/NRFlite (shared SPI) variant didn't work for me, probably due to the complicated TFT_eSPI setup. Now I need time to connect all this and try it.

dparson55 commented 3 years ago

@freetoair and @Lukas1337 just checking in to see if you can try out the new feature.