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

DMD2 library does not work with I2C (RTC DS3231) #67

Open
rtek1000 opened this issue May 30, 2022 · 2 comments
Open

DMD2 library does not work with I2C (RTC DS3231) #67

rtek1000 opened this issue May 30, 2022 · 2 comments

Comments

@rtek1000
Copy link

Library that does not support I2C:
https://github.com/freetronics/DMD2

Library that accepts I2C:
https://github.com/freetronics/DMD

Ref.:
adafruit/RTClib#261

@rtek1000
Copy link
Author

rtek1000 commented May 30, 2022

(P.S.: It didn't work, the brightness was different when using manual scanning. See more details below)

I managed to get it to work by disabling automatic scanning and performing manual scanning using Timer1.

To operate the RTC on the I2C port it was necessary to stop Timer1, and after the RTC was operated, Timer1 was resumed.

  Timer1.stop();
  RtcDateTime now = Rtc.GetDateTime();
  Timer1.resume();

Complete example code (AllDrawingOperations.ino):

/*
  Quick demo of major drawing operations on a single DMD
*/
#include <avr/wdt.h>
#include <TimerOne.h>   //
#include <SPI.h>
#include "DMD2.h"
#include "fonts/SystemFont5x7.h"

SoftDMD dmd(1, 1); // DMD controls the entire display

#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
RtcDS3231<TwoWire> Rtc(Wire);

void ScanDMD()
{
  dmd.scanDisplay();
}

// the setup routine runs once when you press reset:
void setup() {
  wdt_reset(); //  reset watchdog

  wdt_enable(WDTO_4S);

  dmd.setBrightness(10);
  dmd.selectFont(SystemFont5x7);
  dmd.beginNoTimer();

  // Circle with a line at a tangent to it
  dmd.drawCircle(24, 8, 5);
  dmd.drawLine(14, 9, 28, 15);

  // Outline box containing a filled box
  dmd.drawBox(6, 10, 11, 15);
  dmd.drawFilledBox(8, 12, 9, 13);

  Serial.begin(115200);

  Serial.println("Start");

  Rtc.Begin();

  //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display
  Timer1.initialize( 5000 );           //period in microseconds to call ScanDMD. Anything longer than 5000 (5ms) and you can see flicker.
  Timer1.attachInterrupt( ScanDMD );   //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()
}

int n = 123;

// the loop routine runs over and over again forever:
void loop() {
  dmd.drawString(0, 0, String(n));
  n = n + 1;
  delay(1000);

  if (n % 2 == 0) {
    dmd.drawFilledBox(0, 11, 4, 15, GRAPHICS_OFF);
    dmd.drawBox(0, 11, 4, 15);
  } else {
    dmd.drawFilledBox(0, 11, 4, 15);
  }

  Timer1.stop();
  RtcDateTime now = Rtc.GetDateTime();
  Timer1.resume();

  printDateTime(now);
  Serial.println();

  Timer1.stop();
  RtcTemperature temp = Rtc.GetTemperature();
  Timer1.resume();

  temp.Print(Serial);
  // you may also get the temperature as a float and print it
  // Serial.print(temp.AsFloatDegC());
  Serial.println("C");

  wdt_reset(); //  reset watchdog
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt)
{
  char datestring[20];

  snprintf_P(datestring,
             countof(datestring),
             PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
             dt.Month(),
             dt.Day(),
             dt.Year(),
             dt.Hour(),
             dt.Minute(),
             dt.Second() );
  Serial.print(datestring);
}

DMD2_Timer.cpp:

#define NO_TIMERS

Ref.:
https://github.com/Makuna/Rtc/blob/master/src/RtcDS3231.h

@rtek1000
Copy link
Author

rtek1000 commented May 31, 2022

It didn't work, the brightness was different when using manual scanning.

But based on the TimerOne library, Stop and Resume functions have been added:

DMD2_Timer.cpp:

ISR(TIMER1_OVF_vect)
{
  static uint8_t skip_isrs = 0;
  skip_isrs = (skip_isrs + 1) % 2;
  if (skip_isrs)
    return;
  scan_running_dmds();
}

void BaseDMD::stop() {
  TCCR1B = 0;
}

void BaseDMD::resume() {
  TCCR1B = 3;
}

void BaseDMD::begin()
{
  beginNoTimer(); // Do any generic setup

  char oldSREG = SREG;
  cli();
  register_running_dmd(this);
  TIMSK1 = _BV(TOIE1); // set overflow interrupt
  SREG = oldSREG;
}

DMD2.h:

  void end();
  void stop();
  void resume();

  /* Start display, but use manual scanning */
  virtual void beginNoTimer();

Usage mode:

SoftDMD dmd(1, 1); // DMD controls the entire display

void setup () {
...
}

void Loop() {
  ...
  dmd.stop();        // <---- Stop the scan timer
  DateTime now = rtc.now(); // <---- Access routine on the I2C port (RTClib Library etc)
  dmd.resume();  // <---- Resume scan timer
}

P.S.: The timer resume value was wrong here (it was modified), in normal operation the TCCR1B register has a value of 3, or Bit 2:0 in state 1 (CS12:0: Clock Select)

Ref.: https://github.com/PaulStoffregen/TimerOne/blob/master/TimerOne.h

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

No branches or pull requests

1 participant