(Solved) Wrapping Led matrix code into class brings lower framerate

Hello!

Using arduino pro mini 5V 16Mhz,but can test with arduino UNO as well.
Arduino IDE 2.3.2
Daisy chained 74595 shift registers.

So, I got basic code working, and prime goal for now is to create class from the code, just so all irrelevant functions could be called; as I believe is one of reasons to create class in first place. Now then, actually making class didn't pose problem, but what I can't understand is severe framerate drop. I'm planning on making this library to act as both software SPI and hardware SPI, depending on constructor, which I succeeded already, but without getting too sidetracked too much....gotta deal with this framerate drop first. Framerate drop is severe enough so I can see matrix flicker, which is big no for led display obviously. The code has flaw about possible ghosting, but that issue is easy to fix once it happens.

I don't have any actual measurements/data about framerate drop, but I can get them if needed.
Also fontmap is not yet read from flash, It's on the to-do-list as well.

Actual codes;
Fontmap.h

//<-LEFTMOST COLUMN
//LSB=uppest dot
byte ledMatrixFont_8x8 [1008]  =              //numbers stored here
{ //Position, Character
  B00000000, B00000000, B00111110, B01010001, B01001001, B01000101, B00111110, B00000000, // 0          0
  B00000000, B00000000, B01000100, B01000010, B01111111, B01000000, B01000000, B00000000, // 1            1
  B00000000, B00000000, B01100010, B01010001, B01001001, B01001001, B01000110, B00000000, // 2            2
  B00000000, B00000000, B00100010, B01000001, B01001001, B01001001, B00110110, B00000000, // 3            3
  B00000000, B00000000, B00011000, B00010100, B00010010, B01111111, B00010000, B00000000, // 4            4
  B00000000, B00000000, B00100111, B01000101, B01000101, B01000101, B00111001, B00000000, // 5            5
  B00000000, B00000000, B00111100, B01001010, B01001001, B01001001, B00110000, B00000000, // 6            6
  B00000000, B00000000, B00000001, B01110001, B00001001, B00000101, B00000011, B00000000, // 7            7
  B00000000, B00000000, B00110110, B01001001, B01001001, B01001001, B00110110, B00000000, // 8            8
  B00000000, B00000000, B00000110, B01001001, B01001001, B00101001, B00011110, B00000000, // 9            9

  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 10         /n
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 11
  0x81, B01000010, B00000000, B00011000, B00011000, B00000000, B01000010, 0x01, // 12
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 13         /r  ALIENI
  B00000000, B00011000, 0x28, 0x48, 0xfe, 0x08, B00000000, B00000000, // 14
  B00000000, 0xe4, 0xa2, 0xa2, 0xa2, 0x9c, B00000000, B00000000, // 15
  B00000000, 0x3c, B01010010, 0x92, 0x92, 0x0c, B00000000, B00000000, // 16
  B00000000, 0x80, 0x8e, 0x90, 0xa0, 0xc0, B00000000, B00000000, // 17
  B00000000, 0x6c, 0x92, 0x92, 0x92, 0x6c, B00000000, B00000000, // 18
  B00000000, 0x60, 0x92, 0x92, 0x94, B01111000, B00000000, B00000000, // 19
  0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 20
  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // 21
  0x81, B01000010, B00000000, B00011000, B00011000, B00000000, B01000010, 0x01, // 22
  B00000000, 0x84, 0x82, 0xa2, 0xd2, 0x8c, B00000000, B00000000, // 23
  B00000000, B00011000, 0x28, 0x48, 0xfe, 0x08, B00000000, B00000000, // 24
  B00000000, 0xe4, 0xa2, 0xa2, 0xa2, 0x9c, B00000000, B00000000, // 25
  B00000000, 0x3c, B01010010, 0x92, 0x92, 0x0c, B00000000, B00000000, // 26
  B00000000, 0x80, 0x8e, 0x90, 0xa0, 0xc0, B00000000, B00000000, // 27       /esc
  B00000000, 0x6c, 0x92, 0x92, 0x92, 0x6c, B00000000, B00000000, // 28
  B00000000, 0x60, 0x92, 0x92, 0x94, B01111000, B00000000, B00000000, // 29
  0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 30
  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // 31


  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 32         "space"
  B00000000, B00000000, B00000000, 0xFB, 0xFB, B00000000, B00000000, B00000000, // 33           !
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 34          "
  B00000000, B00000000, B00010100, B01111111, B00010100, B01111111, B00010100, B00000000, // 35           #
  B00000000, B00000000, B00100100, B00101010, B01111111, B00101010, B00010010, B00000000,// 36            $
  B00000000, B00000000, B00100011, B00010011, B00001000, B01100100, B01100010, B00000000, // 37           %
  B00000000, B00000000, B00110110, B01001001, B01010101, B00100010, B01010000, B00000000, // 38           &
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 39       '
  B00000000, B00000000, B00000000, B00011100, B00100010, B01000001, B00000000, B00000000, // 40       (
  B00000000, B00000000, B00000000, B01000001, B00100010, B00011100, B00000000, B00000000, // 41        )
  B00000000, B00000000, B00101000, B00010000, B01111100, B00010000, B00101000, B00000000, // 42       *
  B00000000, B00000000, B00010000, B00010000, B01111100, B00010000, B00010000, B00000000, // 43       +
  B00000000, B00000000, B00000000, B01010000, B00110000, B00000000, B00000000, B00000000, // 44       ,
  B00000000, B00000000, B00010000, B00010000, B00010000, B00010000, B00010000, B00000000, // 45       -
  B00000000, B00000000, B01100000, B01100000, B00000000, B00000000, B00000000, B00000000, // 46       .
  B00000000, B00000000, B01000000, B00100000, B00010000, B00001000, B00000100, B00000000,// 47        /

  B00000000, B00000000, B00111110, B01010001, B01001001, B01000101, B00111110, B00000000, // 0          0
  B00000000, B00000000, B01000100, B01000010, B01111111, B01000000, B01000000, B00000000, // 1            1
  B00000000, B00000000, B01100010, B01010001, B01001001, B01001001, B01000110, B00000000, // 2            2
  B00000000, B00000000, B00100010, B01000001, B01001001, B01001001, B00110110, B00000000, // 3            3
  B00000000, B00000000, B00011000, B00010100, B00010010, B01111111, B00010000, B00000000, // 4            4
  B00000000, B00000000, B00100111, B01000101, B01000101, B01000101, B00111001, B00000000, // 5            5
  B00000000, B00000000, B00111100, B01001010, B01001001, B01001001, B00110000, B00000000, // 6            6
  B00000000, B00000000, B00000001, B01110001, B00001001, B00000101, B00000011, B00000000, // 7            7
  B00000000, B00000000, B00110110, B01001001, B01001001, B01001001, B00110110, B00000000, // 8            8
  B00000000, B00000000, B00000110, B01001001, B01001001, B00101001, B00011110, B00000000, // 9            9

  
  B00000000, B00000000, B00000000, B00110110, B00110110, B00000000, B00000000, B00000000, // 58           :
  B00000000, B00000000, B00000000, B01010110, B00110110 , B00000000, B00000000, B00000000, // 59     ;
  B00000000, B00000000, B00000000, B00001000, B00010100, B00100010, B01000001, B00000000,// 60     <
  B00000000, B00000000, B00101000, B00101000, B00101000, B00101000, B00101000, B00000000,// 61      =
  B00000000, B00000000, B00000000, B01000001, B00100010, B00010100, B00001000, B00000000, // 62     >
  B00000000, B00000000, B00000010, B00000001, B01010001, B00001001, B00000110, B00000000, // 63     ?
  B00000000, B00000000, B00110010, B01001001, B01111001, B01000001, B00111110, B00000000, // 64        @
  B00000000, B00000000, B01111100, B00001010, B00001010, B00001010, B01111100, B00000000, // 65            A
  B00000000, B00000000, B01111110, B01001010, B01001010, B01001010, B00110100, B00000000, // 66            B
  B00000000, B00000000, B00111100, B01000010, B01000010, B01000010, B00100100, B00000000, // 67            C
  B00000000, B00000000, B01111110, B01000010, B01000010, B01000010, B00111100, B00000000, // 68            D
  B00000000, B00000000, B01111110, B01001010, B01001010, B01001010, B01001010, B00000000, // 69            E

  B00000000, B00000000, B01111111, B00001001, B00001001, B00001001, B00000001, B00000000, // 70            F
  B00000000, B00000000, B00111100, B01000010, B01010010, B01010010, B00110100, B00000000, // 71            G
  B00000000, B00000000, B01111110, B00010000, B00010000, B00010000, B01111110, B00000000, // 72            H
  B00000000, B00000000, B00000000, B01000010, B01111110, B01000010, B00000000, B00000000, // 73            I
  B00000000, B00000000, B00100000, B01000000, B01000000, B00111010, B00000000, B00000000, // 74            J
  B00000000, B00000000, B01111110, B00011000, B00100100, B01000010, B00000000, B00000000, // 75            K
  B00000000, B00000000, B01111110, B01000000, B01000000, B01000000, B01000000, B00000000, // 76            L
  B00000000, B00000000, B01111110, B00000100, B00001000, B00000100, B01111110, B00000000, // 77            M
  B00000000, B00000000, B01111110, B00000100, B00011000, B00100000, B01111110, B00000000, // 78            N
  B00000000, B00000000, B00111110, B01000001, B01000001, B01000001, B00111110, B00000000, // 111          O

  B00000000, B00000000, B01111110, B00001010, B00001010, B00001010, B00000100, B00000000, // 80            P
  B00000000, B00000000, B00111100, B01000010, B01010010, B01100010, B00111100, B00000000, // 81            Q
  B00000000, B00000000, B01111100, B00001010, B00011010, B00101010, B01000100, B00000000, // 82            R
  B00000000, B00000000, B00100100, B01001010, B01011010, B01010010, B00100100, B00000000, // 83            S
  B00000000, B00000000, B00000010, B00000010, B01111110, B00000010, B00000010, B00000000, // 84            T
  B00000000, B00000000, B00111110, B01000000, B01000000, B01000000, B00111110, B00000000, // 85            U
  B00000000, B00000000, B00011110, B00100000, B01000000, B00100000, B00011110, B00000000, // 86            V
  B00000000, B00000000, B00111111, B01000000, B00111000, B01000000, B00111111, B00000000, // 87            W
  B00000000, B00000000, B01000010, B00100100, B00011000, B00100100, B01000010, B00000000, // 88            X
  B00000000, B00000000, B00000010, B00000100, B01111000, B00000100, B00000010, B00000000, // 89            Y

  B00000000, B01000010, B01100010, B01010010, B01001010, B01000110, B01000010, B00000000,// 90            Z
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 91
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 92
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 93
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 94
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 95
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 96
  B00000000, B00000000, B00100000, B01010100, B01010100, B01010100, B01111000, B00000000, // 97           a
  B00000000, B00000000, B01111111, B01001000, B01000100, B01000100, B00111000, B00000000, // 98           b
  B00000000, B00000000, B00111000, B01000100, B01000100, B01000100, B00000000, B00000000, // 99           c

  B00000000, B00000000, B00111000, B01000100, B01000100, B01001000, B01111111, B00000000, // 100          d
  B00000000, B00000000, B00111000, B01010100, B01010100, B01010100, B00011000, B00000000, // 101          e
  B00000000, B00000000, B00001000, B01111110, B00001001, B00000001, B00000010, B00000000, // 102          f
  B00000000, B00000000, B00001000, B01010100, B01010100, B01010100, B00111100, B00000000, // 103          g
  B00000000, B00000000, B01111111, B00001000, B00000100, B00000100, B01111000, B00000000, // 104          h
  B00000000, B00000000, B00000000, B01001000, B01111101, B01000000, B00000000, B00000000, // 105          i
  B00000000, B00000000, B00100000, B01000000, B01000100, B00111101, B00000000, B00000000, // 106          j
  B00000000, B00000000, B00000000, B01111111, B00010000, B00101000, B01000100, B00000000, // 107          k
  B00000000, B00000000, B00000000, B01000001, B01111111, B01000000, B00000000, B00000000, // 108          l
  B00000000, B00000000, B01111100, B00000100, B01111000, B00000100, B01111000, B00000000, // 109          m


  B00000000, B00000000, B01111000, B00001000, B00000100, B00000100, B01111000, B00000000, // 110          n
  B00000000, B00000000, B00111000, B01000100, B01000100, B01000100, B00111000, B00000000, // 111          o
  B00000000, B00000000, B01111100, B00010100, B00010100, B00010100, B00001000, B00000000, // 112          p
  B00000000, B00000000, B00001000, B00010100, B00010100, B00010100, B01111100, B00000000, // 113          q
  B00000000, B00000000, B01111100, B00001000, B00000100, B00000100, B00001000, B00000000, // 114          r
  B00000000, B00000000, B01001000, B01010100, B01010100, B01010100, B00100000, B00000000, // 115          s
  B00000000, B00000000, B00000100, B00111111, B01000100, B01000000, B00100000, B00000000, // 116          t
  B00000000, B00000000, B00111100, B01000000, B01000000, B00100000, B01111100, B00000000, // 117          u
  B00000000, B00000000, B00011100, B00100000, B01000000, B00100000, B00011100, B00000000, // 118          v
  B00000000, B00000000, B00111100, B01000000, B00011000, B01000000, B00111100, B00000000, // 119          w

  B00000000, B00000000, B01000100, B00101000, B00010000, B00101000, B01000100, B00000000, // 120          x
  B00000000, B00000000, B00001100, B01010000, B01010000, B01010000, B00111100, B00000000, // 121          y
  B00000000, B00000000, B01000100, B01100100, B01010100, B01001100, B01000100, B00000000, // 122          z
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, // 123
  B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000  // 124
};

