Hmm, I get about the same result in a tight loop of analogReads … about 32.7 us per call.
In my design, I have the Spark device plugged into a board where four hall-effect sensors measure the current on an AC plug. I’d like to be able to capture each of them 1200 times/second (that’s 20 samples per AC cycle) and calculate the RMS value. For four pins, that’s 4800 samples/second, or 208 us each. So that should leave plenty of time for the processor to do math and stuff.
I have to give more thought to why I can’t get my code to work. When I time my loop, it seems to take about 5000 us per loop of four samples. There is some math involved, but I don’t think it’s killer expensive; it’s all integer and no arrays. There are four calls to an integer sqrt, but I don’t think they explain the issue.
1000 us are taken up by the delay(1), but the other 4000 are unaccounted for. The four analogReads should take ~130. I can’t take out that call to delay, either, because it seems that the whole Spark magic breaks without it.
(Note also the shift/add stuff is to compute sliding averages without having to use long circular buffers. Essentially, they implement IIR filters: y[t+1] = f*y[t] + (1-f)s[t], where is f is afraction [0,1] and s[t] is the newest sample.)
Here is my preliminary code:
#include <stdint.h>
#include <math.h>
// a fast integer sqrt I cribbed from the
// interwebz
unsigned int sqrt32(unsigned long n) {
unsigned int c = 0x8000;
unsigned int g = 0x8000;
for(;;) {
if(g*g > n) g ^= c;
c >>= 1;
if(c == 0) return g;
g |= c;
}
}
int apins[] = {A0, A1, A2, A3}; // analog pins
int cpins[] = {D0, D1, D2, D3}; // control pins
int32_t rms[4] = { 0,0,0,0 }; // hold rms results
int32_t avgs[4] = {0,0,0,0}; // hold avg results
int32_t avsqs[4] = {0,0,0,0}; // hold avg of squared results
int32_t stats[4] = {0,0,0,0}; // hold on/off status of each channel
unsigned long last;
unsigned long past = 0;
int count = 0;
// Function to be exported to Spark API to allow on/off
// control of each channel
int setOutput(String command) {
String nstring = command.substring(3);
char channels[4] = {0,0,0,0};
int action = -2;
if (nstring.length() == 4) {
action++;
for (int i=0;i<4;i++) {
channels[i] = nstring.substring(i,i+1).toInt();
}
}
if (action > -2) {
if (command.startsWith("set")) {
action = 1;
} else if (command.startsWith("clr")) {
action = 0;
}
}
if (action >= 0) {
for (int i=0;i<4;i++) {
if (channels[i]) {
digitalWrite(cpins[i],action);
stats[i] = action;
};
}
return 0;
}
return -1;
};
void setup() {
Spark.variable("irms0", &rms[0], INT);
Spark.variable("irms1", &rms[1], INT);
Spark.variable("irms2", &rms[2], INT);
Spark.variable("irms3", &rms[3], INT);
Spark.variable("stat0", &stats[0], INT);
Spark.variable("stat1", &stats[1], INT);
Spark.variable("stat2", &stats[2], INT);
Spark.variable("stat3", &stats[3], INT);
Spark.variable("period", &past, INT);
for (int i=0;i<4;i++) {
pinMode(apins[i],INPUT);
pinMode(cpins[i],OUTPUT);
digitalWrite(cpins[i],stats[i]);
}
Spark.function("go",setOutput);
last = micros();
}
void loop() {
for (int i=0;i<4;i++) {
int32_t v = analogRead(apins[i]) << 4;
// we do the average value as a simple IIR LPF.
int32_t avg = avgs[i];
int32_t navg = avg - (avg >> 7) + (v >> 7);
avgs[i] = navg;
// and we do the average f squares the same way
int32_t v2 = (v - navg) * (v - navg);
int32_t avsq = avsqs[i];
int32_t navsq = avsq - (avsq >> 7) + (v2 >> 7);
avsqs[i] = navsq;
rms[i] = sqrt((uint32_t)avsqs[i] >> 0);
}
delay(1);
uint32_t now = micros();
past = past - (past >> 3) + ((now - last) >> 3);
last = now;
count++;
}