chipKIT® Development Platform

Inspired by Arduino™

pulseIn

Created Sun, 24 Jul 2011 14:49:51 +0000 by boutboutnico


boutboutnico

Sun, 24 Jul 2011 14:49:51 +0000

Hi all,

I have a ultrasonic sensor SRF05 that I am trying to make it work. It is needs an output pulse trigger (10ms) and it send an input echo (100us to 25ms) then with this echo I can convert it into a distance (us/58=cm).

So first I tried that :

unsigned long SRF05::getDistance(){

	unsigned long duration;

	// Make sure pin is low before sending a short high to trigger ranging
	pinMode(_pin, OUTPUT);
	digitalWrite(_pin, LOW);           
	delayMicroseconds(2);

	// Send a short 10 microsecond high burst on pin to start ranging
	digitalWrite(_pin, HIGH);          
	delayMicroseconds(10);
	digitalWrite(_pin, LOW);

	pinMode(_pin, INPUT);
	duration = pulseIn(_pin, HIGH/*, TIMEOUT*/);	// Reads echo pulse in from SRF05 in micro seconds
	return duration / 58.0;           			// Dividing this by 58 gives us a distance in cm
}

I suppose the trigger part function but I suspect the pulseIn function is not working for max32. Does anyone know ? If yes, where did you find the answer?

So then I tried to use the Input Compare module of the PIC32MX. So IC1/RD8 is on the pin 68 of the PIC but on the max32 board this is connected to a signal call FM0IO and disappear (by the way, the find function of the PDF is blocked).

Thanks for your help.


dangeljs

Sun, 24 Jul 2011 15:34:29 +0000

Check out this link:

http://chipkit.org/forum/viewtopic.php?f=19&t=137

RD8 is on the bottom header of the Max32.

edit: I looked at the pulsein() function and I wonder if this works for pins that are bit numbers less than 8 of the associated port. I question it because they only alloted 8 bits for the bit mask when there should be 16 bits (for bits 15-0).


Mark

Mon, 25 Jul 2011 22:02:09 +0000

I looked at the pulsein() function and I wonder if this works for pins that are bit numbers less than 8 of the associated port.

You are right, it wont work for bits 8-15. I will get it fixed.

Mark


dangeljs

Tue, 26 Jul 2011 17:54:13 +0000

Thanks for the confirmation.


whoover

Sat, 30 Jul 2011 18:48:36 +0000

Yeah, I see this as well. I'm using a 38kHz IR receiver on pin 2 and it's always returning zero. I moved it to pin 38 on a uno32 and I'm now getting values, but they are much higher than they are on an uno. Are there any known issues with this?


dangeljs

Sat, 30 Jul 2011 20:06:02 +0000

It is possible that the number of clock cycles for the uno aren't the same for uno32 given architectural differences of 8-bit processor and 32-bit. Below is the a note from the wiring_pulse.c file:

// convert the reading to microseconds. The loop has been determined
	// to be 20 clock cycles long and have about 16 clocks between the edge
	// and the start of the loop. There will be some error introduced by
	// the interrupt handlers.
	return clockCyclesToMicroseconds(width * 21 + 16);

and the width is calculated in this loop:

// wait for the pulse to stop
	while ((*portInputRegister(port) & bit) == stateMask) {
		if (numloops++ == maxloops)
			return 0;
		width++;
	}

I'll try to enter an issue on the github site to see if this can be fixed/checked.


EmbeddedMan

Sat, 30 Jul 2011 21:47:17 +0000

I guarentee that the number of operations per second is very different between the 8-bit AVR and the PIC32. Also, you probably don't want to count cycles on the PIC32. Why not use the microsecond clock? (It works really well.)

*Brian


dangeljs

Sat, 30 Jul 2011 22:16:29 +0000

This is a library function that is distributed with the MPIDE (not my code) and I wasn't sure if the calculations were already modified for chipkit.

By microsecond clock are you refering to using micros()? I may modify my library to just that, but I'm not sure if the developers (diligent, etc) will implement it this way. If anything I'll just have to put my version in each time they distribute newer versions.

Thanks for the idea.


whoover

Sun, 31 Jul 2011 18:12:42 +0000

There is another issue with a long pulseIn reading inside an external interrupt (or any other medium length operation). See [url]http://www.chipkit.org/forum/viewtopic.php?f=13&t=173&p=1429[/url]


dangeljs

Sun, 31 Jul 2011 19:05:18 +0000

I don't see where it would affect the interupt routine, but it doesn't strike me as the type of function that you would want to run inside of an interupt service because of inconsistant return times.


whoover

Sun, 31 Jul 2011 19:33:54 +0000

pulseIn worked very accurately/seamlessly inside an interrupt using an uno board :)

In fact, I updated the wiring_pulse.c to the following and I'm now getting comparable readings to what an uno gives (even inside an interrupt):

unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
// cache the port and bit of the pin in order to speed up the
// pulse width measuring loop and achieve finer resolution.  calling
// digitalRead() instead yields much coarser resolution.
int16_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
uint8_t stateMask = (state ? bit : 0);
unsigned long width = 0; // keep initialization out of time critical area

// convert the timeout from microseconds to a number of times through
// the initial loop; it takes 16 clock cycles per iteration.
unsigned long numloops = 0;
unsigned long maxloops = microsecondsToClockCycles(timeout) / 80; //microsecondsToClockCycles(timeout) / 16;

// wait for any previous pulse to end
while ((*portInputRegister(port) & bit) == stateMask)
    if (numloops++ == maxloops)
        return 0;

