Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32-support #48

Open
StefanL38 opened this issue Aug 26, 2021 · 2 comments
Open

ESP32-support #48

StefanL38 opened this issue Aug 26, 2021 · 2 comments

Comments

@StefanL38
Copy link

Hello,

I tried to compile this demo-code onto a ESP32-nodeMCU but the display did not show the text
[code]
#include <DebugTxtVar.h>
#include <LEDMatrixDriver.hpp>

// This sketch draw marquee text on your LED matrix using the hardware SPI driver Library by Bartosz Bielawski.
// Example written 16.06.2017 by Marko Oette, www.oette.info

// Define the ChipSelect pin for the led matrix (Dont use the SS or MISO pin of your Arduino!)
// Other pins are Arduino specific SPI pins
// Uno: MOSI Pin 11 = DIN,
// SCK Pin 13 = CLK of the LEDMatrix)
//see https://www.arduino.cc/en/Reference/SPI
// ESP32 V-SPI-Pins
// CLK GPIO-Pin 18 = CLK
// MOSI GPIO-Pin 23 = DIN
// MISO GPIO-Pin 19

const uint8_t LEDMATRIX_CS_PIN = 5;

// Number of 8x8 segments you are connecting
const int LEDMATRIX_SEGMENTS = 12;
const int LEDMATRIX_WIDTH = LEDMATRIX_SEGMENTS * 8;

// The LEDMatrixDriver class instance
LEDMatrixDriver lmd(LEDMATRIX_SEGMENTS, LEDMATRIX_CS_PIN);

// Marquee text
//char text[] = "** LED MATRIX DEMO! ** (1234567890) ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ <$%/=?'.@,> --";
char text[] = "* DIE MEDIOTHEK HAT GEOEFFNET * 12 UHR BIS 14 UHR *";
// Marquee speed (lower nubmers = faster)
const int ANIM_DELAY = 40;

void PrintFileNameDateTime() {
Serial.println( F("Code running comes from file ") );
Serial.println(FILE);
Serial.print( F(" compiled ") );
Serial.print(DATE);
Serial.print( F(" ") );
Serial.println(TIME);
}

boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - periodStartTime >= TimePeriod )
{
periodStartTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}

unsigned long MyTestTimer = 0; // variables MUST be of type unsigned long
const byte OnBoard_LED = 2;

void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
static unsigned long MyBlinkTimer;
pinMode(IO_Pin, OUTPUT);

if ( TimePeriodIsOver(MyBlinkTimer,BlinkPeriod) ) {
digitalWrite(IO_Pin,!digitalRead(IO_Pin) );
}
}

void setup() {
Serial.begin(115200);
Serial.println( F("Setup-Start") );
PrintFileNameDateTime();
lmd.setEnabled(true);
lmd.setIntensity(0); // 0 = low, 10 = high
}

int x = 0, y = 0; // start top left

