Subtitute for function pulseIn

I i have a problem the sketch that i have for my arduino have one function called pulseIn and the Bluid from spark doesn’t recognize, anyone know how to replace the function ?

thanks for the help

Hi @halext! Would you please post your code that you have now, and explain your need for pulseIn() so we can try to determine a suitable alternative?

int trigPin = D6;
int echoPin = D7;
int led = D1;
int led2 = D0;

void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(led, OUTPUT);
pinMode(led2, OUTPUT);
}

void loop() {
long duration, distance;
digitalWrite(trigPin, LOW); // Added this line
delayMicroseconds(2); // Added this line
digitalWrite(trigPin, HIGH);
// delayMicroseconds(1000); - Removed this line
delayMicroseconds(10); // Added this line
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration/2) / 29.1;
if (distance < 20) { // This is where the LED On/Off happens
digitalWrite(led,HIGH); // When the Red condition is met, the Green LED should turn off
digitalWrite(led2,LOW);
}
else {
digitalWrite(led,LOW);
digitalWrite(led2,HIGH);
}
if (distance >= 200 || distance <= 0){
Serial.println(“Out of range”);
Serial.print(distance);
}
else {
Serial.print(distance);
Serial.println(" cm");
}
delay(500);
}strong text

@halext thanks. Well it looks like you are trying to get an ultrasonic range finder working.

pulseIn() would be the best thing because it gives you the a result in microseconds which is what you need.

Without that I was thinking we could set up an attachInterrupt() function for rising and falling edge and save a snapshot of the micros() timer. However, micros() is not implmented yet, and not even delays and millis() are not functioning in interrupt routines anyway.

I don’t know when these things will be added to the Spark library, but they are definitely needed so I’m sure they are on the list to do!

Yes i’m trying to use the ultrasonic to power up a LED wen someone passes in the hall :smile:

There are several thinks that the Spark library needs, you don’t know if they have a road map do development ?

thanks for the help

1 Like

I’m interested in the pulseIn() function too - I was thinking of using interrupts as well, but hadn’t gotten around to trying it out. I’m guessing I wouldn’t have gotten far based on @Bdub’s comment though.

In short, I’m adding myself to the list of people who’d like to see pulseIn() on the roadmap!

I’ve got a couple of ultrasonic rangefinders I just pulled out last night to play with. Let me see what I can come up with tonight! @BDub if you come up with any clever ideas in the mean time, send me a PM!

1 Like

Okay, I’ve made a little headway on an SR04 library for the Core, though I’ve got to say, better delay() support has has has has has to be a priority for the Spark Team in the near future. Is this on anyone in particular’s Sprint?

I keep thinking, we’re hacking the hell out of things with asm NOP calls, but maybe my time would be better spent just getting the underlying features implemented. The big issue I see is with all the crazy multithreading changes being made by the Team and how that would ultimately affect any implementation I try to come up with.

Okay, so I’ve got this ultrasonic rangefinder working using clever use of while loops and the micros() function. Proof of concept is done, I’ve got the 10uS pulse for triggering the sensor implemented in a single line of code. Reading the echo pulse back is implemented in about 6 lines, but it’s very dirty so I expect that to increase. Right now I’m doing this all in a void loop run, but I today I’ll break it all out into a standalone blocking function.

Ideally this wouldn’t block but I’ve really got no way around that right now, unfortunately. Anyway, I’ll get some code out this afternoon and we’ll go from there!

I took some pictures, but forgot to add it to the previous post. Oh well!

The wind has been blowing so hard and cold around here, it's just too drafty to work in my upstairs lab the last few weeks, so I've been "slumming it" in a recliner by the fire downstairs! :smiley:

Working with a 10+ year old SRF04 (on breadboard with Spark Core) and a more recent HC-SR04 (sitting on breadboard in foreground). Surprisingly the older unit well outperforms the newer one!

Bonus picture of Dogwaffles guarding my box of embedded toys! I've got just about one of everything in there, but always need more!

1 Like

When you say “better delay() support”, do you mean the whole blocking issue?