.INO before wrapping it into class;

#include "FontMap.h"  //font is in external file
#include <digitalWriteFast.h>

#define matrises 4            //define number of matrises, 4-22
#define columns matrises * 8  //calculate columns based how many matrises are in use
byte displayPointer = 0;
int dataPosition;
byte screenBuffer[columns];  // buffer for screen,4x8=32
int screenBufferIndex;
byte pixel, bitMask;
byte xPositionIndex, yPositionIndex;
byte disp, disp2;
byte pixels[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };  //for each column B10000000->B00000001
byte SPIDataOutPin = 2;
byte SPIChipSelectPin = 3;
byte SPIClockPin = 4;

void draw() {
  digitalWriteFast(SPIChipSelectPin, LOW);
  setColumn(displayPointer);              //column scanning
  setData(screenBuffer[displayPointer]);  //bit banging shift registers
  digitalWriteFast(SPIChipSelectPin, HIGH);

  if (++displayPointer == columns)  //32 LED row sections in total
  {
    displayPointer = 0;
  }
}

void setColumn(byte columnToCheck)  //loop that takes care of column scanning
{

  for (dataPosition = columns; dataPosition > -1; dataPosition--) {
    if (columnToCheck == dataPosition) {
      digitalWriteFast(SPIDataOutPin, HIGH);
    } else {
      digitalWriteFast(SPIDataOutPin, LOW);
    }
    digitalWriteFast(SPIClockPin, HIGH);
    digitalWriteFast(SPIClockPin, LOW);
  }
}

