DMD Brightness control

The Dot Matrix Display (DMD) is a 32x16 array of high-brightness LEDs for visually striking effects. [Product Page]
Brissieboy
Posts: 94
Joined: Fri Sep 20, 2013 7:25 am

DMD Brightness control

Post by Brissieboy » Sat Jan 18, 2014 11:37 am

I have played around a fair bit with brightness control for the DMDs. Here is how I achieved it.
First you will need to install a pull-down resistor on the Output Enable line (incorrectly labelled nOE on the little DMD Connector board. The value is not critical but around 10K should be fine. It needs to be connected between nOE (D9) and any convenient Gnd pin. This wont work properly without it. (It also helps prevent the random LED flash on powerup.)
(EDIT: Actually the value is a little more critical than that. It needs to be LESS THAN 10k. This is to ensure the DMD sees a logic low even when/if the Arduino 20k internal pull-up is enabled.) I suggest 4k7 (or 5k6 or 6k8).
In DMD.h:
Change the following lines
#define OE_DMD_ROWS_OFF() { digitalWrite( PIN_DMD_nOE, LOW ); }
#define OE_DMD_ROWS_ON() { digitalWrite( PIN_DMD_nOE, HIGH ); }
to:
#define OE_DMD_ROWS_OFF() { pinMode( PIN_DMD_nOE,INPUT ); } // leaves the line floating
#define OE_DMD_ROWS_ON() { pinMode( PIN_DMD_nOE, OUTPUT ); } // re-asserts with PWM still as set

The brightness can be set/changed with the following line within your sketch:
Timer1.setPwmDuty(PIN_DMD_nOE, Brightness);
where "Brightness" is an integer between 0 (off) and 1024 (100%)
It will need to be set initially in your setup() area and then can be changed anywhere else in your sketch that it needs to be done.
Most control is achieved at the lower range values (around 10 as a minimum useable, and 1024 giving 100% brightness, and 100 giving about half brightness) with the scale looking like it is logarithmic rather than linear. I found the following steps to be an acceptable range: 10, 16, 25, 40, 64, 100, 160, 250, 400, 640, 1024.

EDIT:
As I mention in a later post, you also need to start the PWM by including this in your setup() code:

Code: Select all

  Timer1.pwm(PIN_DMD_nOE, Brightness); // to setup PWM and the starting brightness
  Timer1.attachInterrupt(ScanDMD);
So the steps are:
1. Fit the 4k7 resistor
2. Modify the 2 lines in the dmd.h file
3. Declare the variable 'Brightness' as an int
4. Add Timer1.pwm() to setup() as explained above
5. Set the brightness as required within the body of your sketch using Timer1.setPwmDuty()
6. Make sure the DMD is powerered properly.

Many thanks to stryker for being the guineapig and working through the all this!!
Last edited by Brissieboy on Thu Apr 17, 2014 11:22 am, edited 2 times in total.

User avatar
stryker
Posts: 253
Joined: Sat Jan 14, 2012 2:44 pm

Re: DMD Brightness control

Post by stryker » Sat Jan 18, 2014 1:20 pm

You've done us all a great service here. Thanks ! Geoff

Brissieboy
Posts: 94
Joined: Fri Sep 20, 2013 7:25 am

Re: DMD Brightness control

Post by Brissieboy » Sat Jan 18, 2014 11:59 pm

I probably should add a little more detail on this one.
There are many ways to manipulate the state on the Output Enable line and control the PWM.
However, by using things like digitalWrite(), disabling the PWM (Timer1.disablePwm( )), direct hardware control (PORTB = ??), etc, I could not achieve a good result - sometimes I got very odd results. The PWM would be usually be OK but the brief disabling for the DMD data update seemed to upset things.
As an example, using
#define OE_DMD_ROWS_OFF() { Timer1.disablePwm( PIN_DMD_nOE ); }
#define OE_DMD_ROWS_ON() { Timer1.pwm( PIN_DMD_nOE, Brightness ); }
gave a good result EXCEPT for a few values around 64 for Brightness, where the display was flashy at full brightness - all other values were OK. Very strange! And I am not sure why this happens!! I have some theories, but I stopped looking once I got the result I was looking for.

All my activity has been on the version of the DMD library available here.

burkey
Posts: 1
Joined: Wed Jan 29, 2014 10:29 pm

Re: DMD Brightness control

Post by burkey » Wed Jan 29, 2014 10:34 pm

Hi Brissieboy, I was looking at making a score board by daisy chaining 4 of the dmds together..
my Question is, will the dmds be bright enough to be seen about 100 metres away?

Brissieboy
Posts: 94
Joined: Fri Sep 20, 2013 7:25 am

Re: DMD Brightness control

Post by Brissieboy » Wed Jan 29, 2014 11:42 pm

burkey,
These DMDs are VERY bright. I don't think the lack of brightness will be a problem, especially with an indoor application. I have found that the opposite is the case - they are too bright in many situations, hence the effort to provide some control.
If you are questioning whether or not the brightness control described above will reduce the maximum brightness, the answer is NO - the PWM control goes the full range 0-100%. But if you want full brightness then don't add the complication of the control.

chriss
Posts: 1
Joined: Mon Feb 17, 2014 8:13 am

Re: DMD Brightness control

Post by chriss » Mon Feb 24, 2014 1:14 am

hello Brissieboy

As I’m new to this I’m finding that i'm not getting the dmd brightness control working the way that I hope it would, i'm guessing that i'm still doing something wrong as when I do what yourself has wrote in this forum page all I get is a dmd display that just turns off now I know you said that I need to put a pull down resistor on pin 9 and a Gnd pin and that has been done using all the resistors values that have been suggested, I have notice that every time I edit the DMD.h file that I get a display that basically turns off and when I put in a original (non edited) file everything works but it's at full brightness am at a lost why I can't get this to work

anybodies help would be greatly appreciated on this

thanks chris

Brissieboy
Posts: 94
Joined: Fri Sep 20, 2013 7:25 am

Re: DMD Brightness control

Post by Brissieboy » Mon Feb 24, 2014 7:39 am

chriss,

I'm not sure what you mean by "all I get is a dmd display that just turns off" and "basically turns off"
Does it display anything at all when you are trying to use the brightness control?
When does it go off?

The pulldown resistor will hold the display OFF and the OE lead will then enable the display by pulling it high. If you get no display, it means that the OE lead is not going high. Have you got a way to test this?
Did you use a 4,700 ohm resistor (or close value)? No damage or solder bridges when you made the connection?

Are you using the DMD library version from here:
https://github.com/cjd/DMD

Are you powering the DMD(s) from a good separate 5Volt source capable of supplying enough current (not from the Arduino)?

You should start with these lines somewhere in your setup():

Code: Select all

  Timer1.pwm(PIN_DMD_nOE, brightness); // to set the starting brightness
  Timer1.attachInterrupt(ScanDMD);
with 'brightness' declared (as int) and initialised to a value between 10 and 1024.

Sorry I cannot post a copy of my modified library as I have made quite a few changes in other areas to suit my particular case.

If you post your code I may be able to assist - but no promises. Or you could PM me if you don't want to make your code public.

User avatar
stryker
Posts: 253
Joined: Sat Jan 14, 2012 2:44 pm

Re: DMD Brightness control

Post by stryker » Thu Apr 17, 2014 7:40 am

Hi again,

Glad to report once I followed your instructions to the letter it works a treat.
  • Download the library
  • modify those two lines in DMD.h
  • solder a 4k7 resistor between nOE and GND
  • and importantly power the DMD externally, even if there's only one
Powering the DMD from some Arduino including Freetronics Eleven, dimming worked; but on a clone Uno and my own standalone based board there wasn't enough power over the data lines for the effect to be obvious. Power the DMD externally and you get to see it go from painfully bright at 1024 to off at 0.

Here's a sketch that demonstrates the various levels of dimming that I used to test a few different Arduinos and a single DMD:

Code: Select all

#include <math.h>                                          // maths for pulsing the LED
#include <Wire.h>                                          // I2C protocol for MCP23008 I/O extenders
#include <SPI.h>                                           // for DMD display
// NOTE: REQUIRES dimmable fork of DMD library, https://github.com/cjd/DMD
#include <DMD.h>                                           // also, for DMD display
#include <TimerOne.h>                                      // and THIS, is for the DMD display periodic refreshes
#include "SystemFont5x7.h"                                 // font used for brightness setting confirmation

// DMD PWM tester.  Cycles through PWM values to show effect of dimming.
 
// pin definitions
const int pulseLED = 5;

// DMD
//Fire up the DMD library as dmd
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
#define DISPLAYS_BPP 1
#define WHITE 0xFF
#define BLACK 0
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN, DISPLAYS_BPP);     // 1x DMD displays only

