Hi,
I'm working on a DMD display project, which will receive data (time, temperature, custom messages,...) from my other Moteino nodes and display them on DMD display.
Display, that I'm using in this project, is
32x16 Freetronics DMD display.
And
here is the GitHub LIB.
And now the problem:
When I start sketch, everything works fine - time and temperature info is displayed, but then after 10 minutes or so, sketch freezes, DMD screen goes black and I have no idea why. I've added a timer for debugging purposes, that turns on/off LED diod every 5 sec, and after everything freezes, diod also stops blinking.
Now I'm not sure if this is the wiring problem or something.
Here are the pins, used for DMD:
(
DMD.h)
#warning CHANGE THESE TO SEMI-ADJUSTABLE PIN DEFS!
//Arduino pins used for the display connection
#define PIN_DMD_nOE 14//9 // D9 active low Output Enable, setting this low lights all the LEDs in the selected rows. Can pwm it at very high frequency for brightness control.
#define PIN_DMD_A 6 // D6
#define PIN_DMD_B 7 // D7
#define PIN_DMD_CLK 13 // D13_SCK is SPI Clock if SPI is used
#define PIN_DMD_SCLK 8 // D8
#define PIN_DMD_R_DATA 11 // D11_MOSI is SPI Master Out if SPI is used
//Define this chip select pin that the Ethernet W5100 IC or other SPI device uses
//if it is in use during a DMD scan request then scanDisplayBySPI() will exit without conflict! (and skip that scan)
#define PIN_OTHER_SPI_nCS 10
I've changed pin 9 to pin 14, because 9 is used for Moteino LED. But I'm not sure about other pins. Are maybe there some conflicts with moteino pins - pins from 10 to 13 are used for transceiver.
And here is the sketch (work in progress), that I'm using:
//DMD(Dot Matrix Display) used in this project:
//https://github.com/freetronics/DMD
// #include <Arduino.h>
#include <RFM69.h> //get it here: https://github.com/lowpowerlab/rfm69
#include <RFM69_ATC.h> //get it here: https://github.com/lowpowerlab/RFM69
#include <TimeAlarms.h>
#include <Time.h>
#include <SPI.h> //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise)
#include <DMD.h>
#include <TimerOne.h>
#include "SystemFont5x7.h"
#include "Arial_black_16.h"
//Fire up the DMD library as dmd
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
//LED, blinking every x seconds
#define LED_PIN 9
bool ledIsON = false;
//-------
// IMPORTANT RADIO SETTINGS - YOU MUST CHANGE/CONFIGURE TO MATCH YOUR HARDWARE TRANSCEIVER CONFIGURATION!
//-------
#define GATEWAYID 1
#define NODEID 111
#define NETWORKID 123
#define FREQUENCY RF69_433MHZ
//#define FREQUENCY RF69_868MHZ
//#define FREQUENCY RF69_915MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
#define ENCRYPTKEY "Removed" //has to be same 16 characters/bytes on all nodes, not more not less!
#define IS_RFM69HW_HCW //uncomment only for RFM69HW/HCW! Leave out if you have RFM69W/CW!
//----------
#define ENABLE_ATC //comment out this line to disable AUTO TRANSMISSION CONTROL
#define ATC_RSSI -75
#ifdef ENABLE_ATC
RFM69_ATC radio;
#else
RFM69 radio;
#endif
#define USE_SERIAL // to remove all Serial code when testing actual power consumption
#define SERIAL_BAUD_RATE 115200
//New temperature data is sent every 10 minutes. In case we don't receive new temperature data, we erase old data
#define KEEP_DATA_SEC 0 // 0 seconds
#define KEEP_DATA_MIN 15 //15 minutes
#ifdef USE_SERIAL
#define PRINT(x) Serial.print(x)
#define PRINTLN(x) Serial.println(x)
#define SERIAL_BEGIN Serial.begin(SERIAL_BAUD_RATE)
#else
#define PRINT(x)
#define PRINTLN(x)
#define SERIAL_BEGIN
#endif
//TIME: constants for time sync
#define TIMECMDLEN 11 //T + 10 digits (time_t unix timestamp) e.g. T1398273354
#define TIMEHEADER 'T' //Time sync header (1 char)
#define TIMENEEDSSYNC "SNC" //Message that is sent to server note for sync request
//DMD - currently displayed minute (default -1)
int currentMinute = -1;
//check if the command is time sync command (e.g. T1398096798)
boolean processTimeSync(char* sourceCommand)
{
if (sourceCommand[0] != TIMEHEADER) {
return false;
}
PRINT("Time sync:"); PRINTLN(sourceCommand);
time_t serverTime = 0;
char c;
int timeLength = 0;
for(int i=0; i < TIMECMDLEN ; i++) {
c = sourceCommand[i];
if( c >= '0' && c <= '9') {
serverTime = (10 * serverTime) + (c - '0') ; //convert char to number
timeLength++;
}
}
//10 digits, without "T" header
if (timeLength == TIMECMDLEN - 1) {
setTime(serverTime);
}
return true;
}
//format time string HH:MM
void formatCurrentTime(char *timeString) {
if (timeStatus() == timeNotSet) {
timeString[0] = '\0';
strcat(timeString, "--:--");
timeString[5] = '\0';
} else {
timeString[0] = '\0';
char cstr[16];
itoa(hour(), cstr, 10);
strcat(timeString, cstr);
strcat(timeString, ":");
int min = minute();
if (min < 10) {
strcat(timeString, '0');
}
itoa(min, cstr, 10);
strcat(timeString, cstr);
}
}
/*--------------------------------------------------------------------------------------
Interrupt handler for Timer1 (TimerOne) driven DMD refresh scanning, this gets
called at the period set in Timer1.initialize();
--------------------------------------------------------------------------------------*/
void ScanDMD()
{
dmd.scanDisplayBySPI();
}
//moteino radio
void initRadio() {
radio.initialize(FREQUENCY,NODEID,NETWORKID);
#ifdef IS_RFM69HW_HCW
radio.setHighPower(); //must include this only for RFM69HW/HCW!
#endif
radio.encrypt(ENCRYPTKEY);
#ifdef ENABLE_ATC
radio.enableAutoPower(ATC_RSSI);
#endif
}
void initDMD() {
//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()
//clear/init the DMD pixels held in RAM
dmd.clearScreen(true); //true is normal (all pixels off), false is negative (all pixels on)
//dmd.selectFont(Arial_Black_8);
dmd.selectFont(System5x7);
}
void setup() {
SERIAL_BEGIN; // start the serial interface
pinMode(LED_PIN, OUTPUT);
delay(200);
initRadio();
radio.sendWithRetry(GATEWAYID, "START", 6);
initDMD();
PRINTLN("Started");
//zahteva za uskladitev časa
radio.sendWithRetry(GATEWAYID, TIMENEEDSSYNC, 6);
}
//-99.9°C //7 chars + \0
char tempAir[8] = "\0";
char tempWater[8] = "\0";
char currentTime[6];// = "\0";
AlarmId airTimer; //timer - used for deleting old air temperature data
// AlarmId waterTimer;
//Turn on/off led diode every 5 seconds
AlarmId blinkTimer = Alarm.timerRepeat(5, blinkLed);
//messages:
//M#Hello world\0
void loop() {
Alarm.delay(0); //za TimeAlarm, moramo klicati to funkcijo namesto delaya
//display messages on DMD screen (time, temperature, custom messages,...)
displayMessages();
if (radio.receiveDone()) {
PRINT('[');PRINT(radio.SENDERID);PRINT("] ");
for (byte i = 0; i < radio.DATALEN; i++)
PRINT((char)radio.DATA[i]);
PRINT(" [RX_RSSI:");PRINT(radio.RSSI);PRINTLN("]");
//TODO: GatewayMightyHatNode.ino - message is converted to uppercase
//Time sync command?(T...)
if (processTimeSync(radio.DATA)) {
formatCurrentTime(currentTime);
PRINT("Time set to:"); PRINTLN(currentTime);
//Print Time
} else if (radio.DATALEN > 1 && radio.DATA[0]=='P' && radio.DATA[1]=='T') {
formatCurrentTime(currentTime);
PRINT("Current time is:"); PRINTLN(currentTime);
//Temperature (air)
//AT#-12.3
} else if (radio.DATALEN > 3 && radio.DATA[0]=='A' && radio.DATA[1]=='T' && radio.DATA[2]=='#') {
char *ptrTok;
ptrTok = strtok(radio.DATA, "#"); //1. token = "TA"
ptrTok = strtok(NULL, "#"); //2. token = '-12.3'
strcpy(tempAir, ptrTok); //temp is stored to global variable, which is displayed on DMD
Alarm.free(airTimer); //we delete old data
airTimer = Alarm.timerOnce(0,KEEP_DATA_MIN,KEEP_DATA_SEC, airDelete);
PRINT("Setting temperature Air to:"); PRINTLN(ptrTok);
//M#message
} else if (radio.DATALEN > 2 && radio.DATA[0]=='M' && radio.DATA[1]=='#') {
char *ptrMsg;
ptrMsg = strtok(radio.DATA, "#"); //1. token = 'M'
ptrMsg = strtok(NULL, "#"); //2. token = 'message'
PRINT("Message:"); PRINTLN(ptrMsg);
PRINT("Air temperature:"); PRINTLN(tempAir);
}
//first send any ACK to request
if (radio.ACKRequested())
{
radio.sendACK();
PRINTLN(" - ACK sent.");
}
PRINTLN();
}
}
//Blink led diode every x sec
void blinkLed() {
if (ledIsON) {
digitalWrite(LED_PIN, LOW); // turn the LED off by making the voltage LOW
} else {
digitalWrite(LED_PIN, HIGH); // turn the LED on (HIGH is the voltage level)
}
ledIsON = !ledIsON;
}
void airDelete() {
PRINTLN("Deleting air temperature data.");
tempAir[0] = '\0';
}
void drawCurrentTime() {
formatCurrentTime(currentTime);
dmd.drawString( 2+(32*0), 1+(16*0), currentTime, /*8*/strlen(currentTime), GRAPHICS_NORMAL );
dmd.drawString( 2+(32*0), 9+(16*0), tempAir, /*8*/strlen(tempAir), GRAPHICS_NORMAL );
}
//Prikaz časa
void displayTime() {
if (timeStatus() == timeNotSet) {
//TODO
//send time sync request
} else {
if (currentMinute != minute()) {
currentMinute = minute();
drawCurrentTime();
}
}
}
void displayMessages() {
//PRINT("Current time is:"); PRINTLN(currentTime);
//PRINT("Message:"); PRINTLN(ptrMsg);
//PRINT("Air temperature:"); PRINTLN(tempAir);
displayTime();
}
Any idea what am I doing wrong?
Thanks!