Real interrupt

On one of the documentation pages (http://electricimp.com/docs/api/hardware/pin/configure/) I read it was not a real interrupt, and the callback would get quened until the device again was idle.

Are there any way to do a real interrupt? I am going to read from a wind speed sensor that sends pulses depending on the wind speed, and getting the time between the pulses is important to get right.

You can’t do true interrupts.

We’ve used sensors that work in similar ways before - depending on the speed of the pulses that are sent the sampler may work (it runs in the background, so other code execution does not affect it).

So I could set it to sample at 1kHz, for 1 second, then get the times it triggered within that second and calculate wind speed, stop the sampler, clear the buffer, then start it again?

That’s the general idea (although it’s actually quite a bit simpler because of how the sampler works). You don’t need to worry about starting / stopping the sampler (unless you really want).

The sampler takes an array of buffers (blobs) and a callback as part of the constructor. It fills the buffers in the background, and whenever one is full, it triggers the callback function (which will autoclear the buffer at the end of it).

Your code would look like something like this:

`function onBufferFull(buffer, l) {
// process the buffer:
local bufferLength = l/2; // each sample is 2 bytes
for(local i = 0; i < bufferLength; i++) {
// read the value
local dataPoint = buffer.readn(‘w’);
}
}

// we’re going to create 2 buffers that each store 1sec worth of data
// (each sample is 2 bytes)
buffers <- [ blob(2000), blob(2000) ];

// configure and start the sampler (which runs in the background)
hardware.sampler.configure(hardware.pin9, 1000, buffers, onBufferFull);
hardware.sampler.start();`

If I’m understanding this right, it’s not the sampler that you need, it’s the pulse counter. That is, if the wind speed is just encoded as the pulse rate, for instance if you get one pulse per turn of a cup anemometer. If the wind speed is encoded in a more complex way, you might need to use the sampler (at much higher than the pulse rate) to look for the pulse edges in the incoming stream.

Peter

1 pulse over 1 second is 2.4 km/h wind speed.

Isn’t the pulse counter blocking all other code while it is counting?

I am not sure this would work either… If the pulses are more than 1 second between them, I would not be able to calculate the speed.

Maybe the solution would be to have an attiny85 in a smd package on the board to handle those pulses, and send the result over i2c to the Imp?

The sampler is all hardware, and it should never miss a sample - that means you should be able to count the number of samples between pulses (and even between buffers). Something like this…

`pulseLength <- 0;

function onBufferFull(buffer, length) {
// process the buffer:
local bufferLength = l/2; // each sample is 2 bytes
for(local i = 0; i < bufferLength; i++) {
pulseLength++;
// read the value
local dataPoint = buffer.readn(‘w’);
if (dataPoint > THRESH) {
local windSpeed = pulseLength / 1000.0 * 2.4; // in KPH
// do something with windSpeed??
// …

        // reset pulseLength
        pulseLength = 0;
    }
}

}`

Ah sorry yes, I did misunderstand a bit. If the pulse rate is pretty slow – tens or a few hundreds per second – then the sampler at 1kHz will be just the job, yes.

Peter

A wind speed of 118 km/h should be around 49 pulses per second. And I doubt it will ever get that high.

But I am not sure I understand how I would be able to calculate speed if there are longer between pulses than the length of the sample.

I tried to mess around with this code a bit while waiting for the sensors to arrive, but I think I don’t understand what is going on…

`pulseLength <- 0;

function onBufferFull(buffer, length)
{
local THRESH = 0;
// process the buffer:
local bufferLength = length/2; // each sample is 2 bytes
local windSpeed;

for(local i = 0; i < bufferLength; i++)
{
pulseLength++;
// read the value
local dataPoint = buffer.readn(‘w’);
if (dataPoint > THRESH)
{
windSpeed = pulseLength / 1000.0 * 2.4; // in KPH
// do something with windSpeed??
// …

  // reset pulseLength
  //
  pulseLength = 0;
}

}

server.log("Wind speed: " + windSpeed);
}

buffers <- [ blob(2000), blob(2000) ];

// configure and start the sampler (which runs in the background)
hardware.sampler.configure(hardware.pin1, 1000, buffers, onBufferFull);
hardware.sampler.start();`

I use this code, and got a 10k resistor from pin1 to gnd to pull it down to gnd.

The output I get is
2014-08-28 15:33:51 UTC+2 [Device] Wind speed: 0.0024 2014-08-28 15:33:52 UTC+2 [Device] Wind speed: 0.012 2014-08-28 15:33:53 UTC+2 [Device] Wind speed: 0.012 2014-08-28 15:33:54 UTC+2 [Device] Wind speed: 0.0048 2014-08-28 15:33:55 UTC+2 [Device] Wind speed: 0.0024 2014-08-28 15:33:56 UTC+2 [Device] Wind speed: 0.0072 2014-08-28 15:33:57 UTC+2 [Device] Wind speed: 0.0024 2014-08-28 15:33:58 UTC+2 [Device] Wind speed: 0.0048
and I expected it to just be 0.

Am I totally missing what this actually is?

This is pretty neat code - let’s go through it!

The sampler is constantly running in the background collecting data and storing it in the buffers. Each time one of the buffers is full, it gets passed to the onBufferFull callback (where we process it), and the sampler starts filling up the next one.

We’re collecting 1000 samples a second (and each sample is 2 byte) - so each buffer represents 1 second of data.

Let’s look at onBufferFull - since this is where the magic happens! The onBufferFull function is essentially looking for pulses - and it does it quite naively. We loop through each sample, and check whether it’s above a certain threshold. If it is, we consider it the start of a new pulse, and look at how long it’s been since the last pulse (using the global pulseLength counter).

Each time we find a pulse, we’re able to calculate the windspeed by checking time time between pulses and doing that magic math you mentioned above (1 pulse / second = 2.4 KPH).

Hopefully that makes sense?

I just realized I gave you some goofy code, as it doesn’t care about what the current state of the pin is (HIGH / LOW) - this might work a bit better (although it’s difficult to say without looking at the datasheet)… either way, should be good starter code.

`// Threshold values to consider a high/low transition
// You may want to / need to change these:
// 65535 * 0.8
const HIGH_THRESH = 39321;
// 65535 * .4
const LOW_THRESH = 26214;

// Variables to track pulse lengths
pulseLength <- 0;
pulseHigh <- false;

function onBufferFull(buffer, length)
{
// process the buffer:
local bufferLength = length/2; // each sample is 2 bytes
local windSpeed;

for(local i = 0; i < bufferLength; i++)
{
pulseLength++;
// read the value
local dataPoint = buffer.readn(‘w’);

if (pulseHigh == false) {
  // if last sample was LOW
  if (dataPoint >= HIGH_THRESH)
  {
    // and we've transitioned to high..

    // calculate the wind speed
    windSpeed = pulseLength / 1000.0 * 2.4;  // in KPH
    // do something with windSpeed??
    // ...

    // set the pulseHigh variable
    pulseHigh = true;
    // reset the pulse counter
    pulseCounter = 0;
  }
} else {
    // if the last pulse was high
    if (dataPoint <= LOW_THRESH) {
        // if we transitioned from high to low ... 
        // set the pulseHigh variable
        pulseHigh = false;
    }
}

server.log("Wind speed: " + windSpeed);
}

buffers <- [ blob(2000), blob(2000) ];

// configure and start the sampler (which runs in the background)
hardware.sampler.configure(hardware.pin1, 1000, buffers, onBufferFull);
hardware.sampler.start();`

Cool, think I understand it now! :slight_smile:

And if I want to make it so 4 seconds without a pulse is 0 m/s, I guess I can just make it check if pulseLength is >= 40000 and then set windSpeed to 0?

With the sampler, is it possible to use the internal pullup or do I have to add an external?

Sounds like you’ve got the idea - that’s how you would check/reset at 4 seconds.

You cannot use the internal pullups/downs with the sampler (the sampler is actually designed for analog input, and we’re basically doing a manual analog -> digital conversion on each sample).

Okay, the easiest for me to do is to put a pull up on, so moving the calculating code from one part to the other should do the trick.

Still haven’t decided on which clamps to use for the relay connections. But the rest of the board is starting to look like something. :slight_smile:

I finally got the package with the weather sensors in, and started testing the code, but there are things I don’t understand.

The datasheet says 1 pulse/sec = 2.4 km/h wind speed. But when I put the code in it say the wind speed is around 1.1 - 1.4 km/h. To check how many pulses came through I tried to attach my Extech multimeter and set it to measure Hz, and it returned around 5-6 Hz, should that not give something around 12-14.4 km/h wind speed?

This is the modified version of the code I use. To pull it HIGH I use a 10k resistor between pin 2 and 3v3.
`// Threshold values to consider a high/low transition
// You may want to / need to change these:
// 65535 * 0.8
const HIGH_THRESH = 39321;
// 65535 * .4
const LOW_THRESH = 26214;

// Variables to track pulse lengths
pulseLength <- 0;
pulseLow <- false;

function onBufferFull(buffer, length)
{
// process the buffer:
local bufferLength = length/2; // each sample is 2 bytes
local windSpeed;

for(local i = 0; i < bufferLength; i++)
{
pulseLength++;

// read the value
local dataPoint = buffer.readn('w');

if (pulseLow == true)
{
  // if the last pulse was HIGH
  if (dataPoint >= HIGH_THRESH)
  {
    // if we transitioned from high to low ... 
    // set the pulseLow variable
    pulseLow = false;
  }
}
else
{
  // if last sample was LOW
  if (dataPoint <= LOW_THRESH)
  {
    
    
    // and we've transitioned to high..

    // calculate the wind speed
    windSpeed = pulseLength / 1000.0 * 2.4;  // in KPH
    // do something with windSpeed??
    // ...

    // set the pulseHigh variable
    pulseLow = true;
    // reset the pulse counter
    pulseLength = 0;
  }
}

}

agent.send(“windSpeed”, windSpeed);
}

buffers <- [ blob(2000), blob(2000) ];

// configure and start the sampler (which runs in the background)
hardware.sampler.configure(hardware.pin2, 1000, buffers, onBufferFull);
hardware.sampler.start();`

And the values from high/low is from around 65407 when high to 0-100 when pulled low.

Anything that looks wrong here?

Yeah, I completely messed it up I think. When the speed of the pulses go down, the calculated speed goes up… Bah :expressionless:

A couple of things:

  • The pulse length is not important, I believe. What you are looking for is the time between two rising edges, which tells you the cycle time (high time + low time). If it’s one pulse per second, this will be 1000, whereas depending on the duty cycle, your pulse length count could be anything from 1-1000 (eg for a 1ms high pulse once per second).

  • You are then wanting to turn this into a frequency, so you need to take the reciprocal, ie (1000/cyclelen) * 2.4. As the cycles get shorter, the multiplier goes up. Two pulses per second would be a cyclelen of 500, and show 4.8km/h