ESP32 Exercise: Stepper Motor Pulses With LEDC PWM

After successfully installing PlatformIO’s ESP-IDF support (and a sigh of relief nothing else seems broken on my computer) I resumed practicing writing code for ESP32. The next exercise was motivated by Emily’s optical audio decoder project where we traded a few e-mail about generating stepper motor signals. For her project she used an Arduino and the AccelStepper library, but it has a maximum speed of roughly four thousand steps per second on classic Arduinos. I was confident the ESP32 can do far better than that, and decided to try it myself.

It was also an opportunity to play with a Trinamic TMC2208 breakout board sometimes called the SilentStepStick. I think this board might be a Trinamic original design, but there’s a slight chance they just hosted materials on their website since it was such a popular use of their chip. Either way, there are a lot of Amazon vendors selling these in affordable multi-packs(*) targeting the 3D printer market. Mostly for people who are unhappy with the high-pitched whine of many inexpensive 3D printers, because TMC2208 is a good choice for helping a printer run much silently than they would on the very popular A4988 driver chip that helped start the current wave consumer 3D printers. My own 3D printers had A4988 drivers soldered on the board so I couldn’t use these modules to upgrade, but I foresee these modules becoming useful in other projects.

In the current Sawppy rover context, these drivers may become useful if I investigate using stepper motors in a future rover iteration. I’ve already received requests to drive and steer Sawppy wheels with NEMA17 style stepper motors commonly used in 3D printers, and there’s always that mythical robot arm that my rover is still patiently waiting for. Commodity NEMA17 motors typically have far less torque than LX-16A serial bus servos, but I’m not sure it is a critical difference for a rover and the best way to find out would be to build one.

But for now I’m just looking at the stepper motor driver, which is commanded by two signal pins: one signifying direction, and another that signals a step for the stepper motor. Direction pin is fairly trivial, it’s the step pin that presents a challenge. Generic portable code like AccelStepper couldn’t reliable pulse the step pin at high speeds, that requires coding to the hardware as GRBL did for the ATmega328.

For the ESP32, my experiment used the ADC peripheral to read the position of a potentiometer and the LED control hardware PWM module to generate step pulses. This module is optimized for dynamic adjustment of pulse width duty cycle during application execution, but stepper motor control is a bit of a off-label use where I left the duty cycle at 50% and changed the PWM frequency at runtime in response to knob position.

According to LEDC peripheral documentation, it is theoretically capable of up to 40MHz pulses at 50% duty cycle. However, for any given configuration, the ESP32 is constrained to a subset of the total range of speed possible. I’m not sure how feasible it is to reconfigure the LEDC peripheral at runtime, but such tricks will be required for anyone with ambition to generate a wider range of pulse frequencies. In my exercise it is limited to a range of 32 Hz to 32.5kHz, which is plenty for today as proof we can surpass the 4kHz limit of AccelStepper on a ATmega328. A stepper motor’s torque diminishes as the speed rises, so I expect the stepper motors will run into mechanical problems well before becoming limited by ESP32 PWM frequency range up to 40MHz.

Once I got this exercise up and running, I started eyeing a desirable luxury advertised by PlatformIO: source-level JTAG debugging.

Code and schematic for this practice exercise is publicly available on GitHub.

(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s