Currently our embedded team is focused primarily on two things: fixing CFOD and fixing non-responsiveness due to blocking code. Both are pretty heavy-duty tasks that relate to some nasties with the CC3000 drivers, and so until they are resolved, we’re not able to make much progress on other embedded topics. However we’re eager for pull requests, and if there are particular things you might consider helping out with, just mention them here on the community and we can help make sure they don’t conflict with the things the team is working on.

I think he means the micros() function which wasn’t implemented yet, and sounds like he has implemented one, using assembly code?

@timb I definitely agree we need to start helping out implementing some of these things like micros() and pulseIn() and fixing the polled Serial1 and allowing visibility to millis() and micros() in ISR created with attachInterrupt() and… those are kinds of the big ones, what else am I missing?

Actually, micros() is working just fine! Not sure when they implemented it on the live server, but it’s there!

#core-firmware/src/spark_wiring.cpp

 /*
 * @brief Should return the number of microseconds since the processor started up.
 */
unsigned long micros(void)
{
        return (DWT->CYCCNT / US_TICKS);
}

But yeah, @BDub has it right. I guess I meant bringing the basics (Wiring) up to parity with Arduino. I realize this isn’t an easy thing to do and I’m not trying to downplay what the Team has already accomplished, don’t get me wrong!

So instead of hacking together a function just to get these Ultrasonic Sensors or say NeoPixels working, we should really start spending our time putting together the underlying tools that will allow the rest of the community to easily run or modify existing Arduino code.

With that said, I’m going to get pulseIn() working and build a function for these SR04 Ultrasonic Sensors on top of that! I can easily adapt the existing code I came up with last night to the broader pulseIn feature. Hopefully I’ll have this done in a few hours. :smile:

2 Likes

Sounds awesome - pull requests more than welcome!

Professor Farnsworth: Good news everyone!

I've got pulseIn functioning very efficiently and without the use of interrupts! Basically, my last step is to time the while loop that reads the pin state after transition. Once I figure out how many clock cycles it takes to run that loop I can calculate precisely how long the pulse is, down to roughly one microsecond!

This method will work perfectly so long as the Spark Core is only ever running a single thread. If the Spark Team splits the Core and User loops into two separate processes this method very well may stop working. That said, I think by that time I'll have some other functions implemented that will let me rework pulseIn with little to no issues.

More soon!

Okay, so here’s an early version of pulseIn. Right now I’m just using digitalRead but I’ll be replacing that with some code that directly reads from the port state register this evening. Once I do that we can get much better precision; I wanted to start with existing system calls for simplicity.

I’ve also got to add some math to support custom timeouts. Currently, this function will wait for 10 seconds before aborting. I’ll also use my function generator and scope to do some more precise measurments of the loop timing.

Keep in mind this is code isn’t suitable for production use! This is only meant as a preview, please check this thread tomorrow as I’ll have a Github repository up that you can follow. :smiley:

unsigned long pulseIn(uint8_t pin, uint8_t state) {
    
    unsigned long pulseWidth = 0;
    unsigned long loopCount = 0;
    unsigned long loopMax = 5000000;
    
    // While the pin is *not* in the target state we make sure the timeout hasn't been reached.
    while ((digitalRead(pin)) != state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
    }
    
    // When the pin *is* in the target state we bump the counter while still keeping track of the timeout.
    while ((digitalRead(pin)) == state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
        pulseWidth++;
    }
    
    // Return the pulse time in microsecond!
    return pulseWidth * 2.36; // Calculated the pulseWidth++ loop to be about 2.36uS in length.
}

And here’s an entire sketch that triggers an Ultrasonic Sensor then prints the number of pings, echo pulse time and distance in inches and centimeters to a Digole I2C Display. I’m sure you can see how to easily modify this to fit your needs. Note: Inches doesn’t return a floating point value when called from a print statement. I need to add some maths to make that happen.

int trigger = D2;
int echo = D3;
int ping = 0;
unsigned long triggerTarget;


void setup() {
    pinMode(trigger, OUTPUT);
    pinMode(echo, INPUT);
    digitalWrite(trigger, LOW);
    Wire.begin();
}