void setData(byte dat) {

  for (dataPosition = B10000000; dataPosition > 0; dataPosition >>= 1) {
    if (dat & dataPosition) {
      digitalWriteFast(SPIDataOutPin, HIGH);
    } else {
      digitalWriteFast(SPIDataOutPin, LOW);
    }
    digitalWriteFast(SPIClockPin, HIGH);
    digitalWriteFast(SPIClockPin, LOW);
  }
}

void clearBuffer()  //clear display buffer
{
  for (screenBufferIndex = 0; screenBufferIndex < columns; screenBufferIndex++)  // Empty display buffer
  {
    screenBuffer[screenBufferIndex] = 0;
  }
}

void setPixel(signed char xPosition, signed char yPosition, byte condition) {
  if (xPosition < 0 || yPosition < 0) {
    return;  // outside drawing limits negative
  }
  if (xPosition > (columns - 1) || yPosition > 7) {
    return;  // outside drawing limits positive, x=32, y=8
  }
  pixel = pixels[yPosition];
  bitMask = screenBuffer[xPosition];  // get exsisting data

  if (condition == 2)
    pixel ^= bitMask;  //XOR data to screen
  else if (condition == 1) {
    pixel = ~pixel;
    pixel &= bitMask;  // AND data to screen
  } else {
    pixel |= bitMask;  // OR data to screen
  }
  screenBuffer[xPosition] = pixel;  // apply changes
}

