Looking around, i did not found a faster replacement for the shiftOut procedure (http://www.arduino.cc/en/Reference/ShiftOut) which is also compatible to the existing procedure. So i wrote a new procedure:
Same interface as shiftOut
3-4x faster
Restrictions: Does not turn of PWM and does not modify port directions
The restrictions mean, that you have to configure the clock and data pin correctly before using the replacement.
I did some performance tests with the SpaceTrash game form the DOGM128 Library (Arduino Uno, DOGS102 Display)
DOUBLE_MEM, shiftOut: 9 FPS (frames per second)
DOUBLE_MEM, shiftOutFast: 31 FPS
DOUBLE_MEM, Hardware SPI: 42 FPS
I don't see where you allow for the clock and data to be in the same port (clock byte setting overwrites data byte), or where you deal with an interrupt handler trying to change another bit in either port during your shift.
Here is a version that I implemented for the GLCD port for the pcd8544 (https://github.com/MikeSmith/glcd_pcd8544). It deals with both of those issues, and gave a roughly 5x frame rate improvement. Obviously for LSB first you would replace the loop starting value and shift direction.
...setup...
// Configure display interface pins
pinMode(GLCD_SCLK, OUTPUT);
_sclk.reg = portOutputRegister(digitalPinToPort(GLCD_SCLK));
_sclk.bit = digitalPinToBitMask(GLCD_SCLK);
pinMode(GLCD_SDIN, OUTPUT);
_sdin.reg = portOutputRegister(digitalPinToPort(GLCD_SDIN));
_sdin.bit = digitalPinToBitMask(GLCD_SDIN);
...
void
glcd_Device::_shiftOut(uint8_t data)
{
register uint8_t mask;
register uint8_t sdin_high = _sdin.bit;
register uint8_t sdin_low = ~sdin_high;
register uint8_t sclk_high = _sclk.bit;
register uint8_t sclk_low = ~sclk_high;
// must be volatile as they may alias
register volatile uint8_t *sdin = _sdin.reg;
register volatile uint8_t *sclk = _sclk.reg;
// mask interrupts while we shift the byte out
uint8_t sreg = SREG;
cli();
for (mask = 0x80; mask; mask >>=1) {
if (data & mask) {
*sdin |= sdin_high;
} else {
*sdin &= sdin_low;
}
*sclk |= sclk_high;
*sclk &= sclk_low;
}
// restore interrupt state
SREG = sreg;
}
Would you consider specifying a license for sharing the code?
As indicated on the Arduino FAQ, the Arduino C/C++ microcontroller libraries are under the LGPL. It would be great if you would consider sharing your shiftOutFast code under the LGPL or a compatible license (e.g., BSD, MIT, etc.).