I have a Raspberry Pi Pico board reading 2 AS5048A position encoders via SPI.
If my loop reads either encoder on its own, the read completes in around 100uS.
If I read both sensors, the read time isn’t the 200us I am expecting, its 7x slower at 1400 us!
I think this is why the control loop becomes unstable as soon as the second encoder is added to the main loop. Any thoughts on what would cause this?
I am measuring the read time with this section of the main loop, and comment out one of the update() calls to test the single encoder case.
unsigned long t1 = micros();
sensor0.update();
sensor1.update();
unsigned long t2 = micros();
Serial.println(t2-t1);
Both sensors appear to be working and return sensible values.
Below is the full sketch
`#include "Arduino.h"
#include "SPI.h"
#include "SimpleFOC.h"
#include "SimpleFOCDrivers.h"
#include "encoders/as5048a/MagneticSensorAS5048A.h"
#define SPI_0_MISO 4
#define SPI_0_MOSI 3
#define SPI_0_SCK 2
#define SENSOR0_CS 5
#define SPI_1_MISO 12
#define SPI_1_MOSI 15
#define SPI_1_SCK 14
#define SENSOR1_CS 13
MagneticSensorAS5048A sensor0(SENSOR0_CS, true);
MbedSPI spi_i0(SPI_0_MISO, SPI_0_MOSI, SPI_0_SCK);
MagneticSensorAS5048A sensor1(SENSOR1_CS, true);
MbedSPI spi_i1(SPI_1_MISO, SPI_1_MOSI, SPI_1_SCK);
void setup() {
spi_i0.begin();
sensor0.init(&spi_i0);
spi_i1.begin();
sensor1.init(&spi_i1);
}
void loop() {
// update the sensor (only needed if using the sensor without a motor)
unsigned long t1 = micros();
sensor0.update();
sensor1.update();
unsigned long t2 = micros();
Serial.println(t2-t1);
// get the angle, in radians, including full rotations
float a1 = sensor1.getAngle();
if (sensor1.isErrorFlag()) {
AS5048Error error = sensor1.clearErrorFlag();
Serial.println("Cleaning up sensor 1");
}
// get the angle, in radians, including full rotations
float a0 = sensor0.getAngle();
Serial.println(String(a0)+','+String(a1));
if (sensor0.isErrorFlag()) {
AS5048Error error = sensor0.clearErrorFlag();
Serial.println("Cleaning up sensor 0");
}
delay(500);
}`
The sketch is the only task loaded. I don’t normally use Arduino but my limited understanding is your sketch is all that runs, there is no OS getting in the way.
The main loop measures the time to read the two encoders every 0.5 seconds and the readings are very consistent. Always long when reading 2 encoders, always short when reading 1.
We can see the slow down in the cs timing. Here are the cs pulses with 2 encoders being used. Red is the cs for one channel, blue the cs for the other.
With 2 encoders in use the cs signals go low, then nothing happens for a long time, then finally the read is made and the cs goes high again. Here cs is red, clock is blue.
That transfer function is internal to the framework…
Very interesting bug report.
Since you’re using 2 SPI ports, you could try to run the code for each sensor on separate cores, and see if the problem still occurs.
It looks like some kind of glitch in the RP2040 SPI implementation - I wonder which core is handling the SPI interrupts internally, and if there is some kind of issue there once you add the second sensor.
Using the Arduino Mbed OS RP2040 Boards by Arduino board library I don’t see any concurrency, only the Core 0 message is shown.
Using the Raspberry Pi Pico/RP2040 by Earle F. Philhower, III the concurrency happens, but the SimpleFOC headers wont compile. I saw your fix you made for the pin numbering on github
and applied that. But that just exposed another set of errors.
/Users/jeremy/Documents/Arduino/libraries/SimpleFOCDrivers/src/settings/rp2040/RP2040FlashSettingsStorage.cpp: In member function ‘virtual RegisterIO& RP2040FlashSettingsStorage::operator<<(uint8_t)’:
/Users/jeremy/Documents/Arduino/libraries/SimpleFOCDrivers/src/settings/rp2040/RP2040FlashSettingsStorage.cpp:85:1: error: no return statement in function returning non-void [-Werror=return-type]
The code below reads two sensors each on a different SPI port, each reader running on a different core on a Raspberry Pi Pico with good performance, almost always less than 40uS per read.
To get this working I did as follows:
1
Went with the Raspberry Pi Pico/RP2040 board profile from Earle F. Philhower, III.
2
Commented out the lines in Arduino/libraries/SimpleFOCDrivers/src/settings/rp2040/RP2040FlashSettingsStorage.cpp
causing syntax errors mentioned in the post above. Specifically lines from 82 to just prior to the final #endif in that file.
3
Applied Runger’s patch from github, also mentioned above. Nothing sophisticated using git pulls, I just typed in the change by hand.
4
Changed the way SPI busses and their pinouts are selected to be compatible with the way Philhower does SPI.
And with that done, this simple test case happily reads 2 off AS5048A magnetic encoders in parallel.
Having been forced from mbed to Earles implementation of the Raspberry Pico board integration to get multi core support, it occurred to me the SPI driver code got swapped out too. Perhaps the original SPI performance issue disappeared along with that.
So tried merging the 2 threads back into one, and find it does indeed still perform well.
I am seeing 30us to read the first encoder, and another 20us on the second. Of course with a single thread, these add up, so 50us for both encoders. But thats still a massive 28 times faster than the 1400us I was getting with mbed reading both encoders, and even 4x faster than mbed reading a single encoder!
So in summary, stay clear of mbed if you are working with SPI on the Raspberry Pi Pico and care about performance.
Thanks a lot for this very informative test! That’s really good to know.
I’ve definitely observed the difference in performance between the two cores, but didn’t know what the reason was. pinpointing it to the SPI is very useful indeed.
I wonder if we should just recommend the use of philearlehowers core in the first place?
It’s also hard to understand why Arduino does this to its users? Building on Mbed, which they’ve done on a number of their boards, would seem to benefit no one but themselves, and then only if we assume their aim is to kick new framework versions out the door ASAP, with no regards to size or performance…
Hi Runger. I now have two SimpleFOC motor controllers running and its working well. It’s a tidy solution, each motor controller has its own dedicated core and SPI interface.
I support recommending using Earles code for Pi Pico users starting from the moment SimpleFOC’s code will compile without modification against it. That means the fix you already have in github being released as well as a fix for the empty functions with non void return values.