void drawCharacter(char character, signed char xPosition, signed char yPosition, byte rotation) {
  for (xPositionIndex = 0; xPositionIndex < 8; xPositionIndex++)  // eight rows
  {
    disp = ledMatrixFont_8x8[xPositionIndex + (character * 8)];     //look data from fontmap, (ch<<3)==(ch *8)
    for (yPositionIndex = 0; yPositionIndex < 8; yPositionIndex++)  // eight pixels
    {
      disp2 = disp & pixels[yPositionIndex];
      if (disp2 > 0) {
        if (rotation == 0) {
          setPixel(xPosition + xPositionIndex, yPosition + yPositionIndex, 0);  //0 degrees
        } else if (rotation == 1) {
          setPixel(7 - (yPosition + yPositionIndex), (xPosition + xPositionIndex), 0);  //90 degrees, flip to left
        } else if (rotation == 2) {
          setPixel(7 - (xPosition + xPositionIndex), 7 - (yPosition + yPositionIndex), 0);
        } else {
          setPixel(yPosition + yPositionIndex, 7 - (xPosition + xPositionIndex), 0);  //90 degrees, flip to right
        }
      }
    }
  }
}

void drawText(char* character, signed char xPosition, signed char yPosition, byte rotation)  //strput relies on charput
{
  while (*character) {
    drawCharacter(*character++, xPosition, yPosition, rotation);  //write a string to the display buffer
    xPosition += 7;
  }
}

void setup() {
  pinModeFast(SPIDataOutPin, OUTPUT);
  pinModeFast(SPIChipSelectPin, OUTPUT);
  pinModeFast(SPIClockPin, OUTPUT);
}


void loop() {
  clearBuffer();
  drawText("Hello", 0, 0, 0);
  draw();
}

And finally, the class version that has framerate issues;

#include "FontMap.h"  //font is in external file
#include <digitalWriteFast.h>

class LedMatrix {
public:
  LedMatrix(byte SPIDataOutPin, byte SPIChipSelectPin, byte SPIClockPin) {
    _SPIDataOutPin = SPIDataOutPin;
    _SPIChipSelectPin = SPIChipSelectPin;
    _SPIClockPin = SPIClockPin;
    pinModeFast(_SPIDataOutPin, OUTPUT);
    pinModeFast(_SPIChipSelectPin, OUTPUT);
    pinModeFast(_SPIClockPin, OUTPUT);
  };

#define matrises 4            //define number of matrises, 4-22
#define columns matrises * 8  //calculate columns based how many matrises are in use
  byte displayPointer = 0;
  int dataPosition;
  byte screenBuffer[columns];  // buffer for screen,4x8=32
  int screenBufferIndex;
  byte pixel, bitMask;
  byte xPositionIndex, yPositionIndex;
  byte disp, disp2;
  byte pixels[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };  //for each column B10000000->B00000001

  void draw() {
    digitalWriteFast(_SPIChipSelectPin, LOW);
    setColumn(displayPointer);              //column scanning
    setData(screenBuffer[displayPointer]);  //bit banging shift registers
    digitalWriteFast(_SPIChipSelectPin, HIGH);

    if (++displayPointer == columns)  //32 LED row sections in total
    {
      displayPointer = 0;
    }
  }

  void setColumn(byte columnToCheck)  //loop that takes care of column scanning
  {

    for (dataPosition = columns; dataPosition > -1; dataPosition--) {
      if (columnToCheck == dataPosition) {
        digitalWriteFast(_SPIDataOutPin, HIGH);
      } else {
        digitalWriteFast(_SPIDataOutPin, LOW);
      }
      digitalWriteFast(_SPIClockPin, HIGH);
      digitalWriteFast(_SPIClockPin, LOW);
    }
  }

  void setData(byte dat) {

    for (dataPosition = B10000000; dataPosition > 0; dataPosition >>= 1) {
      if (dat & dataPosition) {
        digitalWriteFast(_SPIDataOutPin, HIGH);
      } else {
        digitalWriteFast(_SPIDataOutPin, LOW);
      }
      digitalWriteFast(_SPIClockPin, HIGH);
      digitalWriteFast(_SPIClockPin, LOW);
    }
  }

  void clearBuffer()  //clear display buffer
  {
    for (screenBufferIndex = 0; screenBufferIndex < columns; screenBufferIndex++)  // Empty display buffer
    {
      screenBuffer[screenBufferIndex] = 0;
    }
  }

  void setPixel(signed char xPosition, signed char yPosition, byte condition) {
    if (xPosition < 0 || yPosition < 0) {
      return;  // outside drawing limits negative
    }
    if (xPosition > (columns - 1) || yPosition > 7) {
      return;  // outside drawing limits positive, x=32, y=8
    }
    pixel = pixels[yPosition];
    bitMask = screenBuffer[xPosition];  // get exsisting data

    if (condition == 2)
      pixel ^= bitMask;  //XOR data to screen
    else if (condition == 1) {
      pixel = ~pixel;
      pixel &= bitMask;  // AND data to screen
    } else {
      pixel |= bitMask;  // OR data to screen
    }
    screenBuffer[xPosition] = pixel;  // apply changes
  }

