How to get ESP32, MCP23017, DM542 working

Ok, this is what I am trying to do. I have got an ESP32S that I want to operate 6 Stepper Motors. First of all, PLEASE do not ask me why I am using stepper motors, not servos. Load is the main reason. That being said, I also have 16 inputs for them from position switch to hall sensor to home them to a potentiometer the will control 3 of the steppers. There are too many inputs and outputs so I want to add one, maybe two MCP23017 I/O Expansions to the system. I looked everywhere and only found one thing that was posted around 5 years ago on how the set up the 2 pins to the driver in Arduino IDE. I have it working just fine right now with one drive without the I/O Expansion card.

Can anyone help with how to code this? I posted the code I am using right now without the expansion. By the way, this is going to run 6 Nema 23 with 6 DM542T drivers.

/* Motor Homing code using AccelStepper and the Serial Monitor

  Created by Yvan / https://Brainy-Bits.com
  This code is in the public domain...
  You can: copy it, use it, modify it, share it or just plain ignore it!
  Thx!

  This is to opperate the steering and the shift from drive to nutrral and reverse of 3 motors in a full size houseboat*/

#include <AccelStepper.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd1(0x27, 20, 4);

const byte FRSTEP_PIN_PORT = 2;
const byte FRDIR_PIN_PORT = 4;
const byte STSTEP_PIN_PORT = 5;
const byte STDIR_PIN_PORT = 12;
const byte FRSTEP_PIN_CENTER = 13;
const byte FRDIR_PIN_CENTER = 14;
const byte STSTEP_PIN_CENTER = 15;
const byte STDIR_PIN_CENTER = 16;
const byte FRSTEP_PIN_STARBOARD = 17;
const byte FRDIR_PIN_STARBOARD = 18;
const byte STSTEP_PIN_STARBOARD = 19;
const byte STDIR_PIN_STARBOARD = 20;
// AccelStepper Setup
AccelStepper stepper1(1, FRSTEP_PIN_PORT, FRDIR_PIN_PORT); // 1 = Easy Driver interface
AccelStepper stepper2(1, STSTEP_PIN_PORT, STDIR_PIN_PORT); // 1 = Easy Driver interface
AccelStepper stepper3(1, FRSTEP_PIN_CENTER, FRDIR_PIN_CENTER); // 1 = Easy Driver interface
AccelStepper stepper4(1, STSTEP_PIN_CENTER, STDIR_PIN_CENTER); // 1 = Easy Driver interface
AccelStepper stepper5(1, FRSTEP_PIN_STARBOARD, FRDIR_PIN_STARBOARD); // 1 = Easy Driver interface
AccelStepper stepper6(1, STSTEP_PIN_STARBOARD, STDIR_PIN_STARBOARD); // 1 = Easy Driver interface

// Define the Pins used. The ones that are set at pin 26 will be changed once I am able to use 
// the MCP23017
#define PFRhome_switch 26 // connected to Home Switch (MicroSwitch)
#define PShome_switch 26 // connected to Home Switch (MicroSwitch)
#define CFRhome_switch 26 // connected to Home Switch (MicroSwitch)
#define CShome_switch 26 // connected to Home Switch (MicroSwitch)
#define SFRhome_switch 26 // connected to Home Switch (MicroSwitch)
#define SShome_switch 26 // connected to Home Switch (MicroSwitch)
#define PortForward 39
#define PortReverse 35
#define CenterForward 36
#define CenterReverse 34
#define StarboardForward 32
#define StarboardReverse 27
// Stepper Travel Variables

const long forwardPosition = 0;
const long neutralPosition = 200;
const long reversePosition = 400;
const long initial_homing = -4000; // Used to Home Stepper at startup

int ForwardPortSwitch;
int ReversePortSwitch;
int ForwardCenterSwitch;
int ReverseCenterSwitch;
int ForwardStarboardSwitch;
int ReverseStarboardSwitch;

void setup() {
//  Serial.begin(115200); // Start the Serial monitor with speed of 9600 Bauds

  // Initialise the LCD 1
  lcd1.begin();
  lcd1.clear();
  lcd1.noCursor();
  lcd1.backlight();
  lcd1.setCursor(0, 0);
// Hall Sensors for homing
  pinMode(PFRhome_switch, INPUT);
  pinMode(PShome_switch, INPUT);
  pinMode(CFRhome_switch, INPUT);
  pinMode(CShome_switch, INPUT);
  pinMode(SFRhome_switch, INPUT);
  pinMode(SShome_switch, INPUT);
  // Switches to set each motor into Forward, Neutral, or Revers.
  pinMode(PortForward, INPUT);
  pinMode(PortReverse, INPUT);
  pinMode(CenterForward, INPUT);
  pinMode(CenterReverse, INPUT);
  pinMode(StarboardForward, INPUT);
  pinMode(StarboardReverse, INPUT);

  delay(50); // Wait for EasyDriver wake up

  // Start Homing procedure of Stepper Motor at startup
  // This will be showing in a display when the power is first turned on

  bool ready = false;

  while ( !ready ) {
  beginning:
  ready = true;

    ForwardPortSwitch = digitalRead(PortForward);
    ReversePortSwitch = digitalRead(PortReverse);
    ForwardCenterSwitch = digitalRead(CenterForward);
    ReverseCenterSwitch = digitalRead(CenterReverse);
    ForwardStarboardSwitch = digitalRead(StarboardForward);
    ReverseStarboardSwitch = digitalRead(StarboardReverse);
      lcd1.setCursor(0, 0);
      lcd1.print("    Drive Status    ");

    if (ForwardPortSwitch == HIGH) {
      lcd1.setCursor(0, 1);
      lcd1.print("  Port in Forward   ");
      //      Serial.println("Port in Forward");
      ready = false;
    }
    if (ReversePortSwitch == HIGH) {
      lcd1.setCursor(0, 1);
      lcd1.print("  Port in Reverse   ");
      //      Serial.println("Port in Reverse");
      ready = false;
    }
    if (ReversePortSwitch == LOW && ForwardPortSwitch == LOW) {
      lcd1.setCursor(0, 1);
      lcd1.print("  Port in Neutral   ");
      //      Serial.println("Port in Reverse");
    }
    //-------------------------------------------------------------------------------------------
    if (ForwardCenterSwitch == HIGH) {
    lcd1.setCursor(0, 2);
      lcd1.print("  Center in Forward ");
      //      Serial.println("Center in Forward");
      ready = false;
    }
    if (ReverseCenterSwitch == HIGH) {
    lcd1.setCursor(0, 2);
      lcd1.print("  Center in Reverse ");
      //      Serial.println("Center in Reverse");
      ready = false;
    }
    if (ReverseCenterSwitch == LOW && ForwardCenterSwitch == LOW) {
    lcd1.setCursor(0, 2);
      lcd1.print("  Center in Neutral ");
      //      Serial.println("Center in Reverse");
    }
    //---------------------------------------------------------------------------------------------------------------
    if (ForwardStarboardSwitch == HIGH) {
    lcd1.setCursor(0, 3);
      lcd1.print("Starboard in Forward");
      //      Serial.println("Starboard in Forward");
      ready = false;
    }
    if (ReverseStarboardSwitch == HIGH) {
    lcd1.setCursor(0, 3);
      lcd1.print("Starboard in Reverse");
      //      Serial.println("Starboard in Reverse");
      ready = false;
    }
    if (ReverseStarboardSwitch == LOW && ForwardStarboardSwitch == LOW) {
    lcd1.setCursor(0, 3);
      lcd1.print("Starboard in Reverse");
      //      Serial.println("Starboard in Reverse");
    }
    //--------------------------------------------------------------------------------------------------------------------
    if ( !ready == false ) {
    delay(4000);
    lcd1.setCursor(0, 3);
      lcd1.print("  ALL drives MUST   ");
      delay(3000);
    lcd1.setCursor(0, 3);
      lcd1.print("    be in Neutral   ");
      delay(3000);
    lcd1.setCursor(0, 3);
      lcd1.print(" You have 5 seconds ");
      //  Serial.println("ALL drives MUST be in Neutral");
      //      Serial.println("You have 5 seconds from NOW!");
      delay(5000);
      goto beginning;
    }
  }
  //-------------------------------------------------------------------------------------------------------------------
  // Once all of the switches are in neutral, is homes the stepper motors.
  // Make the Stepper move CCW until the switch is activated
  // Set Max Speed and Acceleration of each Steppers at startup for homing
  //--------------------------------------------------------------------------------------------------------------------
      lcd1.setCursor(0, 0);
      lcd1.print("Homing Bucket       ");

stepper1.setMaxSpeed(200.0); // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper1.setAcceleration(2000.0); // Set Acceleration of Stepper
    lcd1.setCursor(0, 1);
      lcd1.print("Port Homing         ");
//  Serial.println("Port Drive Homing");
  stepper1.moveTo(initial_homing); // Set the position to move to
  while (digitalRead(PFRhome_switch) == HIGH) {
    stepper1.run(); // Start moving the stepper
    delay(5);
  }
  stepper1.setCurrentPosition(0); // Set the current position as zero for now
 // Serial.println("Port Drive Homing Completed");
  stepper1.setMaxSpeed(200.0); // Set Max Speed of Stepper (Faster for regular movements)
  stepper1.setAcceleration(2000.0); // Set Acceleration of Stepper
  stepper1.runToNewPosition(neutralPosition);
     lcd1.setCursor(0, 1);
      lcd1.print("Port Complete       ");

//----------------------------------------------------------------------------------------------------------

  stepper2.setMaxSpeed(200.0); // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper2.setAcceleration(2000.0); // Set Acceleration of Stepper
    lcd1.setCursor(0, 2);
      lcd1.print("Center Homing      ");
//  Serial.println("Center Drive Homing");
  stepper2.moveTo(initial_homing); // Set the position to move to
  while (digitalRead(CFRhome_switch) == HIGH) {
    stepper2.run(); // Start moving the stepper
    delay(5);
  }
  stepper2.setCurrentPosition(0); // Set the current position as zero for now
  stepper2.setMaxSpeed(200.0); // Set Max Speed of Stepper (Faster for regular movements)
  stepper2.setAcceleration(2000.0); // Set Acceleration of Stepper
  stepper2.runToNewPosition(neutralPosition);
    lcd1.setCursor(0, 2);
      lcd1.print("Center Completed    ");
//  Serial.println("Center Drive Homing Completed");

  //----------------------------------------------------------------------------------------------------------
 
  stepper3.setMaxSpeed(200.0); // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper3.setAcceleration(2000.0); // Set Acceleration of Stepper
    lcd1.setCursor(0, 3);
      lcd1.print("Starboard Homing    ");
//  Serial.println("Starting Port Initialization");
  stepper3.moveTo(initial_homing); // Set the position to move to
  while (digitalRead(SFRhome_switch) == HIGH) {
    stepper3.run(); // Start moving the stepper
    delay(5);
  }
  stepper3.setCurrentPosition(0); // Set the current position as zero for now
  stepper3.setMaxSpeed(200.0); // Set Max Speed of Stepper (Faster for regular movements)
  stepper3.setAcceleration(2000.0); // Set Acceleration of Stepper
  stepper3.runToNewPosition(neutralPosition);
    lcd1.setCursor(0, 3);
      lcd1.print("Starboard Complete   ");
//  Serial.println("Homing Completed");

  //----------------------------------------------------------------------------------------------------------
    lcd1.setCursor(0, 0);
      lcd1.print("Homing Steering     ");
  
  stepper4.setMaxSpeed(200.0); // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper4.setAcceleration(2000.0); // Set Acceleration of Stepper
    lcd1.setCursor(0, 1);
      lcd1.print("Port Homing         ");
//  Serial.println("Starting Port Initialization");
  stepper4.moveTo(initial_homing); // Set the position to move to
  while (digitalRead(PShome_switch) == HIGH) {
    stepper4.run(); // Start moving the stepper
    delay(5);
  }

  stepper4.setCurrentPosition(0); // Set the current position as zero for now

  stepper4.setMaxSpeed(200.0); // Set Max Speed of Stepper (Faster for regular movements)
  stepper4.setAcceleration(2000.0); // Set Acceleration of Stepper
  stepper4.runToNewPosition(neutralPosition);
    lcd1.setCursor(0, 1);
      lcd1.print("Port Completed      ");
//  Serial.println("Homing Completed");

  //----------------------------------------------------------------------------------------------------------

  stepper5.setMaxSpeed(200.0); // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper5.setAcceleration(2000.0); // Set Acceleration of Stepper
    lcd1.setCursor(0, 2);
      lcd1.print("Center Homing       ");
//  Serial.println("Starting Port Initialization");
  stepper5.moveTo(initial_homing); // Set the position to move to
  while (digitalRead(CShome_switch) == HIGH) {
    stepper5.run(); // Start moving the stepper
    delay(5);
  }

  stepper5.setCurrentPosition(0); // Set the current position as zero for now

    lcd1.setCursor(0, 2);
      lcd1.print("Center Completed    ");
//  Serial.println("Homing Completed");
  stepper5.setMaxSpeed(200.0); // Set Max Speed of Stepper (Faster for regular movements)
  stepper5.setAcceleration(2000.0); // Set Acceleration of Stepper
  stepper5.runToNewPosition(neutralPosition);
  
  //----------------------------------------------------------------------------------------------------------
  
  stepper6.setMaxSpeed(200.0); // Set Max Speed of Stepper (Slower to get better accuracy)
  stepper6.setAcceleration(2000.0); // Set Acceleration of Stepper
    lcd1.setCursor(0, 3);
      lcd1.print("Starboard Homing    ");
//  Serial.println("Starting Port Initialization");
  stepper6.moveTo(initial_homing); // Set the position to move to
  while (digitalRead(SShome_switch) == HIGH) {
    stepper6.run(); // Start moving the stepper
    delay(5);
  }

  stepper6.setCurrentPosition(0); // Set the current position as zero for now

  stepper6.setMaxSpeed(200.0); // Set Max Speed of Stepper (Faster for regular movements)
  stepper6.setAcceleration(2000.0); // Set Acceleration of Stepper
  stepper6.runToNewPosition(neutralPosition);
    lcd1.setCursor(0, 3);
      lcd1.print("Starboard Completed ");
//  Serial.println("Homing Completed");

  //----------------------------------------------------------------------------------------------------------

  // Print out Instructions on the Serial Monitor at Start
  //Serial.println("Enter Travel distance (Positive for CW / Negative for CCW and Zero for back to Home): ");
}

