About#
Having been frustrated with many of the inefficiencies of the Arduino core libraries, we have built an alternate set with performance and size in mind. Alastair has given a talk at the Canberra Linux User Group about this library - the slides can be viewed on SlideShare.
Much of the efficiency gains comes from addressing some of the key design deficiencies of the Arduino runtime - we do not store pin/port information in tables in flash, needlessly preallocate objects nor dictate that excessively large buffers must be used. Instead, control of these are handed over to the developer at compile time.
We recommend using cppcheck and the CPPCeclipse Eclipse Plugin for further bug checking in your code.
Design Philosophies#
- Design for the architecture
- Favour efficiency over simplicity
- Hide complexity using macros
- Provide a rich API that exposes all likely usages that are expected
- Fix all warnings!
- Use appropriate datatypes, and use strict typing where possible to minimise the wrong variable being passed
- Favour C++ references over pointers to reduce bad usage which can lead to crashes
- Leverage inheritance to make generic routines available for all objects that need it
- Expensive operations should be asynchronous where possible, so they run in the background while your code does other things
- Enable an event driven approach
- BSD licensed to encourage commercial use (there is a separate GPL project for ports of GPL software to Flame, such as V-USB)
Getting Started#
We recommend developing your Flame projects in Eclipse. For instructions on how to do so, please see our tutorial.
We also have another tutorial showing how to build Flame using make from the command line.
Bootloader#
If an Arduino-style bootloader is required, we recommend Optiboot, which clocks at only a quarter the size of the Arduino bootloader (0.5kb vs 2kb), and a programming baud rate of 115,200bps.
If USB is more your thing, you may want to consider USBaspLoader, which clocks in at 2kb (the same size as the Arduino bootloader), and pretends to be a USBasp programmer. This uses software USB (based on the V-USB library), removing the need for a USB->serial chip, and allows you to flash your chip over USB using AVRdude.
Download#
You can grab the libraries from our GIT repository on GitHub:
git clone https://github.com/InfernoEmbedded/flame.git
or
git clone https://github.com/InfernoEmbedded/flame.git
To update later…
You can also grab a tarball from the releases at the bottom of the page.
Licensing#
This software is licensed under the BSD license. This means you can do what you like with it, including distributing it with your own software licensed under different terms. The only restriction is that you attribute us for our work, and reproduce our copyright:
Copyright (c) 2014, Inferno Embedded
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of New Millennium Networking, Inferno Embedded nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MAKE, HACK, VOID BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Whats Implemented#
- Digital I/O
- Timers
- Serial (both busy-waiting and asynchronous)
- External Interrupts
- PinChange Interrupts
- Servo control
- Analogue to digital
- Hardware PWM
- Gamma correction - calculate on the fly, or lookup tables (recommended)
- Fast synchronous serial shifter
- Software H Bridge for driving naked transistors (with PWM support)
- Realtime Clock & event triggering
- Debouncing (detect button presses, as well as held buttons)
- Software PWM Matrix (for passive LED matrices)
- HT1632 based LED matrix displays such as the Sure Electronics DE-DP105 (search for 0832 led matrix on Ebay)
- HD44780 & compatible LCD character displays
- Software controlled voltage regulator
- EEPROM
- Power Saving (via AVR LibC)
- PID algorithm
- Voltage Regulator (buck/boost controller)
- USB Keyboard emulation (via V-USB)
Todo#
- Optimise servo library
- Input Capture for timers
- SPI
- Full functionality of the Arduino runtime
Contributing#
Send patches, bugs or suggestions to our bug tracker.
Join the Flame Support & Development mailing list.
Summary Driver a stepper motor back and forth.
Code #define MHVLIB_NEED_PURE_VIRTUAL // Bring in the MHV IO header #include <MHV_io.h> // Bring in the Stepper driver #include <MHV_StepperMotorUnipolar.h> // Bring in the realtime clock driver #include <MHV_RTC.h> // Bring in the power management header #include <avr/power.h> #include <avr/sleep.h> // Bring in the timer header #include <MHV_Timer8.h> // Program space header, saves RAM by storing constants in flash #include <avr/pgmspace.h> #if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) #define ATTINY // A timer we will use to tick the RTC MHV_Timer8 tickTimer(MHV_TIMER8_0); MHV_TIMER_ASSIGN_1INTERRUPT(tickTimer, MHV_TIMER0_INTERRUPTS); #else // A timer we will use to tick the RTC MHV_Timer8 tickTimer(MHV_TIMER8_2); MHV_TIMER_ASSIGN_1INTERRUPT(tickTimer, MHV_TIMER2_INTERRUPTS); #endif #define ALARM_COUNT 4 // The RTC object we will use MHV_RTC_CREATE (rtc, ALARM_COUNT); // A timer trigger that will tick the RTC void rtcTrigger(void *data) { rtc.tick1ms(); } /* We have a hard limit of 1000 steps/second due to the 1ms resolution of the RTC class * The motor & control circuitry have a lower limit due to their electrical & mechanical properties */ #define MAX_SPEED 500 #define MIN_SPEED 100 /* The steps per rotation * For the 28BYJ48 geared stepper, this is 32 steps multiplied by a gear ratio of 64, * multiplied by 2 since we are half stepping */ #define STEPS_PER_ROTATION (2*32*64) /* The stepper driver * Available modes are WAVE, FULL and HALF */ MHV_StepperMotorUnipolar stepper(rtc, MHV_STEPPER_MODE_HALF, MHV_PIN_B0); /* A class that tells the stepper what to do next * Note that moveComplete() is called every time the stepper driver has completed a move */ class StepperInstructions : public MHV_StepperListener { private: bool _forward; // The direction we are currently rotating float _speed; // The rotation speed (steps/second) bool _speedUp; // True if we are increasing speed, false otherwise public: StepperInstructions(); void moveComplete(int32_t position); }; StepperInstructions::StepperInstructions() : _forward(true), _speed(1), _speedUp(true) {} void StepperInstructions::moveComplete(int32_t position) { _forward = !_forward; _speed += (_speedUp) ? 100 : -100; if (_speed > MAX_SPEED) { _speed = MAX_SPEED; _speedUp = false; } else if (_speed < MIN_SPEED) { _speed = MIN_SPEED; _speedUp = true; } int32_t newPosition = (_forward) ? 1 * STEPS_PER_ROTATION : 0; stepper.rotate(_forward, _speed, newPosition); } StepperInstructions stepperInstructions; int NORETURN main(void) { // Disable all peripherals and enable just what we need power_all_disable(); #ifdef ATTINY power_timer0_enable(); #define PRESCALER MHV_TIMER_PRESCALER_5_64 #else power_timer2_enable(); #define PRESCALER MHV_TIMER_PRESCALER_7_64 #endif set_sleep_mode(SLEEP_MODE_IDLE); // Register the listener with the stepper driver to be notified when moves are complete stepper.registerListener(stepperInstructions); // Configure the tick timer to tick every 1ms (at 16MHz) tickTimer.setPeriods(PRESCALER, 249, 0); tickTimer.setTriggers(rtcTrigger, 0, 0, 0); tickTimer.enable(); sei(); /* Start with a forward rotation of 1 revolution at 100 steps/second * Further instructions will be triggered from StepperInstructions::moveComplete */ stepper.rotate(true, 100, 1 * STEPS_PER_ROTATION); for (;;) { /* All the interesting things happen in events */ rtc.handleEvents(); // Sleep until an interrupt occurs sleep_mode(); } UNREACHABLE; } Hardware To complete this tutorial, you need a unipolar stepper motor and 4 N channel MOSFETs with internal bypass diodes.
...
Summary Blink an LED connected to Arduino pin 13.
Code // Bring in the MHV IO header #include <MHV_io.h> // Bring in the AVR delay header (needed for _delay_ms) #include <util/delay.h> #include <avr/power.h> int main() { // Disable all peripherals and enable just what we need power_all_disable(); // Enable output on pin 13 of the Arduino - this normally has an LED connected mhv_setOutput(MHV_ARDUINO_PIN_13); while (true) { // Turn off the LED mhv_pinOff(MHV_ARDUINO_PIN_13); // Sleep for 1/3 sec _delay_ms(333); // Turn on the LED mhv_pinOn(MHV_ARDUINO_PIN_13); // Sleep for 1/3 sec _delay_ms(333); } // Main must return an int, even though we never get here return 0; } How it works Line 2 The MHV_io.h header contains basic I/O functionality for MHVLib. It is needed for mhv_setOutput(), mhv_pinOff() and mhv_pinOn().
...
The Flame Runtime can be built from the command line using GNU make.
Getting a Toolchain To do so, you should have an AVR toolchain installed. Windows, Linux & MacOSX users are encouraged to use Inferno Embedded AVR Tools, as this is the toolchain Flame is tested with.
Preparing to Build After cloning the git repository (or extracting the release archive), edit the env script in the top level of the package, and configure it to suit your installation. As shipped, it expects the AVR toolchain to be in /usr/local/mhvavrtools, and will add this to the path.
...
Use object references instead of pointers where applicable Add WS2801 LED driver & RGB pixel types Add Unipolar stepper motor driver Ensure all tutorials use NORETURN/UNREACHABLE Downloads mhvlib-20111227.7z (532.9 KB)
Add VUSB console, allows text output from V-USB devices (such as the MHVBoard) over USB. Requires Paul Stoffregen’s HID Listen program to receive the output. Extended Device_TX with new methods that utilise dynamic memory: printf(), and write(Xint(8|16|32)_t). The following classes inherit from Device_TX and will be able to use the new methods: MHV_Display* (all display classes) MHV_HardwareSerial (serial port driver) MHV_VusbConsole (USB console mentioned above) MHV_VusbTypist (USB Keyboard driver with Device_TX support) Downloads mhvlib-20111109.7z (1.14 MB)
Add Doxygen documentation Address Doxygen warnings Minor optimisations (flash usage in RTC class) New Class: MHV-VusbTypist - allows strings to be sent to an emulated USB keyboard Downloads mhvlib-20111011.7z (1.15 MB)
Illustrate AVR LibC power saving in all tutorials Add new event driven classes: PinChangeManager and ADC Add event functionality to Device_RX and RTC Port Arduino PID class to MHVlib Downloads mhvlib-20110929.7z (112.2 KB)
Bug fixes Added HD44780 via Shift Register driver Added Voltage Regulator Added EEPROM support Downloads mhvlib-20110920.7z (106.9 KB)
Add HD44780 support Downloads mhvlib-20110110.7z (67.1 KB)
Relocate async writing from HardwareSerial to Device_TX. HardwareSerial & Display_Monochrome implement this, and all subclasses now support async text support.
Heads up!
As a result of the above change, the asyncWrite() calls to HardwareSerial are no longer supported, and instead are replaced by write() calls inherited from Device_TX.
Downloads mhvlib-20101231.7z (62.5 KB)