void loop() {
    
    // Pull the trigger pin high for roughly 10uS then pull it low and wait another 10uS.
    triggerTarget = micros();
    while (micros() < triggerTarget + 10) {
        digitalWrite(trigger, HIGH);
    }
    while (micros() < triggerTarget + 20) {
        digitalWrite(trigger, LOW);
    }
    
    // Read the return echo then convert it to in and cm.
    unsigned long sonar = pulseIn(echo, HIGH);
    float in = sonar / 148;
    int cm = sonar / 58;
   
    // Output the readings to a Digole I2C Display.
    Wire.beginTransmission(0x4E);
    Wire.print("CL");
    Wire.print("TT");
    Wire.print("Ping: ");
    Wire.print(ping);
    Wire.write(0x00);
    Wire.print("TRT");
    Wire.print("TT");
    Wire.print("Echo: ");
    Wire.print(sonar);
    Wire.print("uS");
    Wire.write(0x00);
    Wire.endTransmission();
    delay(25);
    Wire.beginTransmission(0x4E);
    Wire.print("TRT");
    Wire.print("TT");
    Wire.print(in);
    Wire.print("in / ");
    Wire.print(cm);
    Wire.print("cm");
    Wire.write(0x00);
    Wire.endTransmission();
    
    // Bump the ping counter.
    ping++;
    
    // Wait one second.
    delay(1000);
}

unsigned long pulseIn(uint8_t pin, uint8_t state) {
    
    unsigned long pulseWidth = 0;
    unsigned long loopCount = 0;
    unsigned long loopMax = 5000000;
    
    // While the pin is *not* in the target state we make sure the timeout hasn't been reached.
    while ((digitalRead(pin)) != state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
    }
    
    // When the pin *is* in the target state we bump the counter while still keeping track of the timeout.
    while ((digitalRead(pin)) == state) {
        if (loopCount++ == loopMax) {
            return 0;
        }
        pulseWidth++;
    }
    
    // Return the pulse time in microsecond!
    return pulseWidth * 2.36; // Calculated the pulseWidth++ loop to be about 2.36uS in length.
}
1 Like

Looks great @timb! May I suggest the following for a more accurate 10us pulse?

triggerTarget = micros();
PIN_MAP[trigger].gpio_peripheral->BSRR = PIN_MAP[trigger].gpio_pin; // HIGH
while (micros() < triggerTarget + 10) {
    PIN_MAP[trigger].gpio_peripheral->BRR = PIN_MAP[trigger].gpio_pin; // LOW after 10us
}

Yeah, I was planning on doing something similar to that, however I’m not sure it’s worth it in this case since you’re bypassing all the safety checks. Thoughts?

In my testing the “10uS” pulse via my digitalRead method was actually around 11uS to 14uS, which isn’t a big deal as these ultrasonic sensors will actually take up to a 50uS pulse without issue! Also, the reason I looped low for an additional 10uS was to add some buffer room as the trigger pulse tends to ring back through the echo pin briefly and I didn’t want that triggering pulseIn.

Speaking of which… I’ve created a separate thread for my pulseIn function! New release with a huge boost in precision, speed and stability! I’ve already got a small list of changes that need to be made, but I think it’s pretty spiffy so far. :smiley:

It's plenty safe, as long as the pin you are controlling is an output.

[quote="timb, post:18, topic:2097"]
In my testing the "10uS" pulse via my digitalRead method was actually around 11uS to 14uS, which isn't a big deal as these ultrasonic sensors will actually take up to a 50uS pulse without issue![/quote]

Hmm, this is why I need to get one of those sensors... I thought you got to control the duration of the output ping... in that case:

digitalWrite(trigger, HIGH); // takes 2us
delayMicroseconds(8);
digitalWrite(trigger, LOW); // takes 2us
delayMicroseconds(8);

Nah, you just raise the trigger for at least 10uS and it sends an 8 cycle ultrasonic burst at 40kHz. The echo pin is then raised for a period in proportion to the time it took said burst to bounce back. If you look at the actual circuit on the modules, it's surprisingly simple. They're just using some simple logic and a MAX232 chip to convert it to a TTL output! Here's a short datasheet explaining the operation.

I had problems getting delayMicroseconds working, which is why I went with the while loop instead. :smile: