4 years, 8 months ago.

What needs to be changed in the Hello World program for two stacked IHM02A1s?

Does a pointer need to be instantiated? I have written code doing that, but it still doesn't work. Does something need to be added in the XNucleoIHM02A1.cpp?

Here are more details: https://stackoverflow.com/questions/57434935/compiles-and-spi-motor-driver-shields-work-individually-but-not-together

I have two dual stepper motor driver boards. Each board drives two motors. I'm using an STM32F767 MCU. The first driver board shield works. The motors move.

The second driver board shield kind of works. On the second (top) shield, if SB23 is left unchanged (the same as the first driver shield). The second board mirrors or does the same thing as the bottom shield. Although, when I unsolder SB23 and solder SB7. "So, when using more than one expansion board, the user must short a different solder bridge among SB7, SB8, SB9 and SB23, for each X-NUCLEO-IHM02A1"​.

#include "mbed.h"
#include "DevSPI.h"
#include "XNucleoIHM02A1.h"

#define L6470_L1M1 (0u) // Index of shield1 motor1
#define L6470_L1M2 (1u) // Index of shield1 motor2

// #define L6470_L2M1 (0u) // Index of shield2 motor1
#define L6470_L2M2 (1u) // Index of shield2 motor2

#define MPR_1 4

#define STEPS_1 (200 * 128)
#define STEPS_2 (STEPS_1 * 2)

#define DELAY_1 1000
#define DELAY_2 2000
#define DELAY_3 5000

L6470 **motors1stLevel; // double pointer, to L6470 (chip) class
L6470 **motors2ndLevel;

XNucleoIHM02A1 *x_nucleo_ihm02a1one; // pointer to function
XNucleoIHM02A1 *x_nucleo_ihm02a1two;

int positionL1M1, positionL1M2, positionL2M1, positionL2M2 = -1;

L6470_init_t init[L6470DAISYCHAINSIZE] = {
    /* First Motor. */
    {
        24.0,                          /* Motor supply voltage in V. */
        200,                           /* Min number of steps per revolution for the motor. */
        1.7,                           /* Max motor phase voltage in A. */
        3.06,                          /* Max motor phase voltage in V. */
        300.0,                         /* Motor initial speed [step/s]. */
        500.0,                         /* Motor acceleration [step/s^2] (comment for infinite acceleration mode). */
        500.0,                         /* Motor deceleration [step/s^2] (comment for infinite deceleration mode). */
        992.0,                         /* Motor maximum speed [step/s]. */
        0.0,                           /* Motor minimum speed [step/s]. */
        602.7,                         /* Motor full-step speed threshold [step/s]. */
        3.06,                          /* Holding kval [V]. */
        3.06,                          /* Constant speed kval [V]. */
        3.06,                          /* Acceleration starting kval [V]. */
        3.06,                          /* Deceleration starting kval [V]. */
        61.52,                         /* Intersect speed for bemf compensation curve slope changing [step/s]. */
        392.1569e-6,                   /* Start slope [s/step]. */
        643.1372e-6,                   /* Acceleration final slope [s/step]. */
        643.1372e-6,                   /* Deceleration final slope [s/step]. */
        0,                             /* Thermal compensation factor (range [0, 15]). */
        3.06 * 1000 * 1.10,            /* Ocd threshold [ma] (range [375 ma, 6000 ma]). */
        3.06 * 1000 * 1.00,            /* Stall threshold [ma] (range [31.25 ma, 4000 ma]). */        
        StepperMotor::STEP_MODE_1_128, /* Step mode selection. */
        0xFF,                          /* Alarm conditions enable. */
        0x2E88                         /* Ic configuration. */
    },

    /* Second Motor. */
    {
        24.0,                           /* Motor supply voltage in V. */
        200,                           /* Min number of steps per revolution for the motor. */
        1.7,                           /* Max motor phase voltage in A. */
        3.06,                          /* Max motor phase voltage in V. */
        300.0,                         /* Motor initial speed [step/s]. */
        500.0,                         /* Motor acceleration [step/s^2] (comment for infinite acceleration mode). */
        500.0,                         /* Motor deceleration [step/s^2] (comment for infinite deceleration mode). */
        992.0,                         /* Motor maximum speed [step/s]. */
        0.0,                           /* Motor minimum speed [step/s]. */
        602.7,                         /* Motor full-step speed threshold [step/s]. */
        3.06,                          /* Holding kval [V]. */
        3.06,                          /* Constant speed kval [V]. */
        3.06,                          /* Acceleration starting kval [V]. */
        3.06,                          /* Deceleration starting kval [V]. */
        61.52,                         /* Intersect speed for bemf compensation curve slope changing [step/s]. */
        392.1569e-6,                   /* Start slope [s/step]. */
        643.1372e-6,                   /* Acceleration final slope [s/step]. */
        643.1372e-6,                   /* Deceleration final slope [s/step]. */
        0,                             /* Thermal compensation factor (range [0, 15]). */
        3.06 * 1000 * 1.10,            /* Ocd threshold [ma] (range [375 ma, 6000 ma]). */
        3.06 * 1000 * 1.00,            /* Stall threshold [ma] (range [31.25 ma, 4000 ma]). */        
        StepperMotor::STEP_MODE_1_128, /* Step mode selection. */
        0xFF,                          /* Alarm conditions enable. */
        0x2E88                         /* Ic configuration. */
    }
};

void startup();
void forward();