  void drawCharacter(char character, signed char xPosition, signed char yPosition, byte rotation) {
    for (xPositionIndex = 0; xPositionIndex < 8; xPositionIndex++)  // eight rows
    {
      disp = ledMatrixFont_8x8[xPositionIndex + (character * 8)];     //look data from fontmap, (ch<<3)==(ch *8)
      for (yPositionIndex = 0; yPositionIndex < 8; yPositionIndex++)  // eight pixels
      {
        disp2 = disp & pixels[yPositionIndex];
        if (disp2 > 0) {
          if (rotation == 0) {
            setPixel(xPosition + xPositionIndex, yPosition + yPositionIndex, 0);  //0 degrees
          } else if (rotation == 1) {
            setPixel(7 - (yPosition + yPositionIndex), (xPosition + xPositionIndex), 0);  //90 degrees, flip to left
          } else if (rotation == 2) {
            setPixel(7 - (xPosition + xPositionIndex), 7 - (yPosition + yPositionIndex), 0);
          } else {
            setPixel(yPosition + yPositionIndex, 7 - (xPosition + xPositionIndex), 0);  //90 degrees, flip to right
          }
        }
      }
    }
  }

  void drawText(char* character, signed char xPosition, signed char yPosition, byte rotation)  //strput relies on charput
  {
    while (*character) {
      drawCharacter(*character++, xPosition, yPosition, rotation);  //write a string to the display buffer
      xPosition += 7;
    }
  }

private:
  byte _SPIDataOutPin;
  byte _SPIChipSelectPin;
  byte _SPIClockPin;
};


byte SPIDataOutPin = 2;
byte SPIChipSelectPin = 3;
byte SPIClockPin = 4;

LedMatrix newMatrix(SPIDataOutPin, SPIChipSelectPin, SPIClockPin);

void setup() {
  Serial.begin(115200);
}


void loop() {
  newMatrix.clearBuffer();
  newMatrix.drawText("Hello", 0, 0, 0);
  newMatrix.draw();
}

I think that's all info I can give at this point.

That is a lot of shift registers :grinning:

Hmm, maybe I worded it bit wrong? Actually there's only 5; one for rows, 4 for columns. Along with darlingtons and resistors of course. :slight_smile: ...

Maybe, but in context, what you meant was obvious, or at least I hoped it was !

Don't put the calls to pinModeFast() in the class's constructor. For global objects, the constructor runs very early .... before init(). So hardware configurations done in the constructor may be undone in init(). Instead, give your class a begin() method to be called from setup(). Put the calls to pinModeFast() in begin().

Oh yes it would most likely!
Couple things to mention at this point;
Currently, matrix screen is wired to use software SPI. No idea why I went with hard wiring software SPI, but I'll open connections so it can use hardware SPI as well

I tested with smaller matrix, only one 8x8 with hardware SPI, and there was similar performance drop. However, the hardware SPI version of code is not yet done; I'd like to find out reason of performance difference from traditional code to OOP version like here with software SPI version.

Also, I want to make library so I can choose during making instance whether to use software, or SPI. Or, I could make separate librares for software and hardware.
That said, It's not mantadory;
Since It's possible to change SS pin to determine which SPI slave listens.
And SPI bus can be released/initiated if needed during runtime.

I'll open matrix connections and test with hardware SPI

Like so?
ALSO, since you mentioned about hardware configurations being undone in init();
I made test to run as vanilla digitalWrite. The same performane drop occured!

So it seems that even though it should use digitalWriteFast, it uses digitalWrite? Does that make sense?

#include "FontMap.h"  //font is in external file
#include <digitalWriteFast.h>

class LedMatrix {
public:
  LedMatrix(byte SPIDataOutPin, byte SPIChipSelectPin, byte SPIClockPin) {
    _SPIDataOutPin = SPIDataOutPin;
    _SPIChipSelectPin = SPIChipSelectPin;
    _SPIClockPin = SPIClockPin;
  };

  begin() {
    pinModeFast(_SPIDataOutPin, OUTPUT);
    pinModeFast(_SPIChipSelectPin, OUTPUT);
    pinModeFast(_SPIClockPin, OUTPUT);
  }

#define matrises 4            //define number of matrises, 4-22
#define columns matrises * 8  //calculate columns based how many matrises are in use
  byte displayPointer = 0;
  int dataPosition;
  byte screenBuffer[columns];  // buffer for screen,4x8=32
  int screenBufferIndex;
  byte pixel, bitMask;
  byte xPositionIndex, yPositionIndex;
  byte disp, disp2;
  byte pixels[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };  //for each column B10000000->B00000001

  void draw() {
    digitalWriteFast(_SPIChipSelectPin, LOW);
    setColumn(displayPointer);              //column scanning
    setData(screenBuffer[displayPointer]);  //bit banging shift registers
    digitalWriteFast(_SPIChipSelectPin, HIGH);

    if (++displayPointer == columns)  //32 LED row sections in total
    {
      displayPointer = 0;
    }
  }

  void setColumn(byte columnToCheck)  //loop that takes care of column scanning
  {

    for (dataPosition = columns; dataPosition > -1; dataPosition--) {
      if (columnToCheck == dataPosition) {
        digitalWriteFast(_SPIDataOutPin, HIGH);
      } else {
        digitalWriteFast(_SPIDataOutPin, LOW);
      }
      digitalWriteFast(_SPIClockPin, HIGH);
      digitalWriteFast(_SPIClockPin, LOW);
    }
  }

