Arduino Nano Freezes - LCD (i2c) x2 + NRF24L01+

My Arduino stops transmitting data through the NRF24L01+ after I add the LCD code update. Especially when I use lcd.print() or lcd.clear(). I am using the i2c protocol when communicating with the 2 LCDs, and then another one to communicate to collect information from another Arduino, thus there are 3 devices using the i2c protocol. If you know why it keeps freezing (stops transmitting) the signal, please let me know, thanks!

Here is my code:


#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#define SLAVE_ADDR 9
/*Create a unique pipe out. The receiver has to 
  wear the same unique code*/
  
const uint64_t pipeOut = 0xE8E8F0F0E1LL; //IMPORTANT: The same as in the receiver

RF24 radio(9, 10); // select  CSN  pin
LiquidCrystal_I2C  leftLCD(0x26, 16, 2);
LiquidCrystal_I2C  rightLCD(0x27, 16, 2);

int rd;
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 100;  //the value is a number of milliseconds



// The sizeof this struct should not exceed 32 bytes
// This gives us up to 32 8 bits channals
struct MyData {
  byte throttle;
  byte yaw;
  byte pitch;
  byte roll;
  byte AUX1;
  byte AUX2;
  byte otherData;
};
MyData data;

void resetData() 
{
  //This are the start values of each channal
  // Throttle is 0 in order to stop the motors
  //127 is the middle value of the 10ADC.
    
  data.throttle = 1;
  data.yaw = 127;
  data.pitch =17;
  data.roll = 1;
  data.AUX1 = 1;
  data.AUX2 = 1;
  data.otherData = 0;
}

void setup()
{
  //Start everything up
  radio.begin();
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.openWritingPipe(pipeOut);
  resetData();
  leftLCD.init(); 
  leftLCD.backlight();
  rightLCD.init(); 
  rightLCD.backlight();
  Wire.begin();

  // Initialize I2C communications as Slave
  Wire.begin(SLAVE_ADDR);

  // Function to run when data received from master
  Wire.onReceive(receiveEvent);

  startMillis = millis();  //initial start time
}





void receiveEvent() {
  // read one character from the I2C
  rd = Wire.read();

}


/**************************************************/

// Returns a corrected value for a joystick position that takes into account
// the values of the outer extents and the middle of the joystick range.
int mapJoystickValues(int val, int lower, int middle, int upper, bool reverse, int decrease, bool roundVal)
{
  val = constrain(val, lower, upper);
  if ( val < middle ){
    val = map(val, lower, middle, 0, 128);
    if(reverse)val+=decrease;
    else val-=decrease;
  }
  else{
    val = map(val, middle, upper, 128, 255);
    val-=decrease;
  }
  if(roundVal)
  {
    if((val-127)<3 && (val-127)>-3){
      val=127;
    }
  }
  return ( reverse ? 255 - val : val );
}

void loop()
{
  // The calibration numbers used here should be measured 
  // for your joysticks till they send the correct values.7
  data.throttle = mapJoystickValues( analogRead(A3), 13, 524, 1015, true, 0, false);
  data.yaw      = mapJoystickValues( analogRead(A2),  1, 505, 1020, true, 3, true);
  data.pitch    = mapJoystickValues( analogRead(A0), 12, 544, 1021, false, -25, true);
  data.roll     = mapJoystickValues( analogRead(A1), 34, 522, 1020, false,-6, true );
  data.otherData     = rd;
  data.AUX1     = digitalRead(4); //The 2 toggle switches
  data.AUX2     = digitalRead(5);
  radio.write(&data, sizeof(MyData));


 lcdUpdate();

}

void lcdUpdate()
{
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    leftLCD.clear();
    rightLCD.clear();
  //  LEFT LED
    leftLCD.setCursor(0,0);
    leftLCD.print("Throttle: ");
    leftLCD.setCursor(13,0);
    leftLCD.print(data.throttle);
    leftLCD.setCursor(0,1);
    leftLCD.print("Yaw: ");
    leftLCD.setCursor(13,1);
    leftLCD.print(data.yaw);
  //  DELAY BEFORE RESET
  //  LEFT LED
    rightLCD.setCursor(0,0);
    rightLCD.print("Pitch: ");
    rightLCD.setCursor(13,0);
    rightLCD.print(data.pitch);
    rightLCD.setCursor(0,1);
    rightLCD.print("Rpll: ");
    rightLCD.setCursor(13,1);
    rightLCD.print(data.roll);
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  }
}

Installation and Troubleshooting is for Problems with the Arduino IDE itself NOT your project. It says so in the description of the section.

Therefore I have moved your post here. Please be more careful where you post in future.

You may want to read this before you proceed:-
how to get the best out of this forum

When the code compiles what figures are you given for the amount of free SRAM it it telling you that you have?
What sort of Arduino do you have?

1 Like

You need to post the code on all the Arduinos that make up you project.

You need to post a schematic for all the devices that make up the N number of separate parts.

So, at least two sketches and two schematics.

You need to describe what the whole system is supposed to accomplish.

We'll wait. Well, I will anyway.

a7

1 Like

Hi, @gdesi
Welcome to the forum.

Can you please post a schematic of your project?
Please include power supplies, component names and pin labels.

How are you powering your project?

Thanks... Tom... :smiley: :+1: :coffee: :australia:

1 Like

I dont see where I can see the sram, here is what it says:

Sketch uses 5886 bytes (19%) of program storage space. Maximum is 30720 bytes.
Global variables use 337 bytes (16%) of dynamic memory, leaving 1711 bytes for local variables. Maximum is 2048 bytes.
C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.49.0_x86__mdqgnx93n4wtt\hardware\tools\avr/bin/avrdude -CC:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.49.0_x86__mdqgnx93n4wtt\hardware\tools\avr/etc/avrdude.conf -v -patmega328p -carduino -PCOM9 -b115200 -D -Uflash:w:C:\Users\PCUSER~1\AppData\Local\Temp\arduino_build_778838/droneTransmitter.ino.hex:i 

avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.49.0_x86__mdqgnx93n4wtt\hardware\tools\avr/etc/avrdude.conf"

         Using Port                    : COM9
         Using Programmer              : arduino
         Overriding Baud Rate          : 115200
         AVR Part                      : ATmega328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : Arduino
         Description     : Arduino
         Hardware Version: 3
         Firmware Version: 4.4
         Vtarget         : 0.3 V
         Varef           : 0.3 V
         Oscillator      : 28.800 kHz
         SCK period      : 3.3 us

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: reading input file "C:\Users\PCUSER~1\AppData\Local\Temp\arduino_build_778838/droneTransmitter.ino.hex"
avrdude: writing flash (5886 bytes):

Writing | ################################################## | 100% 0.88s

avrdude: 5886 bytes of flash written
avrdude: verifying flash memory against C:\Users\PCUSER~1\AppData\Local\Temp\arduino_build_778838/droneTransmitter.ino.hex:
avrdude: load data flash data from input file C:\Users\PCUSER~1\AppData\Local\Temp\arduino_build_7

....Goto #4.......

I copied a schematic online and then modified it by adding lcd(i2c protocol) and also another add on Arduino that also uses i2c protocol.

Here is the schematic


I am using a4 and a5 for i2c protocol, and have that is what I use to talk to the other components, here is the other code:


  
// Include Arduino Wire library for I2C
#include <Wire.h>
 
// Define Slave I2C Address
#define SLAVE_ADDR 9
int pushState = 0;

int moveDir = 2;
bool check = true;
 
void setup() {
 
  Wire.begin();
    Serial.begin(9600);
  pinMode(8, INPUT_PULLUP);
}


int mapJoystickValues(int val, int lower, int middle, int upper, bool reverse)
{
  val = constrain(val, lower, upper);
  if ( val < middle ){
    val = map(val, lower, middle, 0, 128);
  }
  else{
    val = map(val, middle, upper, 128, 255);
  }
  return ( reverse ? 255 - val : val );
}

void loop() {
 int dir=mapJoystickValues( analogRead(A0), 13, 524, 1015, true);
  if(digitalRead(8) == LOW && check==true){
    if(pushState == 0){
      pushState=1;
    }else{pushState=0;moveDir=2;}
    check=false;
  }
  if(digitalRead(8) == HIGH && check==false){
    check=true;
  }

//  Serial.println(pushState);
  if(pushState==1){
    if(dir>200){
      moveDir=3;
    }else if(dir<80){
      moveDir=1;}
    digitalWrite(10, HIGH);
  }else{digitalWrite(10,LOW);}
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write(moveDir);
  Wire.endTransmission();

  delay(100);
}