void loop() {
  // Here it read two of the three switch positions to see what position the stepper should be in and puts it there.
  ForwardPortSwitch = digitalRead(PortForward);
  ReversePortSwitch = digitalRead(PortReverse);
  ForwardCenterSwitch = digitalRead(CenterForward);
  ReverseCenterSwitch = digitalRead(CenterReverse);
  ForwardStarboardSwitch = digitalRead(StarboardForward);
  ReverseStarboardSwitch = digitalRead(StarboardReverse);

    lcd1.setCursor(0, 0);
      lcd1.print("    Drive Status    ");
//
if (ForwardPortSwitch == HIGH) {
    lcd1.setCursor(0, 1);
      lcd1.print("Port in Forward     ");
//    Serial.println("Forward");
    stepper1.runToNewPosition(forwardPosition);
    delay(2000);
  }
  else if (ForwardPortSwitch == LOW && ReversePortSwitch == LOW)
  { 
        lcd1.setCursor(0, 1);
      lcd1.print("Port in Neutral     ");
//Serial.println("Nutral");
    stepper1.runToNewPosition(neutralPosition);
    delay(2000);
  }
  else if (ReversePortSwitch == HIGH) {
        lcd1.setCursor(0, 1);
      lcd1.print("Port in Reverse     ");
//    Serial.println("Reverse");
    stepper1.runToNewPosition(reversePosition);
    delay(2000);
  }

  if (ForwardCenterSwitch == HIGH) {
        lcd1.setCursor(0, 2);
      lcd1.print("Center in Forward   ");
//    Serial.println("Forward");
    stepper1.runToNewPosition(forwardPosition);
    delay(2000);
  }
  else if (ForwardCenterSwitch == LOW && ReversePortSwitch == LOW)
  { 
        lcd1.setCursor(0, 2);
      lcd1.print("Center in Neutral   ");
//    Serial.println("Neutral");
    stepper1.runToNewPosition(neutralPosition);
    delay(2000);
  }
  else if (ReverseCenterSwitch == HIGH) {
        lcd1.setCursor(0, 2);
      lcd1.print("Center in Reverse   ");
//    Serial.println("Reverse");
    stepper1.runToNewPosition(reversePosition);
    delay(2000);
  }

  if (ForwardStarboardSwitch == HIGH) {
        lcd1.setCursor(0, 3);
      lcd1.print("Starboard in Forward");
//    Serial.println("Forward");
    stepper1.runToNewPosition(forwardPosition);
    delay(2000);
  }
  else if (ForwardStarboardSwitch == LOW && ReversePortSwitch == LOW)
  {
        lcd1.setCursor(0, 3);
      lcd1.print("Starboard in Neutral");
//    Serial.println("Neutral");
    stepper1.runToNewPosition(neutralPosition);
    delay(2000);
  }
  else if (ReverseStarboardSwitch == HIGH) {
        lcd1.setCursor(0, 3);
      lcd1.print("Starboard in Reverse");
//    Serial.println("Reverse");
    stepper1.runToNewPosition(reversePosition);
    delay(2000);
  }
}
1 Like

