Dear Community,
I have a project which uses two Arduinos. The Arduino Mega as the main board and the Arduino Nano as Button Interface Controlller.
The Mega is set up as a I2C Master and the Nano as a Slave.
My Goal is to get all Events recognized by the Arduino Nano to the Arduino Mega.
The Problem is that sometimes not all Events get there, especially if i press alot of buttons at once.
The concept for my program is that the Nano scans the inputs and stores the input events in a buffer and the Mega is polling events from that buffer in an interval.
Arduino Mega -> I2C Master -> simplified Code
unsigned long pollLast;
void setup() {
// put your setup code here, to run once:
// Init I2C Communication as a Master
Wire.begin();
Wire.setClock(100000); // Standard Mode
}
void loop() {
if ((micros() - this->_pollLast) > 2000) {
// Send Command
Wire.beginTransmission(SLAVE_ADDR);
Wire.write(GET_EVENT);
switch (Wire.endTransmission()) {
case 0: // success
Wire.requestFrom(SLAVE_ADDR, 2);
// Read response from Slave
while (Wire.available()) {
this->inputEvent.from = Wire.read();
this->inputEvent.type = Wire.read();
}
pollLast = micros();
break;
case 1:
Serial.println("UCI::_poll(): data too long to fit in transmit buffer");
break;
case 2:
Serial.println("UCI::_poll(): received NACK on transmit of address");
break;
case 3:
Serial.println("UCI::_poll(): received NACK on transmit of data");
break;
case 4:
Serial.println("UCI::_poll(): other error.");
break;
}
}
}
The Nano runs a program which successfully scans for an inputEvent to happen ( i checked that it is succesful) and then it tries to store that event in a buffer so the mega can pick it through i2c.
I think my problem lies in the implementation of the buffer…
Here is the simplified code for the Nano, this is more kind of pseudo code to make you understand it more easily:
Arduino Nano -> I2C Slave -> rewritten and more simple Code
#include <Wire.h>
#include "userInterfaceGlobals.h"
#include "buttonMatrix.h"
// Event struct
/*
struct InputEvent {
volatile int8_t from;
volatile int8_t type;
};*/
// Event Buffer
#define EVENT_BUFFER_SIZE 64
InputEvent eventBuffer[EVENT_BUFFER_SIZE];
volatile uint8_t eventBufferHead;
volatile uint8_t eventBufferTail;
volatile bool updateEventBufferHeadFlag = false;
// Buttons
unsigned long buttonLastCheck;
// I2C
#define SLAVE_ADDR 9
// EVENT_SOURCES - > will be stored in inputEvent.from
//enum { NONE = -1 };
// COMMANDS
//enum { GET_EVENT = 100 };
int8_t I2C_command;
// Init global inputEvent variable
InputEvent inputEvent = { NONE, NONE }; // I declared NONE=-1 as a global constant somewhere else
// Init Button Matrix
ButtonMatrix buttonMatrix;
void setup() {
Serial.begin(115200);
// Init I2C Communication as a Slave
Wire.begin(SLAVE_ADDR);
// Function to run when data received from master
Wire.onReceive(onReceiveFromMaster);
Wire.onRequest(onRequestFromMaster);
// Init Event Buffer
for (int i = 0; i < EVENT_BUFFER_SIZE; i++) {
eventBuffer[i] = { NONE, NONE };
}
// Init Button Matrix
buttonMatrix.begin();
}
void loop() {
// clear global inputEvent
inputEvent = { NONE, NONE };
// check for new event
checkInputs();
// Serial.println(inputEvent); // uncommenting this line i see that all events -> thats working until here.
addEventToBuffer();
// Check if onRequest Interrupt happened -> if an event has been picked from the buffer.
//if (updateEventBufferHeadFlag) {
updateEventBufferHead();
//updateEventBufferHeadFlag = false;
//}
}
/* Check Button Input
-------------------------------------------------------------- */
void checkInputs() {
if ((micros() - buttonLastCheck) > 2000) { // this one gets called more often
inputEvent = buttonMatrix.scan(); // This method returns an InputEvent
buttonLastCheck = micros();
}
}
/* Buffer
-------------------------------------------------------------- */
void addEventToBuffer() {
if (inputEvent.from != NONE) {
Serial.println("event");
// Get the next Index
increaseBufferHeadIndex();
// Report Buffer overflow
if (eventBuffer[eventBufferHead].from != NONE) {
Serial.println("Buffer Overflow!");
Serial.print("eventBufferHead = "); Serial.println(eventBufferHead);
}
// Set event to buffer
eventBuffer[eventBufferHead] = inputEvent;
// Clear inputEvent
inputEvent = { NONE, NONE };
}
}
void increaseBufferHeadIndex() {
// Update Buffer Head
if (eventBufferHead < (EVENT_BUFFER_SIZE-1)) {
eventBufferHead++;
} else {
eventBufferHead = 0;
}
}
void updateEventBufferHead() {
//Serial.println("updateEventBufferHead");
// Clear that event in buffer
eventBuffer[eventBufferTail] = { NONE, NONE };
increaseBufferHeadIndex();
}
/* I2C Services
-------------------------------------------------------------- */
void onReceiveFromMaster(int numBytes) {
if (0 < Wire.available()) {
I2C_command = Wire.read();
}
}
void onRequestFromMaster() {
switch(I2C_command) {
case GET_EVENT:
byte answer[2];
// Set tail index one before eventBufferHead
eventBufferTail = (eventBufferHead > 0) ? eventBufferHead -1 : (EVENT_BUFFER_SIZE - 1);
Wire.write(eventBuffer[eventBufferTail].from);
Wire.write(eventBuffer[eventBufferTail].type);
eventBuffer[eventBufferTail] = { NONE, NONE };
//updateEventBufferHeadFlag = true;
increaseBufferHeadIndex();
I2C_command = NONE;
break;
}
}
Can anyone help me understand why sometimes I don’t receive all Events I get in the line
Serial.println(inputEvent); in the Nano’s loop() code on the Arduino Mega?
I tested alot of different things already. At the moment i also have 220 ohm in in series with the SCL, and SDA line to stop reflections because I thought that it is signal quality problem. But actually i think my problem is the buffer. My real code gets kind of big at the moment and I dont have progress with it for some days now. I would be very grateful for any help.
I think that the onRequest Interrupt somehow crashes the writing or reading to the eventBuffer.
EDIT: I updated the Nanos code here, I am getting Buffer Overflow messages when i hit a lot of buttons. So the problems seems to be in the Nano's code
-Flub