  void setData(byte dat) {

    for (dataPosition = B10000000; dataPosition > 0; dataPosition >>= 1) {
      if (dat & dataPosition) {
        digitalWriteFast(_SPIDataOutPin, HIGH);
      } else {
        digitalWriteFast(_SPIDataOutPin, LOW);
      }
      digitalWriteFast(_SPIClockPin, HIGH);
      digitalWriteFast(_SPIClockPin, LOW);
      {}
    }
  }

  void clearBuffer()  //clear display buffer
  {
    for (screenBufferIndex = 0; screenBufferIndex < columns; screenBufferIndex++)  // Empty display buffer
    {
      screenBuffer[screenBufferIndex] = 0;
    }
  }

  void setPixel(signed char xPosition, signed char yPosition, byte condition) {
    if (xPosition < 0 || yPosition < 0) {
      return;  // outside drawing limits negative
    }
    if (xPosition > (columns - 1) || yPosition > 7) {
      return;  // outside drawing limits positive, x=32, y=8
    }
    pixel = pixels[yPosition];
    bitMask = screenBuffer[xPosition];  // get exsisting data

    if (condition == 2)
      pixel ^= bitMask;  //XOR data to screen
    else if (condition == 1) {
      pixel = ~pixel;
      pixel &= bitMask;  // AND data to screen
    } else {
      pixel |= bitMask;  // OR data to screen
    }
    screenBuffer[xPosition] = pixel;  // apply changes
  }

  void drawCharacter(char character, signed char xPosition, signed char yPosition, byte rotation) {
    for (xPositionIndex = 0; xPositionIndex < 8; xPositionIndex++)  // eight rows
    {
      disp = ledMatrixFont_8x8[xPositionIndex + (character * 8)];     //look data from fontmap, (ch<<3)==(ch *8)
      for (yPositionIndex = 0; yPositionIndex < 8; yPositionIndex++)  // eight pixels
      {
        disp2 = disp & pixels[yPositionIndex];
        if (disp2 > 0) {
          if (rotation == 0) {
            setPixel(xPosition + xPositionIndex, yPosition + yPositionIndex, 0);  //0 degrees
          } else if (rotation == 1) {
            setPixel(7 - (yPosition + yPositionIndex), (xPosition + xPositionIndex), 0);  //90 degrees, flip to left
          } else if (rotation == 2) {
            setPixel(7 - (xPosition + xPositionIndex), 7 - (yPosition + yPositionIndex), 0);
          } else {
            setPixel(yPosition + yPositionIndex, 7 - (xPosition + xPositionIndex), 0);  //90 degrees, flip to right
          }
        }
      }
    }
  }

  void drawText(char* character, signed char xPosition, signed char yPosition, byte rotation)  //strput relies on charput
  {
    while (*character) {
      drawCharacter(*character++, xPosition, yPosition, rotation);  //write a string to the display buffer
      xPosition += 7;
    }
  }

private:
  byte _SPIDataOutPin;
  byte _SPIChipSelectPin;
  byte _SPIClockPin;
};


byte SPIDataOutPin = 2;
byte SPIChipSelectPin = 3;
byte SPIClockPin = 4;

LedMatrix newMatrix(SPIDataOutPin, SPIChipSelectPin, SPIClockPin);

void setup() {
  Serial.begin(115200);
  newMatrix.begin();
}


void loop() {
  newMatrix.clearBuffer();
  newMatrix.drawText("Hello", 0, 0, 0);
  newMatrix.draw();
}

Okay, made small test and results don't make sense to me at all! I made simple class, and found out that If I call function without pin number as parameter, it results in slower speed. I measured values with frequency counter.

There Isn't matrix; just pure pin on/off testing.

#include <digitalWriteFast.h>

class MyDigitalWriteTest {
public:
  //Constructor with just pin parameter
  MyDigitalWriteTest(byte pin) {
    _pin = pin;
  };

  //begin function initiates _pin as output
  begin() {
    pinModeFast(_pin, OUTPUT);
  }

  //writePin with pin AND value
  writePin(byte _pin, boolean value) {
    digitalWriteFast(_pin, value);
  }
  //writePin with only VALUE
  writePin(boolean value) {
    digitalWriteFast(_pin, value);
  }

private:
  byte _pin;
};


boolean usePinNumber = 0;

const byte pin = 4;
MyDigitalWriteTest myTest(pin);

void setup() {
  myTest.begin();  //initiate OUTPUT
  Serial.begin(115200);
}

void loop() {
  if (usePinNumber == true) {
    methodsWithPinNumber();  //1.9Mhz
  } else {
    methodsWithoutPinNumber();  //133kHz
  }
}

void methodsWithoutPinNumber() {
  myTest.writePin(1);
  myTest.writePin(0);
}

void methodsWithPinNumber() {
  myTest.writePin(4, 1);
  myTest.writePin(4, 0);
}

Also, if I force pin in this method, that results in fast clock as well

  //writePin with only VALUE
  writePin(boolean value) {
    digitalWriteFast(4, value);
  }

Knowing this, tested with class code with direct addressing pins, resulting in fast speed. Huh!

#include "FontMap.h"  //font is in external file
#include <digitalWriteFast.h>

class LedMatrix {
public:
  LedMatrix(byte SPIDataOutPin, byte SPIChipSelectPin, byte SPIClockPin) {
    _SPIDataOutPin = SPIDataOutPin;
    _SPIChipSelectPin = SPIChipSelectPin;
    _SPIClockPin = SPIClockPin;
  };