// cycle through these values
const int dimmerValues[12] = {
  0, 10, 16, 25, 40, 64, 100, 160, 250, 400, 640, 1024};
unsigned long brightnessUpdateTime;
int dimmerIdx;
int incrementer = 1;

// ---------------------------------------------------------------------------------
// DMD refresh scanning is driven by the Timer1 interrupt every 5ms
//
void ScanDMD() {
  dmd.scanDisplayBySPI();
}

// ---------------------------------------------------------------------------------
//
void setup() {
  // Setup pulse LED
  pinMode(pulseLED, OUTPUT);
  digitalWrite(pulseLED, true);

  // Start I2C
  Wire.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.pwm(PIN_DMD_nOE, 100);                           // set initial brightness
  Timer1.attachInterrupt(ScanDMD);                        // attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()

  //clear/init the DMD, choose the font
  dmd.clearScreen(false);
  dmd.selectFont(System5x7);
}

// ---------------------------------------------------------------------------------
//
void loop() {
  // pulse LED to show this thing is still alive
  float pulseIntensity = (exp(sin(millis()/1000.0*PI)) - 0.36787944)*108.0;
  analogWrite(pulseLED, pulseIntensity);  

  if(millis() > brightnessUpdateTime) {
    int Brightness = dimmerValues[dimmerIdx];
    dimmerIdx += incrementer;
    if(dimmerIdx < 0) { 
      dimmerIdx = 1; 
      incrementer = 1;
    }
    if(dimmerIdx > 11) {
      dimmerIdx = 10; 
      incrementer = -1;
    }
    Timer1.setPwmDuty(PIN_DMD_nOE, Brightness);
    dmd.clearScreen( false );
    dmd.drawString(  2,  1, "PWM", 5, WHITE, BLACK );
    if(Brightness> 999) dmd.drawChar(2,  9, '0'+((Brightness%10000) /1000),  WHITE,BLACK );   // thousands
    if(Brightness> 99) dmd.drawChar(7,  9, '0'+((Brightness%1000) /100),  WHITE,BLACK );   // hundreds
    if(Brightness > 9) dmd.drawChar( 12,  9, '0'+((Brightness%100)  /10),   WHITE,BLACK );   // tens
    dmd.drawChar( 17,  9, '0'+ (Brightness%10),          WHITE,BLACK );   // units

    brightnessUpdateTime = millis() + 500;
  }
}
Thanks again!
Geoff

