Measure time
# help
m
I am looking to measure the time that a pin is high with a pulse. I am unable to find any reference to time now in milliseconds.
k
You can use
Duration.of:
or the lower level
Time.monotonic_us
to get a microsecond count.
f
Depending on your requirements there are multiple different ways. (All examples are untested. If something looks off, please let me know and I fix the post). The easiest is to just measure with
Duration.of
and
pin.wait_for
Copy code
import gpio

main:
  pin := gpio.Pin 32 --input
  // Wait for the pulse to start:
  pin.wait_for 1
  pulse_duration := Duration.of: pin.wait_for 0
  print "It took $pulse_duration.in_ms milliseconds"
  pin.close
pin.wait_for
has a bit of overhead (because it uses the event-queue, ...), but if you are only interested in milliseconds, you probably won't notice. It's the simplest and will allow other tasks and programs to run.
If you need higher precision, you can start a busy look and use `Time.monotonic_us`:
Copy code
import gpio

main:
  pin := gpio.Pin 32 --input
  while pin.get != 1: null  // Wait for the pin to trigger.
  start := Time.monotonic_us
  while pin.get != 0: null  // Wait for the pin to pulse to stop.
  end := Time.monotonic_us
  diff_us = end - start
  print "It took $diff_us us"
  pin.close
This program is more precise, but will busy loop. It will put one of your cores to 100%. You should generally only do this, if you know that the pulse is coming soon, doesn't take a long time, and you need a relatively precise measurement. A good example is an ultrasound sensor that puts a pulse onto the 'echo' pin after it was triggered. See https://docs.google.com/document/d/1K-TYea7jbYfj2ecMUmr0T0zd4JDpk5lo0mJNOLPUrhc/edit (search for "Ultrasound Distance").
If you are dealing with repeated pulses (like from a flow-meter), then another approach is to count the amount of pulses (but not their length) over time and divide the measured duration by the pulse-count.
Copy code
import pulse_counter
import gpio

main:
  pin := gpio.Pin 32
  unit := pulse_counter.Unit
  channel := unit.add_channel pin
  channel.clear  // Reset the pulse count.
  sleep --ms=1_000  // Measure for one second.
  count := channel.value
  frequency := 1_000 / count
  print "Frequency is $frequency Hz"
  channel.close
  unit.close
  pin.close
Finally, if you have a single pulse and need high precision, then the RMT library does what you want. The ultrasound package doesn't use the busy loop from above, but uses the RMT library instead: https://github.com/lask/toit-hc-sr04/blob/c740e8341179fe45b377db826222c23d223629b9/src/driver.toit#L57
Copy code
import gpio
import rmt

main:
  pin := gpio.Pin 32
  // The line is considered idle, when the value doesn't change after
  // idle_threshold ticks.
  // By default a tick is 1us.
  // This value must fit int 16bits.
  idle_threshold := 30_000
  // Pulses that are shorter than filter_ticks are ignored.
  filter_ticks := 10
  channel := rmt.Channel pin
      --input
      --idle_threshold=idle_threshold
      --filter_ticks = filter_ticks
  received_signals := channel.read  // Waits for a pulse.
  if received_signals.size == 0 or (received_signals.level 0) == 0:
    print "Measurement didn't work".
  pulse_width := received_signals.period 0
  print "Received a pulse of $pulse_width"
  channel.close
  pin.close