// This is the font definition. You can use http://gurgleapps.com/tools/matrix to create your own font or sprites.
// If you like the font feel free to use it. I created it myself and donate it to the public domain.
byte font[95][8] = { {0,0,0,0,0,0,0,0}, // SPACE
{0x10,0x18,0x18,0x18,0x18,0x00,0x18,0x18}, // EXCL
{0x28,0x28,0x08,0x00,0x00,0x00,0x00,0x00}, // QUOT
{0x00,0x0a,0x7f,0x14,0x28,0xfe,0x50,0x00}, // #
{0x10,0x38,0x54,0x70,0x1c,0x54,0x38,0x10}, // $
{0x00,0x60,0x66,0x08,0x10,0x66,0x06,0x00}, // %
{0,0,0,0,0,0,0,0}, // &
{0x00,0x10,0x18,0x18,0x08,0x00,0x00,0x00}, // '
{0x02,0x04,0x08,0x08,0x08,0x08,0x08,0x04}, // (
{0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x20}, // )
{0x00,0x10,0x54,0x38,0x10,0x38,0x54,0x10}, // *
{0x00,0x08,0x08,0x08,0x7f,0x08,0x08,0x08}, // +
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08}, // COMMA
{0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06}, // DOT
{0x00,0x04,0x04,0x08,0x10,0x20,0x40,0x40}, // /
{0x00,0x38,0x44,0x4c,0x54,0x64,0x44,0x38}, // 0
{0x04,0x0c,0x14,0x24,0x04,0x04,0x04,0x04}, // 1
{0x00,0x30,0x48,0x04,0x04,0x38,0x40,0x7c}, // 2
{0x00,0x38,0x04,0x04,0x18,0x04,0x44,0x38}, // 3
{0x00,0x04,0x0c,0x14,0x24,0x7e,0x04,0x04}, // 4
{0x00,0x7c,0x40,0x40,0x78,0x04,0x04,0x38}, // 5
{0x00,0x38,0x40,0x40,0x78,0x44,0x44,0x38}, // 6
{0x00,0x7c,0x04,0x04,0x08,0x08,0x10,0x10}, // 7
{0x00,0x3c,0x44,0x44,0x38,0x44,0x44,0x78}, // 8
{0x00,0x38,0x44,0x44,0x3c,0x04,0x04,0x78}, // 9
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // :
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x08}, // ;
{0x00,0x10,0x20,0x40,0x80,0x40,0x20,0x10}, // <
{0x00,0x00,0x7e,0x00,0x00,0xfc,0x00,0x00}, // =
{0x00,0x08,0x04,0x02,0x01,0x02,0x04,0x08}, // >
{0x00,0x38,0x44,0x04,0x08,0x10,0x00,0x10}, // ?
{0x00,0x30,0x48,0xba,0xba,0x84,0x78,0x00}, // @
{0x00,0x1c,0x22,0x42,0x42,0x7e,0x42,0x42}, // A
{0x00,0x78,0x44,0x44,0x78,0x44,0x44,0x7c}, // B
{0x00,0x3c,0x44,0x40,0x40,0x40,0x44,0x7c}, // C
{0x00,0x7c,0x42,0x42,0x42,0x42,0x44,0x78}, // D
{0x00,0x78,0x40,0x40,0x70,0x40,0x40,0x7c}, // E
{0x00,0x7c,0x40,0x40,0x78,0x40,0x40,0x40}, // F
{0x00,0x3c,0x40,0x40,0x5c,0x44,0x44,0x78}, // G
{0x00,0x42,0x42,0x42,0x7e,0x42,0x42,0x42}, // H
{0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x7e}, // I
{0x00,0x7e,0x02,0x02,0x02,0x02,0x04,0x38}, // J
{0x00,0x44,0x48,0x50,0x60,0x50,0x48,0x44}, // K
{0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x7c}, // L
{0x00,0x82,0xc6,0xaa,0x92,0x82,0x82,0x82}, // M
{0x00,0x42,0x42,0x62,0x52,0x4a,0x46,0x42}, // N
{0x00,0x3c,0x42,0x42,0x42,0x42,0x44,0x38}, // O
{0x00,0x78,0x44,0x44,0x48,0x70,0x40,0x40}, // P
{0x00,0x3c,0x42,0x42,0x52,0x4a,0x44,0x3a}, // Q
{0x00,0x78,0x44,0x44,0x78,0x50,0x48,0x44}, // R
{0x00,0x38,0x40,0x40,0x38,0x04,0x04,0x78}, // S
{0x00,0x7e,0x90,0x10,0x10,0x10,0x10,0x10}, // T
{0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x3e}, // U
{0x00,0x42,0x42,0x42,0x42,0x44,0x28,0x10}, // V
{0x80,0x82,0x82,0x92,0x92,0x92,0x94,0x78}, // W
{0x00,0x42,0x42,0x24,0x18,0x24,0x42,0x42}, // X
{0x00,0x44,0x44,0x28,0x10,0x10,0x10,0x10}, // Y
{0x00,0x7c,0x04,0x08,0x7c,0x20,0x40,0xfe}, // Z
// (the font does not contain any lower case letters. you can add your own.)
}; // {}, //

