Netherlands
Online
Jr. Member
Karma: 0
Posts: 88
Profile before you Optimize.
|
 |
« on: February 19, 2012, 02:55:06 pm » |
I am a C# programmer and am used to work with classes and Object Orientation (OO). So I created some simple classes to encapsulate some essentials.
I've attached a .zip file called Libraries. Unzip it in your Arduino folder in My Documents. It contains 3 mini libs: AnalogInput, DigitalInput and DigitalOutput.
Please read the header files for more information on the specific classes.
I find them useful and hope others will too.
Enjoy, Marc Jacobi Netherlands.
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 89
Posts: 9392
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #1 on: February 19, 2012, 05:01:12 pm » |
I like the idea of a flag that the value has changed.
idea: I am missing code to enable the internal pull up resistor
Maybe you can explain the rationale behind the details of these classes ?
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Jr. Member
Karma: 0
Posts: 88
Profile before you Optimize.
|
 |
« Reply #2 on: February 20, 2012, 02:50:59 am » |
It is a work in progress. I build what I need but make sure I can extend later. BTW: there is a method enableInternalPullup on the DigitalInput class  I've created these classes as an exercise (in Arduino dependency management ;-) ) and because I don't like all the static and sequential stuff that seems to be the norm. I understand that it is convenient for beginners, but I am an OO programmer  and like it when I don't have to keep all the low level details in my head  I truly believe that you get better code if you use OO responsibly. But I also understand that it is not the only variable on a platform like the Arduino. That is why I want to learn a bit more on code optimization first, before getting too far ahead of myself.  Also being a beginner in experimenting with the Arduino (although I had previous experience with other types of MCU's) I quickly found that I was repeating myself (in code). To me, that is always a sign 'something needs to be done'. This is my first pass at it. I hope more people will see its value and find these classes useful.
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 89
Posts: 9392
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #3 on: February 20, 2012, 02:06:47 pm » |
BTW: there is a method enableInternalPullup on the DigitalInput class Sorry, I missed it in the quick look I truly believe that you get better code if you use OO responsibly But allways remember that OO is a tool not the goal itself. And any technique should be used responsibly. all the static and sequential stuff that seems to be the norm. Not necessary the norm but sometimes the only way to get the functionality needed packed in the memory available. That all said, keep posting your work as it is allways inspiring to see other peoples code.
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Jr. Member
Karma: 0
Posts: 88
Profile before you Optimize.
|
 |
« Reply #4 on: February 20, 2012, 02:14:25 pm » |
Not necessary the norm but sometimes the only way to get the functionality needed packed in the memory available.
Can you elaborate on that? I have no idea (yet) on how efficient the compiler packs down the code and how smart it is in optimizing. What I saw was staticly defined class instances just so the MyLib.someFunction (like SPI.write or whatever) syntax can be used. Is the compiler smart enough not to package up unused code? Otherwise if you don't use those statics (because you need more than one instance?) they will only take up memory space.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
God Member
Karma: 0
Posts: 596
Arduino rocks
|
 |
« Reply #5 on: February 20, 2012, 02:19:26 pm » |
This brings me to a question I had in my mind since I first posted SimpleTimer on the Playground... what's the best place to share some Arduino code ? Playground seems a bit too "official" sometimes, while libraries posted here in the forum are quickly buried to oblivion due to the sheer amount of activity going on.... The github idea is good IMHO, but it seems the staff doesn't have enough time to bring it forward. I think some improvement is needed in this area.
I apologize with the OP for hijacking his thread ;-P I'll have a look at the libraries ASAP.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
God Member
Karma: 0
Posts: 596
Arduino rocks
|
 |
