SimpleFOC - some timings

Hey,

I’ve been running some timings on SimpleFOC, and I wanted to share. @admins feel free to delete this if you feel it is spam.

I use an AS5048 sensor, and tested on ESP32 (240Mhz), Atmega328P (“Arduino Nano” - 16Mhz) and STM32F103 (“BluePill” 72 MHz).

The following were my results so far, I will post more as I run more tests:

BluePill - total fail - I discovered my chips were not original STM32F103 chips, but rather some kind of clone that did not work :frowning: .

Atmega328P, I2C Sensor @ 100KHz I2C Bus speed ~ 450Hz FOC iteration speed
Atmega328P, I2C Sensor @ 400KHz I2C Bus speed ~ 650Hz FOC iteration speed
ESP32, I2C Sensor @ 400KHz I2C Bus speed ~ 850Hz FOC iteration speed

Ok, that’s surprising! ESP32 is crushingly more powerful than the Atmega, why is it not faster? I looked for the answer using a cheap logic analyser, see the timing diagrams attached below…
Basically, even at 400KHz bus speed the I2C communication takes a really long time. So while the ESP32 is 1000x faster at executing the FOC code, it still needs just as long to read the sensor values. SimpleFOC needs to read the sensor 2x per iteration (something to think about?) so the I2C sensor really limits the performance.

To confirm this I ran some more tests with the SPI version of the AS5048:

BluePill - didn’t bother
Atmega328P - could not get it to read the sensor. Still checking into why, since other people have made it work it seems… will report back once it is working.

ESP32, SPI Sensor @ 1MHz I2C Bus speed ~ 4350Hz FOC iteration speed

Now that’s more like it!

Here’s some timing diagrammes:


AtMega328P, I2C @ 100Khz


ATMega328P, I2C @ 400KHz


ESP32, I2C @400KHz


ESP32, SPI @ 1MHz

For explanation: In these scans, I used 3 digital pins, channel 1 I switched on just before the call to moveFOC() and off immediately afterwards. Channel 2 times the move() routine, and Channel 3 times the getAngle() function, the call to the sensor.

The code I was timing looked something like this (depending on platform):

#include "Arduino.h"
#include <SimpleFOC.h>
#include <Math.h>

#define TIMING_FOC_PIN 2
#define TIMING_MOVE_PIN 0
#define TIMING_SENSE_PIN 4
#define SPI_CS 5

MagneticSensorSPIConfig_s AS5048_SPI = {
  .spi_mode = SPI_MODE1,
  .clock_speed = 1000000,
  .bit_resolution = 14,
  .angle_register = 0x3FFF,
  .data_start_bit = 13,
  .command_rw_bit = 14,
  .command_parity_bit = 15
};


MagneticSensorSPI sensor = MagneticSensorSPI(AS5048_SPI, SPI_CS);
BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver =  BLDCDriver3PWM(25, 26, 27);


void setup() {
	Serial.begin(115200);

	delay(500);
	Serial.println("Initializing...");

	pinMode(TIMING_FOC_PIN, OUTPUT);
	pinMode(TIMING_MOVE_PIN, OUTPUT);
	pinMode(TIMING_SENSE_PIN, OUTPUT);
	digitalWrite(TIMING_FOC_PIN, 0);
	digitalWrite(TIMING_MOVE_PIN, 0);
	digitalWrite(TIMING_SENSE_PIN, 0);

	pinMode(SPI_CS, OUTPUT);
	digitalWrite(SPI_CS, 1);
	sensor.init();

	motor.linkSensor(&sensor);
	driver.voltage_power_supply = 9;
	driver.init();
	motor.linkDriver(&driver);
	motor.controller = ControlType::velocity;
	motor.PID_velocity.P = 0.2;
	motor.PID_velocity.I = 20;
	motor.PID_velocity.D = 0.001;
	motor.PID_velocity.output_ramp = 1000;
	motor.LPF_velocity.Tf = 0.01;
	motor.voltage_limit = 8;
	//motor.P_angle.P = 20;
	motor.init();
	motor.initFOC();
	Serial.println("Init complete...");
}


// velocity set point variable
float target_velocity = 2.0;


void loop() {
	// FOC algorithm function
	digitalWrite(TIMING_FOC_PIN, 1);
	motor.loopFOC();
	digitalWrite(TIMING_FOC_PIN, 0);
	digitalWrite(TIMING_MOVE_PIN, 1);
	motor.move(target_velocity);
	digitalWrite(TIMING_MOVE_PIN, 0);

}

Here some thoughts on what this means in terms of attainable speeds / smoothness:

1 Like

Very interesting! Thanks for the stats.

I found running i2C at 1Mbit closed the gap with spi a little but i2c at 3.4Mbit want much faster.

I had hoped for that, but neither ESP32 (to my surprise) or of course the ATMega support 1Mhz, let alone the 3.4MHz. With ESP32 it looks like it should, but doesn’t and the Arduino ESP32 I2C seems to be fraught with problems (I did some research into this while trying to make it go faster).
So STM was my big hope for faster I2C speeds, but here I was surprised to find that I could not make I2C work at all - which put down to my STM chips being cheap clones, as I found out… when I looked more closely it turned out they were CS32F103 chips, not STM32F103, and no matter what I tried I could not make them talk I2C…

So when buying BluePill MCUs, be careful what you buy!

Hey @runger,
For stm32 you’ll probably need the 3-5kOhm pullups.
Are you using some?

If it hangs on Wire.begin the its probably due to PeripheralPins.c needing to be overriden.
Are you using this board and one of these pins:

If it doesn’t hang then yeh check pullups

Thanks Antun!

Yes, I tried different values for the pull-ups, different pins, different software settings :frowning: spent a whole day on it (meaning my free time, so in reality a few hours :wink: ), discovered they weren’t original chips half way through, spent a few more hours, and decided it wasn’t worth continuing until I had a “proper” BluePill to rule out the clone as the source of the problems.
But I admit there were enough variables that I may just have missed the right combination, since not-working I2C at 100KHz seems pretty bad, even for a clone chip…

No hangs, weirdly enough… it seemed to work, but just returned some apparently random number, the same number until you restarted it, in which case the number might change - but not always…
I already ordered some “proper” STM32F103 boards, and will get a working config with those when they arrive. Then I’ll give that config one more shot on the clone chip, just in case…

Here is a Nano 33 IoT running SimpleFOC with I2C encoders:

100KHz I2C:
image

400KHz I2C:
image

The nice thing about the Nano 33 IoT is that its SAMD21 MCU can actually run I2C at 1MHz (and even faster!):

1 Mhz IC2:
image

While still not as fast as SPI, that’s pretty cool. We see here though that the 48Mhz clock speed (i.e. the MCU performance) is now the limiting factor, since the move() function is now actually taking longer than the sensor reads.

I have some powerful STM32s on the way from china, which can do 1MHz I2C and have much faster processors. Lets see what kind of iteration rates we can get to on those.

Note that despite the good I2C performance and decent overall performance the Arduino Nano 33 IoT is currently not an ideal MCU for SimpleFOC because it only runs the generic 3-PWM driver. However, the SAMD has nice Motor-PWM features, and I am looking at writing a hardware integration for it - lets see if I manage, I will post here if I do, and share the code of course.

I think the Nano 33 IoT is quite attractive as a SimpleFOC MCU because of its small form factor, decent chip, integrated Gyro/Accellerometer (think balance bots) and original Arduino provenance.

1 Like