Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions DMD2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
typedef intptr_t port_reg_t;

SPIDMD::SPIDMD(byte panelsWide, byte panelsHigh)
#ifdef ESP8266
: BaseDMD(panelsWide, panelsHigh, 15, 16, 12, 0)
#if defined(ESP8266)
: BaseDMD(panelsWide, panelsHigh, 0, 16, 12, 15)
#elif defined(ESP32)
: BaseDMD(panelsWide, panelsHigh, 14, 27, 26, 25)
#else
: BaseDMD(panelsWide, panelsHigh, 9, 6, 7, 8)
#endif
Expand All @@ -45,7 +47,7 @@ void SPIDMD::beginNoTimer()
SPI.setDataMode(SPI_MODE0); // CPOL=0, CPHA=0
#ifdef __AVR__
SPI.setClockDivider(SPI_CLOCK_DIV4); // 4MHz clock. 8MHz (DIV2 not DIV4) is possible if you have short cables. Longer cables may need DIV8/DIV16.
#elif defined(ESP8266)
#elif defined(ESP8266) || defined(ESP32)
SPI.setFrequency(4000000); // ESP can run at 80mhz or 160mhz, setting frequency directly is easier, set to 4MHz.
#else
SPI.setClockDivider(20); // 4.2MHz on Due. Same comment as above applies (lower numbers = less divider = faster speeds.)
Expand Down Expand Up @@ -81,7 +83,12 @@ void BaseDMD::scanDisplay()

writeSPIData(rows, rowsize);

#if defined(ESP32)
ledcWrite(ESP32_PIN_NOE_PWM_CHANNEL, 0);
#else
digitalWrite(pin_noe, LOW);
#endif

digitalWrite(pin_sck, HIGH); // Latch DMD shift register output
digitalWrite(pin_sck, LOW); // (Deliberately left as digitalWrite to ensure decent latching time)

Expand All @@ -96,14 +103,18 @@ void BaseDMD::scanDisplay()
scan_row = (scan_row + 1) % 4;

// Output enable pin is either fixed on, or PWMed for a variable brightness display
#if defined(ESP32)
ledcWrite(ESP32_PIN_NOE_PWM_CHANNEL, brightness);
#else
if(brightness == 255)
digitalWrite(pin_noe, HIGH);
else
analogWrite(pin_noe, brightness);
#endif
}

