B-G431B-ESC1 SimpleFOC Driver

Hi Sir,

I am new with B-G431B-ESC1 to run SimpleFOC.
My testing environment is PlatformIO.
I reference B-G431B-ESC1 code from Github Arduino-FOC-dev

My platformio.ini is below

[env:disco_b_g431b_esc1]
platform = ststm32
board = disco_b_g431b_esc1
framework = Arduino
monitor_speed = 115200

lib_deps=
SPI
Wire

The problem I met is,
I can compile and program, but I found there are no PWM outputs from G431 MCU.

Here is the driver definition in my code.
BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL);

I can find A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL define, and aligned with B-G431B-ESC1 sch.

But after I programed the code, it does not work (even I choice motor.controller = MotionControlType::velocity_openloop;)

I don’t know why.

here is my code for your information.

/**

  • B-G431B-ESC1 position motion control example with encoder

*/
#include <SimpleFOC.h>
#include<Arduino.h>

// Motor instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL);
LowsideCurrentSense currentSense = LowsideCurrentSense(0.003, -64.0/7.0, A_OP1_OUT, A_OP2_OUT, A_OP3_OUT);

// encoder instance
// Encoder encoder = Encoder(A_HALL2, A_HALL3, 1000, A_HALL1);
Encoder encoder = Encoder(A_ENCODER_A, A_ENCODER_B, 1000);

// Interrupt routine intialisation
// channel A and B callbacks
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
void doC(){encoder.handleIndex();}

// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.motion(&motor, cmd); }

void setup() {

// initialize encoder sensor hardware
encoder.init();
encoder.enableInterrupts(doA, doB);

// link the motor to the sensor
motor.linkSensor(&encoder);

// driver config
// power supply voltage [V]
driver.voltage_power_supply = 12;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);

// link current sense and the driver
currentSense.linkDriver(&driver);

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

// index search velocity [rad/s]
// motor.velocity_index_search = 3;
// aligning voltage [V]
motor.voltage_sensor_align = 1.8;
// if you are not using aligning voltage, you can set current limitation
motor.phase_resistance = 0.35; // [Ohm]
motor.current_limit = 2; // [Amps] - if phase res is defined

// set motion control loop to be used
motor.controller = MotionControlType::velocity_openloop;

// contoller configuration
// default parameters in defaults.h

// velocity PI controller parameters
motor.PID_velocity.P = 0.2;
motor.PID_velocity.I = 20;
// default voltage_power_supply
motor.voltage_limit = 1;
// jerk control using voltage voltage ramp
// default value is 300 volts per sec ~ 0.3V per millisecond
motor.PID_velocity.output_ramp = 1000;

// velocity low pass filtering time constant
motor.LPF_velocity.Tf = 0.01;

// angle P controller
motor.P_angle.P = 20;
// maximal velocity of the position control
motor.velocity_limit = 4;

// use monitoring with serial
Serial.begin(115200);
// comment out if not needed
motor.useMonitoring(Serial);
motor.monitor_downsample = 100; // setting sample rate, can up to 100+
motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE;

// initialize motor
motor.init();
// align encoder and start FOC
// motor.initFOC();

motor.target = 1;

// add target command T
command.add(ā€˜T’, doTarget, ā€œtarget angleā€);

Serial.println(F(ā€œMotor ready.ā€));
Serial.println(F(ā€œSet the target angle using serial terminal:ā€));
_delay(1000);

}

void loop() {
// main FOC algorithm function
//motor.loopFOC();

// Motion control function
//motor.move();

// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!
motor.monitor();

// user communication
command.run();

// Debug encoder, done, everything is correct
// iterative function updating the sensor internal variables
// it is usually called in motor.loopFOC()
// not doing much for the encoder though
// encoder.update();
// display the angle and the angular velocity to the terminal
// Serial.print(encoder.getAngle());
// Serial.print(ā€œ\tā€);
// Serial.println(encoder.getVelocity());

}

Added two pictures here, the motor is ok, my self driver board can run the motor well.

You have to set libarchive = false in your platformio.ini file to make it work.

/Chris

Yep, add a line

lib_archive = false

to your platformio.ini.

1 Like

Thanks Runger, Grizzly,

After I added libarchive - false