void loop() {
BlinkHeartBeatLED(OnBoard_LED,100);

if ( TimePeriodIsOver(MyTestTimer,1000) ) {

}
// Draw the text to the current position
int len = strlen(text);
drawString(text, len, x, 0);
// In case you wonder why we don't have to call lmd.clear() in every loop: The font has a opaque (black) background...

// Toggle display of the new framebuffer
lmd.display();

// Wait to let the human read the display
delay(ANIM_DELAY);

// Advance to next coordinate
if( --x < len * -8 ) {
x = LEDMATRIX_WIDTH;
}

}

/**

  • This function draws a string of the given length to the given position.
    /
    void drawString(char
    text, int len, int x, int y )
    {
    for( int idx = 0; idx < len; idx ++ )
    {
    int c = text[idx] - 32;

    // stop if char is outside visible area
    if( x + idx * 8 > LEDMATRIX_WIDTH )
    return;

    // only draw if char is visible
    if( 8 + x + idx * 8 > 0 )
    drawSprite( font[c], x + idx * 8, y, 8, 8 );
    }
    }

/**

  • This draws a sprite to the given position using the width and height supplied (usually 8x8)
    /
    void drawSprite( byte
    sprite, int x, int y, int width, int height )
    {
    // The mask is used to get the column bit from the sprite row
    byte mask = B10000000;

for( int iy = 0; iy < height; iy++ )
{
for( int ix = 0; ix < width; ix++ )
{
lmd.setPixel(x + ix, y + iy, (bool)(sprite[iy] & mask ));

  // shift the mask by one pixel to the right
  mask = mask >> 1;
}

// reset column mask
mask = B10000000;

}
}
[/code]

So I started reading what might be the error and I found that SPI.begin() can be used with optional parameters fpr the used IO-Pins.
SPI.begin(SPI_CLK, SPI_MISO, SPI_MOSI);
So I modified the constructor in the LedMatrixDriver.cpp to
LEDMatrixDriver::LEDMatrixDriver(uint8_t N, uint8_t ssPin, uint8_t flags, uint8_t* fb):
#ifdef USE_ADAFRUIT_GFX
Adafruit_GFX(N8, N),
#endif
N(N),
spiSettings(5000000, MSBFIRST, SPI_MODE0),
flags(flags),
frameBuffer(fb),
selfAllocated(fb == nullptr),
ssPin(ssPin)
{
if (selfAllocated)
frameBuffer = new uint8_t[N
8];

clear();	// initally clear the buffer as the memory will not be initialized on reset (old content will be in memory yet)

pinMode(ssPin, OUTPUT);
digitalWrite(ssPin, 1);

#ifdef ESP32
SPI.begin(18,19,23);
#else
SPI.begin();
#endif
`
Which is a simple solution but not the optimal solution because the ESP32 offers two SPI-buses VSPI and HSPI
my code-modification has the VSPI-IO-pins hardcoded.

It would be much better if the LedMatrixDriver.cpp would have options for using VSPI and for HSPI and any other GPIOs that can be used on a ESP32.

best regards Stefan

@bartoszbielawski
Copy link
Owner

Hi Stefan,

Your remark is spot on. The way it was coded is slightly wrong, but on the other hand it simplifies users' code.

I'm considering adding (I have already considered it before) a dependency injection via a dedicated constructor: users themselves would be responsible for creating/initializing SPI object. This way any SPI can be used - VSPI, HSPI or software SPI. The begin method will have to be called before passing the object to the constructor. This method differs between implementations so it also simplifies my code!

The new API would be:

LEDMatrixDriver(SPIClass& spi, uint8_t ssPin, uint32_t speed, uint8_t N, uint8_t flags = 0, uint8_t* frameBuffer = nullptr);

Or something similar. I have added speed because it should be configurable as well. We should consider argument order...

I do not have access to the hardware for another two weeks so even if I implement it I won't be able to test it.
On the other hand I accept pull requests! 😎

Cheers,
Bartosz

@bartoszbielawski
Copy link
Owner

Okay, I have modified the library to accept the bus object (and frequency). Check the new branch and the new constructor the code contains. I can't test it - still no HW for at least two weeks. I would be grateful if you could try the new code.

Cheers,
Bartosz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants