STM32 code duration and organisation

Hi there!
I’m still working on my STM32G030 with STM32duino. I got some interesting results on gimbal motors for light weight applications (I’ll show that soon). So far so good.

Well, for this application, I’ve got quite a lot of data to transfer between my computer and stm32.
As a result I got some interferences on the Simplefoc regulation (I.E. the motor got some ‘bump’ when rotating and transferring datas).

My STM is 64MHz, F_CPU variable seems to confirm that.
But strangely, loopFOC()+move() takes around 850us (checked with micros() function).
It seems a bit high compared to the table on the docs.

I tried to use some interrupt to prioritize (I saw some post about it earlier, that seems to not be an option), and I only can use the code @900Hz and it makes a terrible noise and current consumption is not good such as the behaviour.

Any idea? hints? Voodoo stuff to help me solve my problem?

My guess are: try to speed up the transmission, but my hardware seems to makes some issues about that. Or my UC is a liar and is not running fast enough to allow me to make a nice interrupt.

Thanks a lot folks!

Hi, sounds like a cool project, show us more :wink:

The STM32G0 is a lower power MCU, so you should expect to have to use its resources carefully. A few questions:

  • are you using current sensing?
  • what kind of sensor are you using?
  • what kind of data are you transferring, and how often?
  • what transport are you using for this? (Serial via USB?)

For good performance you should aim for a FOC loop speed of more than 1kHz, 10kHz is much better. The move function does not have to be called quite as often (see the parameter “motion_downsample”).

Nonetheless, designing a communications protocol to run on the same MCU next to a real-time critical process like the FOC-control is not super-simple.

It is made much simpler if you can reduce the data traffic as much as possible and keep within the limits of what is actually possible. Some ideas:

  1. increase your comms speed as much as possible while still having reliable communications. Usually, 256,000 or even more is possible on a USB serial port.
  2. increase your serial buffer sizes a little bit. The default sizes are usually quite low. (USART_RX_BUF_SIZE/USART_TX_BUF_SIZE).
  3. make sure you are sending data compactly. Use a binary format, and perform conversions, cleaning up etc… on the receiving side, where you have more CPU cycles to spare.
  4. don’t send more at a time than the transmit buffer can hold, or your code will block and slow down the loop
  5. don’t send more per second than the hardware can naturally support, or you will have delays, and of course won’t hit the desired bit-rate anyway
  6. design an asynchronous, unacknowledged protocol for maximum throughput

So for example for Serial at 115200 baud, you should be able to get 12800 bytes/s. So this means if you aim for 5kHz FOC loop speed, you should send no more than 2 bytes per loop iteration. Probably better would be to fill the buffer with 20 bytes over 10 loop iterations, and then send that in one go.

Hi @runger,
Thanks for your answers and interest!

  • are you using current sensing?

Nope, just simple position control based on angle.

  • what kind of sensor are you using?

The AS5600L, and in fact I just double check and I saw I missed the I2C duration on the table that takes about 1000us.
I tried to use 800Khz com, doesn’t seems to change anything.

  • what kind of data are you transferring, and how often?

In fact I try to be compatible with dynamixel protocol, to have a known base that works.

  • what transport are you using for this? (Serial via USB?)

Nope, only serial.

Thanks a lot for the ideas!

  1. increase your comms speed as much as possible while still having reliable communications. Usually, 256,000 or even more is possible on a USB serial port.
  1. Increasing the com speed was an idea that I had, but it seems that my hardware won’t work with the baudrate of 1M (dynamixel use 9600 56700 115200 1M, …).
    That makes another constraint
  1. increase your serial buffer sizes a little bit. The default sizes are usually quite low. (USART_RX_BUF_SIZE/USART_TX_BUF_SIZE).
  1. Good though about augmenting the USART_RX_BUF_SIZE, I’ve to explore that, didn’t anything about yet.
  1. make sure you are sending data compactly. Use a binary format, and perform conversions, cleaning up etc… on the receiving side, where you have more CPU cycles to spare.
  1. I must respect the protocol.
  1. don’t send more at a time than the transmit buffer can hold, or your code will block and slow down the loop
  1. Sure :slight_smile:
  1. don’t send more per second than the hardware can naturally support, or you will have delays, and of course won’t hit the desired bit-rate anyway
  1. indeed
  1. design an asynchronous, unacknowledged protocol for maximum throughput
  1. Still have some more contraints

Maybe you are right, I can send data when I’v got some time. I’ll check what I can do.
I’ll try to explore how to speed up sensor com and how to manage the serial com.

I should have read more about the AS5600 :wink:
This is my biggest problem. Even if on the datasheet they say it can use “Fast-mode Plus”, it takes itself around 500us…Dammit

EDIT:
Found something about the I2C clock and AS5600.
In setup function I2C must be change as follow:
sensor.init(&Wire);
And then
Wire.setClock(400000);
In my case, otherwise the clock change didn’t apply.

Good news for me: now loopFOC()+move() is about 500us at 400khz on the I2C! :slight_smile:
But at 1000000, it doesn’t seem to work.

Ok, it sounds like you’ve found the issue - the I2C sensors are just a bit slow. Use an SPI or ABI type interface to get more speed, like an AS5047 or AS5058A… (I know, they’re more expensive :frowning: )

Fast mode plus (1MHz) I2C is tricky to get working, I think. I know the sensors support it, but I have not made it work so far. Many MCUs don’t even support it, but yours actually does…

Indeed the price :slight_smile:
Well, weirdly 1MHz seems to work correctly with the sensor only but not with simplefoc algorithm. I have to investigate a bit.
I tried as you mention earlier to get a bigger TX buffer (since my problem seems to be transmission), but I don’t get significant results.
I don’t have yet very good improvement but still, this is interesting.
Thanks again @runger!

Hmmm… in this case maybe messing with the value of the pull-up resistors can help. An oscilloscope can also help finding the problem in this case. Shielding/twisting the cables, etc… but if you’re too near the electrical reliability it is not good either, then the sensor can be unreliable due to bit errors.

I just checked on the oscilloscope and you were right, signal raised slowly. I lowered the pullup and now it works. 5.6k => 2k works well.
Now I’ve got 480us, was not a huge gain but it is still nice.
I’ll check 1M Serial now to check if I get improvement and if not I’ll change my optic about serial com management.

Ok! Seems to work with 1M UART. The issue was the low cost FTDI I used.
I do have a lot of thing to test and implement now, but that seems nice and smooth :stuck_out_tongue:
@runger I’ll keep you updated as soon as I have something pretty to show!
Thanks you very much!!

1 Like

Hi!
@runger As promised: here is my little devices!

Size: D34x23mm
I did a special video for you, very quick and dirty!

I apologize, I didn’t take the time to tune the PID on those 3 :smiley: !!

1 Like

Hey @robotsmith , thanks for sharing!

Very impressive! And I didn’t fully get it before, but I finally understand where you’re going with the Dynamixel protocol, and I must say this is really very cool!

Lots of robots use dynamixels, and this could be a BLDC replacement while keeping the existing hardware and software on the controlling end, right? Totally cool concept.