Current sensing on custom board based on EVSPIN32G4

Hi @runger - both myself and @DarkMajster have designs loosely based on stspin32g4 eval board. This is a lowside design very similar to b-g431-esc1. i.e. using 3 internal opamp/comparator to measure shunts. Each phase has opp, opo, opn pins however I think 1 of the pins is different to b-g431-esc1.

Am I right in thinking I can lift and shift the b-g431-esc1 code with a few tweaks?

I spent a lot of time in the esc1 current sense code recently… it should be very straightforward to change the pin.

You need to change this to match the correct input (see op amp config defines in the HAL reference for G431): https://github.com/simplefoc/Arduino-FOC/blob/master/src/current_sense/hardware_specific/stm32/b_g431/b_g431_mcu.cpp#L56

You also would normally need to change this to init the right pins… but it looks like all of the possible IO for the opamp are being initialized as analog inputs? https://github.com/simplefoc/Arduino-FOC/blob/master/src/current_sense/hardware_specific/stm32/b_g431/b_g431_hal.cpp#L246

I think the connection of the opamp to the ADC should be unchanged for different opamp input pins so no other changes, I think.

Hey,

I did not do this comparison properly, but my impression is maybe the F4/G4 code is slightly newer than the G431 code.

So personally my approach will be to use the standard G4 current sensing code (low side) and add the OPAMP initialisation on-top.

My impression is Candas and others have done a lot to improve the STM32 current sensing code recently, but their focus was F1/F4/G4, and I have not checked to see if all the improvements also made it to the G431 codebase…

Longer term, I think the specific g431 code should be replaced anyways :slight_smile:

1 Like

Hi Richard,

These are the recent improvements:

  • ADC calibration, it was already merged for g431 (here)
  • removing the adc interrupt for injected adc,no adc interrupt is used in the g431 current sense driver so no change
  • fix when using only 2 phase currents, it was merged and is not chip dependent

So it sounds like they should be in a similar state then :slight_smile:

@runger what is the “opamp init code at the top” that you talk about?
I’ve tried https://github.com/Candas1/Arduino-FOC/#stm32_adc_no_interrupt and normal simplefoc and am getting the following during setup:

IM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N score: 1
STM32-DRV: best: TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N score: 1
STM32-DRV: Restarting timer 1
MOT: Monitor enabled!
STM32-CS: ERR: Analog pins dont belong to the same ADC!
MOT: Init
MOT: Enable driver.
2.0000  2.5000  2.0000  0.0667
2.0000  2.5000  2.0000  0.1429
2.0000  2.5000  2.0000  0.2176

That is with the following code:

#include <Arduino.h>
#include "SimpleFOC.h"
#include "SimpleFOCDrivers.h"
#include "drivers/stspin32g4/STSPIN32G4.h"
#include "stm32g4xx_hal.h"
// #include "HardwareSerial.h"
#include "SoftwareSerial.h"

SoftwareSerial Serial1X(PA9, PA10);

LowsideCurrentSense currentSense = LowsideCurrentSense(0.01, 20, PA2, PA6, PB1);

STSPIN32G4 driver = STSPIN32G4();
BLDCMotor motor = BLDCMotor(6);

void setup()
{
    Serial1X.begin(115200);
    SimpleFOCDebug::enable(&Serial1X);
    driver.voltage_power_supply = 24.0f;
    driver.voltage_limit = 5.0f;
    driver.init();
    motor.useMonitoring(Serial1X);
    motor.voltage_limit = driver.voltage_limit / 2.0f;
    motor.controller = MotionControlType::velocity_openloop;
    motor.linkDriver(&driver);

    currentSense.linkDriver(&driver);

    // current sensing
    currentSense.init();
    // no need for aligning
    currentSense.skip_align = true;
    motor.linkCurrentSense(&currentSense);

    motor.enable();
    motor.init();
    pinMode(PC2, OUTPUT);
}

void loop()
{
    motor.move(2.0f); // 5 rad/s open loop
    motor.monitor();
    delayMicroseconds(100); // STM32G4 is very fast, add a delay in open loop if we do nothing else
}

My custom board is wired like this:

@runger Please correct me if I am wrong.
All STM low side current sense drivers require the pins/channels to be on the same ADC, except the G431-ESC1 that is using 2 ADCs but is very hardware specific.

I started to work on a new setup with a nucleo-ihm16m1 and I have the same error message. I couldn’t investigate in details yet.

I am not sure if there are alternative pins that can let you pick the same pin on a different adc as a workaround ( see pinmap )
[EDIT] No PA2, PA6 and PB1 cannot be used with the same ADC it seems.
This would work with the G431 current sense driver, the pins are the same.

Ideally, the drivers should be improved to be able to initialize different ADCs if needed, but that could be complex.

So then for the moment you have to use the G431 code…

Longer term, the general STM32 code should work also with multiple ADCs, and the B-G431-ESC1-specific code should be reduced to configuring the OP-Amps which is the part that is unique to that board…

Generally speaking using different ADCs is actually better since the conversions can happen in parallel rather than sequentially. We’ll have to look over the code though to make sure the way we read the values in injected conversion doesn’t make it happen sequentially in the end…

I’m somewhat confused, @runger - you suggest I used G431 code but that doesn’t have any OPAMP configuration which is what I want as the stspin has OPAMP1, OPAMP2, OPAMP3 configured. So it looks to me like my board needs to use code similar to B-G431-ESC1. There are some things stopping me from simply setting -D ARDUINO_B_G431B_ESC1 (pretending to be that board)

  1. OPAMP2 pins are a bit different on my board
  2. b_g431_mcu.cpp has references to defines e.g. A_POTENTIOMETER that cause the code not to compile

I could start a new hardware specific folder for stspin32 (based on ESC1) - looking for some guidance on what might land best.

I’m sorry, I realise now that must be pretty confusing…

So the situation is this:

  • At the moment, you should certainly base your solution on the B-G431-ESC1 code. This both because of the OP-Amps, and also because it is currently the codebase that works with more than one ADC.

  • Please don’t start another hardware specific folder for STSPIN, that seems like the least preferable solution to me…

  • Longer term, in the future, both the B-G431-ESC1 and your STSPIN code should just be re-factored into the main G4 driver. There is nothing special about either of these hardwares, they are both standard G431s in terms of how their ADCs are configured.

  • Longer term, we should add some code to configure the op-amps. This is what is “different” in the B-G431-ESC to the standard current sensing code with no op-amps. So we should find a way to make it an optional add-on to the standard code.

We want to avoid a situation where each hardware combination becomes a new current sensing hardware folder in the main library. If anything, that would be for the drivers library, but even better would be a situation where different hardwares are just “examples” showing how to configure the standard driver…

Does this make better sense?

1 Like

You can configure the op-amp without any interaction with the library, I don’t think that should be an issue, just use the Cube MX code.

I think the harder part will be getting the simpleFOC code to use the Vout from opamp as the input to the ADC. This is easy to configure if you do manually as in ESC1 ADC config but I’m not sure how to convince the library to do this for you as PinMap in stm32duino doesn’t include the opamp channels (ADC1_IN13, ADC2_IN16, ADC2_IN18) : https://github.com/stm32duino/Arduino_Core_STM32/blob/main/variants/STM32G4xx/G431C(6-8-B)U_G441CBU/PeripheralPins.c#L34-L59

It shouldn’t be so hard to add opamp PinMap, this would make things somewhat more Arduino-friendly…

Thanks all - I’ll probably start by forking and putting a bunch of additional defines in the existing b_g431 hal files until I get something working. Happy to try to shake out the OPAMP stuff too with guidance.

I also need one for the TIM_ETR signal, please, to implement the HWEncoder index pin :slight_smile:

And the LPTIM timers are also missing from the PinMaps. There’s a lot of omissions, actually, but adding them to stm32duino is a big job due to the huge number of STM32 MCUs…

Perhaps it might be better, since these are STM32-specific concerns anyways, to just base the API directly on PinNames (PA_12_ALT1) rather than the Arduino pin numbers and avoid the translation problems from the outset, and not need any PinMaps.

I don’t know how they generate those maps… I hope it is not by hand, there are so many variants.
It would be possible to generate them somewhat trivially for all peripherals, although quite slowly, by using some tools like Tabula: Using Tabula to Parse PDF Tables – Vivonomicon's Blog

Yes I think they must be parsing the datasheets.

Usually the internal adc pins like VREF are not in the pinmap.
Maybe stmduino should handle the opamp adc channels in the same way.

1 Like

If you look in stm32duino there are a lot of extra scripts and cmake targets. I think they generate at least all the generic variants, but TBH I could not figure it out completely last time I looked into it.