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.

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
}
}