5
\$\begingroup\$

Problem

I'll be receiving pulses and want to know the relative times of pulse start/end with microsecond precision (or better).

Pulse characteristics:

  • pulse frequency: probably 1Hz to 10Hz
  • pulse length: 1μs to 200ms
  • pulse spacing: >10μs between consecutive pulses

I want to measure (ideally) the durations of HIGH/LOW levels, or otherwise absolute times of edges (relative to internal clock) from which I can then calculate the durations. I want durations/timestamps to have microsecond precision or better. 100ns would be great!

My ideal output data would be a series of sequential HIGH/LOW durations for example:

  • HIGH for 205μs
  • LOW for 134μs
  • HIGH for 18μs
  • ...

This is just a hobby project, so if I mess up measurement of 1% of events then I can just drop those values. No mission-critical requirements or angry customers :)

I figure that I can use some STM32 MCU, with timer in "input" configuration. Then have it store timestamps every time an input pin raises or lowers.

The "filtering" that the STM32 timers can perform will be great for debouncing and noise rejection too.

The times of pulse rises/falls need to be precise to the microsecond or better, but there are no other tight realtime constraints. If it takes an extra 500ms after an edge, before these timestamps get transmitted, that's fine.

Initial solution idea

Ok, not my first solution (that was an oscillator plus a huge pile of 7474+7476 for clock counting and edge-triggered buffering of the clock value)...

schematic

simulate this circuit – Schematic created using CircuitLab

Question

Is the solution really just as simple as:

  1. connect my signal to a timer-input pin on the STM32
  2. configure a 32-bit timer as input (so timer's value is stored on an input edge transition) and with appropriate filtering
  3. configure an interrupt to take the stored timer value after an edge and put the value into a queue
  4. process that queue during idle-time, since there's no realtime requirements on getting the data

The input signal will be the output of a transimpedance amplifier, driven by a filtered photodiode. Signal-to-noise is expected to be pretty good, at least 30dBV.

I'm planning to use STM32G431KBT6 just because it's easily available and I can hand-solder it. I'm not strongly tied to using this MCU part though.

Time wrap-around could also be an issue if counting at e.g. 16MHz with 16-bit timer. I guess I can just slave another 16-bit timer to it and use the other one to count wraparounds, effectively giving me a 32-bit timestamp when reading both timers? Although provided that, at most, only one wraparound event occurs between two timestamps (in the case of a 32-bit timer), unsigned integer subtraction should give me the interval correctly anyway.

Extra thoughts

Since the timer input is filtered, I'm thinking to eliminate the Schmitt buffer/inverter.

Also I'm wondering whether to use the STM32's internal comparators so I have a bit of extra fine tuning for edge thresholds and hysteresis, and connect the comparator output to the timer input, so that edge transitions on the comparator output drive clock inputs, allowing me to record precise timestamps of when edge-transitions occurred. I'd "tune" the thresholds by connecting DAC output to other comparator input.

Some STM32 parts have opamps built-in too, which I could maybe use for the transimpedance amplifier. The slew rate is only 0.7V/μs as far as I've seen, but that might be fast enough, I don't have a hard figure yet for what bandwidth I need.

Oh wait, the GaN STM32G-series parts have much faster opamps that are totally suitable for what I want to do!

I also considered using the analog watchdog, but STM32L0: Fast processing of an analog sinusoidal signal suggests that it will be too slow for microsecond-resolution timing and it's a bit of a hack to use it for this.

\$\endgroup\$
5
  • \$\begingroup\$ What does "pulse spacing: >10μs" mean? How does this relate (if at all) to 'frequency'? \$\endgroup\$ Mar 23, 2020 at 23:26
  • \$\begingroup\$ To me this looks a lot more like a CPLD problem than a microcontroller problem. \$\endgroup\$
    – The Photon
    Mar 24, 2020 at 0:13
  • \$\begingroup\$ @BruceAbbott: There will generally be 1 to 10 pulses per second, with space of at least 10μs between any two consecutive pulses (most of the time, much larger gap). \$\endgroup\$ Mar 24, 2020 at 1:37
  • 1
    \$\begingroup\$ Does it have to be DIY? This is the kind of thing that keeps those cheap USB National Instruments DAQ boards selling. \$\endgroup\$ Mar 24, 2020 at 2:25
  • \$\begingroup\$ @user1850479 : It needs to be small+light+wireless (wearable) and cost around €15 max in parts per unit as I'll probably end up wanting 10-20 of them. I think that I can get away with using on each unit: STM32G4 + bluetooth module + 2x CR2302 \$\endgroup\$ Mar 24, 2020 at 18:47

1 Answer 1

2
\$\begingroup\$

Yes. It's pretty straightforward. As long as your timer clock is fast enough you should have no problem grabbing edges with a timer. You may need to do a bit of math when the timer overflows if you're grabbing continuously. Or you can tweak your clock speed. it's doable. This is called "input capture". I think you'll find it not too difficult to get set up. Maybe tricky to clean up all the occasional glitches.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks, I think input capture is the droid I was looking for. Timer wraparound should be fine as long as the total difference is less than the timer maximum value (so unsigned subtraction will be find for calculating differences). \$\endgroup\$ Mar 24, 2020 at 18:45
  • \$\begingroup\$ Accepting this answer, because I now don't think I'm missing any knowledge in order to solve this problem. Just soldering and code now! \$\endgroup\$ Mar 25, 2020 at 22:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.