Skip to main content

Altera Agilex 3 FPGA Stepper Motor Control for CNC Retrofits

Image Source: .shock/stock.adobe.com

By Jean-Jacques DeLisle for Mouser Electronics

Published June 12, 2026

Retrofitting legacy computer numerical control (CNC) equipment presents both a challenge and an opportunity. Older machines are often still mechanically sound but rely on proprietary or unsupported control electronics that prevent integration with modern software tools and workflows. Replacing an entire CNC system can be expensive and inflexible, while off-the-shelf retrofit solutions may limit customization or experimentation. This project explores an alternative approach: using a field-programmable gate array (FPGA)-based control architecture to create a prototype for modernizing legacy CNC hardware while preserving full control over the system design.

Project Materials & Resources

Project Bill of Materials (BOM)

Software and Downloads

  • Quartus Prime Pro Software (latest version) and associated licenses
    • Altera Agilex 3 C-Series FPGA Software (latest license version of Agilex 3 Device Support)
    • Agilex common files
    • USB Blaster III Driver (latest version; part of Quartus Prime Pro Software)
    • UART FTDI Driver (latest version; part of Quartus Prime Pro Software)
  • Arduino IDE
  • Ponoor PowerSTEP01 Library v 1.1.0 (available through the Arduino IDE)

Project Code

Helpful Documents

Project Technology Overview

This project article describes how to build and test a multi-axis stepper motor control system using an Altera Agilex 3 FPGA on a Terasic Technologies Atum A3 Nano Board, working alongside an Arduino-based SPI motor-control stack (Figure 1). Three stepper motors—corresponding to the x-, y-, and z-axes of an old CNC milling machine—are reverse-engineered, rewired, and driven through FPGA-selected Serial Peripheral Interface (SPI) chip-select logic. Pushbuttons and switches on the Atum A3 Nano Board provide immediate, hardware-level control and visual feedback, illustrating how FPGAs can act as highly flexible CNC interface devices.

Figure 1: A Terasic Technologies Atum A3 Nano Board, STMicroelectronics X-NUCLEO-IHM03A1 stepper motor driver board (attached to an Arduino UNO R4 Wi-Fi board), and a stepper motor extracted from a CNC mill. (Source: Author)

This advanced project provides experience with FPGA-based logic, SPI communication, and CNC system retrofits. By completing this project, readers will gain practical insight into how modern programmable logic can extend the life and capability of legacy machines while laying the groundwork for more advanced CNC interfaces, including PC control and G-code interpretation.

While not strictly required, experience with Quartus Prime, Verilog HDL, FPGAs, Arduino UNO, SPI communications, and stepper motor drivers will make the project easier to follow and implement.

Terasic Technologies Atum A3 Nano Board

The Terasic Technologies Atum A3 Nano Board is a compact FPGA development platform built around the Altera Agilex™ 3 FPGA. The FPGA, offered in its largest configuration with around 135K logic elements, leverages Altera’s HyperFlex architecture and integrates advanced features such as dual Arm® Cortex®-A55 cores and hardened peripherals, enabling significantly higher performance than earlier Cyclone® V FPGAs, along with faster transceivers and support for modern memory, such as LPDDR4.

Arduino UNO R4 Wi-Fi

The Arduino UNO R4 Wi-Fi combines a 32-bit Renesas RA4M1 microcontroller—based on a 48MHz Arm Cortex-M4 core with an integrated ESP32-S3 module to deliver built-in Wi-Fi and Bluetooth® connectivity. This dual-processor architecture provides substantially expanded memory—256kB flash, 32kB SRAM, and 8kB EEPROM—along with enhanced performance and peripherals, including a real-time clock, digital-to-analog converter (DAC), and CAN bus.

STMicroelectronics X-NUCLEO-IHM03A1 Expansion Board

The STMicroelectronics X-NUCLEO-IHM03A1 Expansion Board is a high-power stepper motor driver platform built around the advanced powerSTEP01 controller, delivering precise and efficient motor control. It enables fully digital motion control with programmable speed profiles, positioning calculations, and a comprehensive set of protection features, providing both high performance and robustness for demanding applications. The board supports a wide operating range, handling supply voltages from 10.5V to 50V and phase currents up to 10A RMS, while offering fine motor control through up to 1/128 micro-stepping and features such as sensorless stall detection and overtemperature protection. Designed for flexibility, it is compatible with Arduino UNO R3/R4 connectors and can be stacked with additional boards to drive up to three stepper motors, making it a scalable and easy-to-integrate solution for industrial, robotics, and motion-control applications.