// wait for the pulse to start
while ((*portInputRegister(port) & bit) != stateMask)
    if (numloops++ == maxloops)
        return 0;

// wait for the pulse to stop
while ((*portInputRegister(port) & bit) == stateMask) {
    if (numloops++ == maxloops)
        return 0;
    width++;
}

// convert the reading to microseconds. The loop has been determined
// to be 20 clock cycles long and have about 16 clocks between the edge
// and the start of the loop. There will be some error introduced by
// the interrupt handlers.
return clockCyclesToMicroseconds(width * 10 + 80);//clockCyclesToMicroseconds(width * 21 + 16);
}

dangeljs

Sun, 31 Jul 2011 20:28:20 +0000

That's good to know, I guess the /16 had to do with the OSC frequency not a number of cycles in the loop. I've modified mine to use the micros() function and tested with a signal generator up to 31khz and it's pretty close to spot on, if your interested.

Thanks for your updates.


whoover

Sun, 31 Jul 2011 22:30:47 +0000

The micros() solution seems to have accurate results, but with the stress tests I ran, it took substantially more time to execute.

  1. "pulseIn" using the micros() solution took an average of 36542us
  2. "pulseIn" using "clockCyclesToMicroseconds" with 80 took an average of 9619us

This may be why they aren't using micros() to begin with.


dangeljs

Sun, 31 Jul 2011 22:39:35 +0000

Hmm, That would make sense. I'm actually a little dissapointed because when I tried other pins with the signal generator I was getting very different results using higher frequencies. It seems that using any pin on PORTD above bit 7 was withing a few microseconds (2-5), but when checking other pins it could be off by 20 to 30 microseconds! So my test results weren't completely accurate since it didn't hold for all pins.

Thanks again for your test results.

Edit: Could you explain how you are doing a stress test? I don't get those results. Are you testing the timeout period for if it doesn't get a pulse in time, because the library says it can measure a pulse with a width of 3 minutes, and the default time out is 1 second. Below is what I tested with while injecting a squarewave at various frequencies.


whoover

Sun, 31 Jul 2011 23:41:17 +0000

My tests may not be as comprehensive as they could be, but I was doing a similar test to what your doing in PulseInTest.pde by using micros() to time how long pulseIn took (I didn't provide a timeout as you did, but I don't think that will make a difference seeing the default is 1000000L in WProgram.h). My test used a 12 bit 38kHz signal from a universal remote control and a IR receiver on the pin that the pulseIn is being performed. Also, keep in mind that it was done inside an interrupt and called pulseIn(38, LOW). I also tried it with pin 7 and got the same results.

Maybe another test would be to use a PWM output pin and generate a signal using analogWrite and read it on another pin using a jumper from the output pin to our input pin.

btw, I added a comment to the issue you created regarding this: [url]https://github.com/chipKIT32/chipKIT32-MAX/issues/63[/url]


dangeljs

Mon, 01 Aug 2011 00:34:45 +0000

I think I understand what you did. You measured the overall process and compounding inefficient overhead and that is how you had such high numbers. I was worried that maybe your pulsein was just timing out and returning zero, and with your modifications it would have happened faster than mine. But that's not the case and you are getting valid data, right?

Also, pin seven only works when bit is declared as 16 bit type, right? I'm just trying to get a sanity check, incase my suspisions were wrong.


whoover

Mon, 01 Aug 2011 13:36:34 +0000

If you consider a repetitive 12 bit pulse "compounded overhead", then yes. I'm getting valid data for pulseIn on pin 38 regardless if bit is uint8_t or int16_t, but using pin 7 it always returns zero when using uint8_t for the bit mask and I get valid results on pin 7 when bit is int16_t. All of which coincides with your previous notion that 8-15 wont work unless bit is int16_t. The tests I performed to compare the micros() solution vs solution below used int16_t in all use cases and never returned zero.

As far as reliably valid results [color=#000080]wiring_pulse.c[/color] had to change from...

unsigned long maxloops = microsecondsToClockCycles(timeout) / [color=#FF0000]16[/color];

to...

unsigned long maxloops = microsecondsToClockCycles(timeout) / [color=#008000]80[/color];

and...

return clockCyclesToMicroseconds(width * [color=#FF0000]21[/color] + [color=#FF0000]16[/color]);

to...

return clockCyclesToMicroseconds(width * [color=#008000]10[/color] + [color=#008000]80[/color]);

along with your update to bit from...

[color=#FF0000]uint8_t[/color] bit = digitalPinToBitMask(pin);

to...

[color=#008000]int16_t[/color] bit = digitalPinToBitMask(pin);


dangeljs

Mon, 01 Aug 2011 16:54:04 +0000

Yeah, that doesn't make much sense for only 12 bits. It may have something to do with the interrupt routine, but to be 4 times longer doesn't make sense to me either. That is why I was questioning a time out since your code would time out about 5 times sooner (but it would take much longer than 36ms for mine to time out).

Anyway I did some testing with the main line code use of pulsein() (as before) using cycle counting and put it up on github as well (if you have any interest in it). I'm also using version "mpide-0022-win-20110710-test" in case your version is different (maybe something there also).

Best of luck with converting your project from arduino to chipkit.


whoover

Mon, 01 Aug 2011 23:39:25 +0000

I was using mpide-0022-chipkit-win-20110619. Tried mpide-0022-win-20110710-test and I get the same results.

Update: After a lot of testing (if you can call it that w/o the expensive test equipment) I concur that the use of micros() has more accurate results over a larger range of devices.