#ifdef ESP8266
// No SoftDMD for ESP8266 for now
#if defined(ESP8266) || defined(ESP32)
// No SoftDMD for ESP8266 or ESP32 for now
#else
SoftDMD::SoftDMD(byte panelsWide, byte panelsHigh)
: BaseDMD(panelsWide, panelsHigh, 9, 6, 7, 8),
Expand Down Expand Up @@ -171,8 +182,10 @@ BaseDMD::BaseDMD(byte panelsWide, byte panelsHigh, byte pin_noe, byte pin_a, byt
pin_a(pin_a),
pin_b(pin_b),
pin_sck(pin_sck),
#ifdef ESP8266
default_pins(pin_noe == 15 && pin_a == 16 && pin_b == 12 && pin_sck == 0),
#if defined(ESP8266)
default_pins(pin_noe == 0 && pin_a == 16 && pin_b == 12 && pin_sck == 15),
#elif defined(ESP32)
default_pins(pin_noe == 14 && pin_a == 27 && pin_b == 26 && pin_sck == 25),
#else
default_pins(pin_noe == 9 && pin_a == 6 && pin_b == 7 && pin_sck == 8),
#endif
Expand All @@ -183,8 +196,17 @@ BaseDMD::BaseDMD(byte panelsWide, byte panelsHigh, byte pin_noe, byte pin_a, byt

void BaseDMD::beginNoTimer()
{
#if defined(ESP32)
pinMode(pin_noe, OUTPUT);
// configure LED PWM functionalitites
ledcSetup(ESP32_PIN_NOE_PWM_CHANNEL, ESP32_PWM_FREQ, ESP32_PWM_RES);

// attach pin_noe to pwm channel
ledcAttachPin(pin_noe, ESP32_PIN_NOE_PWM_CHANNEL);
#else
digitalWrite(pin_noe, LOW);
pinMode(pin_noe, OUTPUT);
#endif

digitalWrite(pin_a, LOW);
pinMode(pin_a, OUTPUT);
Expand Down
21 changes: 17 additions & 4 deletions DMD2.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,21 @@
#ifndef DMD2_H
#define DMD2_H

// ESP32 doesn't define byte datatype
#ifndef byte
#define byte uint8_t
#endif

#include "Arduino.h"
#include "Print.h"
#include "SPI.h"
#include "DMD2.h"

#if defined(ESP32)
#define ESP32_PIN_NOE_PWM_CHANNEL 0
#define ESP32_PWM_FREQ 5000
#define ESP32_PWM_RES 8
#endif

// Dimensions of a single display
const unsigned int PANEL_WIDTH = 32;
Expand Down Expand Up @@ -140,7 +153,7 @@ class DMDFrame

void drawString(int x, int y, const char *bChars, DMDGraphicsMode mode=GRAPHICS_ON, const uint8_t *font = NULL);
void drawString(int x, int y, const String &str, DMDGraphicsMode mode=GRAPHICS_ON, const uint8_t *font = NULL);
#if defined(__AVR__) || defined(ESP8266)
#if defined(__AVR__) || defined(ESP8266) || defined(ESP32)
void drawString_P(int x, int y, const char *flashStr, DMDGraphicsMode mode=GRAPHICS_ON, const uint8_t *font = NULL);
inline void drawString(int x, int y, const __FlashStringHelper *flashStr, DMDGraphicsMode mode=GRAPHICS_ON, const uint8_t *font = NULL) {
return drawString_P(x,y,(const char*)flashStr, mode, font);
Expand All @@ -151,7 +164,7 @@ class DMDFrame
int charWidth(const char letter, const uint8_t *font = NULL);

//Find the width of a string (width of all characters plus 1 pixel "kerning" between each character)
#if defined(__AVR__) || defined(ESP8266)
#if defined(__AVR__) || defined(ESP8266) || defined(ESP32)
unsigned int stringWidth_P(const char *flashStr, const uint8_t *font = NULL);
inline unsigned int stringWidth(const __FlashStringHelper *flashStr, const uint8_t *font = NULL) {
return stringWidth_P((const char*)flashStr, font);
Expand Down Expand Up @@ -261,8 +274,8 @@ class SPIDMD : public BaseDMD
void writeSPIData(volatile uint8_t *rows[4], const int rowsize);
};

#ifdef ESP8266
// No SoftDMD for ESP8266 for now
#if defined(ESP8266) || defined(ESP32)
// No SoftDMD for ESP8266 or ESP32 for now
#else
class SoftDMD : public BaseDMD
{
Expand Down
2 changes: 1 addition & 1 deletion DMD2_Text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ template <class StrType> __attribute__((always_inline)) inline unsigned int _str
}


#if defined(__AVR__) || defined (ESP8266)
#if defined(__AVR__) || defined (ESP8266) || defined(ESP32)
// Small wrapper class to allow indexing of progmem strings via [] (should be inlined out of the actual implementation)
class _FlashStringWrapper {
const char *str;
Expand Down
51 changes: 51 additions & 0 deletions DMD2_Timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@

#define ESP8266_TIMER0_TICKS microsecondsToClockCycles(250) // 250 microseconds between calls to scan_running_dmds seems to works better than 1000.

// Assuming esp32 using frequency of 80MHz...
#define ESP32_TIMER0 0
// run counter to increment every 1 microseconds
#define ESP32_TIMER0_PRESCALER 80
// call scan_running_dmds every 250 microseconds on ESP32
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

250 ms is too fast. changing back to 1000

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interrupts need IRAM_ATTR functions, so this is definitely not gonna work. One solution is to use RTOS task scheduling, but I don't have the resources to test it now since my project is already done. I was using beginNoTimer() and call scanDisplay() in loop function.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I have found your ESP32 port and I am attempting to use it to drive a DMD with my ESP32, but I can not find the complete wiring. Looking in the code, I found these: pin_noe == 14 && pin_a == 27 && pin_b == 26 && pin_sck == 25
But the panel also has CLK and R(1) pins. Where do those go?
Thank you very much in advance!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure CLK and R(1) are SPI pins. R(1) is the data pin if you want to use red led and B(1) is for blue led (if any).

Copy link

@adricl adricl Apr 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found the 250ms is good for one panel if you want to use more than one panel you need to change this to 500ms or higher depending on how many screens. If you have 250ms as the value it will freeze when you add more than one panel.

#define ESP32_TIMER0_RELOAD_ON 250

#ifdef NO_TIMERS

// Timer-free stub code which gets compiled in only if NO_TIMERS is set
Expand Down Expand Up @@ -159,6 +166,50 @@ void BaseDMD::end()
scanDisplay();
}

#elif defined(ESP32)
hw_timer_t *timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR esp32_ISR_wrapper(){
// claim interrupt handling
portENTER_CRITICAL_ISR(&timerMux);

scan_running_dmds();

// end interrupt handling
portEXIT_CRITICAL_ISR(&timerMux);
}

void BaseDMD::begin()
{
beginNoTimer();

timer = timerBegin(ESP32_TIMER0, ESP32_TIMER0_PRESCALER, true);

register_running_dmd(this);

timerAttachInterrupt(timer, &esp32_ISR_wrapper, true);
timerAlarmWrite(timer, ESP32_TIMER0_RELOAD_ON, true);

// safety net
yield();
timerAlarmEnable(timer);
}

void BaseDMD::end()
{
bool still_running = unregister_running_dmd(this);
if(!still_running)
{
timerAlarmDisable(timer);
timerDetachInterrupt(timer);
timerEnd(timer);
timer = NULL;
}
clearScreen();
scanDisplay();
}

#endif // ifdef __AVR__

/* Following functions are static non-architecture-specific functions
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ sentence=Updated (beta) library for Freetronics DMD dot matrix displays.
paragraph=Supports graphics operations (test, images, etc.) Still experimental, the stable library is called called "DMD"
category=Display
url=https://github.com/freetronics/DMD2/
architectures=avr,sam,esp8266
architectures=avr,sam,esp8266,esp32