u8g2 ST7920 display with nRF24l01+ radio display corruption

Having a few issues with a 128x64 LCD, code is below.

First hooked this up yesterday, to an Arduino Nano as the only thing on it to fiddle with - got it working no real issues.

Today I have added an nRF24l01+ radio module (and an indicator LED with resistor), this seems to have corrupted the display in a curious way

this is what the screen looks like, you can probably work out what its meant to look like but its three rectangles horizontally, each with some text within - the "R" indicates the radio module is detected. Its picking up the speed its displaying over the radio, so it works.. just not quite right.

Arduino connections:

SPI Clock (pin 13) - display clock, radio clock
MOSI (pin 11) - display MOSI, radio MOSI
MISO (pin 12) - radio MISO
pin 8 - display select
pin 7 - radio CE
pin 6 - radio CSN

radio IRQ is left unconnected

code

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

#include <printf.h>
#include <nRF24L01.h>
#include <RF24_config.h>
#include <RF24.h>

#define LED   4

RF24 radio(7,6);  // CE, CSN
const byte radio_address[6] = "00001";
byte ThisDevice = 0x91;   // this device for radio comms
byte ListenToDevice = 0x81;   // the device to listen to messages from
bool RadioConnected = false;

unsigned long CarValue1[8] = {0}; // car data array
unsigned long CarValue2[8] = {0}; // car data array
unsigned long TNow = 0;
unsigned long LEDOff = 0;

U8G2_ST7920_128X64_F_HW_SPI u8g2(U8G2_R0, /* CS=*/ 8, /* reset=*/ U8X8_PIN_NONE);

#define SMALL_FONT  u8g2_font_t0_12_tr    // 8 px high font
#define LARGE_FONT  u8g2_font_crox3cb_tf     // 12 px high font
#define HUGE_FONT   u8g2_font_logisoso24_tf   // 24 px font


void setup(void) {
  pinMode(LED, OUTPUT);

  digitalWrite(LED, HIGH);
  delay(500);
  digitalWrite(LED, LOW);
  
  u8g2.begin();
  radio.begin();
  radio.setPALevel(RF24_PA_MIN);
  radio.setAutoAck(false);    // disable auto acknowledgement to enable broadcast mode to multiple devices at once
  radio.openReadingPipe(0, radio_address);
  radio.startListening();
  RadioConnected = radio.isChipConnected();
}

void loop(void) {
  TNow = micros();

  if (radio.available())
  {
    // radio packet!
    byte ReadBuffer[32] = {0};
    
    radio.read(&ReadBuffer, sizeof(ReadBuffer));

    if (ReadBuffer[1] == ListenToDevice)
    {
      // message from the thing we are listening to

      digitalWrite(LED, HIGH);
      LEDOff = TNow + 100000;
    
      switch (ReadBuffer[2])
      {
        case 0x02:
        {
          // highest speed message
          CarValue1[ReadBuffer[3]] = (ReadBuffer[4] << 24);
          CarValue1[ReadBuffer[3]] |= (ReadBuffer[5] << 16);
          CarValue1[ReadBuffer[3]] |= (ReadBuffer[6] << 8);
          CarValue1[ReadBuffer[3]] |= (ReadBuffer[7]);
          break;
        }
        case 0x04:
        {
          // most recent speed message
          CarValue1[ReadBuffer[3]] = (ReadBuffer[4] << 24);
          CarValue1[ReadBuffer[3]] |= (ReadBuffer[5] << 16);
          CarValue1[ReadBuffer[3]] |= (ReadBuffer[6] << 8);
          CarValue1[ReadBuffer[3]] |= (ReadBuffer[7]);
          
          break;
        }
        default:
        {
          // something we don't care about
        }
      }
    }
    
  }

  DisplaySpeed("Speed Car", 1,CarValue1[1]);    // always display car 1 for now

  if (TNow >= LEDOff)
  {
    digitalWrite(LED, LOW);
  }
  
  delay(1000);  
}


// show a single speed on the display, _Title goes in the header formatted with the car ID
// speed is in m/s * 1000
void DisplaySpeed(const char *_Title, byte CarID, unsigned long Speed)
{
    u8g2.clearBuffer();          // clear the internal memory

  // useful graphical functions
  //  .drawFrame(x, y, w, h);     // rectangular frame
  //  .drawRFrame(x, y, w, h, r);  // rounded frame
  //  .drawLine(x1, y1, x2, y2);
  //  .drawHLine(x, y, len);
  //  .drawVLine(x, y, len);
  //  .drawTriangle(x1, y1, x2, y2, x3, y3);
  //  .drawStr(x, y, "xyz");     // draw null terminated string, x,y is bottom left
  //  .getStrWidth("xyz"), returns width in pixels of a string, returns u8g2_uint_t

  // draw a header frame
  u8g2.drawFrame(0,0,128,14);

  char Title[32] = {0};

  sprintf(Title, "%s: %d", _Title, CarID);
  
  u8g2.setFont(SMALL_FONT);
  u8g2.drawStr(((128-(u8g2.getStrWidth(Title)))/2),11,Title); 

  if (RadioConnected)
  {
    u8g2.drawStr(5,11, "R");
  }
  else
  {
    u8g2.drawStr(5,11, "-");
  }

  // centred text
  char Buffer[10] = {0};
  dtostrf((Speed/1000.0), 4,2,Buffer);
  u8g2.drawFrame(0,15, 128, 34);
  u8g2.setFont(HUGE_FONT);
  u8g2.drawStr(((128-(u8g2.getStrWidth(Buffer)))/2),44, Buffer);

  char Footer[16] = "True m/s";
  u8g2.drawFrame(0,50, 128,14);
  u8g2.setFont(SMALL_FONT);
  u8g2.drawStr(((128-(u8g2.getStrWidth(Footer)))/2),61,Footer);    
  
  u8g2.sendBuffer();          // transfer internal memory to the display
}

the idea is there are radio packets going back and forth between two (other) devices, this listens in on the comms.

I suspected the LED on the SPI clock pin, so have removed the LED (this has fixed Nano SPI issues on other boards) but it appears to have made no difference here.

I have had a look on google, which noted not to use software and hardware SPI together, here I think I'm using hardware SPI for both devices

any ideas?

The ST7920 misbehaves in SPI mode. It listens even when CS is false.
You might be able to experiment with the PS pin.

But I suspect others have already tried that.

So you are stuck with wasting GPIO pins on software SPI.

David.

thats fair enough if thats what it takes, device this is going in is basically just the radio, the display, probably a 4 pin DIP switch (can put that on the analogue pins) and an RGB LED (ditto, well mostly since A6 & A7 don't work for outputs). so should have the pins

cheers, if its a known problem will have to work around it

:slight_smile:

moved to software SPI for the display, now works perfectly, many thanks