Search code examples
arduinoiotraspberry-pi-pico

Why this adafruit screen code interferes with this code?


I have a code for artificial neural network on Arduino. I'm using an Arduino UNO at 16Mhz and a SSD1306 led screen. The ANN is a simple logic XOR function. The code generates two random numbers 1.0 or 0.0, then passes the values to the inputs of the ANN, then the ANN inference the value and prints the inference time in milliseconds on the led screen, after that, prints on Serial monitor the input values, the output value and the inference time. Complete code is:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

volatile unsigned long adcTime = 0;

const float NEFTIS_E = 2.71828183;
const int NEFTIS_ANN_LENGHT = 13;    // Total neurons in the network.
const int NEFTIS_OUT_LENGHT = 1;    // Total output neurons.
const int NEFTIS_INPUT_LENGHT = 2;  // Total input neurons.

enum ENUM_ActivationFuntionType
{ 
  AF_Logistic,     // Logistic sigmoid.
  AF_TanH,         // Hypervolic tangent.
  AF_ArcTan,       // Arc tangent.
  AF_ReLU,         // Rectified Linear Unit.
  AF_LeakyReLU,    // Leaky ReLU.
  AF_ELU,          // Exponentian Linear Unit.
  AF_SoftPlus,     // 
  AF_Boolean,      // Boolean.
};

// Synapse structure
typedef struct
{
  float weight;
  int inputNeuron;
} struct_synapse;

// Neuron structure
typedef struct
{
  float value;
  float bias;
  int indexStart;
  int nInputs;
  bool isInput;
  ENUM_ActivationFuntionType activationFunction;
  float linearDelta;
} struct_neuron;

struct_neuron Neftis_Neurons[] = {
  {1.0f, 0, 0, 0, true, AF_Logistic, 0.01},
  {1.0f, 0, 0, 0, true, AF_Logistic, 0.01},
  {0.0f, 0, 0, 2, false, AF_Logistic, 0.01},
  {0.0f, 0, 2, 2, false, AF_Logistic, 0.01},
  {0.0f, 0, 4, 2, false, AF_Logistic, 0.01},
  {0.0f, 0, 6, 2, false, AF_Logistic, 0.01},
  {0.0f, 0, 8, 2, false, AF_Logistic, 0.01},
  {0.0f, 0, 10, 2, false, AF_Logistic, 0.01},
  {0.8f, 0, 12, 2, false, AF_Logistic, 0.01},
  {0.0f, 0, 14, 2, false, AF_Logistic, 0.01},
  {0.0f, 0, 16, 2, false, AF_Logistic, 0.01},
  {0.0f, 0, 18, 2, false, AF_Logistic, 0.01},
  {0.0f, 0, 20, 10, false, AF_Logistic, 0.01}
};

struct_synapse Neftis_Synapses[] = {
  {-5.43316f, 0},
  {-5.543714f, 1},
  {-4.262666f, 0},
  {1.139778f, 1},
  {2.446421f, 0},
  {-6.2367f, 1},
  {-2.993009f, 0},
  {-0.5112332f, 1},
  {-3.330907f, 0},
  {0.02449156f, 1},
  {-1.701479f, 0},
  {-1.936165f, 1},
  {0.5805757f, 0},
  {1.178081f, 1},
  {-3.712192f, 0},
  {0.5605027f, 1},
  {-4.816404f, 0},
  {-4.946669f, 1},
  {-3.816507f, 0},
  {0.6793132f, 1},
  {-9.65515f, 2},
  {2.788617f, 3},
  {5.523755f, 4},
  {0.8867579f, 5},
  {1.384886f, 6},
  {-0.4491375f, 7},
  {-3.600839f, 8},
  {1.99833f, 9},
  {-6.788064f, 10},
  {2.101213f, 11}
};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);/*
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.display();*/
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  float inputs[NEFTIS_INPUT_LENGHT];
  inputs[0] = (float) random(0, 2);
  inputs[1] = (float) random(0, 2);
  Neftis_SetInputs(inputs);
  unsigned long start = micros();
  Neftis_Run();
  adcTime = micros() - start;
  display.clearDisplay();
  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(1, 16);     // Start at top-left corner
  display.print(adcTime);
  Serial.println(Neftis_Neurons[0].value);
  Serial.println(Neftis_Neurons[1].value);
  Serial.println(Neftis_Neurons[12].value);
  display.display();
  Serial.println(adcTime);
  digitalWrite(LED_BUILTIN, true);
  delay(1000);
  digitalWrite(LED_BUILTIN, false);
  delay(500);
}

void Neftis_SetInputs(float inputs[])
{
  for(int i = 0; i < NEFTIS_INPUT_LENGHT; i++)
  {
    Neftis_Neurons[i].value = inputs[i];
  }
}

void Neftis_Run()
{
// for every neuron
  for(int i = 0; i < NEFTIS_ANN_LENGHT; i++)
  {
    float sum = 0.0f;
    for(int j = 0; j < Neftis_Neurons[i].nInputs; j++)
    {
// sums the inputs
      sum += Neftis_Synapses[Neftis_Neurons[i].indexStart + j].weight * Neftis_Neurons[Neftis_Synapses[Neftis_Neurons[i].indexStart + j].inputNeuron].value;
    }
    sum += Neftis_Neurons[i].bias;
// apply activation function if is not input neuron
    if(Neftis_Neurons[i].isInput == false)
    {
// >> Logistic
      if(Neftis_Neurons[i].activationFunction == AF_Logistic){
        Neftis_Neurons[i].value = (float) (1 / (1 + pow(NEFTIS_E, -sum)));
// >> TanH.
      }
    }
  }
}

void Neftis_GetOutputs(float* outArray)
{
  for(int i = 0; i < NEFTIS_OUT_LENGHT; i++)
  {
    outArray[i] = Neftis_Neurons[NEFTIS_ANN_LENGHT - NEFTIS_OUT_LENGHT + i].value;
  }
}

The problem is, the screen don't show anything and the serial monitor shows strange values for the inputs, output and inference time, as show in image below.

enter image description here

But if I remove the lines

display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();*/

and

display.clearDisplay();
  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(1, 16);     // Start at top-left corner

then the serial monitor shows the right values for inputs, output and elapsed time for inference.

Now, I modified this line of code from this:

Neftis_Neurons[i].value = (float) (1 / (1 + pow(NEFTIS_E, -sum)));

to this:

Neftis_Neurons[i].value = (float) (1 / (1 + pow(NEFTIS_E, -1.5)));

and then the screen works and shows the inference time. The question is simple, why the screen code is interfering with pow function and serial monitor? or pow function is interfering with screen and serial monitor code? By the way, I executed the same code on a Raspberry Pi Pico and works ok, no issues there.

Thank you very much, I hope you find the answer.


Solution

  • I followed the suggestion of CherryDT and posted my question on the Arduino forum and was answered in [https://forum.arduino.cc/t/why-this-adafruit-screen-code-interferes-with-this-other-code/1049580]this link1

    You are running out of dynamic memory on the Uno, which causes unpredictable errors during run time.

    This line allocates a screen buffer of 1024 bytes, which won't be shown in the memory usage report during compiling/uploading:

    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

    To save dynamic memory space, you can put your other data arrays in program memory using the PROGMEM keyword. Check the Arduino reference for usage.

    I tried the same code but with a smaller ANN model and it worked.