As I understand it, you need to feed the DM524T with a PWM signal. An MCP23017 isn't going to give you one. I also suspect you'll have a problem driving the DM524T's signal pins from an MCP23017 since the DM524T seems to draw ca. 10mA from its logic inputs.

Please verify the above; if this is correct, I'd recommend having a look at e.g. the PCA9685 instead of MCP23017.

Commenting on the code that is there.

Using those pins can cause issues. Make sure those pins do not change state during programming or booting.

This pin, on an ESP32 has an LED connected to it and can cause issues with devices.

You will find that you CANNOT use those pins for outputs, those pins do not have pull up/down resistors as GPIO ports. If you are using a ESP32S you can use the RTC API to program those ports to behave as regular GPIO ports. Those pins as GPIO pins are best used as A:D inputs.

If you want to have the ESP32 generate PWM you might be interested in using the ESP32 MCPWM API.

You can use the below code as a model to generate PWM via the MCPWM under the Arduino IDE.

/*
   Project, use solar cells to generate power
   2/2/2020

*/
// https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html
///esp_timer_get_time(void) //gets time in uSeconds like Arduino Micros. see above link
//////// http://www.iotsharing.com/2017/09/how-to-use-arduino-esp32-can-interface.html
#include "sdkconfig.h"
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
// #include "esp32/ulp.h"
// #include "driver/rtc_io.h"
#include <SimpleKalmanFilter.h>
#include <driver/adc.h>
#include "esp_sleep.h"
#include "driver/mcpwm.h"
const int TaskCore1 = 1;
const int TaskCore0 = 0;
const int TaskStack20K = 20000;
const int Priority3 = 3;
const int Priority4 = 4;
const int SerialDataBits = 115200;
volatile bool EnableTracking = true;
////
//
////
void setup()
{
  Serial.begin( 115200 );
  // https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
  // set up A:D channels
  log_i( "Setup A:D" );
  adc_power_on( );
  vTaskDelay( 1 );
  adc1_config_width(ADC_WIDTH_12Bit);
  // ADC1 channel 0 is GPIO36 (ESP32), GPIO1 (ESP32-S2)
  adc1_config_channel_atten(ADC1_CHANNEL_0 , ADC_ATTEN_DB_11); // azimuth 0
  //  // ADC1_CHANNEL_3  ADC1 channel 3 is GPIO39 (ESP32)
  adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11); // azimuth 1
  //  // ADC1 channel 5 is GPIO33
  adc1_config_channel_atten(ADC1_CHANNEL_5, ADC_ATTEN_DB_11); // altitude 1
  //  // ADC1 channel 6 is GPIO34
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11); // altitude 0
  //  // adc for light dark detection, ADC1 channel 7 is GPIO35 (ESP32)
  adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_11);
  // adc for solar cell voltage detection, ADC1 channel 4 is GPIO33 (ESP32)
  adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_11);
  //
  log_i( "A:D setup complete" );
  // control for relay to supply power to the servos
  pinMode( 5, OUTPUT );
  vTaskDelay(1);
  log_i( "setup MCPWM" );
  //
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_NUM_4 ); // Azimuth
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_NUM_12 ); // Altitude servo
  //
  mcpwm_config_t pwm_config = {};
  pwm_config.frequency = 50;    //frequency = 50Hz, i.e. for every servo motor time period should be 20ms
  pwm_config.cmpr_a = 0;    //duty cycle of PWMxA = 0
  pwm_config.cmpr_b = 0;    //duty cycle of PWMxb = 0
  pwm_config.counter_mode = MCPWM_UP_COUNTER;
  pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
  log_i( "MCPWM complete" );
  //
  //
  mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);    //Configure PWM0A timer 0 with above settings
  mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_config);    //Configure PWM0A timer 1 with above settings
  //  ////
  fMoveAltitude( 1525 );
  fMoveAzimuth( 1500 );
  ////