Brissieboy
Posts: 94
Joined: Fri Sep 20, 2013 7:25 am

Re: DMD Brightness control

Post by Brissieboy » Thu Apr 17, 2014 10:55 am

I've had a look at the Freetronics version of the DMD library available here https://github.com/freetronics/DMD/ and it handles the critical parts in exactly the same way. I see no reason why this method should not work with that version of the library.

[EDIT]
I just downloaded this version of the library and tried it out. It does work as expected.

Brissieboy

User avatar
stryker
Posts: 253
Joined: Sat Jan 14, 2012 2:44 pm

Re: DMD Brightness control

Post by stryker » Fri Apr 18, 2014 11:45 am

Hi, and yes confirmed it this side too.

Here's a version of the dimmer test to run with the Freetronics DMD library with just those 3 lines modified:

Code: Select all

#include <math.h>                                          // maths for pulsing the LED
#include <Wire.h>                                          // I2C protocol for MCP23008 I/O extenders
#include <SPI.h>                                           // for DMD display
// NOTE: uses modified Freetronics DMD library
#include <DMD.h>                                           // also, for DMD display
#include <TimerOne.h>                                      // and THIS, is for the DMD display periodic refreshes
#include "SystemFont5x7.h"                                 // font used for brightness setting confirmation

// DMD PWM tester.  Cycles through PWM values to show effect of dimming.
 
// pin definitions
const int pulseLED = 5;

// DMD
//Fire up the DMD library as dmd
DMD dmd(1, 1);     // 1x DMD displays only

// cycle through these values
const int dimmerValues[12] = {
  0, 10, 16, 25, 40, 64, 100, 160, 250, 400, 640, 1024};
unsigned long brightnessUpdateTime;
int dimmerIdx;
int incrementer = 1;

// ---------------------------------------------------------------------------------
// DMD refresh scanning is driven by the Timer1 interrupt every 5ms
//
void ScanDMD() {
  dmd.scanDisplayBySPI();
}

// ---------------------------------------------------------------------------------
//
void setup() {
  // Setup pulse LED
  pinMode(pulseLED, OUTPUT);
  digitalWrite(pulseLED, true);

  // Start I2C
  Wire.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.pwm(PIN_DMD_nOE, 100);                           // set initial brightness
  Timer1.attachInterrupt(ScanDMD);                        // attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()

  //clear/init the DMD, choose the font
  dmd.clearScreen(true);
  dmd.selectFont(System5x7);
}

// ---------------------------------------------------------------------------------
//
void loop() {
  // pulse LED to show this thing is still alive
  float pulseIntensity = (exp(sin(millis()/1000.0*PI)) - 0.36787944)*108.0;
  analogWrite(pulseLED, pulseIntensity);  

  if(millis() > brightnessUpdateTime) {
    int Brightness = dimmerValues[dimmerIdx];
    dimmerIdx += incrementer;
    if(dimmerIdx < 0) { 
      dimmerIdx = 1; 
      incrementer = 1;
    }
    if(dimmerIdx > 11) {
      dimmerIdx = 10; 
      incrementer = -1;
    }
    Timer1.setPwmDuty(PIN_DMD_nOE, Brightness);
    dmd.clearScreen( true );
    dmd.drawString(  2,  1, "PWM", 5, GRAPHICS_NORMAL );
    if(Brightness> 999) dmd.drawChar(2,  9, '0'+((Brightness%10000) /1000),  GRAPHICS_NORMAL );   // thousands
    if(Brightness> 99) dmd.drawChar(7,  9, '0'+((Brightness%1000) /100),  GRAPHICS_NORMAL );   // hundreds
    if(Brightness > 9) dmd.drawChar( 12,  9, '0'+((Brightness%100)  /10),   GRAPHICS_NORMAL );   // tens
    dmd.drawChar( 17,  9, '0'+ (Brightness%10),          GRAPHICS_NORMAL );   // units

    brightnessUpdateTime = millis() + 500;
  }
}
I've rolled back my IDE to that version now. Will be easier to keep dimmable and non-dimmable projects compatible.

Cheers, and thanks again!
Geoff

Post Reply

Who is online

Users browsing this forum: No registered users and 7 guests