This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/DRV8885EVM: DRV8885EVM Firmware Bug?

Part Number: DRV8885EVM

Tool/software: Code Composer Studio

Hi All,

I'm experiencing some trouble with the DRV8885EVM's firmware (FW).  The FW seems to ignore G_MAUNAL_ADVANCE commands from both my software and the EVM software.

Generally, once the part is setup, to move a certain number of steps, the process is:

 - Write the desired # steps to G_NUM_STEPS by writing to address 0x11A0.

 - Write a boolean true or logic 1 to 0x11CC, the G_MANUAL_ADVANCE variable, this should start the motor moving.

 - Poll 0x11C8, the G_MOTOR_CMD_ACTIVE2 variable until it clears, this should indicate that the motor has completed the move.

The issue I'm having is that maybe 1/10 writes to G_MANUAL_ADVANCE seem to be ignored, when I poll G_MOTOR_CMD_ACTIVE2 just after the write, it is clear, when I couldn't possibly be, I'm asking the motor to move 100 steps, this should take 100mS plus.  See the attached serial scope shot.

Steps to reproduce, see pic of the EVM screen.

I've pulled the FW down in CCS for it and similar EVMs, all seem to miss the commands.  The issue seems to be related the asynchronous POKE/PEEKs that come in from the SW, somehow causing a clearing of the G_MANUAL_ADVANCE or G_MOTOR_CMD_ACTIVE2 flags.  Writes to these locations seem to only occur in a few places, GUI defaults, but most importantly maybe, when the motor control state machine determines the unit is in IDLE.

Any advice / suggestions would be very much appreciated.

Here is a link to the software for the DRV8885EVM.

Thanks,

Adam

  • Hi Adam,

    There appears to be times when the mcu does not accept the command. This may be due to servicing an interrupt or calculating a floating point number.

    After interrogating the G_MOTOR_CMD_ACTIVE2 and seeing a bad result, you can re-send the command until you get the proper response. This is acceptable if you know this device cannot complete the move in the time between the issuance of the command and the read of the status.
  • Hi Duncan,

    Thanks for your reply.

    I'm fairly sure the byte gets received properly and written to memory, I've modified the serial command handler to read back each read from memory once written and respond with a 1 byte ACK.

    What I think is going on is that the byte I write gets clobbered before the determine movement and state machine updates occur.  The is probably because when idle, the firmware just sits there clearing all the variables.  Maybe it can be modified to only clear the idle variables the first time it goes into that state, that would at least limit the possibility of it happening unless the byte comes in between just a few instructions.  Maybe I'll try to implement that soon.

    Yes, that workaround will work, but only for steps that I know can't get accomplished before I can poll it.  But I'd really like make it work without resorting to this.  Maybe I could also put a small delay in at the start of a run that is was long enough to know for sure the write took as a quick / dirty fix.

    I thought potentially this might get read by the developer and it might jog a memory and maybe result in a quick fix.

    Thanks again,

  • I think I've resolved the issue, but limited testing has been performed.

    I believe the issue was here:

    void MotorStateMachine()
    
    {
    
        // update the SteppingRateTMR if required
    
        // reduce the number of calculations
    
        if (UpdateSteppingRateTMR == true)
    
        {
    
            SteppingRateTMR = SMCLK_FREQ/SteppingRate;  // calculate new value
    
            UpdateSteppingRateTMR = false;              // clear flag
    
        }
    
        switch (AccelerateState)
    
        {
    
        case (IDLE):
    
        if(G_RECIPROCATION == false && G_WAKE == high && G_ENABLE == high)
    
            {
    
            G_MOTOR_CMD_ACTIVE1 = false;
    
            G_MOTOR_CMD_ACTIVE2 = false;
    
            G_MOTOR_CMD_ACTIVE3 = false;
    
            G_ENBL_START_STOP = false;          // enable with false, allow Start Stop
    
            G_MANUAL_ADVANCE = false;           // clear the flags once stops
    
           G_ENBL_RECIPROCATION_BUTTON = false;
    
            G_RUN_MOTOR = false;
    
            G_ENBL_MOVE_STEPS = false;
    
            MoveSteps = false;                  // clear the MoveSteps flag here
    
            // reset the timers if the last command was run motor
    
            if (LastCommandWasRunSteps == true)
    
                {
    
                    TACTL &= ~MC_3;                     // Stop timerA
    
                    TBCTL &= ~MC_3;                     // Stop timerB
    
                }
    
            }

    The IDLE case was running often, and clobbering all of the GUI writes to those GLOBALS before DetermineMotorMovement() could take action on them.  I added a PrevAccelerateState variable, and set it to AccelerateState just before each time it changed.

    Now the UpdateStateMachine() only clears the GLOBALS on the first transition into IDLE:

    void MotorStateMachine()
    
    {
    
        // update the SteppingRateTMR if required
    
        // reduce the number of calculations
    
        if (UpdateSteppingRateTMR == true)
    
        {
    
            SteppingRateTMR = SMCLK_FREQ/SteppingRate;  // calculate new value
    
            UpdateSteppingRateTMR = false;              // clear flag
    
        }
    
        switch (AccelerateState)
    
        {
    
           case (IDLE):
    
           {
    
               if (PrevAccelerateState == IDLE)
    
               {
    
                   // do nothing, make sure we only clear the globals listed below once on a state change
    
               }
    
               else
    
               {
    
                   PrevAccelerateState = IDLE;     // Set state to idle
    
                   if(G_RECIPROCATION == false && G_WAKE == high && G_ENABLE == high)
    
                   {
    
                       G_MOTOR_CMD_ACTIVE1 = false;
    
                       G_MOTOR_CMD_ACTIVE2 = false;
    
                       G_MOTOR_CMD_ACTIVE3 = false;
    
                       G_ENBL_START_STOP = false;          // enable with false, allow Start Stop
    
                       G_MANUAL_ADVANCE = false;           // clear the flags once stops
    
                       G_ENBL_RECIPROCATION_BUTTON = false;
    
                       G_RUN_MOTOR = false;
    
                       G_ENBL_MOVE_STEPS = false;
    
                       MoveSteps = false;                  // clear the MoveSteps flag here
    
                       // reset the timers if the last command was run motor
    
                       if (LastCommandWasRunSteps == true)
    
                       {
    
                          TACTL &= ~MC_3;                     // Stop timerA
    
                           TBCTL &= ~MC_3;                     // Stop timerB
    
                       }
    
                   }
    
               }
    
           }
    
    

    I'll leave a CCS 7.2.0 project here in case anyone else has this issue, this FW image calls itself v1.1.

    Thanks,
    Adam

    DRV8885EVM_v1p0.zip