[SOLVED] pulsein (unimplemented)

thakshak
Fri May 08, 2015 7:34 am
i am trying to interface the HC-SR04 UltraSonic Distance sensor with my stm32f103c8t6 board using arduino IDE… for receiving the echo signal pulse length(time taken), pulsein method is used but pulsein is in TODO list in maple official website. so are there any alternatives for that…?

tried modifying the code but output always shows “out of range”.

*/
#define trigPin PA6
#define echoPin PA7
#define led PA4
#define led2 PB0

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

}


madias
Fri May 08, 2015 9:40 am
…just a quick think of mine: Does the utrasonic works with 3.3V instead of 5V?

RogerClark
Fri May 08, 2015 10:11 am
umm

looks like this must be something added in Arduino 1.0 API, and no one else has noticed its missing ;-)

i will get back to you shortly


RogerClark
Fri May 08, 2015 10:26 am
ok.

we need to add a function for this

This is the SAM version

/*
Copyright (c) 2011 Arduino. All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "Arduino.h"
#include "wiring_private.h"

/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
* to 3 minutes in length, but must be called at least a few dozen microseconds
* before the start of the pulse. */
extern uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t 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.
PinDescription p = g_APinDescription[pin];
uint32_t 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 22 clock cycles per iteration.
uint32_t numloops = 0;
uint32_t maxloops = microsecondsToClockCycles(timeout) / 22;

// wait for any previous pulse to end
while (PIO_Get(p.pPort, PIO_INPUT, p.ulPin) == state)
if (numloops++ == maxloops)
return 0;

// wait for the pulse to start
while (PIO_Get(p.pPort, PIO_INPUT, p.ulPin) != state)
if (numloops++ == maxloops)
return 0;

// wait for the pulse to stop
while (PIO_Get(p.pPort, PIO_INPUT, p.ulPin) == state) {
if (numloops++ == maxloops)
return 0;
width++;
}

// convert the reading to microseconds. The loop has been determined
// to be 52 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 * 52 + 16);
}


RogerClark
Fri May 08, 2015 11:30 am
Here is my first pass at pulseIn


#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
#define microsecondsToClockCycles(a) ( (a) * (F_CPU / 1000000L) )

/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
* to 3 minutes in length, but must be called at least a few dozen microseconds
* before the start of the pulse. */
uint32_t pulseIn( uint32_t pin, uint32_t state, uint32_t 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.

gpio_dev *dev=PIN_MAP[pin].gpio_device;
uint32_t bit = (1U << PIN_MAP[pin].gpio_bit);

uint32_t 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 22 clock cycles per iteration.
uint32_t numloops = 0;
uint32_t maxloops = microsecondsToClockCycles(timeout) / 22;

// wait for any previous pulse to end
while ( (dev->regs->IDR & bit) == state)
if (numloops++ == maxloops)
return 0;

// wait for the pulse to start
while ((dev->regs->IDR & bit) != state)
if (numloops++ == maxloops)
return 0;

// wait for the pulse to stop
while ((dev->regs->IDR & bit) == state) {
if (numloops++ == maxloops)
return 0;
width++;
}

// convert the reading to microseconds. The loop has been determined
// to be 52 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 * 52 + 16);
}


thakshak
Fri May 08, 2015 11:56 am
RogerClark wrote:Here is my first pass at pulseIn

I’ve not tested it, and we’d also need to look at the code dissasembly to see how many cycle it takes in each of the while loops.

The Due code has 16 cycles per while loop, the STM32 may be different,

But you may as well give it a go, and let us know if it vaguely works

I can do it properly tomorrow using the square wave generator on my scope, but I can’t do it now because its getting to late and I’ve had a hard day


thakshak
Fri May 08, 2015 11:57 am
madias wrote:…just a quick think of mine: Does the utrasonic works with 3.3V instead of 5V?

zoomx
Fri May 08, 2015 3:27 pm
madias wrote:…just a quick think of mine: Does the utrasonic works with 3.3V instead of 5V?

RogerClark
Sat May 09, 2015 2:10 am
The version of pulseIn I posted didn’t work because I misunderstood the way one of the PIO_Get function on the Due works, I’m just going to use direct gpio as it will be faster and we don’t have the PIO_Get function

But I will need to put the function in an F1 specific file, or probably just have a wrapper in wirish_digital, and then call a processor specific implementation of the low level stuff


RogerClark
Sat May 09, 2015 5:03 am
Guys

FYI

I have found what appears to be a bug in pulseIn on both AVR and SAM

I’ve done an issue on GitHub

https://github.com/arduino/Arduino/issues/3112


RogerClark
Sat May 09, 2015 5:15 am
OK

This has now been implemented.

Its a change deep in the core, so I’d recommend you just download the repo again and replace all your files


Note

I have only tested using my oscilloscope using a 1khz square wave, but I have calibrated to this.

I don’t think pulseIn is guaranteed to be that accurate on either AVR or Due, as it doesnt take into account the time for any interrupts.
But I’ve used the same base code as AVR and Due (SAM) so the implementation should give similar results to the Due

I have noticed there are at least 10 bugs logged on GitHub against pulseIn for various reasons, and I’ve logged another because the AVR and Due code doesn’t do what the API spec says it does, in terms of the timeout.

Edit

Looking on the old leaflabs site, it looks like 2 other functions are not implemented

tone(): TODO
noTone(): TODO
pulseIn(): TODO

So I guess we ( i ) need to look at how to code these. I’ll put it on my To Do list ;-)


thakshak
Sat May 09, 2015 8:34 am
RogerClark wrote:Guys

FYI

I have found what appears to be a bug in pulseIn on both AVR and SAM

I’ve done an issue on GitHub

https://github.com/arduino/Arduino/issues/3112


RogerClark
Sat May 09, 2015 9:28 am
My sensor outputs a square wave with HIGH period length equal to the time delay

Yes. You can measure this by either coding to wait for rising edge or use attach interrupt.

I posted a simple sketch however that works viewtopic.php?f=44&t=106

Porting of NewPing is a separate issue, as its AVR only and probably uses interrupts

The STM32 has some fancy features where the hardware timers can use external interrupts, however for now, I thought it was most expedient just to port the Arduino (SAM) code to STM32 for the greatest compatibility

Please feel free to write a version or NewPing etc which uses the STM32 hardware to the best of its abilities


RogerClark
Sat May 30, 2015 7:11 am
There now appears to be an assembly version for due

https://github.com/arduino/Arduino/comm … ba533d12ef

We may be able to use it


zoomx
Sat May 30, 2015 1:27 pm
* AVR+SAM: reworked pulseIn() function to become GCC agnostic
* AVR+SAM: added pulseInLong() (based on micros()) to help getting good results in interrupt-prone environments

RogerClark
Sat May 30, 2015 9:29 pm
Ok.

This is something to keep on the To Do list


Leave a Reply

Your email address will not be published. Required fields are marked *