« Reply #6 on: February 20, 2012, 02:24:24 pm » |
Is the compiler smart enough not to package up unused code?
I think unreferenced code is stripped by the linker. Therefore you get into the final .hex file only the code that is actually called (to be precise, that appears to be called at compile time - there's no run-time analysis of dead codepaths, of course).
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Jr. Member
Karma: 0
Posts: 88
Profile before you Optimize.
|
 |
« Reply #7 on: February 20, 2012, 04:43:52 pm » |
I dont get why an empty program -with just an empty setup and loop method- is still 466 bytes long!? 
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
God Member
Karma: 0
Posts: 596
Arduino rocks
|
 |
« Reply #8 on: February 20, 2012, 04:50:15 pm » |
Here's main.cpp from Arduino 1.0: #include <Arduino.h>
int main(void) { init();
#if defined(USBCON) USB.attach(); #endif setup(); for (;;) { loop(); if (serialEventRun) serialEventRun(); } return 0; }
At least setup() and init() are called, even on an "empry" sketch, therefore some code has to be compiled in.
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Jr. Member
Karma: 0
Posts: 88
Profile before you Optimize.
|
 |
« Reply #9 on: February 23, 2012, 01:51:59 pm » |
Its not complete or done, by any means, I'm just playing around with this... Debug.h #ifndef _Debug_h_ #define _Debug_h_
#include <Stream.h>
#ifdef DEBUG
class Debug { public: Debug(Stream* output) { _output = output; } inline bool inDebug() { return true; } inline void writeLine(const char* string) { _output->println(string); } inline void assert(bool condition, const char* description) { if(condition) return;
_output->print("WARNING: Debug assertion failed: "); _output->println(description); _output->print(__FILE__); _output->print(" ("); _output->print(__LINE__); _output->print("):"); _output->println(__func__); } private: Stream* _output; };
#else
class Debug { public: Debug(Stream* output) {} inline bool inDebug() { return false; } inline void writeLine(const char* string) {} inline void assert(bool condition, const char* description) {} };
#endif //DEBUG
#endif //_Debug_h_
I'm still struggling to get the __FILE__ and __LINE__ to work...  usage: #define DEBUG // comment out for Release build.
#include "Debug.h"
Debug debug(&Serial);
void setup() { if(debug.inDebug()) { Serial.begin(9600); } }
void loop() {
debug.writeLine("inside loop"); delay(1000);
debug.assert(false==true, "Test Assertion");
}
Constructive criticism is appreciated. Hope you like it.
|
|
|
|
« Last Edit: February 23, 2012, 01:54:51 pm by obiwanjacobi »
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 89
Posts: 9392
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #10 on: February 23, 2012, 03:48:44 pm » |
I dont get why an empty program -with just an empty setup and loop method- is still 466 bytes long!? that are two functions, called from main() - C:\Program Files (x86)\arduino-0022\hardware\arduino\cores\arduino\main.cpp #include <WProgram.h>
int main(void) { init();
setup(); for (;;) loop(); return 0; } SO it does more than the eye can see (directly)
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 20
|
 |
« Reply #11 on: February 25, 2012, 12:52:14 am » |
Thank you for sharing your codes
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Jr. Member
Karma: 0
Posts: 88
Profile before you Optimize.
|
 |
« Reply #12 on: February 25, 2012, 03:01:14 am » |
Thanx! I hope it will lead to new ideas 
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Jr. Member
Karma: 0
Posts: 88
Profile before you Optimize.
|
 |
« Reply #13 on: February 25, 2012, 03:11:39 am » |
I think unreferenced code is stripped by the linker. Therefore you get into the final .hex file only the code that is actually called (to be precise, that appears to be called at compile time - there's no run-time analysis of dead codepaths, of course).
I was reading up on the underlying avr toolset and libraries and came across this page: http://www.nongnu.org/avr-libc/user-manual/library.htmlAt the "How the linker works" section it describes how the linker uses complete object files to decide what to include and what not. So only if you write each function in a separate file, it cannot get optimized even when it is not in use. There goes the class file 
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Online
Jr. Member
Karma: 0
Posts: 88
Profile before you Optimize.
|
 |
« Reply #14 on: March 03, 2012, 09:00:15 am » |
BitArray.h #ifndef __BITARRAY_H__ #define __BITARRAY_H__
#include <Arduino.h>
// The BitArray class stores bits in one or more bytes. // This class can be used for maintaining boolean flags in a memory effecient way. // A normal boolean takes up a whole byte. // T is an (unsigned) integer datatype. template<typename T> class BitArray { public: BitArray(T initialValues) { _bits = initialValues; }
bool Set(byte bitIndex, bool value) { if (bitIndex > getMaxBits()) return false;
T mask = 1 << bitIndex; // clear bit _bits &= ~mask;
if (value) { // set bit _bits |= mask; }
return true; }
bool IsTrue(byte bitIndex) { if (bitIndex > getMaxBits()) return false;
T mask = 1 << bitIndex; return ((_bits & mask) > 0); }
bool IsFalse(byte bitIndex) { if (bitIndex > getMaxBits()) return false;
T mask = 1 << bitIndex; return ((_bits & mask) == 0); }
byte getMaxBits() { return (sizeof(T) * 8); }
bool operator[] (byte bitIndex) { return IsTrue(bitIndex); }
operator T() { return _bits; }
private: T _bits; };
#endif //__BITARRAY_H__
usage: #include <HardwareSerial.h>
#include "BitArray.h"
BitArray<byte> bits(0);
void setup() { Serial.begin(115200);
bits.Set(0, false); bits.Set(1, false); bits.Set(2, true); bits.Set(3, false); bits.Set(4, false); bits.Set(5, false); bits.Set(6, true); bits.Set(7, true); }
void loop() { Serial.print(bits.getMaxBits()); Serial.println(" bits"); Serial.print("value = "); Serial.println(bits);
for (int i = 0; i < bits.getMaxBits(); i++) { Serial.print(i); Serial.print(" = "); Serial.println(bits.IsTrue(i) ? "true" : "false"); } delay(2000); }
|
|
|
|
« Last Edit: March 03, 2012, 09:17:35 am by obiwanjacobi »
|
Logged
|
|
|
|
|
|