I’m running into a problem with encoder sensor. I’m running SimpleFOC on an STM32F303RE Nucleo board. Motor is iPower GM4108 with L6234D driver IC. I managed to get the motor running, however, initialization fails (“Failed to notice movement”). Encoder signal looks good on an oscilloscope, and STM32 is able to perform digitalRead() on the pins I’m using for the encoder.
To debug this issue, I removed the motor code, and focused only on the encoder. I used the example from the bottom of this page, hardware interrupts. I can get some readings, so the MCU definitely reads the encoder. getAngle() returns increasing numbers when rotating in both directions. getVelocity() does return some negative values, but they are predominantly positive.
With Quadrature ON 1 full rotation results in angle of 2-2.5rads. With Quadrature OFF I get closer values of 3.x, despite AMT103 being quadrature.
I also tried different resolutions (5120PPR, 2500PPR, 640PPR), but the result is the same.
Pin assignment:
// PWM pins
const int pin_pwm_a = PC0; // phase A
const int pin_pwm_b = PC1; // phase B
const int pin_pwm_c = PC2; // phase C
// current sense pins
const int pin_is_a = PA1; // current sense for phase A
const int pin_is_b = PA4; // current sense for phase B
// encoder pins (initially tried commented-out values, but changed them to the ones shown here)
const int pin_enc_a = PA8; // PC10; // encoder A
const int pin_enc_b = PB10; // PC12; // encoder B
const int pin_enc_x = PB4; // PA13; // encoder X
// enable pins
const int pin_enable = PB0; // enable for motor 1
I would appreciate any help troubleshooting this. I was unable to find similar issues here, sorry if it’s a duplicate. Thank you!
Testing with just the encoder is the right approach.
For one full turn of the motor, the sensor has to return ±6.28 radians (2π). Until it does that, no point in trying closed loop control.
Would you mind sharing the code you use to initialize the encoder? You should specify the PPR value (not the CPR, which is 4x higher with quadrature).
On STM32 MCUs you can also try the STM32HWEncoder class from our drivers library: Arduino-FOC-drivers/src/encoders/stm32hwencoder at master · simplefoc/Arduino-FOC-drivers · GitHub
You’ll have to use CH1 and CH2 of a general purpose timer like TIM3 to connect the encoder pins.
The advantage is that this implementation does not use interrupts, and uses the STM32s built in hardware encoder driver, so you get the encoder working with no overheads at all.
How is power supplied to the encoder?
How long are the wires between encoder and MCU?
In the dataheet the of the atm103 there are only couple of PPR that you can choose from and none of them seems to correspond to the ones you try. Do you have some other variant of the amt103?
Here is the datasheet: https://www.mouser.fr/datasheet/2/670/amt10_v-1775837.pdf
And the resolution setting
Any encoder can be used in quadrature mode or not, its related to how the pulses are counted rather than to the mechanics/electronics of the sensor. So you should get the same result regardless of is the quadrature mode is on or off.
The difference being that if you dont enable the quadrature mode, the resolution of the sensor is PPR and if you enable the quadrature mode the resolution is 4xPPR. But this is all handled within the Encoder class, and if you provide the correct PPR you should not see any difference when you call getAngle (except maybe a difference in precision/resolution).
Thank you for the STM32HWEncoder suggestion! I’ll give it a try.
My test setup is as follows:
I’m using a rev.1 driver PCB that I designed for current sensing, motor phases are connected via screw terminals on the board. It is powered with a lab power supply set to 12V. It has 3.3V LDO for powering current sense ICs (MAX4372HEUK+TDKR).
I’m using L6234D breakout board with supporting components soldered to is as per its datasheet. Output and power supply wires are soldered to the PCB, input wires and enable are connected to the MCU via a breadboard
Encoder is powered from the PCB with jumper cables and a pin header. Encoder A,B, and X outputs are wired through the breadboard and to STM32 with 2x 20cm jumper cables
STM32 is powered with my laptop over USB. Ground is shared to the breadboard and PCB
I’m less familiar with STM32F3 series, but this is just basic interrupt code, it should work just fine.
One thing you could check is if using different pins helps at all.
I’m also not sure how the encoder interfaces - you configure external pull-ups but I’m not sure this encoder needs any pull-ups.
You mentioned checking the signal with a scope - was that with everything connected, or just the sensor?
Is is possible there is a mechanical problem with the connection to the motor shaft?
Otherwise I’m afraid I’m out of ideas for the moment…
@runger, I’ve tried STM32HWEncoder with no luck. It outputs 0s. I tried various pins on TIM2, TIM3, and TIM4. Ch1 → A, Ch2 → B, Ch3 → index (however, STM32HWEncoder docs say that index is not used).
@Antun_Skuric. Through experimentation, I found that only Quadrature::ON works for some reason. When I set it to OFF, I get readings of 0. With it ON, I’m unable to get angle anymore (displays 0). I used a spreadsheet to sum all the velocities readings, and it’s not 0.
The velocities are point in time measurements, you’d have to print them with their timestamps and integrate the area between the resulting curve and the time axis…
Even so it would not work out very exactly as the velocity signal is differentiated from the position and has quite some error.
I haven’t tried the HWEncoder with F3 MCUs but it should work. It can be tricky to get the pins right, as sometimes you have to use the alternate functions like encoder._pinA = PB_7_ALT2;
For technical reasons you can’t set the alternate pin names via the constructor, you have to set them afterwards.
But since neither interrupt or HWEncoder are working it could be indicative of another issue.
Thanks for the ALT pin suggestion, @runger! Encoders work now!
I’m including my code for future reference. Using STM32F303RE Nucleo board and STM32HWEncoder class. 2 TIMs tested TIM3 and TIM2, both use CH1 and CH2. Code for TIM3 is shown, code for TIM2 is in the comments
#include <SimpleFOC.h>
#include "SimpleFOCDrivers.h"
#include "encoders/stm32hwencoder/STM32HWEncoder.h"
...
STM32HWEncoder sensor = STM32HWEncoder(
960,
PC6, // PA0 for TIM2
PC7 // PA1 for TIM2
// index pin is not used
);
void setup() {
sensor._pinA = PC_7_ALT1; // PA_0
sensor._pinB = PC_6_ALT1; // PA_1
// initialize encoder hardware
sensor.init();
Serial.printf("Is encoder initialized? %u\r\n", sensor.initialized);
}
void loop() {
// IMPORTANT - call as frequently as possible
// update the sensor values
sensor.update();
if (abs(sensor.getVelocity()) > 0.01) {
// display the angle and the angular velocity to the terminal
Serial.print(sensor.getAngle());
Serial.print("\t");
Serial.println(sensor.getVelocity());
}
}
Also, for anyone troubleshooting STM32HWEncoder setup, there are 4 conditional checks in the STM32HWEncoder::init() function that may stop initialization. Adding print statements to those 4 fail conditions helped me a lot with finding the solution.
@runger, I saw it was you who worked on STM32HWEncoder class implementation. Would you like to update the README file to include that it was tested and works on F3-series with TIM2 and TIM3?
Proceeding to test it with a motor, there are still some issues:
MOT: Align current sense.
CS: Err A - all currents same magnitude!
MOT: Align error!
MOT: Init FOC failed.
I will do more testing next week, but since this issue is not related to the encoder, I can end this thread.