Developing the Project

The wiring of the stepper motors used in this project cannot be easily determined from the visible electronics in the milling machine. However, one can determine the stepper motor coil configuration and wiring by extracting the stepper motors from the mill and reverse-engineering the electronics.

Extract the Stepper Motors

Extract the stepper motors from the CNC milling machine (Figure 2). The steps in this process will depend on the specific machine undergoing the retrofit, but most machines will require removing mounting bolts and hardware, as well as wiring harnesses or interface boards.

Figure 2: The stepper motor extracted from the CNC mill. (Source: Author)

Determine Stepper Motor Coil Configuration and Wiring

The CNC mill electronics (Figure 3) indicate that the stepper motor uses an eight-wire configuration, operates at 24V DC, and requires less than 1.5A.

Note: The Nucleo boards’ terminal blocks can support a maximum input voltage of 50VDC. Ensure that your motors’ operating voltages are less than 50VDC.

Figure 3: The stepper motor power supply for the CNC mill. (Source: Author)

However, the motor’s wiring interface (Figure 4) does not show exactly how the motor is wired. If you are working with salvaged or unlabeled stepper motors, start by identifying the coil pairs. If your motor is already a known four-wire motor with documented lead mapping, you can skip to the driver connection step.

Figure 4: A wiring interface extracted from the CNC mill that does not contain any readily deciphered description of the stepper motor lead destinations. (Source: Author)

Using a multimeter in resistance (Ω) mode, identify coil pairs by probing wire-to-wire combinations. A true coil pair will show a low, stable resistance (often 1Ω to 5Ω); non-pairs will read open circuit (OL) or very high resistance.

If the motor is an eight-wire type, it will have four independent coils (i.e., four distinct low-resistance pairs). If the motor is a six-wire type, each phase has a center tap. As a result, end-to-end resistance will be roughly double the end-to-center-tap resistance.

If you have an eight-wire or six-wire motor, you will need to convert it to a standard 4-wire driver configuration. To do this, choose a series or parallel wiring scheme for each phase and map the resulting four leads to A+, A-, B+, and B- on the Nucleo board.

Ensure the power supply is completely disconnected and discharged before testing motor leads. Manually turning stepper motors while they are connected to an unpowered driver board generates back-electromotive force (back-EMF), which can skew multimeter readings and permanently damage the onboard powerSTEP01 ICs.

After identifying the individual winding pairs, determine which windings belong to the same motor phase and their relative polarity. For an eight-wire motor, two windings belong to phase A and two belong to phase B. Temporarily connect one candidate phase to A+/A− and another candidate phase to B+/B−, then run the driver at a low current limit and low speed. If the motor only vibrates or stalls, power down and either reverse the polarity of one phase or test a different phase grouping.

Note: Ensure the DC power supply is properly connected to the Nucleo board’s positive (+) and negative (-) terminals. Consult the X-NUCLEO-IHM03A1 datasheet for voltage and power-handling capabilities and verify that the onboard light-emitting diode (LED) indicator illuminates when DC power is applied.

Test the Stepper Motor Functionality

Test a stepper motor’s functionality by connecting it to an X-NUCLEO-IHM03A1 stepper motor driver board stacked on the Arduino UNO R4 Wi-Fi board.

  1. Connect the motor phase leads and their motor input power wires to the screw terminals on the Nucleo board (Figure 5).

Figure 5: Testing the stepper motor wiring configuration by using the X-NUCLEO-IHM03A1 stepper motor driver. (Source: Author)

  1. Connect the Nucleo board to the Arduino UNO R4 Wi-Fi board.
  2. Connect the Arduino board to the PC via a USB cable.
  3. Install the Ponoor PowerSTEP01 Library v1.1.0 via the Arduino IDE Library Manager.
  4. Run the powerSTEP01SimpleTest.ino example.
  5. If you have correctly wired the stepper motor to the Nucleo board, the motor should spin forward and then reverse.

Assemble the Stepper Motor Board and Arduino Stack

Assuming the stepper motors are identical, each of the three stepper motors can be wired to a separate X-NUCLEO-IHM03A1 driver board using the same wiring method. The Nucleo boards are pinout-compatible with an Arduino UNO configuration and with each other. Therefore, they are stackable, and all three Nucleo boards can be attached to a single Arduino UNO. The SPI interface pins of the Arduino UNO match those of the X-NUCLEO-IHM03A1 boards and can directly drive up to three stepper motor drivers using the appropriate libraries.