  begin() {
    pinModeFast(2, OUTPUT);
    pinModeFast(3, OUTPUT);
    pinModeFast(4, OUTPUT);
  }

#define matrises 4            //define number of matrises, 4-22
#define columns matrises * 8  //calculate columns based how many matrises are in use
  byte displayPointer = 0;
  int dataPosition;
  byte screenBuffer[columns];  // buffer for screen,4x8=32
  int screenBufferIndex;
  byte pixel, bitMask;
  byte xPositionIndex, yPositionIndex;
  byte disp, disp2;
  byte pixels[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };  //for each column B10000000->B00000001

  void draw() {


    digitalWriteFast(3, LOW);
    setColumn(displayPointer);                     //column scanning
    setData(screenBuffer[displayPointer]);  //bit banging shift registers
    digitalWriteFast(3, HIGH);

    if (++displayPointer == columns)  //32 LED row sections in total
    {
      displayPointer = 0;
    }
  }

  setColumn(byte columnToCheck)  //loop that takes care of column scanning
  {


    for (dataPosition = columns; dataPosition > -1; dataPosition--) {
      if (columnToCheck == dataPosition) {
        digitalWriteFast(2, HIGH);
      } else {
        digitalWriteFast(2, LOW);
      }
      digitalWriteFast(4, HIGH);
      digitalWriteFast(4, LOW);
    }
  }

  setData(byte dat) {

    for (dataPosition = B10000000; dataPosition > 0; dataPosition >>= 1) {
      if (dat & dataPosition) {
        digitalWriteFast(2, HIGH);
      } else {
        digitalWriteFast(2, LOW);
      }
      digitalWriteFast(4, HIGH);
      digitalWriteFast(4, LOW);
      {}
    }
  }

  void clearBuffer()  //clear display buffer
  {
    for (screenBufferIndex = 0; screenBufferIndex < columns; screenBufferIndex++)  // Empty display buffer
    {
      screenBuffer[screenBufferIndex] = 0;
    }
  }

  void setPixel(signed char xPosition, signed char yPosition, byte condition) {
    if (xPosition < 0 || yPosition < 0) {
      return;  // outside drawing limits negative
    }
    if (xPosition > (columns - 1) || yPosition > 7) {
      return;  // outside drawing limits positive, x=32, y=8
    }
    pixel = pixels[yPosition];
    bitMask = screenBuffer[xPosition];  // get exsisting data

    if (condition == 2)
      pixel ^= bitMask;  //XOR data to screen
    else if (condition == 1) {
      pixel = ~pixel;
      pixel &= bitMask;  // AND data to screen
    } else {
      pixel |= bitMask;  // OR data to screen
    }
    screenBuffer[xPosition] = pixel;  // apply changes
  }

  void drawCharacter(char character, signed char xPosition, signed char yPosition, byte rotation) {
    for (xPositionIndex = 0; xPositionIndex < 8; xPositionIndex++)  // eight rows
    {
      disp = ledMatrixFont_8x8[xPositionIndex + (character * 8)];     //look data from fontmap, (ch<<3)==(ch *8)
      for (yPositionIndex = 0; yPositionIndex < 8; yPositionIndex++)  // eight pixels
      {
        disp2 = disp & pixels[yPositionIndex];
        if (disp2 > 0) {
          if (rotation == 0) {
            setPixel(xPosition + xPositionIndex, yPosition + yPositionIndex, 0);  //0 degrees
          } else if (rotation == 1) {
            setPixel(7 - (yPosition + yPositionIndex), (xPosition + xPositionIndex), 0);  //90 degrees, flip to left
          } else if (rotation == 2) {
            setPixel(7 - (xPosition + xPositionIndex), 7 - (yPosition + yPositionIndex), 0);
          } else {
            setPixel(yPosition + yPositionIndex, 7 - (xPosition + xPositionIndex), 0);  //90 degrees, flip to right
          }
        }
      }
    }
  }

  void drawText(char* character, signed char xPosition, signed char yPosition, byte rotation)  //strput relies on charput
  {
    while (*character) {
      drawCharacter(*character++, xPosition, yPosition, rotation);  //write a string to the display buffer
      xPosition += 7;
    }
  }

private:
  byte _SPIDataOutPin;
  byte _SPIChipSelectPin;
  byte _SPIClockPin;
};


byte SPIDataOutPin = 2;
byte SPIChipSelectPin = 3;
byte SPIClockPin = 4;

LedMatrix newMatrix(SPIDataOutPin, SPIChipSelectPin, SPIClockPin);

void setup() {
  Serial.begin(115200);
  newMatrix.begin();
}


void loop() {
  newMatrix.clearBuffer();
  newMatrix.drawText("Hello", 0, 0, 0);
  newMatrix.draw();
}

This is repository of digitalWriteFast library I use.

