Pages: [1]   Go Down
Author Topic: FastShiftOut with Print interface (experimental)  (Read 1322 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Find below an experimental class that implements a FastShiftOut Class which is derived from the Print class.
This means that all print and println interfaces are available to FSO, including printing of strings, floats and ints.
The class does not implement the latch signal (e.g. to be used for one or more 74HC595)

The class is not tested so use at your own risk smiley-wink

as always comments and remarks are welcome.

FastShiftOut.h
Code: (experimental)
//
//    FILE: FastShiftOut.h
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.03
// PURPOSE: shiftout that implements the Print interface
//     URL:
//
// Released to the public domain
//

#ifndef FastShiftOut_h
#define FastShiftOut_h

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

#define FASTSHIFTOUT_LIB_VERSION "0.1.03"

#include "Print.h"

class FastShiftOut : public Print
{
  public:
FastShiftOut(uint8_t, uint8_t, uint8_t);
    size_t write(uint8_t);
    int read(void);

  private:
    uint8_t _bitorder;
    int _value;
    
uint8_t _databit;
    volatile uint8_t *_dataout;
    
uint8_t _clockbit;
    volatile uint8_t *_clockout;
};

#endif
// -- END OF FILE --

FastShiftOut.cpp
Code: (experimental)
//
//    FILE: FastShiftOut.cpp
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.03
// PURPOSE: shiftout that implements the Print interface
//     URL:
//
// Released to the public domain
//

#include "FastShiftOut.h"

//
// Constructor
// prepares the digitalWrite()
FastShiftOut::FastShiftOut(uint8_t datapin, uint8_t clockpin, uint8_t bitOrder)
{
    _bitorder = bitOrder;
    _value = -1;
    pinMode(datapin, OUTPUT);
    pinMode(clockpin, OUTPUT);
    
    // uint8_t _datatimer  = digitalPinToTimer(datapin);
    // if (_datatimer != NOT_ON_TIMER) turnOffPWM(_datatimer); TODO
uint8_t _dataport   = digitalPinToPort(datapin);
    _dataout = portOutputRegister(_dataport);
_databit = digitalPinToBitMask(datapin);
    
    // uint8_t _clocktimer = digitalPinToTimer(clockpin);
    // if (_clocktimer != NOT_ON_TIMER) turnOffPWM(_clocktimer);
uint8_t _clockport  = digitalPinToPort(clockpin);
    _clockout = portOutputRegister(_clockport);
_clockbit   = digitalPinToBitMask(clockpin);
}

//
// write() must implement the virtual write of Print class
//
size_t FastShiftOut::write(uint8_t data)
{
    _value = data;
    for (uint8_t i = 0; i < 8; i++)  
    {
        uint8_t v;
        if (_bitorder == LSBFIRST)   v = !!(_value & (1 << i));
        else                        v = !!(_value & (1 << (7 - i)));
        
        uint8_t oldSREG = SREG;
        cli();
        if (v == LOW)  *_dataout &= ~_databit;
        else           *_dataout |= _databit;
        *_clockout |= _clockbit;
        *_clockout &= ~_clockbit;
        SREG = oldSREG;
    }
    return 1;
}

//
// reads back the last value written.
//
int FastShiftOut::read()
{
    return _value;
}
// -- END OF FILE --

FSO001.ino, tests some performance compared to standard shiftOut()
Code: (experimental)

#include "FastShiftOut.h"

FastShiftOut FSO(12, 13, LSBFIRST);

void setup()
{
  Serial.begin(115200);
  Serial.println("Start FSO");

  unsigned long start = millis();
  for (int i=0; i<10000; i++)
  {
    FSO.write(0x55);
  }
  Serial.println((millis() - start)/10.0, 4);

  start = millis();
  for (int i=0; i<10000; i++)
  {
    FSO.write(0x55);
    FSO.write(0x55);
  }
  Serial.println((millis() - start)/10.0, 4);

  start = millis();
  for (int i=0; i<10000; i++)
  {
    shiftOut(12, 13, 0x55, LSBFIRST);
  }
  Serial.println((millis() - start)/10.0, 4);

  start = millis();
  for (int i=0; i<10000; i++)
  {
    shiftOut(12, 13, 0x55, LSBFIRST);
    shiftOut(12, 13, 0x55, LSBFIRST);
  }
  Serial.println((millis() - start)/10.0, 4);

  Serial.println("test print interface");
  start = millis();
  for (int i=0; i<10000; i++)
  {
    FSO.println("Hello world");
  }
  Serial.println((millis() - start)/10.0, 4);

  start = millis();
  for (int i=0; i<10000; i++)
  {
    FSO.println(1357);
  }
  Serial.println((millis() - start)/10.0, 4);

  start = millis();
  for (int i=0; i<10000; i++)
  {
    FSO.println(3.14159265, 4);
  }
  Serial.println((millis() - start)/10.0, 4);

  Serial.println("done");
}

void loop()
{
}

output:
Start FSO
61.3000
122.4000
114.8000
229.5000
test print interface
812.8000
403.8000
572.5000
done

The FSO Class is almost 2x faster than normal shiftOut() [times in uSec]
Times for strings, ints and floats are approx. as expected. (add newline chars too)

update:
latest version check - https://github.com/RobTillaart/Arduino/tree/master/libraries -
« Last Edit: January 25, 2014, 01:23:41 pm by robtillaart » Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Note: the timings found above might be hard to reproduce as my print.cpp and print.h contains several speed ups (including experimental).
These are discussed in this thread - http://forum.arduino.cc/index.php?topic=167414.0 -
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

speed optimized version of the write, ~twice as fast, but it disables interrupts for the whole byte; and its larger ..
(replace in lib above)
Code: (highly experimental)
// approx 32 us / byte
size_t FastShiftOut::write(uint8_t data)
{
    _value = data;
    // prep masks
    uint8_t dm1 = *_dataout | _databit;
    uint8_t dm0 = *_dataout & ~_databit;
    uint8_t cm1 = *_clockout | _clockbit;
    uint8_t cm0 = *_clockout & ~_clockbit;
   
    uint8_t oldSREG = SREG;
    cli();
    if (_bitorder == LSBFIRST)
    {
        for (uint8_t m = 0x01; m != 0x80; m <<= 1) 
        {
            if (_value & m) *_dataout = dm1;
            else           *_dataout = dm0; 
            *_clockout = cm1;
            *_clockout = cm0;
        }
    }
    else
    {
        for (uint8_t m = 0x80; m > 0; m >>= 1) 
        {
            if (_value & m) *_dataout = dm1;
            else           *_dataout = dm0; 
            *_clockout = cm1;
            *_clockout = cm0;
        }   
    }
    SREG = oldSREG;
    return 1;
}

use at own risk smiley-wink
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pakistan
Offline Offline
Sr. Member
****
Karma: 6
Posts: 357
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Rob,
Thanks for this new approach in Shiftout. I shall check how can i utilize it in my Graphical waterfall project.
Regards
Logged


Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

latest version can be found here - https://github.com/RobTillaart/Arduino/tree/master/libraries -
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pakistan
Offline Offline
Sr. Member
****
Karma: 6
Posts: 357
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for the generosity and sharing:) I shall come back and report..
Regards
Logged


Pages: [1]   Go Up
Jump to: