Go Down

Topic: Higher Performance IO (Read 8736 times) previous topic - next topic

mem

Quote
Of course, you may use the code, especially since they are mods of arduino core stuff which is under the GPL.  No attribution required, but thanks for asking. :)

ditto

chippey


chippey

I think I must have done something wrong, but I can't figure out what.

I put all the macros into a file called "fastSB.h", and include that in the header for the library. I then swapped out all calls to digitalWrite to fastWrite, and all shiftOut calls to shitOutByte. Now, when I try to build my example sketch, I get tons of strange errors:
Code: [Select]



/Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o: In function `ShiftBrite::initPins()':

/Applications/arduino-0011/hardware/libraries/ShiftBright/ShiftBrite.cpp:49: multiple definition of `ShiftBrite::initPins()'

/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o:/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.cpp:49: first defined here

/Applications/arduino-0011/hardware/tools/avr/bin/../lib/gcc/avr/4.0.2/../../../../avr/bin/ld: Warning: size of symbol `_ZN10ShiftBrite8initPinsEv' changed from 164 in /Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o to 72 in /Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o

/Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o: In function `ShiftBrite::ShiftBrite(int)':

/Applications/arduino-0011/hardware/libraries/ShiftBright/ShiftBrite.cpp:20: multiple definition of `ShiftBrite::ShiftBrite(int)'

/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o:/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.cpp:20: first defined here

/Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o: In function `ShiftBrite::ShiftBrite(int)':

/Applications/arduino-0011/hardware/libraries/ShiftBright/ShiftBrite.cpp:20: multiple definition of `ShiftBrite::ShiftBrite(int)'

/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o:/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.cpp:20: first defined here

/Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o: In function `ShiftBrite::ShiftBrite(int, int, int, int)':

/Applications/arduino-0011/hardware/libraries/ShiftBright/ShiftBrite.cpp:10: multiple definition of `ShiftBrite::ShiftBrite(int, int, int, int)'

/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o:/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.cpp:10: first defined here

/Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o: In function `ShiftBrite::ShiftBrite(int, int, int, int)':

/Applications/arduino-0011/hardware/libraries/ShiftBright/ShiftBrite.cpp:10: multiple definition of `ShiftBrite::ShiftBrite(int, int, int, int)'

/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o:/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.cpp:10: first defined here

/Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o: In function `ShiftBrite::sendPacket(int, int, int, int)':

/Applications/arduino-0011/hardware/libraries/ShiftBright/ShiftBrite.cpp:59: multiple definition of `ShiftBrite::sendPacket(int, int, int, int)'

/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o:/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.cpp:59: first defined here

/Applications/arduino-0011/hardware/tools/avr/bin/../lib/gcc/avr/4.0.2/../../../../avr/bin/ld: Warning: size of symbol `_ZN10ShiftBrite10sendPacketEiiii' changed from 9382 in /Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o to 306 in /Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o

/Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o: In function `ShiftBrite::setColor(int, int, int)':

/Applications/arduino-0011/hardware/libraries/ShiftBright/ShiftBrite.cpp:40: multiple definition of `ShiftBrite::setColor(int, int, int)'

/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o:/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.cpp:40: first defined here

/Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o: In function `ShiftBrite::setPower(int)':

/Applications/arduino-0011/hardware/libraries/ShiftBright/ShiftBrite.cpp:35: multiple definition of `ShiftBrite::setPower(int)'

/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o:/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.cpp:35: first defined here

/Applications/arduino-0011/hardware/libraries/ShiftBritev1/ShiftBrite.o: In function `ShiftBrite::setPower(int, int, int)':

/Applications/arduino-0011/hardware/libraries/ShiftBright/ShiftBrite.cpp:30: multiple definition of `ShiftBrite::setPower(int, int, int)'

/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.o:/Applications/arduino-0011/hardware/libraries/ShiftBrite/ShiftBrite.cpp:30: first defined here

Couldn't determine program size: hardware/tools/avr/bin/avr-size: '/tmp/build56400.tmp/shiftbright5.hex': No such file



chippey

Ok, that's just bizarre.  The exact same code works as long as it's in the original library folder, and not the duplicate folder I made to version up with.  I tried just duplicating the library with no code changes at all, and it fails to compile (with the above errors).  But the original library (exact same code, same files even) works.   :o

So the macros are working now that I'm working out of the original library folder.  Strange.

mem

You can't have multiple cpp files with duplicate shiftBrite function names in the directories containing the libraries. If you want to keep multiple versions for testing you need to give the methods and public variables different names for each version.

follower

Quote
If you want to keep multiple versions for testing you need to give the methods and public variables different names for each version.

Another approach is to move one of the conflicting versions into a folder named disabled, for example, while you're testing the other.

--Phil.

chippey

*slaps head* of course!  Heh, I feel somewhat silly now. :-[

I think I'll keep the old version in a separate unused folder.  Make more sense that way now that I think about it too.

On a side note, I think I may have to switch to using functions instead of macros, as when the compiler flattens out all the macros, it takes up a lot of room :(  (A simple example sketch I made took up about 11k!).  The macros work really well, but seems to take up a lot of room.

mem

Quote
On a side note, I think I may have to switch to using functions instead of macros, as when the compiler flattens out all the macros, it takes up a lot of room :(  (A simple example sketch I made took up about 11k!).  The macros work really well, but seems to take up a lot of room.


The fastWrite macro produces two bytes of code for every place its used in the source file so I would be surprised if that alone is causing the code size increase. Function calling has significant overhead compared to the time writing directly to a port so if speed is important it's worth seeing if you can find out why the code is as big as it is, it may not be the macros themselves, but the way they are used.

Perhaps if you post the source code for both versions, you can get some advice on how to get the size of the macro version down.



MartinFick

If you find that they are taking too much space, use the macros only where you really need the speed, of course.  The big one is shiftOut().  The fastWrite() is probably not worth it unless you are doing a bunch in a row that need to be fast.  Nevertheless, I am having a hard time imagining 11K worth. :)  If you happen to be calling shiftOutByte() many places in your code it makes sense to use something like shiftOutRaw() instead which is a function call, as long as you are always using the same pins it should work.

chippey

Sure!  Here's the ShiftBrite.cpp file:
Code: [Select]
//Matt G.
//onion@doorcreekorchard.com
//July 2008

#include "ShiftBrite.h"


//====Public
//==Constructors
ShiftBrite::ShiftBrite(int dp, int lp, int ep, int cp)
{
     datapin=dp;
     latchpin=lp;
     enablepin=ep;
     clockpin=cp;
     initPins();
}


ShiftBrite::ShiftBrite(int cp)
{
     clockpin=cp;
     enablepin=cp+1;
     latchpin=cp+2;
     datapin=cp+3;
     initPins();
}

//==
void ShiftBrite::setPower(int r, int g, int b)
{
     sendPacket(B01,r,g,b); //B01 sets the mode to write to the current registers
}

void ShiftBrite::setPower(int p)
{
     sendPacket(B01,p,p,p);
}

void ShiftBrite::setColor(int r, int g, int b)
{
     sendPacket(B00,r,g,b); //B00 sets the mode to write to the PWM registers
}
#if _5BIT_SB
void ShiftBrite::setColor5b( byte r, byte g, byte b)
{
     setColor(SB_5bLUT_basic[0][r],SB_5bLUT_basic[1][g],SB_5bLUT_basic[2][b]);
}

void ShiftBrite::setColor5b(int val)
{
     /*byte r,g,b;
     
     //extract the channels
     b = val & 0x1F;
     g = (val >> 5) & 0x1F;
     r = (val >> 10) & 0x1F;
     */
     setColor5b((val >>10) & 0x1F,(val >> 5) & 0x1F,val & 0x1F);
}
#endif
//============


//====Private
void ShiftBrite::initPins()
{
     pinMode(datapin, OUTPUT);
     pinMode(latchpin, OUTPUT);
     pinMode(enablepin, OUTPUT);
     pinMode(clockpin, OUTPUT);
     fastWrite(latchpin, LOW);
     fastWrite(enablepin, LOW);
}

void ShiftBrite::sendPacket(int mode, int r, int g, int b)
{
     unsigned long SB_CommandPacket;
     
     SB_CommandPacket = mode & B11;
     SB_CommandPacket = (SB_CommandPacket << 10)  | (b & 1023);
     SB_CommandPacket = (SB_CommandPacket << 10)  | (r & 1023);
     SB_CommandPacket = (SB_CommandPacket << 10)  | (g & 1023);
     
     shiftOutByte(datapin, clockpin, MSBFIRST, SB_CommandPacket >> 24);
     shiftOutByte(datapin, clockpin, MSBFIRST, SB_CommandPacket >> 16);
     shiftOutByte(datapin, clockpin, MSBFIRST, SB_CommandPacket >> 8);
     shiftOutByte(datapin, clockpin, MSBFIRST, SB_CommandPacket);
     
     delay(1); // adjustment may be necessary depending on chain length
     fastWrite(latchpin,HIGH); // latch data into registers
     delay(5); // adjustment may be necessary depending on chain length
     fastWrite(latchpin,LOW);
}



chippey

ShiftBrite.h:
Code: [Select]
#ifndef ShiftBrite_h
#define ShiftBrite_h

#define SB_Ver 1.1

#ifndef _5BIT_SB
#define _5BIT_SB 1 //default include the 5bit part of the library.
#endif

#include "wiring.h"
#include "fastSB.h"
#include "LUTs_SB.h"

class ShiftBrite
{
 private:
     int datapin; //pins the ShiftBrite is connected to
     int latchpin;
     int enablepin;
     int clockpin;
     
     void initPins(); //sets up pins modes, etc.
     void sendPacket(int mode, int r, int g, int b);
 
public:
   ShiftBrite(int dp, int lp, int ep, int cp);
     ShiftBrite(int cp);
     
     void setPower(int r, int g, int b);
     void setPower(int p);
     
     void setColor(int r, int g, int b);
#if _5BIT_SB
     void setColor5b(byte r, byte g, byte b); //sets a 5 bit color via a LUT
     void setColor5b(int val); //same as above, but from a packed 16 bit word
#endif
};

#endif


chippey

and fastSB.h:
Code: [Select]
//credit of the following code goes to mem on the arduino board (for fastWrite)
//and to MartinFick (all the shiftOut stuff)



//fastWrite()
// the following macro sets a digital pin high or low, pin must be between 0 and 13 inclusive
// usage: fastWrite(2,HIGH); fastWrite(13,LOW);
#define fastWrite(_pin_, _state_) ( _pin_ < 8 ? (_state_ ?  PORTD |= 1 << _pin_ : PORTD &= ~(1 << _pin_ )) : (_state_ ?  PORTB |= 1 << (_pin_ -8) : PORTB &= ~(1 << (_pin_ -8)  )))
// the macro sets or clears the appropriate bit in port D if the pin is less than 8 or port B if between 8 and 13



#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))

#define sbipin(pin) sbi((pin)<8 ? PORTD:PORTB, (pin) - ((pin)<8 ? 0:8))
#define cbipin(pin) cbi((pin)<8 ? PORTD:PORTB, (pin) - ((pin)<8 ? 0:8))

#define bitWrite(pin, val) { \
if ((val) == LOW) cbipin(pin); \
else              sbipin(pin); \
}

#define shiftOutBit(dataPin, clockPin, val, bit) { \
bitWrite(dataPin, ((val) & (1 << (bit))) ? HIGH:LOW); \
bitWrite(clockPin, HIGH); \
bitWrite(clockPin, LOW); \
}

#define shiftOutByte(dataPin, clockPin, bitOrder, val) { \
shiftOutBit(dataPin, clockPin, val, (bitOrder) == LSBFIRST ?0:7); \
shiftOutBit(dataPin, clockPin, val, (bitOrder) == LSBFIRST ?1:6); \
shiftOutBit(dataPin, clockPin, val, (bitOrder) == LSBFIRST ?2:5); \
shiftOutBit(dataPin, clockPin, val, (bitOrder) == LSBFIRST ?3:4); \
shiftOutBit(dataPin, clockPin, val, (bitOrder) == LSBFIRST ?4:3); \
shiftOutBit(dataPin, clockPin, val, (bitOrder) == LSBFIRST ?5:2); \
shiftOutBit(dataPin, clockPin, val, (bitOrder) == LSBFIRST ?6:1); \
shiftOutBit(dataPin, clockPin, val, (bitOrder) == LSBFIRST ?7:0); \
}




chippey

If you need here's the LUT I made.  I tried excluding it because at first I thought it was the culprit for the large size, but it only reduced the size by about ~200 bytes or so when I did:

LUTs_SB.h:
Code: [Select]
/*
*  LUTs.h
*  
*
*  Created by Chippey on 8/9/08.
*  
*
*/
#if _5BIT_SB //only include lookup tables if they're going to be used

