Accurate timing and control of GPIO for Ultrasonic Sensor


#1

I’ll just preface with saying that I’m quite new to development with mangOH red and legato.

TL:DR - how to control and read GPIO pins with microsecond accuracy?

I’m trying to integrate a simple time-of-flight ultrasonic sensor into my mangOH red project with a wp7700 module onboard. The sensor needs relatively precise (microsecond scale) timing for different functions such as holding certain GPIO pins HIGH for a set amount of time or measuring the time between two GPIO interrupts.

Specifically, the sensor must hold a trigger pin HIGH for 10 us, then measure the length of an echo pulse on an echo pin which will last from 300-10000 us.
image

My approach to the 10us pulse has been to set the trigger pin HIGH, start a le_timer that has been preconfigured for 10 us timeout and then the callback handler will set the trigger LOW again after 10us. To confirm the timing, I record time (just after I set the trigger HIGH and then again after LOW) with le_clk_getRelativeTime() function.

To measure the HIGH time of the echo pulse I use both rising and falling edge interrupts to starrt / stop a timer.

The results are quite poor. It is rarely reporting the correct distance, sometimes a wildly wrong distance and sometimes never getting the echo pulse falling edge at all.

Is this approach the best way to set and read GPIO pins with the kind of accuracy I’m looking for (microsec)?

If not, would someone have advice on what to use or if anyone has tried integrating an ultrasonic sensor with mangOH red?

#include "legato.h"
#include "interfaces.h"

enum systemStates {READY, TRIGGERED, RECEVIED_ECHO, CALCULATING};
enum systemStates systemState = READY;
bool state = true;
le_clk_Time_t timeA, timeB, timeC, timeD;


static void calculateAndReport(){
	LE_INFO("The two times in microsec were: C = %ld, D = %ld",timeC.usec, timeD.usec);
	le_clk_Time_t echoLength = le_clk_Sub(timeD, timeC);
	LE_INFO("The ECHO length in microsec is: %ld us", echoLength.usec);
	float distance_cm = echoLength.usec / 58;
	LE_INFO("The distance is: %f cm",distance_cm);
	systemState = READY;
}

static void	echoInterruptHandler(bool state, void * ctx)
{
	if(state){
		if(systemState == TRIGGERED){
			timeC = le_clk_GetRelativeTime();
			systemState = RECEVIED_ECHO;	
		}
		//LE_INFO("ECHO pin rising edge, start timer");

	} else {
		if(systemState == RECEVIED_ECHO){
			timeD = le_clk_GetRelativeTime();
			systemState = CALCULATING;
			calculateAndReport();
		}	
	}
}

static void echoPinSetup()
{
	ultrasonicEchoPin_SetInput(ULTRASONICECHOPIN_ACTIVE_HIGH);
	ultrasonicEchoPin_EnablePullDown();
	ultrasonicEchoPin_AddChangeEventHandler(ULTRASONICECHOPIN_EDGE_BOTH , echoInterruptHandler , NULL , 0);
}

static void trigger
(
	le_timer_Ref_t triggerTimerRef
)
{	
	// Set State
	systemState = TRIGGERED;
	// activate / set trigger pin HIGH
	ultrasonicTriggerPin_Activate();
	// Start to capture this time point
	timeA = le_clk_GetRelativeTime();
	// start a timer for 10 us
	le_timer_Start(triggerTimerRef);
	
}

static void triggerTimerHandler(
	le_timer_Ref_t triggerTimerRef
){
	
	// Just want to turn set the trigger pin LOW here
	ultrasonicTriggerPin_Deactivate();
	timeB = le_clk_GetRelativeTime();
}

static void triggerTimerSetup(le_timer_Ref_t triggerTimerRef)
{
	// Set the trigger time to 0 seconds, 10 us
	le_clk_Time_t triggerTime = {0,10};
	le_timer_SetInterval(triggerTimerRef, triggerTime);
	
    // Set the handler when the timer expires
    le_timer_SetHandler(triggerTimerRef, triggerTimerHandler);
}

COMPONENT_INIT
{
	// TRIGGER = GPIO42 = IOT0_GPIO1 (pin24)
	// ECHO = GPIO13 = IOT0_GPIO2 (pin25)

	le_timer_Ref_t triggerTimerRef = le_timer_Create("Trigger Timer");

	// configure trigger pin as output, active high, start value = low
	ultrasonicTriggerPin_SetPushPullOutput( ULTRASONICTRIGGERPIN_ACTIVE_HIGH , false);
	ultrasonicTriggerPin_EnablePullDown();
	// Setup the trigger timer
	triggerTimerSetup(triggerTimerRef);
	// Setup the echo pin
	echoPinSetup();

	if(systemState == READY){
		trigger(triggerTimerRef);
		systemState = TRIGGERED; 		
		sleep(1); // sleep for a second
	}

}

#2

Hello

I think it will be difficult to have precision. A small Mcu will be a better solution with uart or spi communication with the WP module.

This only my opinion.

Regards
Francis


#3

As it’s on mangOH Red, I’d be looking at the Cortex-M4 on there …


#4

Thanks for the lead.

The Cortex-M4 is within the MT7697 WiFi + BLE Chipset. I’ve managed to follow the tutorial on https://github.com/mangOH/mangOH/wiki/mangOH-Red-mt7697-WiFi to download , build and compile the firmware. Now I need to figure out how control the GPIO on the wp7700 module and get my wp7700 module communicating with the MT7697.