I am struggeling with a behaviour of my Arduino I do not fully understand.
Long story short:
When starting the communication over I2C the Arduino freezes. In my opinion during the "Wire.write()" command.
Long story and background:
I want to connect my Arduino Uno to an Arduino MKR Wifi 1010 via I2C. I implemented the code for the communication step by step, so I started with the code below.
Code for the Master Arduino Uno:
#include <Wire.h>
#include <Arduino.h>
#define SLAVE_ADRESS 2
void Send_Data(int receiver, int data)
{
Wire.beginTransmission(receiver);
Wire.write(data);
Wire.endTransmission();
Serial.println(F("Data sent"));
}
void setup() {
Serial.begin(38400);
while (!Serial) {;} /* Wait for serial interface to be connected and ready for use. */
Serial.setTimeout(2000);
Serial.println(F("Serial Connection ready"));
Wire.begin(); // join i2c bus (address optional for master)
}
void loop() {
static int LedStatus = 0;
if (LedStatus == 0)
{
LedStatus = 1;
}
else
{
LedStatus = 0;
}
Serial.print(F("Master LED status: "));
Serial.println(LedStatus);
Send_Data(SLAVE_ADRESS,LedStatus);
delay(500);
}n
Code for the Slave Arduino MKR Wifi 1010:
#include <Wire.h>
#include <Arduino.h>
#define NODE_ADDRESS 2
int led = 0;
void setup()
{
Serial.begin(38400);
while (!Serial)
{
; /* Wait for serial interface to be connected and ready for use. */
}
Serial.setTimeout(1000);
Wire.begin(NODE_ADDRESS);
Wire.onReceive(receiveEvent);
}
void receiveEvent(int bytes)
{
led = Wire.read();
Serial.println("Data reveived!");
Serial.print("Slave Value led: ");
Serial.println(led);
}
void loop()
{
}
This piece of code works fine as expected. So I implemented the very same functionality for the master into my projekt.
/****************************************************************************/
/*-------------------------------Description--------------------------------*/
/****************************************************************************/
/*
Used board: Arduino Uno
>>> Pin usage overview <<<
0:
1:
2: waterlevel tank sensor low (black sensor wires)
3: waterlevel tank sensor high (red sensor wires)
4: waterlevel reservoir sensor low (not used yet)
5: waterlevel reservoir sensor high (not used yet)
6: pump level tank
7: pump level reservoir
8: water temperature sensor
9: water temperature sensor
10:
11:
12:
13:
A0: EC sensor
A1: pH sensor
A2:
A3:
A4:
A5:
/*
/****************************************************************************/
/*---------------------------------Includes---------------------------------*/
/****************************************************************************/
#include <Arduino.h>
#include <RTClib.h>
#include <TimerOne.h>
#include <Wire.h>
#include "WaterCondition.h"
#include "WaterFlow.h"
#include "Serial.h"
/****************************************************************************/
/*----------------------------------Macros----------------------------------*/
/****************************************************************************/
#define TIMER_INTERVAL 2000000 // 5sec (timer in microsec)
#define RTC_INIT_TIME_SECOND 0
#define RTC_INIT_TIME_MINUTE 0
#define RTC_INIT_TIME_HOUR 0
#define RTC_INIT_TIME_DAY 0
#define RTC_INIT_TIME_MONTH 0
#define RTC_INIT_TIME_YEAR 0
#define OPERATING_MODE_AUTO 0
#define OPERATING_MODE_TEST_TEMP_SENSOR 1
#define OPERATING_MODE_TEST_EC_SENSOR 2
#define OPERATING_MODE_TEST_PH_SENSOR 3
#define OPERATING_MODE_TEST_RTC 4
#define OPERATING_MODE_TEST_WATERLEVEL 5
#define OPERATING_MODE_TEST_COMMUNICATION 6
#define SLAVE_ADRESS 2 // adress of the slave for communication
/****************************************************************************/
/*-----------------------------Global Variables-----------------------------*/
/****************************************************************************/
/*
OPERATING_MODE 0: Automatic
OPERATING_MODE 1: Testing / Calibration
*/
uint8_t OperatingMode = 0;
/* Used for Serial.h to read the input from serial connection */
extern char StringBuffer[STRING_BUFFER_SIZE];
extern float WaterConPhVolt, WaterConEcVolt, WaterConPhVal, WaterConEcVal, WaterConTempVal;
/****************************************************************************/
/*------------------------------Initialization------------------------------*/
/****************************************************************************/
RTC_DS3231 rtc;
DateTime now;
int freeRam()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
/* standard operations */
void ISR_Task(void)
{
if (OperatingMode == OPERATING_MODE_AUTO) // Automatic
{
Serial.println(F("Running in automatic mode"));
uint8_t min;
min = now.second(),DEC;
if ((min == PUMP_TANK_ON_INTERVALL_1) || (min == PUMP_TANK_ON_INTERVALL_2))
{
//Serial.println(F("Test: RTC min = 0 or 30");
//Activate pump
//Function tbd
}
else if ((min == PUMP_TANK_OFF_INTERVALL_1) || (min == PUMP_TANK_OFF_INTERVALL_2))
{
//Serial.println(F("Test: RTC min = 20 or 50");
//Deactivate pump
//Function tbd
}
WaterConTempVal = WaterCon_Sensor_TEMP(0);
WaterConEcVal = WaterCon_Sensor_EC();
WaterConPhVal = WaterCon_Sensor_PH();
if (Waterflow_Tank() == 99)
{
// tbd
}
}
else // Testing
{
/* >>> Test the temperature sensor <<< */
if (OperatingMode == OPERATING_MODE_TEST_TEMP_SENSOR)
{
Serial.print(F("Water temperature filtered: "));
Serial.println(WaterCon_Sensor_TEMP(0));
}
/* >>> Test the PH sensor <<< */
else if (OperatingMode == OPERATING_MODE_TEST_PH_SENSOR)
{
float test_ph = 0;
test_ph = WaterCon_Analog_Read(PH_PIN, VOLTAGE_PIN, RESOLUTION_SENSOR_PH);
Serial.print(F("PH-Sensor-Value raw from 0 - 5000mV: "));
Serial.println(test_ph);
Serial.print(F("PH-Value from 0 - 14: "));
Serial.println(WaterCon_Sensor_PH());
}
/* >>> Test the PH sensor <<< */
else if (OperatingMode == OPERATING_MODE_TEST_EC_SENSOR)
{
float test_ec = 0;
test_ec = WaterCon_Analog_Read(EC_PIN, VOLTAGE_PIN, RESOLUTION_SENSOR_EC);
Serial.print(F("EC-Sensor-Value raw from 0 - 5000mV: "));
Serial.println(test_ec);
Serial.print(F("EC-Value from 0 - 2000uS: "));
Serial.println(WaterCon_Sensor_EC());
}
/* >>> Test the RTC clock <<< */
else if (OperatingMode == OPERATING_MODE_TEST_RTC)
{
Serial.print(F("\nRTC-Time: "));
Serial.println(now.second(),DEC);
}
/* >>> Test the waterlevel sensors <<< */
else if (OperatingMode == OPERATING_MODE_TEST_WATERLEVEL)
{
int WaterLvlSensorLow = 0;
int WaterLvlSensorHigh = 0;
WaterLvlSensorLow = digitalRead(TANK_LVL_LOW_PIN);
WaterLvlSensorHigh = digitalRead(TANK_LVL_HIGH_PIN);
Serial.print(F("Waterlevel Sensor Low: "));
Serial.println(WaterLvlSensorLow);
Serial.print(F("Waterlevel Sensor High: "));
Serial.println(WaterLvlSensorHigh);
}
/* >>> Test the communication over I2C <<< */
else if (OperatingMode == OPERATING_MODE_TEST_COMMUNICATION)
{
static int LedStatus = 0;
if (LedStatus == 0)
{
LedStatus = 1;
}
else
{
LedStatus = 0;
}
Serial.print(F("Master LED status: "));
Serial.println(LedStatus);
Send_Data(SLAVE_ADRESS,LedStatus);
}
}
}
void Send_Data(int receiver, int data)
{
Wire.beginTransmission(receiver);
Wire.write(data);
Wire.endTransmission();
Serial.println(F("Data sent"));
}
/****************************************************************************/
/*-------------------------Function Implementations-------------------------*/
/****************************************************************************/
void setup() {
Serial.begin(38400);
while (!Serial) {;} /* Wait for serial interface to be connected and ready for use. */
Serial.setTimeout(2000);
Serial.println(F("Serial Connection ready"));
/* Initialize sensors */
Serial.println(F("Setup Sensors"));
WaterCon_Sensor_Init();
Waterflow_Sensor_Init();
/* Initialize RTC */
Serial.println(F("Setup RTC"));
rtc.begin();
Serial.println(F("Test"));
/* Initialize timers */
Serial.println(F("Setup Timers"));
Timer1.initialize(TIMER_INTERVAL);
Timer1.attachInterrupt(ISR_Task);
Serial.println(F("Setting the time for the RTC..."));
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
/* Initialize I2C Master-Slave */
Wire.begin();
}
void loop()
{
now = rtc.now();
delay(200);
Serial_Read(1);
/* Change operating mode to automatic */
if (strcmp("opauto",StringBuffer) == 0)
{
Serial.println(F("Operating Mode changed to automatic"));
OperatingMode = 0;
}
/* Change operating mode to testing */
else if (strcmp("optest1",StringBuffer) == 0)
{
Serial.println(F("Operating Mode changed to Testing: temperature sensor"));
OperatingMode = 1;
}
else if (strcmp("optest2",StringBuffer) == 0)
{
Serial.println(F("Operating Mode changed to Testing: EC sensor"));
OperatingMode = 2;
}
else if (strcmp("optest3",StringBuffer) == 0)
{
Serial.println(F("Operating Mode changed to Testing: pH sensor"));
OperatingMode = 3;
}
else if (strcmp("optest4",StringBuffer) == 0)
{
Serial.println(F("Operating Mode changed to Testing: RTC clock"));
OperatingMode = 4;
}
else if (strcmp("optest5",StringBuffer) == 0)
{
Serial.println(F("Operating Mode changed to Testing: Waterlevel Sensors"));
OperatingMode = 5;
}
else if (strcmp("optest6",StringBuffer) == 0)
{
Serial.println(F("Operating Mode changed to Testing: Communication via I2C Master-Slave"));
OperatingMode = 6;
}
}
Some explanation for you to understand what I am trying to do: Above you can see the code from the Main.ino file for a hydroponic project. I wanted to realize different operating modes for automatic and testing. So if I encounter a fault, I want to be able to plug the laptop on the USB port and start to read out some information over the serial port. Later this should be accomplished over the air but for the beginning this should be fine. To achieve this, I put string compare into the loop to notice if the user did some input and respond to it. I tested that functionality a lot and it worked fine. I am able to jump from any operating mode to another.
There is an external real time clock running for using interrupts and run code at specific times. During this interrupt I check what operating mode is active and run the respective code. With the string compare I mentioned above I can jumo into the respective code with the next interrupt.
ISSUE: Now I can describe the actual issue. Everytime I enter the "operating mode 6" to test the I2C connection, the Arduino freezes. As you can see I used the very same code inside the "else if" as tested before. This is the relevant part of the code:
/* >>> Test the communication over I2C <<< */
else if (OperatingMode == OPERATING_MODE_TEST_COMMUNICATION)
{
static int LedStatus = 0;
if (LedStatus == 0)
{
LedStatus = 1;
}
else
{
LedStatus = 0;
}
Serial.print(F("Master LED status: "));
Serial.println(LedStatus);
Send_Data(SLAVE_ADRESS,LedStatus);
}
}
}
void Send_Data(int receiver, int data)
{
Wire.beginTransmission(receiver);
Wire.write(data);
Wire.endTransmission();
Serial.println(F("Data sent"));
}
In the following picture it looks like the Board freezes during the serial communication when it prints out "Master LED status: ". I testet this by commenting out the serial.print commands and insert a print command between Wire.begin and Wire.write in the code.
I think the main problem is caused by the Wire.write function, but I am not able to debug it other than using serial.print commands. But the printed commands do not correlate with the line of code when the board actually freezes. I think I would need real debugger that stops the processor and gives me the possibility to go through the code step by step.
At first I thought this issue was caused because the SRAM got filled. So I put the Serial.print commands in the flash memory and inserted some lines of code for checking the usage of the SRAM and the Stack. You can see the "freeRam()" function in the code, but I removed them for better readability.
Did anyone have a similar issue or do you know what could cause this issue?
Thanks a lot in advance!