//  xTaskCreatePinnedToCore( TrackSun, "TrackSun", TaskStack20K, NULL, Priority3, NULL, TaskCore1 ); // assigned to core
//  xTaskCreatePinnedToCore( fDaylight, "fDaylight", TaskStack20K, NULL, Priority3, NULL, TaskCore0 ); // assigned to core
  ////  // esp_sleep_enable_timer_wakeup( (60000000 * 2) ); // set timer to wake up once a minute 60000000uS * 2

}
//
void fDaylight( void * pvParameters )
{
  int lightLevel = 0;
  log_i( "Start up fDaylight" );
  while (1)
  {
    // sufficent voltage at the solar cells to do the thing?
    log_i( "Solar Cell: %d", adc1_get_raw(ADC1_CHANNEL_4) );
    if (adc1_get_raw(ADC1_CHANNEL_4) > 1600 )
    {
      lightLevel = adc1_get_raw(ADC1_CHANNEL_7);
      if ( adc1_get_raw(ADC1_CHANNEL_7) >= 300 )
      {
        log_i( "Light Level: %d", lightLevel );
        EnableTracking = true;
        digitalWrite( 5, LOW ); // power to relay module/servos
        vTaskDelay( 1 );
      } else {
        // if light level to low park boom
        fMoveAltitude( 1475 );
        fMoveAzimuth( 1900 );
        //     put esp32 into deep sleep
        digitalWrite( 5, HIGH ); // deenergize servo motors
        EnableTracking = false;
        esp_sleep_enable_timer_wakeup( (60000000 * 5) ); // set timer to wake up once a minute 60000000uS
        esp_deep_sleep_start();
      }
    } else {
              digitalWrite( 5, HIGH ); // deenergize servo motors
        EnableTracking = false;
        esp_sleep_enable_timer_wakeup( (60000000 * 5) ); // set timer to wake up once a minute 60000000uS
        esp_deep_sleep_start();
    }
    vTaskDelay( 1000 );
  } // while(1)
} // void fDaylight( void * pvParameters )
////
/**
   @brief Use this function to calcute pulse width for per degree rotation
   @param  degree_of_rotation the angle in degree to which servo has to rotate
   @return
       - calculated pulse width
*/
//static uint32_t servo_per_degree_init(uint32_t degree_of_rotation)
//{
//  const int SERVO_MIN_PULSEWIDTH = 500; //Minimum pulse width in microsecond
//const int SERVO_MAX_PULSEWIDTH 2500 //Maximum pulse width in microsecond
//const int SERVO_MAX_DEGREE 180 //Maximum angle in degree upto which servo can rotate
//  uint32_t cal_pulsewidth = 0;
//  cal_pulsewidth = (SERVO_MIN_PULSEWIDTH + (((SERVO_MAX_PULSEWIDTH - SERVO_MIN_PULSEWIDTH) * (degree_of_rotation)) / (SERVO_MAX_DEGREE)));
//  return cal_pulsewidth;
//}
////
void mcpwm_gpio_initialize(void)
{
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_NUM_4 );
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_NUM_12 );
}
////
// void TrackSun( int Altitude, int Azimuth )
void TrackSun( void * pvParameters )
{
  log_i( "Startup TrackSun" );
  int64_t EndTime = esp_timer_get_time();
  int64_t StartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros
  int Altitude = 1500;
  int Azimuth = 900;
  int maxAltitudeRange = 2144;
  int minAltitudeRange = 900;
  int maxAzimuthRange = 2144;
  int minAzimuthRange = 900;
  float AltitudeThreashold = 10.0f;
  float AzimuthThreashold = 10.0f;
  float kalmanThreshold = 80.0f;
  SimpleKalmanFilter kfAltitude0( AltitudeThreshold, kalmanThreshold, .01 ); // kalman filter Altitude 0
  SimpleKalmanFilter kfAltitude1( AltitudeThreshold, kalmanThreshold, .01 ); // kalman filter Altitude 1
  SimpleKalmanFilter kfAzimuth0( AzimuthThreshold, kalmanThreshold, .01 ); // kalman filter Azimuth 0
  SimpleKalmanFilter kfAzimuth1( AzimuthThreshold, kalmanThreshold, .01 ); // kalman filter Azimuth 1
  float filteredAltitude_0 = 0.0f;
  float filteredAltitude_1 = 0.0f;
  float filteredAzimuth_0 = 0.0f;
  float filteredAzimuth_1 = 0.0f;
  uint64_t AzimuthEndTime = esp_timer_get_time();
  uint64_t AzimuthStartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros,but rolls over after 207 years
  uint64_t AltitudeEndTime = esp_timer_get_time();
  uint64_t AltitudeStartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros,
  int StartupCount = 0;
  int TorqueAmmount = 5;
  while (1)
  {

    if ( EnableTracking )
    {
      //Altitude
      AltitudeEndTime = esp_timer_get_time() - AltitudeStartTime; // produce elapsed time for the simpleKalmanFilter
      kfAltitude0.setProcessNoise( float(AltitudeEndTime) / 1000000.0f );
      kfAltitude1.setProcessNoise( float(AltitudeEndTime) / 1000000.0f );
      // Serial.println( AltitudeEndTime,6 );
      filteredAltitude_0 = kfAltitude0.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_6) );
      filteredAltitude_1 = kfAltitude1.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_5) );
      //      Serial.print( filteredAltitude_0 );
      //      Serial.print( ", " );
      //      Serial.print( filteredAltitude_1 );
      //      Serial.print( ", " );
      //      Serial.println();
      if ( (filteredAltitude_0 > filteredAltitude_1) && (abs(filteredAltitude_0 - filteredAltitude_1) > AltitudeThreshold))
      {
        Altitude -= TorqueAmmount;
        // log_i( "> Alt %d", Altitude );
        if ( Altitude < minAltitudeRange )
        {
          Altitude = 900;
        }
        fMoveAltitude( Altitude );
        AltitudeStartTime = esp_timer_get_time();
      }
      if ( (filteredAltitude_0 < filteredAltitude_1) && (abs(filteredAltitude_0 - filteredAltitude_1) > AltitudeThreshold) )
      {
        Altitude += TorqueAmmount;
        if ( Altitude >= maxAltitudeRange )
        {
          Altitude = 900;
        }
        fMoveAltitude( Altitude );
        // log_i( "< Alt %d", Altitude );
        AltitudeStartTime = esp_timer_get_time();
      }
      //// AZIMUTH
      AzimuthEndTime = esp_timer_get_time() - AzimuthStartTime; // produce elasped time for the simpleKalmanFilter
      //      Serial.print( (float)adc1_get_raw(ADC1_CHANNEL_3) );
      //      Serial.print( "," );
      //      Serial.print( (float)adc1_get_raw(ADC1_CHANNEL_0) );
      //      Serial.print( "," );
      kfAzimuth0.setProcessNoise( float(AzimuthEndTime) / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
      kfAzimuth1.setProcessNoise( float(AzimuthEndTime) / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
      filteredAzimuth_0 = kfAzimuth0.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_3) );
      filteredAzimuth_1 = kfAzimuth1.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_0) );
      //      Serial.print( filteredAzimuth_0 );
      //      Serial.print( ", " );
      //      Serial.print( filteredAzimuth_1 );
      //      Serial.println();
      if ( (filteredAzimuth_0 > filteredAzimuth_1) && (abs(filteredAzimuth_0 - filteredAzimuth_1)) > AzimuthThreashold )
      {
        Azimuth += TorqueAmmount;
        if ( Azimuth >= maxAzimuthRange )
        {
          Azimuth = 900;
        }
        // log_i( "> Az %d", Azimuth );
        fMoveAzimuth( Azimuth );
        AzimuthStartTime = esp_timer_get_time();
      }
      //    //
      if ( (filteredAzimuth_0 < filteredAzimuth_1) && (abs(filteredAzimuth_1 - filteredAzimuth_0)) > AzimuthThreashold )
      {
        // log_i( "< Az %d", Azimuth );
        Azimuth -= TorqueAmmount; // make new position to torque to
        if ( (Azimuth >= maxAzimuthRange) || (Azimuth <= minAzimuthRange) )
        {
          Azimuth = 900;
        }
        fMoveAzimuth( Azimuth );
        AzimuthStartTime = esp_timer_get_time();
      } //azmiuth end
      if ( StartupCount < 500 )
      {
        ++StartupCount;
      } else {
        TorqueAmmount = 1;
        // esp_sleep_enable_timer_wakeup( (60000000 / 30) ); // set timer to wake up
        // esp_sleep_enable_timer_wakeup( (60000000 / 20) ); // set timer to wake up
        // esp_light_sleep_start();
      }
    }
     vTaskDelay( 65 );
  } // while(1)
} //void TrackSun()
////
void fMoveAltitude( int MoveTo )
{
  mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, MoveTo);
  vTaskDelay( 12 );
}
//////
void fMoveAzimuth( int MoveTo )
{
  mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A, MoveTo);
  vTaskDelay( 12 );
}
////
void loop() {}
////