//basic lut is just that. it puts most of the range in 0-400, but the whole
//thing is linear, from 0-400, then 400-1023
const uint16_t SB_5bLUT_basic[][32] =
{{
     0, //0  //RED
     16, //1
     32, //2
     48, //3
     64, //4
     80, //5
     96, //6
     112, //7
     128, //8
     144, //9
     160, //10
     176, //11
     192, //12
     208, //13
     224, //14
     240, //15
     256, //16
     272, //17
     288, //18
     304, //19
     320, //20
     336, //21
     352, //22
     368, //23
     384, //24
     400, //25
     503, //26
     607, //27
     711, //28
     815, //29
     919, //30
     1023 //31
},
{
     0, //0  //GREEN
     16, //1
     32, //2
     48, //3
     64, //4
     80, //5
     96, //6
     112, //7
     128, //8
     144, //9
     160, //10
     176, //11
     192, //12
     208, //13
     224, //14
     240, //15
     256, //16
     272, //17
     288, //18
     304, //19
     320, //20
     336, //21
     352, //22
     368, //23
     384, //24
     400, //25
     503, //26
     607, //27
     711, //28
     815, //29
     919, //30
     1023 //31
},
{
     0, //0  //BLUE
     16, //1
     32, //2
     48, //3
     64, //4
     80, //5
     96, //6
     112, //7
     128, //8
     144, //9
     160, //10
     176, //11
     192, //12
     208, //13
     224, //14
     240, //15
     256, //16
     272, //17
     288, //18
     304, //19
     320, //20
     336, //21
     352, //22
     368, //23
     384, //24
     400, //25
     503, //26
     607, //27
     711, //28
     815, //29
     919, //30
     1023 //31
}};


#endif



chippey

Last bit.  When the above is used with this sketch, the result is ~ 11k.

example sketch:
Code: [Select]
#include "ShiftBrite.h"

ShiftBrite SB(10); //A ShiftBrite starting on pin 10, assumes the next pins are sequentially going up

void setup() {
 pinMode(9,OUTPUT);
 digitalWrite(9,HIGH); //this is un UGLY HACK to supply +5 on pin 9
                   //so the SB can be directly hooked on the the arduino.  
                   //This will probably burn out your arduino and cause the end of days.  
                   //Find a better way of supply power to the SBs
 SB.setPower(127); //Full power captin!
}


//This examples has three ShiftBrites chained together in series, and cycles some colours through them
void loop() {
 SB.setColor(1023,0,0); // SB #3 (since the data gets pushed through the SBs, the last one is set first
 SB.setColor(0,1023,0); // SB #2
 SB.setColor(0,0,1023); // SB #1
 delay(500);
 SB.setColor(0,1023,0);
 SB.setColor(0,0,1023);
 SB.setColor(1023,0,0);
 delay(500);
 SB.setColor(0,0,1023);
 SB.setColor(1023,0,0);
 SB.setColor(0,1023,0);
 delay(500);
}


MartinFick

I think that you are better off using the shiftOutHPPM() function for your library since you are allowing things (the latchpins) to not be hardcoded.  Since you are not hardcoding them it is probably easier and safer to use the function.  There is no real speed gain if you do not hardcode the pins.

Go Up