simplefoc / Arduino-FOC

Arduino FOC for BLDC and Stepper motors - Arduino Based Field Oriented Control Algorithm Library
https://docs.simplefoc.com
MIT License
2.06k stars 532 forks source link

[BUG] MCPWM on ESP32-C6 with two BLDC motors #440

Open kondor1622 opened 1 week ago

kondor1622 commented 1 week ago

I am trying to run two BLDC gimbal motors on ESP32-C6. When using only one of the motors everything works fine.

The problem is with MCPWM setup when using second motor - error log:

============ Before Setup End ============
[   517][V][esp32-hal-uart.c:408] uartBegin(): UART0 baud(115200) Mode(800001c) rxPin(17) txPin(16)
[   526][V][esp32-hal-uart.c:497] uartBegin(): UART0 not installed. Starting installation
[   534][V][esp32-hal-uart.c:560] uartBegin(): UART0 initialization done.
[   541][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type GPIO (1) successfully set to 0x42004b6c
[   552][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 7 successfully set to type GPIO (1) with bus 0x8
[   562][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type GPIO (1) successfully set to 0x42004b6c
[   573][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 0 successfully set to type GPIO (1) with bus 0x1
[   582][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type GPIO (1) successfully set to 0x42004b6c
[   593][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 1 successfully set to type GPIO (1) with bus 0x2
ESP32-DRV: Configuring 3PWM in group: 0 on timer: 0
ESP32-DRV: Configuring 2 operators.
ESP32-DRV: Configuring 3 comparators.
ESP32-DRV: Configuring 3 generators.
ESP32-DRV: Configuring center-aligned pwm.
ESP32-DRV: Enabling timer: 0
ESP32-DRV: MCPWM configured!
MOT: Monitor enabled!
MOT: Init
MOT: Enable driver.
Motor 0 ready.
[  1640][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type GPIO (1) successfully set to 0x42004b6c
[  1652][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 10 successfully set to type GPIO (1) with bus 0xb
[  1662][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type GPIO (1) successfully set to 0x42004b6c
[  1673][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 11 successfully set to type GPIO (1) with bus 0xc
[  1683][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type GPIO (1) successfully set to 0x42004b6c
[  1694][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 2 successfully set to type GPIO (1) with bus 0x3
ESP32-DRV: Configuring 3PWM in group: 1 on timer: 0
E (2118) mcpwm: mcpwm_new_timer(92): invalid group ID:1
ESP32-DRV: ERROR - Could not initialize the timer in group: 1
FAIL DRIVER 1

After quick investigation I found that SOC_MCPWM_GROUPS=1 on ESP32-C6, however the library tries to configure second group. My quick fix was to change _findBestGroup() in https://github.com/simplefoc/Arduino-FOC/blob/master/src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.cpp to use SOC_MCPWM_GROUPS

int _findBestGroup(int no_pins, long pwm_freq, int* group, int* timer){
  // an empty group is always the best option
  for(int i=0; i<SOC_MCPWM_GROUPS; i++){
    if(!group_pins_used[i]){
      *group = i;
      *timer=0; // use the first timer in an empty group
      return 1;
    }
  }

  // if 3 or 1pwm 
  // check if there is available space in one of the groups
  // otherwise fail
  if(no_pins == 3 || no_pins==1){
    // second best option is if there is a group with 
    // pair number of pwms available as we can then 
    // set the pwm frequency 
    for(int i=0; i<SOC_MCPWM_GROUPS; i++){
      if(_hasAvailablePins(i, no_pins+1)) {
        *group=i;
        *timer = _findNextTimer(i);
        return 1;
      }
    }
    // third best option is any group that has enough pins
    for(int i=0; i<SOC_MCPWM_GROUPS; i++){
      if(_hasAvailablePins(i, no_pins)) {
        *group=i;
        *timer = _findLastTimer(i);
        return 1;
      }
    }
  }

After this change both motors work and no error is displayed. I have only tested it in open_loop mode.


#include <SimpleFOC.h>

#define MOTOR_1
#define MOTOR_0

#ifdef MOTOR_0
BLDCMotor motor = BLDCMotor(7, 7.0f, 100);
BLDCDriver3PWM driver = BLDCDriver3PWM(7, 0, 1);
#endif

#ifdef MOTOR_1
BLDCMotor motor1 = BLDCMotor(7, 7.0f, 100);
BLDCDriver3PWM driver1 = BLDCDriver3PWM(10, 11, 2);
#endif

void setup()
{
  Serial.begin(115200);
  SimpleFOCDebug::enable(&Serial);

#ifdef MOTOR_0
  driver.voltage_power_supply = 12;

  if (!driver.init())
  {
    Serial.println("FAIL DRIVER 0");
    while (true);
  }
  motor.linkDriver(&driver);
  motor.controller = MotionControlType::velocity_openloop;
  motor.voltage_limit = 4;
  motor.useMonitoring(Serial);
  motor.init();
  Serial.println("Motor 0 ready.");
#endif

#ifdef MOTOR_1
  driver1.voltage_power_supply = 12;

  if (!driver1.init())
  {
    Serial.println("FAIL DRIVER 1");
    while (true);
  }
  motor1.linkDriver(&driver1);
  motor1.controller = MotionControlType::velocity_openloop;
  motor1.voltage_limit = 4;
  motor1.useMonitoring(Serial);
  motor1.init();
  Serial.println("Motor 1 ready.");
#endif

  _delay(1000);
}

void loop()
{
  motor.move(10);
  motor1.move(10);
}
runger1101001 commented 1 week ago

Thank you very much for this report, and also finding the solution! We'll incorporate that fix into the next release version.

The C6 is quite new, and I think you're the first to try it out with 2 motors probably! Thanks for reporting it.