I just looked into the PCA9685. The problem is that it is only for servos, not stepper motors.

These are all going to be inputs, But I do realize the are analog, not digital.

I think what I may have to do is use the MCP23017 for my inputs of the switches, that should leave enough pins on the ESP32 for the drivers.

Do the steppermotors all have to drive with a different speed? And or at different times?

What is the maximum rotations per minute the stepper-motors need to rotate?

How many steps do your stepper-motors have per a full rotation as fullsteps?
What resolution do you need = what step-mode do you need? fullstep, halfstep
something below half-step?

If all this can work from a single ESP32 depends on these numbers I'm asking for.

You seem to want to keep the real application a secret. Well this means that better suitable solutions can't be suggested. You seem to be not very experienced in motions-control otherwise you wouldn't have to ask.

Depends on you how much you want to tell, to - maybe following a way that works better. Can't really say it because the real application is unknown.

best regards Stefan

It's a PWM chip. I've used it for LEDs, which also aren't stepper motors. Worked nicely. If you need additional PWM outputs, a PCA9685 will provide them. I wouldn't recommend having them directly drive a load, but in combination with a suitable driver it should work fine.

That's a valid alternative.
I've never been a huge fan of the MCP23017 for most purposes. It's just awkward to have any and all pin manipulations go through the I2C bus. Works OK if only slooooow stuff is needed of course.

All of the steppers run at the same speed, but 3 steppers are running at any given time.
The max speed is set to 2000.
A full rotation is 800 steps
I want them to run 1.8% per step for full torque.

I just spent the whole day programing my ESP32 and MCP23017 to do all of the input needed to control the stepper motors. The reason for the MCP23017 was because I had 12 outputs and 11 inputs.

2000 what?

2000 rotations per minute?
2000 step-pulses per second?
2000 microseconds delay between step-pulses?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.