int main()
{      
    /* Initializing SPI bus. */
#ifdef TARGET_STM32F429
    DevSPI dev_spi(D11, D12, D13);
#else
    DevSPI dev_spi(D11, D12, D13);
#endif

    /* Initializing Motor Control Expansion Board. */
    x_nucleo_ihm02a1one = new XNucleoIHM02A1(&init[0], &init[1], A4, A5, D4, A2, &dev_spi);
    // x_nucleo_ihm02a1two = new XNucleoIHM02A1(&init[0], &init[1], A0, A1, D1, D2, &dev_spi);  
    x_nucleo_ihm02a1two = new XNucleoIHM02A1(&init[0], &init[1], A4, A5, D4, D2, &dev_spi);

  //																				First shield works, motors move.
  //																				Second shield (3rd motor) does nothing...

    /* Building a list of motor control components. */
    motors1stLevel = x_nucleo_ihm02a1one->get_components();
    motors2ndLevel = x_nucleo_ihm02a1two->get_components();

    // startup();

    forward();
          

}  
    /*----- Functions -----*/ /*----- -----*/ 

void startup()
{
    /*----- Initialization. -----*/
    motors1stLevel[L6470_L1M1]->set_home();
    motors1stLevel[L6470_L1M2]->set_home();
    // motors2ndLevel[L6470_L2M1]->set_home(); 
    motors2ndLevel[L6470_L2M2]->set_home();

    wait_ms(DELAY_1);

    positionL1M1 = motors1stLevel[L6470_L1M1]->get_position();
    positionL1M2 = motors1stLevel[L6470_L1M2]->get_position();
    // positionL2M1 = motors2ndLevel[L6470_L2M1]->get_position();
    positionL2M2 = motors2ndLevel[L6470_L2M2]->get_position();
      
    wait_ms(DELAY_1);    
}

void forward()
{
        motors1stLevel[L6470_L1M1]->move(StepperMotor::FWD, STEPS_1);
        motors1stLevel[L6470_L1M2]->move(StepperMotor::FWD, STEPS_1);
      wait_ms(DELAY_3);
        motors2ndLevel[L6470_L2M2]->move(StepperMotor::FWD, STEPS_1);	// There is no L2M1
        motors2ndLevel[L6470_L2M2]->move(StepperMotor::FWD, STEPS_1);
}

Question relating to:

2 Answers

4 years, 7 months ago.

Hey Adam,

I was having the same problem as you for quiet some time. I found that changing the busy and flag pins on the second shield fixed the problem(I used A0 and A1) so I can control all the motors. Cheers,

Edit: Seems like I made an error. I can control all 4 motors so long as I prepare the actions and run them at the same time. I cannot for instance run the 2 motors on shield 1 then later start the 2 motors on shield 2. I'm still working on getting it working, and the lack of documentation for this board renders that tedious. Best of luck, Ill try and post whatever I can figure out.

Matthew

4 years, 8 months ago.

Adam -

Stacked X-Nucleo-IHM02A1 expansion boards need to have their jumpers configured correctly to enable two-by-two daisy-chaining. Up to four boards can be daisy-chained by setting appropriate solder bridges to change the SSEL pin for each board. The four allowed SSEL pins in "Arduino" terminology are A2, D2, D10 and D5. The default solder bridge configuration uses A2.

It looks like your code uses the non-default SSEL pin D2 for x_nucleo_ihm02a1 and the default SSEL pin A2 SSEL for x_nucleo_ihm02a1two.

I think you need to "open" SB-23 and "close" SB_7 on the board that uses SSEL pin D2. See this link or the User Manual (UM1964) for the expansion board.

https://os.mbed.com/teams/ST/code/X_NUCLEO_IHM02A1/

Yes. I did that. I moved the zero-ohm from SB23 on the second board, and soldered it to SB7. That's why I'm confused. That has not worked.

posted by Adam Aero 14 Aug 2019

So since that didn't work, I created the code in the edited question. I just want to interdependently control three motors.

posted by Adam Aero 15 Aug 2019

I think you might be having problems with the handshaking that is taking place between the expansion board and the MCU. Both daisy-chained boards use the same "busy_irq" signal, so I think a "busy" (or "flag") from one board can block a new command to the other board.

You can use the "wait_while_active()" method to make sure that the desired motor has completed the commanded task before issuing another command. There is an example of this in the "control of 2 motors" test application on the /Components/X-NUCLEO-IHM02A1 Two Axis Stepper Motor Driver page.

To run multiple commands simultaneously, I think you need to first "prepare" them (eg. "prepare_run()") and then execute them simultaneously using "perform_prepared_actions()". This is done in the "control of 2 motors" example. You can find these function calls in the L6470.h header file in the X_NUCLEO_IHM02A1 Library.

You might want to test the "control of 2 motors" example with your "default" board to verify that everything works as expected.

The HelloWorld_IHM01A1_2Motors example may also help you with the code architecture for controlling daisy-chained STM stepper motor expansion boards, even though it is for a different controller IC.

posted by J Roth 16 Aug 2019

The Hello World program is what I started with. Even with the wait_while_active, a second set of motors still do not move.

As I already said, both levels of motors work. Whichever "new XNucleoIHM02A1(&init[0], &init[1]" comes first, causes the motors to move. But the second instance (second set of motors) still does not work.

Having the flag, busy and standby/reset pins different has the same results as seen from the commented out line:

x_nucleo_ihm02a1two = new XNucleoIHM02A1(&init[0], &init[1], A0, A1, D1, D2, &dev_spi); 

Is there something physically that needs to change when defining A0, A1, D1?

posted by Adam Aero 19 Aug 2019