Skip to main content
Associate
August 5, 2026
Solved

Integrating an AS5048A Absolute SPI Encoder into STM32 MCSDK for Sensored FOC and Position Control

  • August 5, 2026
  • 4 replies
  • 176 views

Hello,

I have an STM32G474RE Nucleo-64 with an X-NUCLEO-IHM16M1 driving a GB2208 motor with 7 pole pairs. My goal is to use an AS5048A absolute magnetic encoder for sensored FOC and position control.

MCSDK already runs the motor correctly in sensorless mode, and I can reliably read the AS5048A. However, integrating it into MCSDK has been much less straightforward than expected.

Current implementation

I use TIM1 CH4 to trigger TIM2. TIM2 starts the AS5048A SPI transaction approximately 3 µs after the trigger. My assumption was that this provides a relatively quiet switching interval, avoids interfering with current ADC sampling, and reduces MOSFET switching noise. I am not certain whether this assumption is valid or whether encoder acquisition should instead be synchronized with a specific PWM/ADC event.

After determining the encoder direction and electrical offset, I calculate the electrical angle as:

electrical_angle = (pole_pairs * mechanical_angle + electrical_offset);

I then inject the encoder-derived electrical and mechanical angles into the FOC path from:

__weak uint8_t TSK_HighFrequencyTask(void)

For position control, I implemented an outer PID loop running at 500 Hz, or once every 2 ms. Its output is a speed reference sent through:

MC_ProgramSpeedRampMotor1(...)

The rotor initially spins, often for multiple revolutions, and then stops with an observer/convergence or speed-feedback fault.

My current understanding is that I have replaced the angle used by FOC without replacing the State Observer + PLL feedback component. Therefore, the FOC uses the AS5048A angle while the sensorless observer still performs estimation, startup convergence, reliability checks, and fault generation. Unsurprisingly, those two feedback paths do not remain consistent. MCSDK has a generic Speed & Position Feedback componentspeed_pos_fdbk.h, while the existing implementation is specifically the State Observer + PLL component sto_pll_speed_pos_fdbk.c+1 . This suggests that overwriting angle variables inside the high-frequency task is the wrong abstraction. (This is just an opinion and maybe wrong)

Questions

  1. Is my encoder sampling timing reasonable?
    Is triggering the AS5048A read approximately 3 µs after TIM1 CH4 a valid way to avoid ADC acquisition and switching noise? Is there a recommended PWM event or ADC-injected-conversion completion point for triggering SPI encoder acquisition on the STM32G474?

  2. Must the observer be replaced completely?
    For absolute-encoder FOC, should I implement a new Speed & Position Feedback component derived from MCSDK’s generic feedback interface and remove the STO-PLL from:

    • electrical-angle selection,
    • startup convergence,
    • speed calculation/reliability checks, and
    • fault generation?

    Or does MCSDK provide a supported configuration or existing component for SPI absolute encoders?

  3. What is the cleanest integration method?
    Is there a documented way to integrate a custom absolute encoder into MCSDK without modifying generated high-frequency-task code? My current approach -- overwriting angles inside TSK_HighFrequencyTask() -- feels like a hack.

  4. Is the outer position-control architecture valid?
    Is a 500 Hz position PID producing a speed reference through MC_ProgramSpeedRampMotor1() appropriate, or should the position controller output an Iq/torque reference instead? Also, does repeatedly calling the speed-ramp API every 2 ms restart or interfere with the ramp state machine?

My MCSDK version is 6.4.2, generated with Motor Control Workbench.

I would appreciate confirmation of whether the overall architecture is valid and which MCSDK interfaces should be implemented or replaced.

Best answer by Gustave

Hi ​@Ali_Sa,

I did a integration of the AS5048A with Nucleo-G431RE + IHM16M01 + Gimball3506 + Magnetic encoder AS5048A.
You can find it on my github : https://github.com/Gustar00/Magnetic_encoder_AS5048A_MC_SDK_STM32

This integration is made for speed control, but the position control implementation is pretty straightforward.
I used DMA instead of Timer to acquire the motor angle, it almost erased any race condition with the FOC loop.

Kind regards,

Gustave
 

 

4 replies

Associate II
August 6, 2026

Please check the feedback from ST AI tools and feedback if it is helpful. Thanks

 

=====================================================================

Your current conclusion about the architecture is directionally consistent with the MCSDK structure: MCSDK uses a Speed & Position Feedback component as the abstraction that provides rotor speed and angle, with implementations for sensorless estimation and encoder-based feedback, so overwriting angle variables inside the high-frequency task does not match the documented abstraction.

For timing, timer-synchronized acquisition is reasonable in principle, because STM32G4 supports PWM/timer-triggered synchronized sampling and precise trigger-controlled ADC timing, and SPI/DMA can be used for encoder acquisition; however, the documentation I found does not give a specific recommendation for TIM1 CH4 + ~3 µs or for a specific PWM/ADC event to trigger an SPI absolute encoder read on STM32G474.

Detailed Explanation

1) Encoder sampling timing

The STM32G4 ADC is designed for motor-control synchronization: it supports PWM-triggered ADC injected conversions, synchronized sampling, and precise timing control through timer triggers. The trigger edge can define when sampling starts and when conversion begins, which is exactly the kind of mechanism used to place acquisition in a quieter portion of the PWM cycle.

The same material also states that SPI can be used to interface with external encoders, and DMA can offload CPU activity during data transfers.

So, at a high level, your idea of synchronizing encoder reads with timer events to reduce switching-noise sensitivity is compatible with the STM32G4 motor-control feature set.

What I could not confirm from the retrieved documentation is any official recommendation that the encoder read should be triggered ~3 µs after TIM1 CH4, or specifically at ADC injected-conversion completion, for an AS5048A on STM32G474.

2) Whether the observer must be replaced completely

The MCSDK documentation states that the Speed and Position Feedback component is the block that provides the rotor speed and angular position, and that MCSDK has multiple implementations for this role, including Hall sensor feedback, sensorless Back-EMF/state-observer + PLL, and encoder-based feedback.

One retrieved source explicitly says encoder-based feedback includes absolute encoder via SPI. That supports your view that the clean architecture is to integrate feedback at the Speed & Position Feedback layer rather than patching the angle later in TSK_HighFrequencyTask().

However, I did not find retrieved documentation that explicitly explains, for MCSDK 6.4.2, how a custom SPI absolute encoder interacts with:

  • STO-PLL startup convergence,
  • observer reliability checks,
  • speed-feedback fault logic,
  • or fault generation when mixed with sensored angle injection.

So I cannot confirm from the official material retrieved here whether the observer must be fully removed, disabled, or partially retained in your exact configuration.

3) Is there a supported MCSDK configuration for SPI absolute encoders?

This is the most important point where the retrieved material is not fully consistent.

Evidence suggesting support

One source says the MCSDK supports encoder-based feedback including absolute encoder via SPI, and also provides APIs for speed control and position control.

Evidence limiting Workbench position-control usage

Another source says that in the MC Workbench, position control is only accessible when a quadrature encoder is selected as the main speed-sensing sensor. The same retrieved material references sensored FOC operation with quadrature incremental encoders and Hall sensors, but does not explicitly show a Workbench flow for SPI absolute encoders such as AS5048A.

Practical conclusion from the official material

  • The architecture of MCSDK clearly contains a feedback-component abstraction for rotor angle/speed.
  • But the Workbench-oriented material retrieved here points mainly to quadrature encoder support for position-control enablement.
  • So, from the documents available here, there is no clear, fully documented, contradiction-free path for AS5048A SPI absolute encoder + Workbench-generated position control on MCSDK 6.4.2.

4) Cleanest integration method

The cleanest method supported by the MCSDK architecture is to provide rotor angle/speed through the Speed & Position Feedback component rather than overwriting internal angle variables later in the control path.

That said, I did not find a retrieved official procedure that explains how to integrate a custom SPI absolute encoder into MCSDK without modifying generated high-frequency-task code. The documentation I found confirms the abstraction exists, but does not provide the concrete integration steps you are asking for.

5) Outer position-control architecture

The retrieved material confirms that MCSDK supports position control, that it can be enabled in the Workbench, and that it requires an encoder for speed and position feedback. It also states that APIs such as MC_ProgramPositionCommandMotor* are available to set a target mechanical angle and movement duration, and MC_GetCurrentPosition1 can be used to read the current rotor position.

The same material says that when position control is active, speed and torque control modes cannot be used simultaneously.

For speed control, the API MC_ProgramSpeedRampMotor1() is described as programming a speed ramp for the motor. One retrieved source also states that in a position-control application, the outer loop typically generates a speed reference, which is then handled by the speed loop.

So, from the retrieved material:

  • A position loop producing a speed reference is consistent with the described control layering.
  • MCSDK also provides a dedicated position-command API, which is the more directly documented path for position control.
  • I did not find official documentation here stating whether calling MC_ProgramSpeedRampMotor1() every 2 ms restarts or interferes with the internal ramp state machine.

Bottom line

From the official material available here, I would summarize the situation like this:

  1. Your timer-synchronized encoder read concept is reasonable, but the documents do not identify TIM1 CH4 + 3 µs as a recommended official sampling point for SPI absolute encoders.

  2. Your architectural concern is valid: MCSDK is built around a Speed & Position Feedback abstraction, so injecting angle values directly in the high-frequency task does not match the documented component model.

  3. The retrieved documentation is incomplete/conflicting about direct SPI absolute encoder support in the Workbench flow:

    • one source says absolute encoder via SPI is supported,
    • while another says position control is accessible when a quadrature encoder is selected as the main speed sensor.
  4. For position control, the most clearly documented path is to use the built-in position-control feature and APIs rather than building an external loop around repeated speed-ramp calls.

Would you like me to focus next on one narrower point: the MCSDK feedback-component architecture, the Workbench position-control limitations, or the STM32G4 timer/ADC synchronization options for encoder sampling?

Ali_SaAuthor
Associate
August 6, 2026

Thank you for the AI-generated feedback. It is useful as a high-level summary, but I would still appreciate confirmation from an ST motor-control expert, especially regarding MCSDK 6.4.2 implementation details.

I selected the 3 us delay mainly to avoid overlapping the AS5048A SPI transaction with the shunt-current ADC conversion. My intention was to give the current-sampling circuitry and ADC a quieter interval, not because I found 3 us in any ST documentation. I’d like to know whether this concern is technically justified and whether ST recommends a specific PWM event or interval for reading an SPI encoder.

I’d  also appreciate references to the documentation that describes the Speed & Position Feedback component/object, particularly for implementing a custom sensor. The source files appear to define a generic feedback abstraction in

speed_pos_fdbk.c/.h

, while 

sto_speed_pos_fdbk.h

provides the common interface for state-observer implementations. However, I have not found practical guidance explaining:

  • Which functions a custom absolute-encoder feedback component must implement.
  • Where its handle must be instantiated and connected.
  • How it replaces the STO-PLL as the main angle and speed source.
  • How startup convergence, reliability checks, and observer-related faults should be handled.
  • Which generated files can be modified safely without losing changes when regenerating the project.

Because Motor Control Workbench does not offer the AS5048A as a selectable feedback sensor, I selected Sensorless Back-EMF + PLL only to generate the base project. I now suspect this is why the generated startup and fault-management code still expects observer convergence, even though I later overwrite the FOC angle with the AS5048A angle.

The relevant code is difficult to follow because the feedback object, high-frequency task, startup state machine, speed loop, and fault logic are spread across several generated files. If ST has an application note, example project, or documentation describing how to add a custom SPI absolute encoder as the main MCSDK Speed & Position Feedback component, a link would be extremely helpful.

I am specifically looking for the supported architecture. 

 

GustaveBest answer
ST Employee
August 7, 2026

Hi ​@Ali_Sa,

I did a integration of the AS5048A with Nucleo-G431RE + IHM16M01 + Gimball3506 + Magnetic encoder AS5048A.
You can find it on my github : https://github.com/Gustar00/Magnetic_encoder_AS5048A_MC_SDK_STM32

This integration is made for speed control, but the position control implementation is pretty straightforward.
I used DMA instead of Timer to acquire the motor angle, it almost erased any race condition with the FOC loop.

Kind regards,

Gustave
 

 

Ali_SaAuthor
Associate
August 7, 2026

Hi ​@Gustave,

I really appreciate your help. Please give me some time to go through your code carefully and see if I can get a good understanding of it.

 

Regards,

Ali