STMicroelectronics provides example code for driving three stepper motors on the X-NUCLEO-IHM03A1 boards (refer to the X-NUCLEO-IHM03A1 user manual for configuration details), but there are few standard libraries for quickly enabling SPI communication to three boards using a single Arduino UNO. In this project, the FPGA routes the chip select (CS) signal from the Arduino UNO to the desired Nucleo stepper motor driver board. This approach allows up to three X-NUCLEO-IHM03A1 boards to be stacked and inserted into the Arduino UNO, which handles SPI communications.

To enable this approach, remove or bend the CS leads protruding from the bottom of each Nucleo board. Then route Arduino UNO D10 (CS) to Terasic FPGA GPIO 5 through the level shifter. Route the FPGA-controlled CS outputs from GPIO 2, GPIO 3, and GPIO 4 to the CS pins on the bottom, middle, and top X-NUCLEO-IHM03A1 boards, respectively. The exact physical FPGA/header pins must match the pin mapping in Table 1.

  1. Wire the stepper motors to the X-NUCLEO-IHM03A1 stepper motor driver boards.
  2. On each Nucleo board, clip or bend the CS pin so it does not connect to the Arduino header or the Nucleo board header below.
  3. Attach a lead to the CS pin of each Nucleo board, either through the board’s top header or on the bent pin (if applicable).
  4. Attach a lead from the CS pin on the FPGA to pin D10 on the Arduino board.
  5. Stack the Nucleo boards on top of each other, and attach the stack to the Arduino UNO board.

Wire FPGA GPIO from Arduino to Appropriate FPGA GPIO

The Terasic Atum A3 Nano Board operates at 3.3V logic, while the Arduino UNO R4 Wi-Fi—including the SPI GPIO pins—operates at 5V logic. Directly driving 3.3V logic devices with 5V signals can permanently damage the FPGA. To ensure safe and reliable operation, a bidirectional logic level shifter must be integrated between the Arduino and Terasic boards to translate the voltage levels appropriately (Figure 6).

Figure 6: Block diagram illustrating the 5V to 3.3V bidirectional logic level shifter interconnects between the Agilex 3 FPGA and the Arduino UNO. (Source: Mouser Electronics)

Wire the system according to the logic paths defined in Table 1.

Note: Ensure you route the Arduino board’s 5V logic pins to the high-voltage (HV) side of the logic level shifter, and the Terasic board’s 3.3V pins to the low-voltage (LV) side.

  1. Connect the Arduino D10 (CS) pin to the Terasic FPGA GPIO 5 through the level shifter.
  2. Connect the Terasic board’s pins 2, 3, and 4 through the level shifter to the CS pin 10 on each of the three X-NUCLEO-IHM03A1 boards, respectively.
  3. Connect the FPGA-generated direction command outputs from the Terasic board to the Arduino through the level shifter: Terasic FPGA GPIO 0 to Arduino D7 for FORWRD, and Terasic FPGA GPIO 1 to Arduino D6 for REVERSE. The Atum board push buttons are read by the FPGA internally; the FPGA then drives these GPIO outputs to the Arduino.
  4. Power the Atum A3 Nano board via its required 5V DC input.
  5. Power the Arduino through USB or through its appropriate supply input
  6. Power the X-NUCLEO-IHM03A1 motor-driver boards from a separate motor supply connected to VS and GND. Tie all grounds together.
  7. Connect the Terasic board to the PC via USB.

Table 1. Project logic wiring description (Routed via Level Shifter)

Device 1

Device 1 Pin

Device 2

Device 2 Pin

Terasic board FPGA GPIO

0

Arduino UNO

7

Terasic board FPGA GPIO

1

Arduino UNO

6

Terasic board FPGA GPIO

2

Bottom X-NUCLEO-IHM03A1 board

10 (CS)

Terasic board FPGA GPIO

3

Middle X-NUCLEO-IHM03A1 board

10 (CS)

Terasic board FPGA GPIO

4

Top X-NUCLEO-IHM03A1 board

10 (CS)

Terasic board FPGA GPIO

5

Arduino UNO

D10 (CS)

Terasic board FPGA GPIO

6

for CS testing

unwired

Reprogram the Arduino

Reprogram the Arduino UNO with the local ard_control.ino script. The code uses a modified version of the powerSTEP01SimpleTest.ino example. The Arduino configures SPI communication to use SPI Mode 3 (Clock Polarity [CPOL] = 1 and Clock Phase [CPHA] = 1), ensuring the clock polarity and phase correctly synchronize with the custom CS logic and the powerSTEP01 IC.

The modification defines Arduino UNO pins 7 and 6 as digital inputs to read the forward and reverse logic signals from the FPGA. When the Arduino detects that pin 7 is high, it generates and sends a single forward-step command via SPI to the active motor driver. The Arduino introduces a 20ms delay between steps. When pin 6 is high, the Arduino sends a reverse-step command via SPI.

Set Up the FPGA

For background on installing the Quartus Prime software required to program the Atum A3 Nano board, consult the Terasic Technologies documentation. The Atum A3 Nano Board Getting Started Guide and My First FPGA explain how to install Quartus Prime, obtain license files, and run an example project.

Program the FPGA:

  1. In Quartus Prime, click File and select New Project Wizard.
  2. Set the working directory, project name, and top-level entity name (e.g., fpga_control).
  3. Click Assignments, then click Device.
  4. In the window that opens, click the Family dropdown menu and select Agilex 3.
  5. Click the Device dropdown menu and select Atum A3 Nano Board.
  6. Add the HDL file: Click Project, then click Add/Remove Files in Project, and select fpga_control.v. Set the file as the top-level entity if prompted
  7. Assign FPGA pins: Click Assignments, then click Pin Planner. Map the design signals to physical FPGA pins (Figure 7).

Figure 7: The Atum A3 Nano FPGA pin designations from the Quartus Prime Pin Planner used in this project. (Source: Author)

  1. Click Processing, and then click Start Compilation. Quartus will generate a .sof programming file.
  2. Click Tools, and then click Programmer.
  3. Click Hardware Setup and select the connected USB Blaster device.
  4. Add the generated .sof file (if not automatically added), select the Program/Configure checkbox, then click Start.

Stepper Motor Control

Stepper motor control in this project relies on SPI communication handled by an Arduino UNO R4 Wi-Fi, with motor selection and control logic driven by input signals from the Atum A3 Nano FPGA. Pushbuttons on the Terasic Technologies Atum A3 Nano Board control the stepper motors’ forward and reverse motion via dedicated logic inputs on the Arduino.

To control the three X-NUCLEO-IHM03A1 boards, engineers can configure the boards using a daisy-chain SPI method. This involves using a resistor bank to set the register that determines how the SPI motor controller communicates. In this standard method, the SPI host sends multiple bytes in sequence, and the SPI device receives a designated byte.

However, this project employs the FPGA to route the CS signal directly to each stepper motor controller’s SPI interface (Figure 8). The SPI devices receive a transmission only while their CS signal is pulled low; the signal must be pulled high again after the transmission. The FPGA programming accounts for this behavior, eliminating the need to desolder and resolder resistor values.

Figure 8: Logic flowchart and visual diagram comparing standard SPI daisy-chaining versus the custom FPGA-routed CS topology used in this project. (Source: Mouser Electronics)

Stacking multiple X-NUCLEO-IHM03A1 boards requires isolating the CS pin from the bottom of each stacked board so it does not connect to the microcontroller unit (MCU) on the Arduino UNO. A separate CS lead is then run from a dedicated FPGA GPIO to the CS pin of the stepper motor driver (labeled CS on the X-NUCLEO-IHM03A1 boards and pin D10 on the Arduino UNO R4 Wi-Fi).

Using the Arduino’s pin D10 CS signal, the FPGA applies simple logic to activate the CS pin under specific conditions. In this example, the two switches on the Atum A3 Nano Board select the active motor. The Atum A3 Nano Board’s LED bank provides visual feedback on the FPGA and CS signal behavior. LEDs 0 and 1 indicate the selected motor in binary (e.g., OFF is 0; motor 1 is 00, motor 2 is 01, and motor 3 is 11). LED 3 flashes in response to CS signal activity, mirroring the TX LED on the Arduino UNO.

Verilog HDL File

The Verilog HDL file initializes the FPGA’s inputs and outputs, using simple logic to drive the output signals from the switches, pushbuttons, and Arduino CS signal to the Arduino command inputs, the X-NUCLEO-IHM03A1 boards’ chip-select lines, and the FPGA board’s LEDs. When multiple X-NUCLEO-IHM03A1 boards are stacked, their CS signals are isolated and routed through the FPGA. This allows the Arduino’s CS signal to target a single stepper motor driver at a time. The FPGA determines which motor receives the SPI communication based on the switch inputs.

To implement this custom routing, the FPGA uses simple AND-gate logic to tie the CS signal directly to the active switch state. For example, using proper logical NOT operators (represented by the ! symbol), the basic routing statements look like this in the code block:

assign gpio_motor_1 = (!switch[0] & !switch[1]) & CS;

assign gpio_motor_2 = (switch[0] & !switch[1]) & CS;

assign gpio_motor_3 = (switch[0] & switch[1]) & CS;

The FPGA’s forward GPIO output is the logical NOT of the designated pushbutton, as these pushbuttons are active low. The reverse function is programmed similarly. LEDs 0 and 1, used to indicate motor selection, display the FPGA board switches’ inverted states in binary. The CS_LED output connects to LED 3 of the FPGA board and flashes in sequence with the Arduino’s CS signal (Figure 9). The CS_out signal is strictly for testing. As shown in the assign statements above, the FPGA gates the Arduino CS line with the switch-selected motor enable so that only one driver’s CS line is active during an SPI transfer.

Figure 9: The fpga_control.v Verilog HDL file used in this project to program the Atum A3 Nano FPGA Board. (Source: Author)

Once pin designations are assigned in Quartus Prime, compile the project. Quartus generates the fpga_control.sof file, which the Programmer uses to configure the FPGA (Figure 10).

Figure 10: The Quartus Prime Programmer window is used to send the .sof file information to the FPGA for programming. (Source: Author)

Operating the System

To control the motors, use the two switches on the Atum A3 Nano to select the desired motor, and press the pushbuttons to drive it.

  • Motor 1 (00 in binary): Both switches are in the DOWN position (toward the edge of the board).
  • Motor 2 (01 in binary): The switch next to the pushbuttons (SW0) is in the UP position (away from the edge of the board), and the switch closest to the board’s corner (SW1) is in the DOWN position.
  • Motor 3 (11 in binary): Both switches are in the UP position.

After the hardware has been wired (Figure 11), the FPGA has been programmed, and the Arduino UNO is running the ard_control.ino code, the system operates as follows:

  • With both switches DOWN (motor 1 selected), holding the Key0 pushbutton drives the motor forward one step per 20ms. The Key1 pushbutton reverses the motor.
  • With both switches UP, motor 3 responds identically to motor 1.
  • With SW1 DOWN and SW0 UP, motor 2 responds identically to motor 1, assuming the HDL maps Motor 2 to the switch state 01.

Figure 11: A picture of the rough wiring and testing of the project setup. (Source: Author)

Final Thoughts

This project explores using an FPGA to develop a prototype multi-axis motor-control interface for retrofitting a legacy CNC mill with three stepper motors. By integrating an Arduino UNO for SPI communication and a Terasic Technologies Atum A3 Nano Board for control logic, developers can manage multi-motor systems using onboard switches and pushbuttons. While this prototype relies on an Arduino, developers could replace the Arduino with FPGA logic by implementing an SPI master, a powerSTEP01 command sequencer, and the required configuration/state-machine logic in HDL. Furthermore, integrating external controllers or PC-based software to interpret G-code would expand the FPGA’s utility as a primary CNC interface.

About the Author

Jean-Jacques (JJ) DeLisle attended the Rochester Institute of Technology, where he graduated with a BS and MS degree in Electrical Engineering. While studying, JJ pursued RF/microwave research, wrote for the university magazine, and was a member of the first improvisational comedy troupe @ RIT. Before completing his degree, JJ contracted as an IC layout and automated test design engineer for Synaptics Inc. After 6 years of original research--developing and characterizing intra-coaxial antennas and wireless sensor technology--JJ left RIT with several submitted technical papers and a U.S. patent. Further pursuing his career, JJ moved with his wife, Aalyia, to New York City. Here, he took on work as the Technical Engineering Editor for Microwaves & RF magazine. At the magazine, JJ learned how to merge his skills and passion for RF engineering and technical writing. In the next phase of JJ's career, he moved on to start his company, RFEMX, seeing a significant need in the industry for technically competent writers and objective industry experts. Progressing with that aim, JJ expanded his companies scope and vision and started Information Exchange Services (IXS).

Profile Photo of Jean-Jacques DeLisle