Time of calculation OR Display frequency is too LOW. ECG Monitor.

Hi, I'm working on an mini ECG project with a OLED SPI display.
Including :
An arduino NANO
A AD8232 ECG board from SPARKFUN
A SH1106 SPI OLED display 128x64

The project is wired as follow :
OLED SPI
CLK -> Pin J13
MOSI -> Pin D11
RES -> Pin D7
DC -> Pin D8
CS -> Pin D10

AD8232
LO+ -> Pin D5
LO- -> Pin D6
Output -> Pin A0

Buzzer -> D9

The program I did is inspired by a program I found on github.

Here is the Code :

#include <Adafruit_SH1106.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Wire.h>

int BPMT=0;
int T=1;
int D=0;
int E=0;
int F=0;
int G=0;
int x=0;
int lastx=0;
int lasty=0;
int LastTime=0;
bool BPMTiming=false;
bool BeatComplete=false;
int BPM=0;
const int buzzer = 9;

#define UpperThreshold 490
#define LowerThreshold 470

#define OLED_MOSI   11
#define OLED_CLK   13
#define OLED_DC    8
#define OLED_CS    10
#define OLED_RESET 7
Adafruit_SH1106 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);


void setup() {

  
  Serial.begin(9600);
  pinMode(5, INPUT); // Setup for leads off detection LO +
  pinMode(6, INPUT); // Setup for leads off detection LO -
  pinMode(buzzer, OUTPUT);
  display.begin(SH1106_SWITCHCAPVCC);
 
  display.clearDisplay();
  display.setTextSize(1);
  display.display(); 
  
}

void loop() {
   Serial.println(analogRead(A0)); 
      
    
      if(x>127)  
  {
    display.clearDisplay();
    x=0;
    lastx=x;
  }
 // Take the analog value and print it on the screen by using lines drawing
  int value=analogRead(A0);
  display.setTextColor(WHITE);
  int y=60-(value/14);
  display.writeLine(lastx,lasty,x,y,WHITE);
  lasty=y;
  lastx=x;

  // calcul bpm
  if(value>UpperThreshold)
  {
    if(BeatComplete)
    {
      BPM=millis()-LastTime;
      BPM=int(60/(float(BPM)/1000));
      BPMTiming=false;
      BeatComplete=false;
      tone(buzzer, 4000,5);

  
// Do a average of BPM with the 4 last values
 if(T==4)
   {
     G=BPM ;
     BPMT=int((D+E+F+G)/4) ;
     T=1 ;
   }
   if(T==3)
   {
     F=BPM ;
     T++;
   } 
   if(T==2)
   {
     E=BPM ;
     T++;
   }
   if(T==1)
   {
     D=BPM ;
     T++;
   }    
  }
    if(BPMTiming==false)
    {
      LastTime=millis();
      BPMTiming=true;
    } 
  }
 
  if((value<LowerThreshold)&(BPMTiming))
  {
    BeatComplete=true;
   }
 
// display BPM value
  display.writeFillRect(0,50,90,16,BLACK);
  display.setCursor(50,55);
  //display.print(BPM);
  display.print(BPMT);
  display.print(" BPM");
  display.display();
  noTone(buzzer);
 
  x++;  
  }

The thing is when I use à simple programme to display the ECG waves on the IDE serial plotter like this:

void setup() {

  Serial.begin(9600);
  pinMode(5, INPUT); // Setup for leads off detection LO +
  pinMode(6, INPUT); // Setup for leads off detection LO -
 }

void loop() {
  
  if((digitalRead(5) == 1)||(digitalRead(6) == 1)){
    Serial.println('!');
  }
  else{
    // send the value of analog input 0:
      Serial.println(analogRead(A0));
  }
  delay(1);
}

I've got a nice and smooth ECG line.

But when I use the OLED display program the ECG graph is not as good because of either the time calculation of drawing lines or the time for displaying pixels is to high, and then, when the loop comes back to "int value=analogRead(A0);" after printing on screen the last line, it has missed a lot of analog values.

It results in a less readable curve (but still acceptable), sometimes it misses QRS (wich are 100ms long).

I tried to increase the clock value in the SPI.h library unsuccessfully (I may have did it wrong), I tried to change the SPI pins to the arduino unsuccessfully, I tried to modify the SH1106 library unsuccessfully, I tried to display pixels instead of lines : same results in term of speed...

I also tried to get rid of all the BPM calculation part in the program and the result is still the same.

My Loop should execute in less than 10-30 ms to be sure not to miss any important data is it possible with OLED SPI dipays and arduino nano?

My question is : is it possible to optimise either the program or libraries to get a result on OLED more similar to what i've got one the serial plotter? Or do i need to buy a chip with a better clockrate and throw my nano away?

I join you pictures of the serial plotter in the two situation (OLED program and simple Serial program)

Thank you!

  if((value<LowerThreshold)&(BPMTiming))

You sure you want to do this? I suspect you actually want && there.

Yes thanks i will change that, anybody has an idea about the main issue?

I don't know the library, but things like

  display.writeFillRect(0,50,90,16,BLACK);

are suspect. Sounds like a lot of data coming out of that. Start by minimising your writes to the display. Or do some Serial.println(micros()) to get an idea of how long various steps take.

I did what you said thanks, I found 30ms for one loop which does't sound bad, but still i'm wondering if i could get like 10ms-15ms for the loop.... that would be really better...

I already tried to get rid of every drawing command except display.writeLine() and the result is still the same. So either the command Line takes for ever to be calculate or there is some time-consuming command I haven't figured out yet...

EDIT// I tried the programme with no display command in the loop, and i got 11ms for the loop. So a lot faster. It means any display operation to light up even one pixel takes 19ms which is a lot for me :).

Any idea to reduce the time to display pixels on a SPI OLED SH1106 128x64 monitor with Adafruit Drivers (SSD1306 driver modified for SH1106) ?

ThANKS

You may get a better response in the "Displays" part of the forum (use the "report to moderator" link at the bottom of any of your posts and ask them to move this thread there).

I found a solution! my SH1106 librairy wasnt selecting Hardware SPI to comunicate with the screen but the built in SPI. I manage to change that by editing the Aafruit_SH1106.ccp file.

Now i'm using HWSPI and i've got a 11ms Loop with a lot of display instructions :wink: nice nice nice.
Thanks all.