I am aiming at precise speed control of this BLDC motor: it has an integrated controller, outputting digital Hall signal (period 20.8ms on oscilloscope, w/o load) and taking PWM as input for speed regulation.

As far as my knowledge goes, this is a task for PID: measure Hall pulses at input, adjust duty cycle of the PWM based on target period/frequency of the Hall output.

The speed should be controlled with <1% error (even less is better).

  • Is this goal realistic with this particular motor?
  • How should I measure pulse duration?
  • Is pulseIn (with interrupts disabled) going to be sufficiently precise? Should I measure lows or highs?
  • Should I measure several pulses instead (and how)? Or should I accept imprecision in the pulse period and compensate (smooth) it using integral/derivative terms?
  • Do I need more than 8-bit PWM resolution for this task? (I will use Nano at first, but might switch to Nano Every, which has 10-bit PWM).

Any other comments/suggestions are welcome.

  • you can have 16bit PWM with Timer1 (library) on Nano – Juraj Jun 25 '20 at 9:53

This is only a partial answer, about measuring pulse period or duration.

For best accuracy, I would recommend using the “input capture” feature of a 16-bit timer. This is not as easy as using pulseIn() or timing the signal with micros(): you will have to carefully study the MCU's datasheet and manually configure the bits of some I/O registers. You will be rewarded with high accuracy (single-cycle if the timer runs at the MCU clock speed) and without the jitter inherent to any software-based approach.

Beware that the Nano and Nano Every use different MCUs, with very different timers. Both have input capture capability, but if you switch from one to the other you will have to redo most of the work. Note that the Nano is capable of 10-bit PWM if you program it low-level.

A software-based approach (pulseIn() or attachInterrupt() + micros()) has the advantage of portability.


To expand a little on Edgar's answer:

There are two main ways of measuring frequency, and both require different resources and are better for different situations.

The method Edgar describes using the Input Capture method, is good for rapidly changing low frequency signals where you want to respond very quickly to changes in the frequency. It works by measuring the time between two pulses using a free-running timer. Of course you can only measure frequencies as fast as the timer can run, which is pretty fast anyway, and if configured right it can run almost entirely asynchronously so you can just query the current recorded time whenever you need to.

The other option is to count the number of pulses within a given time period. This can also be done in hardware but using a different set of peripherals.

For this you have two timers. Timer 1 has the ability to us an external signal on pin D5 as its clock. This basically turns it into a pulse counter, and every time a pulse arrives on the timer pin it increments the count by one.

Then you have a second timer which triggers an interrupt at a predefined period. What that period is depends on the responsiveness you want and the frequency range you want to measure. You can also use the "prescaler" of Timer 1 to increase the frequency measurement range by only counting every 2nd or 4th or 8th etc edge.

Of course, all that timer use would interfere with PWM generation on the Nano, but should be better on the Nano Every, but you'd want to check the datasheet for timer usages.

So in summary:

Input capture

  • Fast response
  • Limited frequency range

Pulse counting with timer 1

  • Slower response
  • Naturally smoothed output
  • Greater frequency range
  • Understands the concept of zero Hz
  • Interferes with PWM generation

Whichever method you choose, sure, feed it through PID to create a stable output RPM.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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