Permalink
Browse files

4 Level powers of 2 PWM with less flickering.

  • Loading branch information...
marcmerlin committed Jan 4, 2015
1 parent 4209097 commit 6d12652033349ab64876951cff03bfd8eca2676d
Showing with 61 additions and 24 deletions.
  1. +27 −10 LED_Matrix.cpp
  2. +2 −2 LED_Matrix.h
  3. +1 −0 arduino2.h
  4. +30 −12 examples/directmatrix8x8_bicolor_direct_sr/directmatrix8x8_bicolor_direct_sr.ino
  5. +1 −0 pins2_arduino.h
View
@@ -175,6 +175,10 @@ volatile GPIO_pin_t *DirectMatrix_COL_PINS;
volatile GPIO_pin_t *DirectMatrix_SR_PINS;
// How many colors in the array
volatile uint8_t DirectMatrix_NUM_COLORS;
// 4 frequencies for the ISR to make PWM colors
volatile uint32_t DirectMatrix_ISR_FREQ[4];
// profiling
volatile uint32_t DirectMatrix_ISR_runtime;
volatile uint32_t DirectMatrix_ISR_latency;
@@ -194,8 +198,10 @@ void DirectMatrix_RefreshPWMLine(void) {
static uint32_t time = micros();
static uint8_t row = 0;
static uint8_t pwm = 1;
// we use 4 ISR frequencies for 16 bits of PWM and keep track of which
// next interval (powers of 2) we set for next time this ISR should run
static uint8_t isr_freq_offset = 0;
int8_t oldrow = row - 1;
int16_t colormask = 0xF;
int8_t col_pin_offset = 0;
uint16_t pwm_shifted = pwm;
@@ -215,8 +221,8 @@ void DirectMatrix_RefreshPWMLine(void) {
for (int8_t col = 0; col <= DirectMatrix_ARRAY_COLS - 1; col++)
{
digitalWrite(DirectMatrix_COL_PINS[col + col_pin_offset],
((DirectMatrix_MATRIX[row * DirectMatrix_ARRAY_COLS + col] &
colormask) >= pwm_shifted)?HIGH:LOW);
(DirectMatrix_MATRIX[row * DirectMatrix_ARRAY_COLS + col] &
pwm_shifted)?HIGH:LOW);
}
}
else
@@ -226,13 +232,12 @@ void DirectMatrix_RefreshPWMLine(void) {
{
digitalWrite(DirectMatrix_SR_PINS[CLK], LOW);
digitalWrite(DirectMatrix_SR_PINS[DATA],
((DirectMatrix_MATRIX[row * DirectMatrix_ARRAY_COLS + col] &
colormask) >= pwm_shifted)?HIGH:LOW);
(DirectMatrix_MATRIX[row * DirectMatrix_ARRAY_COLS + col] &
pwm_shifted)?HIGH:LOW);
digitalWrite(DirectMatrix_SR_PINS[CLK], HIGH);
}
digitalWrite(DirectMatrix_SR_PINS[color], HIGH);
}
colormask <<= 4;
pwm_shifted <<= 4;
col_pin_offset += DirectMatrix_ARRAY_COLS;
}
@@ -244,8 +249,16 @@ void DirectMatrix_RefreshPWMLine(void) {
if (row >= DirectMatrix_ARRAY_ROWS)
{
row = 0;
pwm++;
if (pwm > DirectMatrix_PWM_LEVELS) pwm = 1;
pwm <<= 1;
isr_freq_offset++;
if (pwm >= DirectMatrix_PWM_LEVELS)
{
pwm = 1;
isr_freq_offset = 0;
}
// for 4 bits of PWM, only have 4 interrupts for 16 shades by having
// each following interrupt be twice as long.
Timer1.setPeriod(DirectMatrix_ISR_FREQ[isr_freq_offset]);
}
// Record how long the function took
@@ -274,7 +287,7 @@ DirectMatrix::DirectMatrix(uint8_t num_rows, uint8_t num_cols,
// Array of of pins for vertical lines, and columns.
void DirectMatrix::begin(GPIO_pin_t __row_pins[], GPIO_pin_t __col_pins[],
GPIO_pin_t __sr_pins[]) {
GPIO_pin_t __sr_pins[], uint32_t __ISR_freq) {
_row_pins = __row_pins;
_col_pins = __col_pins;
_sr_pins = __sr_pins;
@@ -283,6 +296,10 @@ void DirectMatrix::begin(GPIO_pin_t __row_pins[], GPIO_pin_t __col_pins[],
DirectMatrix_ROW_PINS = _row_pins;
DirectMatrix_COL_PINS = _col_pins;
DirectMatrix_SR_PINS = _sr_pins;
DirectMatrix_ISR_FREQ[0] = __ISR_freq;
DirectMatrix_ISR_FREQ[1] = __ISR_freq << 1;
DirectMatrix_ISR_FREQ[2] = __ISR_freq << 2;
DirectMatrix_ISR_FREQ[3] = __ISR_freq << 3;
// Init the lines and cols with the opposite voltage to turn them off.
for (uint8_t i = 0; i < _num_rows; i++)
@@ -319,7 +336,7 @@ void DirectMatrix::begin(GPIO_pin_t __row_pins[], GPIO_pin_t __col_pins[],
// on the matrix size)
// 400 isn't long enough to make full colors, 1000+ is better
// but it makes PWM colors blink
Timer1.initialize(400);
Timer1.initialize(DirectMatrix_ISR_FREQ[0]);
Timer1.attachInterrupt(DirectMatrix_RefreshPWMLine);
}
View
@@ -28,7 +28,7 @@
#define DINV 255
#endif
#define DirectMatrix_PWM_LEVELS 7 // 3 bits -> 400 ns refresh with 324ns free
#define DirectMatrix_PWM_LEVELS 16 // 4 bits done with 4 interrupts per line
#define LED_RED_VERYLOW 1
#define LED_RED_LOW 2
#define LED_RED_MEDIUM 5
@@ -54,7 +54,7 @@
class DirectMatrix {
public:
DirectMatrix(uint8_t, uint8_t, uint8_t);
void begin(GPIO_pin_t [], GPIO_pin_t [], GPIO_pin_t []);
void begin(GPIO_pin_t [], GPIO_pin_t [], GPIO_pin_t [], uint32_t);
void writeDisplay(void);
void clear(void);
uint32_t ISR_runtime(void);
View
@@ -71,12 +71,15 @@ PWMDirectMatrix *matrix;
void setup() {
// Initializing serial breaks one row (shared pin)
if (DEBUG) Serial.begin(57600);
if (DEBUG) while (!Serial);
if (DEBUG) Serial.println("DirectMatrix Test");
matrix = new PWMDirectMatrix(8, 8, 2);
matrix->begin(gnd_line_pins, column_pins, sr_pins);
// The ISR frequency is doubled 3 times to create 4 PWM values
// and will run at x, x*2, x*4, x*16 to simulate 16 levels of
// intensity without causing 16 interrupts at x, leaving more
// time for the main loop and causing less intensity loss.
matrix->begin(gnd_line_pins, column_pins, sr_pins, 200);
}
static const uint8_t PROGMEM
@@ -109,45 +112,60 @@ static const uint8_t PROGMEM
B00111100 };
void loop() {
void show_isr() {
if (DEBUG) Serial.print (F("ISR runtime: "));
if (DEBUG) Serial.print (matrix->ISR_runtime());
if (DEBUG) Serial.print (F(" and latency: "));
if (DEBUG) Serial.println(matrix->ISR_latency());
}
void loop() {
show_isr();
matrix->clear();
matrix->drawLine(0,2, 7,2, LED_RED_VERYLOW);
matrix->drawLine(0,3, 7,3, LED_RED_LOW);
matrix->drawLine(0,4, 7,4, LED_RED_MEDIUM);
matrix->drawLine(0,5, 7,5, LED_RED_HIGH);
matrix->drawLine(2,0, 2,7, LED_GREEN_VERYLOW);
matrix->drawLine(3,0, 3,7, LED_GREEN_LOW);
matrix->drawLine(4,0, 4,7, LED_GREEN_MEDIUM);
matrix->drawLine(5,0, 5,7, LED_GREEN_HIGH);
matrix->writeDisplay();
delay(4000);
show_isr();
matrix->clear();
matrix->drawBitmap(0, 0, smile_bmp, 8, 8, LED_RED_HIGH);
matrix->writeDisplay();
delay(1000);
show_isr();
matrix->clear();
matrix->drawBitmap(0, 0, neutral_bmp, 8, 8, LED_GREEN_HIGH);
matrix->writeDisplay();
delay(1000);
show_isr();
matrix->clear();
matrix->drawBitmap(0, 0, frown_bmp, 8, 8, LED_ORANGE_HIGH);
matrix->writeDisplay();
delay(1000);
matrix->clear();
matrix->drawLine(0,0, 7,7, LED_GREEN_LOW);
matrix->writeDisplay(); // write the changes we just made to the display
delay(500);
show_isr();
matrix->clear();
matrix->drawRect(0,0, 8,8, LED_ORANGE_HIGH);
matrix->drawRect(1,1, 6,6, LED_GREEN_MEDIUM);
matrix->fillRect(2,2, 4,4, LED_RED_HIGH);
matrix->writeDisplay(); // write the changes we just made to the display
matrix->writeDisplay();
delay(3000);
show_isr();
matrix->clear();
matrix->drawCircle(3,3, 3, LED_RED_MEDIUM);
matrix->writeDisplay(); // write the changes we just made to the display
matrix->writeDisplay();
delay(500);
matrix->setTextWrap(false); // we don't want text to wrap so it scrolls nicely
matrix->setTextWrap(false); // we don't wrap text so it scrolls nicely
matrix->setTextSize(1);
matrix->setTextColor(LED_GREEN_HIGH);
matrix->setRotation(3);
View

0 comments on commit 6d12652

Please sign in to comment.