I tried to use `THROW_ERROR_IF_NOT_FAST (all compiler warnings turned on), but no warnings/errros about slowness in any case. huh.

I posted results at post #9 when I debugged with frequency counter and with digiralWriteFast.h library. It turns out that library drops to digiralWriteFast since in class pin variables are not const? However, it does work outside class, which is odd. I'll continue testing more tomorrow, I'm not at lab right now.

There's one test result. Similar difference with matrix as well between slow/fast, I mean it really refreshes much slower than it should. I can take measurement tomorrow. I also tested matrix code by setting pins to pre-set value and it also resulted in fast update rate.

Wohoo! Got it working, "only" had to make pins as const byte function parameters to fed used with digitalWriteFast.

In the end, following code worked!

#include "FontMap.h"  //font is in external file
#include <digitalWriteFast.h>

class LedMatrix {
public:
  LedMatrix(byte SPIDataOutPin, byte SPIChipSelectPin, byte SPIClockPin) {

    _SPIDataOutPin = SPIDataOutPin;
    _SPIChipSelectPin = SPIChipSelectPin;
    _SPIClockPin = SPIClockPin;
  };

  void begin() {
    pinModeFast(_SPIDataOutPin, OUTPUT);
    pinModeFast(_SPIChipSelectPin, OUTPUT);
    pinModeFast(_SPIClockPin, OUTPUT);
  }

#define matrises 4
#define columns matrises * 8  //calculate columns based how many matrises are in use
  byte displayPointer = 0;
  int dataPosition;
  byte screenBuffer[columns];

  int screenBufferIndex;
  byte pixel, bitMask;
  byte xPositionIndex, yPositionIndex;
  byte disp, disp2;
  byte pixels[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };  //for each column B10000000->B00000001

  void draw(const byte _SPIDataOutPin, const byte _SPIChipSelectPin, const byte _SPIClockPin) {

    digitalWriteFast(_SPIChipSelectPin, LOW);
    setColumn(displayPointer, _SPIDataOutPin, _SPIClockPin);              //column scanning
    setData(screenBuffer[displayPointer], _SPIDataOutPin, _SPIClockPin);  //bit banging shift registers
    digitalWriteFast(_SPIChipSelectPin, HIGH);


    if (++displayPointer == columns)  //32 LED row sections in total
    {
      displayPointer = 0;
    }
  }



  void setColumn(byte columnToCheck, const byte _SPIDataOutPin, const byte _SPIClockPin)  //loop that takes care of column scanning
  {

    for (dataPosition = columns; dataPosition > -1; dataPosition--) {
      if (columnToCheck == dataPosition) {
        digitalWriteFast(_SPIDataOutPin, HIGH);
      } else {
        digitalWriteFast(_SPIDataOutPin, LOW);
      }
      digitalWriteFast(_SPIClockPin, HIGH);
      digitalWriteFast(_SPIClockPin, LOW);
    }
  }



  void setData(byte dat, const byte _SPIDataOutPin, const byte _SPIClockPin) {

    for (dataPosition = B10000000; dataPosition > 0; dataPosition >>= 1) {
      if (dat & dataPosition) {
        digitalWriteFast(_SPIDataOutPin, HIGH);

      } else {
        digitalWriteFast(_SPIDataOutPin, LOW);
      }
      digitalWriteFast(_SPIClockPin, HIGH);
      digitalWriteFast(_SPIClockPin, LOW);
    }
  }

  void clearBuffer()  //clear display buffer
  {
    for (screenBufferIndex = 0; screenBufferIndex < columns; screenBufferIndex++)  // Empty display buffer
    {
      screenBuffer[screenBufferIndex] = 0;
    }
  }

  void setPixel(signed char xPosition, signed char yPosition, byte condition) {
    if (xPosition < 0 || yPosition < 0) {
      return;  // outside drawing limits negative
    }
    if (xPosition > (columns - 1) || yPosition > 7) {
      return;  // outside drawing limits positive, x=32, y=8
    }
    pixel = pixels[yPosition];
    bitMask = screenBuffer[xPosition];  // get exsisting data

    if (condition == 2) {
      pixel ^= bitMask;  //XOR data to screen
    } else if (condition == 1) {
      pixel = ~pixel;
      pixel &= bitMask;  // AND data to screen
    } else {
      pixel |= bitMask;  // OR data to screen
    }
    screenBuffer[xPosition] = pixel;  // apply changes
  }

  void drawCharacter(char character, signed char xPosition, signed char yPosition, byte rotation) {
    for (xPositionIndex = 0; xPositionIndex < 8; xPositionIndex++)  // eight rows
    {
      disp = ledMatrixFont_8x8[xPositionIndex + (character * 8)];     //look data from fontmap, (ch<<3)==(ch *8)
      for (yPositionIndex = 0; yPositionIndex < 8; yPositionIndex++)  // eight pixels
      {
        disp2 = disp & pixels[yPositionIndex];
        if (disp2 > 0) {
          if (rotation == 0) {
            setPixel(xPosition + xPositionIndex, yPosition + yPositionIndex, 0);  //0 degrees
          } else if (rotation == 1) {
            setPixel(7 - (yPosition + yPositionIndex), (xPosition + xPositionIndex), 0);  //90 degrees, flip to left
          } else if (rotation == 2) {
            setPixel(7 - (xPosition + xPositionIndex), 7 - (yPosition + yPositionIndex), 0);
          } else {
            setPixel(yPosition + yPositionIndex, 7 - (xPosition + xPositionIndex), 0);  //90 degrees, flip to right
          }
        }
      }
    }
  }

  void drawText(char* character, signed char xPosition, signed char yPosition, byte rotation)  //strput relies on charput
  {
    while (*character) {
      drawCharacter(*character++, xPosition, yPosition, rotation);  //write a string to the display buffer
      xPosition += 7;
    }
  }

private:
  byte _SPIDataOutPin;
  byte _SPIChipSelectPin;
  byte _SPIClockPin;
};


byte SPIDataOutPin = 2;
byte SPIChipSelectPin = 3;
byte SPIClockPin = 4;
char text[] = "Hello";

LedMatrix newMatrix(SPIDataOutPin, SPIChipSelectPin, SPIClockPin);

void setup() {
  Serial.begin(115200);
  newMatrix.begin();
}


void loop() {
  newMatrix.clearBuffer();
  newMatrix.drawText(text, 0, 0, 0);
  newMatrix.draw(SPIDataOutPin, SPIChipSelectPin, SPIClockPin);
}

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