The purpose of my project is to talk to a receiver with an add on and just transmit data.

Sorry, what do you mean Go to #4

Post #4 asks for some information.

You have supplied more information, but it still seems incomplete.

There must be two NRF24L01s, presumably each attached to an Arduino.

You have a sketch with no mention of the radio. Is that a third Arduino?

And this

The purpose of my project is to talk to a receiver with an add on and just transmit data.

may mean more to you than it does to us.

How about a block diagram showing all the parts, how they are connected, how they are to communicate with one another, and share a few more words described the purpose of the entire project?

We could guess but I bet five people could come up with five very different interpretations that would fit the facts you have supplied so far.

a7

It is here:-

This is read write memory used to store variables, in hardware terms this uses the SRAM ( Static, Random Access Memory). The Static bit means it does not have to be refreshed every few millisecond, as opposed the type of memory that needs refreshing which is called DRAM ( Dynamic, Random Access Memory).
This might be confusing because the description of this memory from the compilers point of view, is not of what the physical type of memory is, but what the memory is used for.

Now that is only the memory you have requested from the compiler at compile time. When your code runs the code can ask for memory to be set aside for things and this can't be predicted by the compiler. But 1711 bytes is a good start.

However, using any form of display requires a buffer and this memory is requested from the remaining free memory at run time. This is normally a large chunk but it can be smaller for a character only display. This can be measured during run time using the freeMemory() function.
See the SRAM section from this link:-
https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory

I would suggest that you include this call at the end of the setup function (in the code you originally posted). Note as explained you will need to install a small library to do this.
It looks you might be running out of memory and a code freeze or some other function not working is one of the things that running out of memory will give you.

As to your hardware there are several mistakes and you have not provided full information for your schematic. The things that seem to be missing are:-

  1. You seem to have no pull up resistors on your I2C bus, typical for a 5V system is to use a 4K7 resistor from A4 to 5V and another from A5 to 5V.

  2. Your two switches are connected incorrectly, you should not put 5V and ground on the same switch. Sure you might get away with it but it is very bad practice because the mechanical quality of cheap versions might cause a power supply short. So remove the 5V and define those pins as INPUT_PULLUP in the pinMode call in the setup function.

  3. You need capacitors on both the input and output side of every voltage regulator. The exact value will depend on the exact manufacturer of the regulator you are using so look it up in that manufacturer's data sheet for the device.

Hi,
Thanks for the diagram, but a cut and paste image is not showing much that we need.

Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, component names and pin labels for both ends of your project.

Reverse engineering your project will help you check your wiring.

Can you please post some images of your project, so we can see your component layout.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

I guess those I2C LCD displays have pull-up resistors on board so there should be enough on that bus. The grounds are common ?

What is interesting is that the Arduino which has the role of I2C master for writing to the displays has, simultaneously, the role of I2C slave for the other Arduino. In principle, this is not wrong (see Arduino as I2C "Master" and "Slave" at the same time? ) but I can't see how contention for the I2C buffer is managed with asynchronous requests coming in, in this case.

Especially lcd.clear() blocks for a few ms so may be prone to causing conflicts.

I tried to follow the website to see the available ram, but I litteraly tried everything and I cant get it work, can you maybe clarify what the site is trying to say? Into simpler steps?

That is a long post. Can you be more specific about what you are not understanding please.

Hey, sorry for the incomplete responses, I just have to submit this assignment in 2 days and I don't have enough time to draw things again.

Here is the video explanation:

@gdesi THX. I'm looking through the little window just now, I will view you video again later.

But I think you may be better off not using I2C for the pushbutton add on.

It would be easy, easier probably, and less hard (!) to use serial communication for the add on. You can use a low data rate and software serial, staying off the real serial ports pins.

No timing issues, the comms would be in the background and your code just picks up anything transmitted and acts on it when it has the time.

It feels like a conflict caused by the dual roll of master ans slave on the one Arduino. As @6v6gt said, OK in principle, but perhaps fraught.

a7

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