Good point about measure and compare. It's also a lot closer to my heart as an experimental biologist =)
Here's a tidbit I've tested (along with some specific measurements):
You can write digital output to Maple's pins *twice as fast* if you use
gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
instead of
digitalWrite(Pin, HIGH);
(Example code below)
The means measured in my setup were:
0.23 us per execution of gpio_write
0.57 us per execution of digitalWrite
Here's how I did it:
Using Maple Mini rev2, I wrote a generic sketch that measures and returns the average time to execute a block of code (albeit at the expense of information about variance):
double CycleDurationSum = 0;
unsigned int MeasurementStartTime = 0;
unsigned int MeasurementEndTime = 0;
void setup() {
}
void loop(){
CycleDurationSum = 0;
for(int CycleIndex = 0; CycleIndex < 100000; CycleIndex++){
MeasurementStartTime = micros();
// -----------------Lines of code being measured------------------
//---------------------------------------------------------------
MeasurementEndTime = micros();
CycleDurationSum = CycleDurationSum + (MeasurementEndTime - MeasurementStartTime);
}
CycleDurationSum = CycleDurationSum/100000;
SerialUSB.println(CycleDurationSum);
}
With nothing in the space between the "Lines of code being measured" comments, the average cycle duration is 0.94us. I subtracted 0.94us from any measurements made with code in that space. (Since micros() returns a minimum value of 1 or else 0, this is probably an overestimate... but since it rounded up to 1us 94% of the time, the true value ought to be between 0.5us and 1us) so I made sure the number of repetitions of the code of interest was large enough to cause a large increase in the total time measured with respect to 1us, allowing for meaningful comparison between two conditions)
For the digital write measurements I cited above, I used the code modified as follows, and uncommenting the 30 "digital write" lines to be measured:
#include <stdio.h>
#include <gpio.h>
#define PIN_PORT GPIOB
byte Pin = 16;
byte PinIndexOnPortB = 6;
double CycleDurationSum = 0;
unsigned int MeasurementStartTime = 0;
unsigned int MeasurementEndTime = 0;
void setup() {
pinMode(Pin, OUTPUT);
}
void loop(){
CycleDurationSum = 0;
for(int CycleIndex = 0; CycleIndex < 100000; CycleIndex++){
MeasurementStartTime = micros();
// -----------------Lines of code being measured------------------
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
digitalWrite(Pin, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
// gpio_write_bit(PIN_PORT, PinIndexOnPortB, HIGH);
//---------------------------------------------------------------
MeasurementEndTime = micros();
CycleDurationSum = CycleDurationSum + (MeasurementEndTime - MeasurementStartTime);
}
CycleDurationSum = CycleDurationSum/100000;
SerialUSB.println(CycleDurationSum);
}
For gpio_write_bit, the system returned 7.97us.
7.97us - 0.94us (empty loop) = 7.03us.
7.03us/30 (repetitions of the line) = 0.23us
For digitalWrite, the system returned 17.90us.
17.90us - 0.94us (empty loop) = 16.96us.
16.96us/30 (repetitions of the line) = 0.57us.
For those of you who are new to gpio_write_bit, the basic concept is to use Maple's Master Pin Map ( http://leaflabs.com/docs/hardware/maple.html#master-pin-map ) to address lines by their GPIO address(Column 2 in the table) instead of their pin number (Column 1). Each pin has a port address (usually letters A-D) and an index within that port (i.e. pin 39 on the maple is also pin PA13 = Port A, Pin 13.) To use gpio_write_bit, you need to add:
#include <stdio.h>
#include <gpio.h>
and for each pin port you plan to use, add
#define PIN_PORT_A GPIOA . . .
#define PIN_PORT_X GPIOX
Some threads touching on this already exist in the forum:
http://forums.leaflabs.com/topic.php?id=1107#post-6827
http://forums.leaflabs.com/topic.php?id=517#post-2644
It seems there are even faster ways to manipulate pins through DMA channels or direct updates... one example was given that won't compile with my Maple Mini Rev2 + Win 7:
//------------------------------------------------------
/* QuickererPin :-)
*
* Turns a GPIO pin on and off fast using direct updates.
* Copyright 2010 G Bulmer
*/
#include <gpio.h>
#include <boards.h>
int pinNumb = 13;
GPIO_Port *const port = PIN_MAP[pinNumb].port;
const int32 pinOffset = PIN_MAP[pinNumb].pin;
void setup() {
// initialize the digital pin as an output:
pinMode(pinNumb, OUTPUT); // don't bother doing this at a low-level, use the library
}
void loop()
{
while(true) { // An infinite loop, going fast (can be faster, but yeuk)
port->BSRR = 0xFFFF0000 | (1<<pinOffset);
port->BSRR = 1<<(pinOffset+16);
}
}
//--------------------------------------------------------------
This code generates the following error (I am using Maple 0.0.12):
error: expected constructor, destructor, or type conversion before '*' token
removing const* gives:
error: 'GPIO_Port' does not name a type.
(Sounds like the library is modified somehow since then?)
Anyhow, I'll post more speed tips as I figure them out.
~J