Optimized, MSQ6441C Four Digit Stick Hex Display, Arduino Driver

A cathode voltage pulse after optimizing the code with direct register writes. Ideal (delay only) pulse would be 1 ms in length according to the loop I set up, which almost matches what we see here (referring to the downward pulse).

The assumed way of setting digital pins in Arduino is to use the digitalWrite procedure to set each pin. That is slow, however, as you make a procedure call (presumably — I’m not sure exactly how much inlining happens in the compiler) and also you have to set one pin at a time.

However, since the pins map to bits that are stuffed into eight-bit registers in the microcontroller, you can just write a byte to each register and change multiple pins at once. And it is just two clock cycles for that operation.

The tradeoff is you have to look up the processor register mappings, and have decent bit toggling skills.

E.g., the code to set eight pins low and four pins high, i.e., to “reset” the LED anodes and cathodes, becomes…

PORTD &= 0b10000011;
PORTD |= 0b10000000;
PORTB &= 0b11100110;
PORTB |= 0b00100110;

Just four opcodes, and no procedure calls. To figure that out, you would need to reference the Arduino Uno pinout, and also the 328P register guide:

http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf#G3.1187134

https://upload.wikimedia.org/wikipedia/commons/c/c9/Pinout_of_ARDUINO_Board_and_ATMega328PU.svg

And also understand how to use the & and | operators to turn bits high or low. This guide is a shortcut:

https://www.arduino.cc/en/Reference/PortManipulation

The current iteration of the code:

/*
  Copyright 2020 Christopher Howard

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

/* Pins 1-12 on MSQ6X41C should be mapped to pins 2-13 on Uno */

#define LP1 2
#define LP2 3
#define LP3 4
#define LP4 5
#define LP5 6
#define LP6 7
#define LP7 8
#define LP8 9
#define LP9 10
#define LP10 11
#define LP11 12
#define LP12 13

#define SA LP11
#define SB LP7
#define SC LP4
#define SD LP2
#define SE LP1
#define SF LP10
#define SG LP5
#define SDOT LP3

enum characters
  {
   ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
   NINE, ALPHA, BRAVO, CHARLIE, DELTA, ECHO, FOXTROT, BLANK
  };

enum digit {
	D_ONE, D_TWO, D_THREE, D_FOUR
};

void setup() {
	pinMode(LP1, OUTPUT);
	pinMode(LP2, OUTPUT);
	pinMode(LP3, OUTPUT);
	pinMode(LP4, OUTPUT);
	pinMode(LP5, OUTPUT);
	pinMode(LP6, OUTPUT);
	pinMode(LP7, OUTPUT);
	pinMode(LP8, OUTPUT);
	pinMode(LP9, OUTPUT);
	pinMode(LP10, OUTPUT);
	pinMode(LP11, OUTPUT);
	pinMode(LP12, OUTPUT);
}

void set_led_pins(byte ch, byte dig, bool point) {
  /* blank all digits */
  PORTD &= 0b10000011;
  PORTD |= 0b10000000;
  PORTB &= 0b11100110;
  PORTB |= 0b00100110;
	switch(dig) {
	case D_ONE:
    PORTB &= 0b11011111;
		break;
	case D_TWO:
    PORTB &= 0b11111011;
		break;
	case D_THREE:
    PORTB &= 0b11111101;
		break;
	case D_FOUR:
    PORTD &= 0b01111111;
		break;
	}
	switch(ch)
    {
    case BLANK :
      break;
    case ZERO :
      PORTD |= 0b00101100;
      PORTB |= 0b00011001;
      break;
    case ONE :
      PORTD |= 0b00100000;
      PORTB |= 0b00000001;
      break;
    case TWO :
      PORTD |= 0b01001100;
      PORTB |= 0b00010001;
      break;
    case THREE :
      PORTD |= 0b01101000;
      PORTB |= 0b00010001;
      break;
    case FOUR :
      PORTD |= 0b01100000;
      PORTB |= 0b00001001;
      break;
    case FIVE :
      PORTD |= 0b01101000;
      PORTB |= 0b00011000;
      break;
    case SIX :
      PORTD |= 0b01101100;
      PORTB |= 0b00011000;
      break;
    case SEVEN :
      PORTD |= 0b00100000;
      PORTB |= 0b00010001;
      break;
    case EIGHT :
      PORTD |= 0b01101100;
      PORTB |= 0b00011001;
      break;
    case NINE :
      PORTD |= 0b01101000;
      PORTB |= 0b00011001;
      break;
    case ALPHA :
      PORTD |= 0b01100100;
      PORTB |= 0b00011001;
      break;
    case BRAVO :
      PORTD |= 0b01101100;
      PORTB |= 0b00001000;
      break;
    case CHARLIE :
      PORTD |= 0b00001100;
      PORTB |= 0b00011000;
      break;
    case DELTA :
      PORTD |= 0b01101100;
      PORTB |= 0b00000001;
      break;
    case ECHO :
      PORTD |= 0b01001100;
      PORTB |= 0b00011000;
      break;
    case FOXTROT :
      PORTD |= 0b01000100;
      PORTB |= 0b00011000;
      break;
    }
}

byte tc = 0;
unsigned int dc = 0;

void loop() {
	set_led_pins((dc >> 12) & 0xF, D_ONE, false);
	delay(1);
	set_led_pins((dc >> 8) & 0xF, D_TWO, false);
	delay(1);
	set_led_pins((dc >> 4) & 0xF, D_THREE, false);
	delay(1);
	set_led_pins(dc & 0xF, D_FOUR, false);
	delay(1);
  tc++;
  if(tc % 64 == 0) dc++;
}

1 thought on “Optimized, MSQ6441C Four Digit Stick Hex Display, Arduino Driver”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s