Schip's added/modified "contributions" to Arduino Core code. Non-pre-emptive Task Scheduler. freeRam() function to see how much memory you have left. ADC interrupt and averaging code. Message receive delimiter interface. Plus free bonus code! MMA8452Q accelerometer interface library Template project allows one to (mostly) avoid Arduino IDE. For a precis of the functions see the BlinkTask/BlinkTask.ino file. More documentation is below. INSTALLATION Copy/Paste files from cores directory to your arduino development tree. Versions are provided for Arduino v1.0.4 and v1.0.5-r2. If you have a different base version you should compare the files with name.original_vXXX to what you have in your arduino tree and make any changes that seem to be indicated in the new files. On Widows http://winmerge.org/ has a particularly useful tool for this. All files should be copied from: cores/arduino/[your-version] to: arduino-[your_version]/hardware/arduino/cores/arduino/ For the Task Scheduler installed in the tick interrupt: wiring.c wiring.c.original_v[your_version] schip/*.* // create the entire directory, ie: arduino/schip/scheduler.h For the ADC free running interrupt, averaging, and ADCTask() posting: wiring_analog.c wiring_analog.c.original_v[your_version] Note that you can edit various ifdef SCHIP* defines to remove some of the behaviors. See the code file for "help". For the message receive delimiter interface: HardwareSerial.cpp HardwareSerial.cpp.original_v[your_version] HardwareSerial.h HardwareSerial.h.original_v[your_version] The rest can just go in your Arduino project tree: BlinkTask -- test and demo program. libraries/MMA8452Q -- Accelerometer interface code. libraries/Template -- My way of avoiding the Arduino IDE. DOCUMENTATION Scheduler: The scheduler provides a non-pre-emptive multi-tasking system with some limitations. It replaces the use of delay() in normal Arduino code with the ability to schedule a function's execution at some specified number of milli-seconds in the future. Each "Task" can have a single integer sized argument (which can be coerced into a pointer to a memory location as needed). Tasks should not use delay() or other blocking calls and should be fairly short lived. If you have long running functions they should be broken into multiple Tasks that can be run sequentially. void scheduler(void) -- Checks the task list and executes any who's time has come. Put a call to this method in your loop() function. void postTask( uint16_t ticks, PFV func, uint16_t arg ) -- Posts a Task to be run by the scheduler: ticks -- number of milli-sec until execution, 0 is right now (or very soon) The max is 0xfffd milli-sec or about 65.5 seconds. -1 and -2 (0xffff or 0xfffe) are special, do not use; func -- the function to be executed, PFV == pointer to a function returning void see below; arg -- integer argument to be passed to the function; void repostTask( uint16_t ticks, uint16_t arg ) -- Repost the current task to be run again: ticks -- number of milli-sec until execution, arg -- argument to be passed to the function; Can only be called from within an executing Task. Note that the default number of Tasks is eight (8). This can be changed in the scheduler.h header file. Tasks posted beyond that number are silently ignored, as are repostings outside of a valid Task. PFV -- void Task( uint16_t arg ) -- The signature of a Task that can be posted. It takes one integer sized argument and returns void. In order to pass more data you can make a structure and coerce the argument to be a pointer: void myTask( uint16_t arg ) { struct* ptr = (struct*)arg; /// ... return; } Which is posted like this: struct arg; postTask( 100, myTask, (uint16_t) &arg ); Bonus Function: uint16_t freeRam() -- Returns the number of bytes of memory between the top of the stack at this call and the top of the static or malloc heap. I.e: an estimate of how much RAM is not used. ADC Interrupt, etal: This code adds a free-running ADC interrupt that continuously converts all the available ADC channels in the "background". By default this is channels 0-3,6,7 since channels 4&5 are used by the I2C interface and the Pro-Mini brings out the hidden 6&7 channels. This works out to a cycle time of 110 micro-seconds or about 9K samples per second. Note that this may not be appropriate for high speed or regular period sampling such as audio conversion. YMMV... Also added is code to average all the channel readings over 64 samples and return 8-bit values. As part of this an ADCTask() is posted at the end of each averaging period or every 43 milli-seconds (23/sec). You can change some of this behavior by editing the wiring_analog.c file to your own specifications. uint8_t analogReadAvg(uint8_t pin) -- Returns the current 8-bit average similar to analogRead(pin) which now returns the most recent instantaneous 10-bit ADC reading without blocking for the 13uS conversion time. pin -- Arduino ADC pin number 0-8 void ADCTask( uint16_t numADC ) -- Task posted at the end of each averaging period. This should be defined in the user's program but can do nothing if one wishes. numADC -- number of ADC's available, usually 8 with 4&5 not used. Messaging: This code adds to the HardwareSerial class the ability to set a message terminator character and query if it has been received. This allows Serial messages to be read without blocking -- which is necessary to good Task scheduling. The normal usage is to get a text string delimited with a newline, '\n', but astute users may notice that more robust framed protocols can be implemented with this simple addition. Again, YMMV... void Serial.setMsgTerm( char term ) -- Set the message terminator to the specified character. term -- character to use (often '\n'); int Serial.msgAvailable() -- Returns the number of the specified terminator characters that are in the input queue. If non-zero we've probably received a whole message which can be read without blocking. The example code shows a usage where a messageRead() task is posted to do the dirty work. MMA8452Q library: Interface class library for the MMA8452Q Accelerometer sold by SparkFun. This is a lightly massaged version of MMA8452Q Basic Example Code Nathan Seidle SparkFun Electronics November 5, 2012 Turned into a library with optional Output Data Rate setting by Michael Schippling bozotronics Feb 2014. The comments at the head of the MMA8452Q.cpp file describe how to wire the sucker up. The chip needs a 3.3v power supply but there is no reason to fiddle with level converters when interfacing with a 5v system. The Output Data Rate (ODR) can be set in the MMA8452Q.h header with the USEODR #define. This may, or may not, change the averaging period over which accelerations are collected. The default is 50 Hz or 20 ms. It uses the Wire.h library to access I2C so both header files need to be included in your main program. Using the advanced and interrupt features of the chip is left as an exercise for the reader. There is a test and demo program under the testMMA8452Q directory. My experience with this chip indicates that it's fine for detecting orientation and bumping of a device but way too noisy to actually derive motion and speed -- this may be a failing on my part. Also there is an occasional lapse of I2C communication which causes the read to hang-up, so there is a recovery timeout which returns an error on this failure but it takes a few passes of busy-waiting. #include class MMA8452Q -- MMA8452Q(void) -- default constructor. byte init(void) -- Start Wire I2C lib and initialize device to default condition; returns 1 if OK or 0 if not. int* readData( int *destination ); Read raw data into a packet of 3 signed integers in given int array: X,Y,Z. return -- pointer to destination on success or null on error void toAccelG( int *data, float *accel ); Convert raw data to actual floating point acceleration values. data -- raw values returned from readData(); accel -- resulting float values for each orientation; Another EXTRA ADDED BONUS!!! library/Template -- My experience with the Arduino IDE has been less than satisfactory. As a build environment it is entirely opaque and as an editor it is nearly useless. So I've reverse engineered just enough to make a palatable replacement. The problem with the IDE it that it imports all the source files in a project directory and then ignores any external changes, so you can't easily use some other editor. Then it hides all the build process, so you can't easily replace it. UNLESS your source files are NOT in the main project directory... My Template project attempts to remedy much of this. It is in the library sub-directory. All the actual code is in files in what would be a library, with the Template.h header file for external references. The mainexec.ino file is in a subdirectory, here called mainexec (it could be under the top level Arduino directory, but why duplicate?). It contains only the necessary calls to get everything to compile by linking with the Template.h library (and any others that are used). So, now I can use VIM or Eclipse to edit all but the mainexec file to my heart's content. The mainexec.ino is still open in the Arduino IDE, but one hopes it is edited very infrequently. When it comes time to compile and test I use the Arduino IDE just like always, but otherwise I can ignore it. It's not a completely Integrated Integrated Development Environment, but at least it's a Development Environment. I've included a parallel testexec sub-directory that could be used to develop system test functions as a separate project while not unduly disturbing the main project. The project uses "Plot", another utility library of my own invention, to localize formatting of logging messages for different uses. Feel free to exercise or excise any of this.