I got below error : (

Processing disco_b_g431b_esc1 (platform: ststm32; board: disco_b_g431b_esc1; framework: arduino)
--------------------------------------------------------------------------------------------Verbose mode can be enabled via -v, --verbose option
CONFIGURATION: Redirecting...
PLATFORM: ST STM32 (15.4.1) > ST B-G431B-ESC1 Discovery
HARDWARE: STM32G431CBU6 170MHz, 32KB RAM, 128KB Flash
DEBUG: Current (stlink) On-board (stlink) External (blackmagic, cmsis-dap, jlink)
PACKAGES:

  • framework-arduinoststm32 @ 4.20200.221104 (2.2.0)
  • framework-cmsis @ 2.50700.210515 (5.7.0)
  • toolchain-gccarmnoneeabi @ 1.90201.191206 (9.2.1)
    LDF: Library Dependency Finder → Library Dependency Finder (LDF) — PlatformIO latest documentation
    LDF Modes: Finder ~ chain, Compatibility ~ soft
    Found 12 compatible libraries
    Scanning dependencies…
    Dependency Graph
    |-- SPI @ 1.0
    |-- Wire @ 1.0
    |-- Simple FOC @ 2.3.0
    | |-- Wire @ 1.0
    | |-- SPI @ 1.0
    Building in release mode
    Linking .pio\build\disco_b_g431b_esc1\firmware.elf
    c:/users/qianmichael/.platformio/packages/toolchain-gccarmnoneeabi/bin/…/lib/gcc/arm-none-eabi/9.2.1/…/…/…/…/arm-none-eabi/bin/ld.exe: .pio/build/disco_b_g431b_esc1/libb3d/Arduino-FOC-dev/current_sense/hardware_specific/stm32/b_g431/b_g431_mcu.cpp.o: in function _configureOPAMP(OPAMP_HandleTypeDef*, OPAMP_TypeDef*)': b_g431_mcu.cpp:(.text._Z15_configureOPAMPP19OPAMP_HandleTypeDefP13OPAMP_TypeDef+0x22): undefined reference to HAL_OPAMP_Init’
    c:/users/qianmichael/.platformio/packages/toolchain-gccarmnoneeabi/bin/…/lib/gcc/arm-none-eabi/9.2.1/…/…/…/…/arm-none-eabi/bin/ld.exe: .pio/build/disco_b_g431b_esc1/libb3d/Arduino-FOC-dev/current_sense/hardware_specific/stm32/b_g431/b_g431_mcu.cpp.o: in function _configureADCLowSide(void const*, int, int, int)': b_g431_mcu.cpp:(.text._Z20_configureADCLowSidePKviii+0x6a): undefined reference to HAL_OPAMP_Start’
    c:/users/qianmichael/.platformio/packages/toolchain-gccarmnoneeabi/bin/…/lib/gcc/arm-none-eabi/9.2.1/…/…/…/…/arm-none-eabi/bin/ld.exe: b_g431_mcu.cpp:(.text._Z20_configureADCLowSidePKviii+0x70): undefined reference to HAL_OPAMP_Start' c:/users/qianmichael/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: b_g431_mcu.cpp:(.text._Z20_configureADCLowSidePKviii+0x76): undefined reference to HAL_OPAMP_Start’
    collect2.exe: error: ld returned 1 exit status
    *** [.pio\build\disco_b_g431b_esc1\firmware.elf] Error 1
    ================================ [FAILED] Took 6.47 seconds ================================
  • The terminal process ā€œC:\Users\qianmichael.platformio\penv\Scripts\platformio.exe ā€˜runā€™ā€ terminated with exit code: 1.
  • Terminal will be reused by tasks, press any key to close it.

Attached a snapshot of my project.

I think the B-G431B still needs some build-flags, at least -DHAL_OPAMP_MODULE_ENABLED
looking at the errors you’re getting.

2 Likes

Thanks, I can compile successfully, I will program and verify later whether H/W works.
By the way, what does -DHAL_OPAMP_MODULE_ENABLED and libarchive = false means.
I am a freshman for PlatformIO IDE tool.

Hey,

The -DHAL_OPAMP_MODULE_ENABLED is a build flag to include the op-amp support in ST Micros HAL library.

The lib_archive is an option needed only by platformio without which it won’t handle ā€œweak bindingsā€ correctly…

1 Like

Hi Runger,

Thanks, with the suggestions, my code works.
Just a further question on lib_archive, I am confused with your word, ā€˜it won’t handle ā€œweak bindingsā€ correctly’.
lib_archive is which lib ? My SimpleFoC lib or others in PlatformIO ?

It applies to the linker, for all object files AFAIK

This is a fairly complex question and you’ll need some familiarity with how gcc and native compiling work…

1 Like

OK, let me ask in a simple way, in what’s kind of situation I need to added lib_archive = false ?
(As I create a new project, I never see platformio.ini includes a line with ā€˜lib_archive = false’ ).

It’s needed for any project using SimpleFOC, and I would say anytime else you want to use weak bindings. But I can’t say for 100% - ArduinoIDE does not need it, so there must be some subtle difference in the way they are configured when building.

1 Like

What are ā€˜weak bindings’ in PlatformIO ?

1 Like

Thanks Runger, still much confused, but I got the message and impressed here, will pay attention in the future.

Hey, it is like I said - this topic is in the space of compilers/linkers and how the code is converted into binary objects for execution by the processor. If you’re interested in how compilers work, the seminal book on this topic is the ā€œdragon bookā€: Compilers: Principles, Techniques, and Tools - Wikipedia

Learning about C++ and C object linking is even more difficult and mysterious, and the final steps are quite hardware dependent. I don’t really have a good reference to give for this.

But this topic is very far removed from motor control, and certainly not needed to understand the concepts needed for motor driving, or working with Arduino in general!

1 Like

Hi, Runger
Thanks for the detailed explanation!