Pages: [1]
Author Topic: More efficient multiplex code  (Read 3563 times)
Dr.Wizard
Newbie
*
Posts: 2



View Profile WWW Email
« on: June 03, 2016, 01:27:21 PM »

digitalWrite is very slow and inefficient because it does error checking to make sure the user isn't trying something stupid, and because it has to decode which port and bit the requested pin is on.  And it makes your code much easier to read and understand.  Not necessarily bad, but in a multiplex routine, especially one called from an interrupt, speed counts.  The code gets executed hundreds of times a second.  If it's slow and inefficient, it leaves less processing power for other things.

A faster and more efficient way to control pins is the write directly to the control registers.  The disadvantages to this are the opposites of what I mentioned above.  You need to know what port and bit the pin is on.  You better get it right, because if you do it wrong, god only knows what could happen.  And it involves binary math and bit manipulation which can be rather confusing.

So here it is, a routine for controlling the output pins that writes directly to the ports.  It is literally 100 times faster (I benchmarked it!).

Code:
void setOutputs(byte bank, byte digit1, byte digit2) {

byte val1 = digit1 << 2; // Store number 1 in value 1, shift bits 2 places left (Move BCD value on last 4 bits to middle 4 bits)
byte val2 = digit2 << 6; // Put least 2 bits of Number 2 into upper 2 bits of Value 1
byte val3 = digit2 >> 2; // put highest 2 bits of Number 2 into lowest 2 bits of Value 2
byte val4 = (1 << (bank + 2));  // Choose which bit is needed to control the bank pins 10-13
// The bank selection is middle 4 bits, so the number needs to be shifted over by 2 bits

PORTD &= B00000011; // Turn pins 2-7 off
PORTB &= B11000000; // Turn pins 8-13 off
PORTD |= val1; // Set pins 2-5 to match BCD number held in middle 4 bits of Value 1
PORTD |= val2; // Set pins 6 & 7 to match highest 2 bits of value 1 which is lowest 2 bits of num2
PORTB |= val3; // Set pins 8 and 9 to lowest 2 bits of value 2 which is highest 2 bits of num2

PORTB |= val4; // Turn the appropriate pin (10-13) for the bank
}

This code is very specific to Arduino models Uno, Micro, Mini, Nano, and other Arduino clones that use the 328P chip.  To use it on a Mega, or some other type of microcontroller, you will need to change the ports and which bits get manipulated.
Logged

nonentity
Co-Owner, Robotpirate
Administrator
Full Member
*****
Posts: 182



View Profile
« Reply #1 on: June 09, 2016, 02:53:10 PM »

digitalWrite is very slow and inefficient because it does error checking to make sure the user isn't trying something stupid, and because it has to decode which port and bit the requested pin is on.  And it makes your code much easier to read and understand.  Not necessarily bad, but in a multiplex routine, especially one called from an interrupt, speed counts.  The code gets executed hundreds of times a second.  If it's slow and inefficient, it leaves less processing power for other things.

A faster and more efficient way to control pins is the write directly to the control registers.  The disadvantages to this are the opposites of what I mentioned above.  You need to know what port and bit the pin is on.  You better get it right, because if you do it wrong, god only knows what could happen.  And it involves binary math and bit manipulation which can be rather confusing.

So here it is, a routine for controlling the output pins that writes directly to the ports.  It is literally 100 times faster (I benchmarked it!).

Code:
void setOutputs(byte bank, byte digit1, byte digit2) {

byte val1 = digit1 << 2; // Store number 1 in value 1, shift bits 2 places left (Move BCD value on last 4 bits to middle 4 bits)
byte val2 = digit2 << 6; // Put least 2 bits of Number 2 into upper 2 bits of Value 1
byte val3 = digit2 >> 2; // put highest 2 bits of Number 2 into lowest 2 bits of Value 2
byte val4 = (1 << (bank + 2));  // Choose which bit is needed to control the bank pins 10-13
// The bank selection is middle 4 bits, so the number needs to be shifted over by 2 bits

PORTD &= B00000011; // Turn pins 2-7 off
PORTB &= B11000000; // Turn pins 8-13 off
PORTD |= val1; // Set pins 2-5 to match BCD number held in middle 4 bits of Value 1
PORTD |= val2; // Set pins 6 & 7 to match highest 2 bits of value 1 which is lowest 2 bits of num2
PORTB |= val3; // Set pins 8 and 9 to lowest 2 bits of value 2 which is highest 2 bits of num2

PORTB |= val4; // Turn the appropriate pin (10-13) for the bank
}

This code is very specific to Arduino models Uno, Micro, Mini, Nano, and other Arduino clones that use the 328P chip.  To use it on a Mega, or some other type of microcontroller, you will need to change the ports and which bits get manipulated.


Wow, that's pretty awesome. 

It'd be nice to get a fresh codebase for the ArduiNIX one day, I've been looking into it, but I am not a coder, I am more on the art side and hardware side.

Very neat work!
Logged

nonentity
Robotpirate Founder
www.robotpirate.com

Pages: [1]
Print
Jump to: