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.

LAUNCHXL-F280049C: GPIO CMD switch control fault startup

Guru 56308 points

Part Number: LAUNCHXL-F280049C
Other Parts Discussed in Thread: MOTORWARE

Universal motor control SDK via GPIO switch and symbol (CMD_SWITCH_EN) cause immediate motor startup fault.

Random other faults then appear just clearing fault flag bit. Simply adding the symbol into the project build adds below variables that lead to the immediate motor startup fault flag after MCU reset, application not run in CCS debug. Setting motor run (flagEnableRunAndIdentify = true) has no effect without CCS debug. So tried to configure GPIO to control the flag from an outside source but that causes other issues to evolve as described.

Applicaiton don't even have to call below function for the startup fault to occur. Setting the initial GPIO input state to write a low or high makes no difference, debounce delay time set very high >1000U. So the outside control uses 2 GPIO one is output the other input with jumper wire between booter pins so a connected HID controls motor run/stop via GPIO in the application. 

// GPIO58->CMD State Button Run/Stop (J4-34)
GPIO_setMasterCore(58, GPIO_CORE_CPU1);
GPIO_setPinConfig(GPIO_58_GPIO58);
GPIO_setDirectionMode(58, GPIO_DIR_MODE_IN);
GPIO_setPadConfig(58, GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode(58, GPIO_QUAL_6SAMPLE);
GPIO_setQualificationPeriod(58, 6);

// GPIO59->CMD Motor State output (J2-11)
GPIO_setMasterCore(59, GPIO_CORE_CPU1);
GPIO_setPinConfig(GPIO_59_GPIO59);
GPIO_setDirectionMode(59, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(59, GPIO_PIN_TYPE_STD);
GPIO_writePin(59, 0);

Why does adding these variables cause immediate motor startup fault to occur? Alternatively, do we need to issue SW interrupt for (flagEnableRunAndIdentify) to write symbol name and set bool flag state when CCS debug is NOT being used to control several bool flags in the project build? 

#if defined(CMD_SWITCH_EN)
void setExtCmdSwitchParams(MOTOR_Handle handle)
{
   MOTOR_Vars_t *objMtr = (MOTOR_Vars_t *)handle;

   objMtr->cmdSwitch.delayTimeSet = USER_M1_SWITCH_WAIT_TIME_SET;
   objMtr->cmdSwitch.highTimeCnt = 0;
   objMtr->cmdSwitch.lowTimeCnt = 0;

   objMtr->cmdSwitch.flagCmdRun = false;
   objMtr->cmdSwitch.flagEnablCmd = false;
   return;
} // end of updateExtCmdCapFreq() function

  • Alternatively, do we need to issue SW interrupt for (flagEnableRunAndIdentify) to write symbol name and set bool flag state when CCS debug is NOT being used to control several bool flags in the project build? 

    That would be one way with ARM Cortex MCU with NVIC controller. Though a much simpler approach HWREG data address with the desired flag state actually works. It would seem C syntax and CPU pneumonic code is not created correctly by the compiler. Another more likely possibly compiler is not linking variable (obj symbol) to an or correct address of the bool state changes.

    Possible clue being the address where the bool flag resides does not recognize or allow immediate B2B writes. Yet after a while the enable flag state can be set once again after it was cleared. Verified while the application runs inside CCS debug memory browser when HID controls the address @data word state changes.

  • Hello Genatco,

    1. The first thing I notice is that you're using the F280049C, which the Universal Lab does not have built-in support for. How have you verified the functionality of your custom code?

    2. Second thing I note is that you state that you're setting flagEnableRunAndIdentify without use of CCS debug. Are you verifying before you do so that flagEnableSystem = 1? Startup and offset calibration must occur before flagEnableRunAndIdentify should be set, and once these are completed, the software automatically sets flagEnableSystem and awaits further user input.
    3. You mentioned that there's a fault bit immediately set upon system boot. Which bit? If you're referring to startupFailed, then something is wrong with the adapted code. It should be impossible for this flag to be set until after flagEnableSystem has been set- it indicates that motor startup failed, not system startup.

    Please let me know the answer to each of these questions so that I can assist further.

    Regards,
    Jason Osborn

  • Hello Jason,

    How have you verified the functionality of your custom code?

    That would be a big affirmative since x49c conversion runs motors from CCS debug and now in standalone after work around issues below.

    How have you verified the functionality of your custom code?

    Project works with or without CCS debug but the GPIO control is oddly bugged. As the post states, fault (startup failed). Gave up on GPIO and used another method to set/clear and read these bool flags by data address. Why does obj-> to the struct member not link to the data word the real question. The added modules have the proper header and footer to denote C code to the compiler. Yet the linking to the symbol names are not occurring.

    #ifdef __cplusplus
    extern "C"
    {
    #endif

    // My code

    #endif
    //
    #ifdef __cplusplus
    }
    #endif // extern "C"

    Are you verifying before you do so that flagEnableSystem = 1?

    If that was the case nothing would work without CCS debug. The HWREGH call to set the flag enable bit or read back variable data works but none of the C syntax links symbols to below noted addresses in modules that are not part of the original TI build. Though custom modules virtual file paths/folder can exist under SDK under libraries folder or UMC folder, so path is not the issue. Somehow the compiler is skipping over pointers to the struct members not linking them to the data word.

     Example of failed compiled code:

        MOTOR_Vars_t *obj = (MOTOR_Vars_t *)motorHandle_M1;

    Fails: motorHandle_M1.flagEnableRunAndIdentify = true; 

    Works: HWREGH(0x0000074B) = 0x1;

    Fails: if((obj->flagEnableRunAndIdentify == true) && (obj->flagRunIdentAndOnLine == true))

    Works: if((HWREGH(0x0000074B) == 0x1) && (HWREGH(0x0000074C) == 0x1))

    Fails: obj->flagEnableRunAndIdentify = true;

    Works: HWREGH(0x0000074B) |= 0x1; 

    Fails: watt = (powerReal_W / 100), 0, 0); // No data 

    Works: watt = HWREGH(0x000006AE) / 100), 0, 0); 

    if((motorVars_M1.speed_Hz == 0.0f) && (HWREGH(0x0000C011) == 0x1)) //(systemVars.flagEnableSystem == true)

    to be set until after flagEnableSystem has been set- it indicates that motor startup failed, not system startup.

    The systemVars.flagEnableSystem flag is set automatically by CPUTimer0 function after 1 second relay delay

    if(systemVars.timerBase_1ms > systemVars.powerRelayWaitTime_ms)
    {
        systemVars.flagEnableSystem = true;

        systemVars.timerBase_1ms = 0;

        obj->ISRCount = 0;

        SCIprintf(">> UserParmsLoaded %c\n");
    }

  • Hello again,

    This is an interesting set of problems that I've not seen before. I'll consult with some colleagues- in the meantime, I do have a couple follow-up questions and comments.

    1. I didn't realize from prior posts that the code was failing to compile. Are there compilation or linker errors being logged in the problems window?

    2. Import a fresh Universal Motor Control Lab example into the workspace. Compare the project properties between the two.
      1. 'CCS General'
        1. Are the project options the same in your project, accounting for differences in device?
      2. 'CCS Build'
        1. 'C2000 Compiler'
          1. Are the 'Processor Options' and 'Optimization' options the same in your project, accounting for differences in device? 
        2. 'C2000 Linker'
          1. Are the 'Basic Options' and 'File Search Path' options the same in your project?

    3. If CCS thinks that the code is being compiled correctly and your linker options all look correct, the fastest way I can think of offhand to see exactly what's happening on the backend is to take a quick glance at some assembly files.

      1. Once you've enabled the option to keep the assembly file, re-build the project.
      2. In project explorer, navigate to the generated build folder:
      3. Ctrl-F "SYSTEM_Vars_t"
      4. There should be 2 occurrences in this file. Between them, each variable in the struct is listed.
      5. Is everything there that you expect to be there?

    Regards,
    Jason Osborn

  • I didn't realize from prior posts that the code was failing to compile. Are there compilation or linker errors being logged in the problems window?

    No there is no indication of errors the IDE is failing to create links of these symbols to actual data addresses. Verbose diagnostic display does not reveal any warnings during linking process. Given the HWREGH replacements work should be an indication of something, what is the question for TI experts.

    Modified the x25 project build to make x49 and project speed & optimizations are the same. Interestingly adding #pragma to reduce speed and optimizations on these functions with link issues does not have any effect either. Functions running from ram or flash produce the same results though the placement of the #pragma in LSRAM sections does have an affect on the application even working with ISR loops mentioned below. 

    #pragma FUNCTION_OPTIONS (my_fuctions, "--opt_level=0 --opt_for_speed=1")
    #pragma CODE_SECTION(my_functions, ".TI.ramfunc"); 

     Odder yet is the time delay HWREGH to enable the data word after it has been asserted will not allow reassert for long time after the motor stops. Setting the flag flagEnableRunAndIdentify = true again only allowed after many seconds. The forever while loop of UMC project runs much faster even with 1ms CPU timer than did the SDK. Good reason to try and get the GPIO CMD switch to run where the function controls flagEnableRunAndIdentify to start and stop the motor. About fault flag (Startup_fail), oddly timeout 20 seconds when CMD switch is enabled trips immediately. Suspect startup fail fault time set is to high and branching occurs in the application due to CPU timer 1ms since we use the GPIO to toggle launch pad yellow run LED in the loop testing for fault condition to toggle the red LED to indicate fsult.

    if(obj->faultMtrUse.all != 0)
    {
       HAL_toggleLED(halHandle,HAL_GPIO_LED1C); // Red LED

      obj->flagEnableRunAndIdentify = false; // added 5-31-23
    }

    //! \brief Defines the number of startup failed setting time
    //! timer base = 5ms, 10s
    #define USER_M1_STARTUP_FAIL_TIME_SET (1000) //!2000=10sec

    //! \brief Defines the number of stop wait time
    //! timer base = 5ms, 10s
    #define USER_M1_STOP_WAIT_TIME_SET (2000)

    //! \brief Defines the number of restart wait time
    //! timer base = 5ms, 10s
    #define USER_M1_RESTART_WAIT_TIME_SET (2000)

  • Apologies, I'm writing a response and did not mean to mark your answer. Will post response in just a moment. Sorry!

  • Hello,

    I have 5 points to address. Points 1 and 3, and 4 are statements, points 2 and 5 are questions I have for you.

    1. It's good to know that optimization & compilation errors don't seem to be the cause of the issue. Thank you for confirming.

    2. Did you have a chance to look into question 3 from my previous post?

    3. It is intended behavior that the motor cannot be immediately restarted. I made this to quickly show how this is determined:

        1. I made this flowchart because I had just made the one below this and I already had the software open, so it was convenient.

    4. I'm still struggling to understand how the obj->faultMtrNow.bit.startupFailed = 1; line of code is being executed so quickly. To walk myself through the process, I drafted up a quick flowchart to determine the absolute minimum amount of time it should take before faultMtrNow.bit.startupFailed could be set.



      1. By default, (flagEnableFlyingStart = true) and (flagEnableAlignment = false). This means that the absolute minimum amount of time before startupFailed can be set is, by default, (flyingStartTimeDelay + startupFailTimeSet).
        1. Therefore, the minimum wait time before startupFailed can be set is (USER_M1_STARTUP_FAIL_TIME_SET + (USER_M1_PWM_FREQ_kHz * 1000 * 0.5)), or somewhere around 10,000 ticks if your PWM is set to 18 kHz. Each tick should be approx. 5ms, so that should be nearly a minute after flagEnableRunAndIdentify is set before you can see bit.startupFailed = 1.
      2. But you're saying that faultMtrNow.bit.startupFailed is being set immediately upon running the code? Unless something was fundamentally altered about the state machine of the system, I'm uncertain how this is possible.

    5. You mention that the code executes faster- do you mean to say that the if statement containing HAL_getCPUTimerStatus() is not properly gating code? That's concerning. What speed does the counter appear to be counting at?

    Regards,
    Jason Osborn

  •  Odder yet is the time delay HWREGH to enable the data word after it has been asserted will not allow reassert for long time after the motor stops. Setting the flag flagEnableRunAndIdentify = true again only allowed after many seconds.

    The restart/stop delays user.h setting above post had to reduced, 200ms was minimum without crashing CPU timer. So restart is now resolved, allows resume during deceleration without a flying restart delay period. When the motor speed trajectory had not yet reached deceleration target pressing start resumes speed back up to previous set trajectory, like a cruise control might do. Though regeneration during deceleration has not been tested. Suspecting disabling PWM drive should not stop main control ISR and angle generation.

  • But you're saying that faultMtrNow.bit.startupFailed is being set immediately upon running the code? Unless something was fundamentally altered about the state machine of the system, I'm uncertain how this is possible.

    That makes two of us - lol

    You mention that the code executes faster- do you mean to say that the if statement containing HAL_getCPUTimerStatus() is not properly gating code? That's concerning. What speed does the counter appear to be counting at?

    I mean the SDK forever loop is07 runs much slower then UMC forever loop. So controlled deceleration is much faster in the UMC loop.

    I'm still struggling to understand how the obj->faultMtrNow.bit.startupFailed = 1; line of code is being executed so quickly.

    Seemingly SCI ISR executes TXFIFO prior to the CPU timer loop enabling systemVars flag and attempts to send fault status data to the HID. Yet that occurs even without CMD switch symbol being enabled. BTW: Nice flow chart will copy it down. 

    //systemVars.flagEnableSystem = true;

  • About Startup failure fault: The struct member used to set the fault bits runMotorMonitor() are different from the reported struct member in CCS debug expressions tab. Using the same struct member FaultMtrNow.bit in runMotorMonitor() to test the faults inside SCI interrupt context must use FaultMtrPrev.bit or several faults cannot ever be cleared by setting motorVars_M1.flagClearFaults = 1. Oddly CCS debug uses FaultMtrPrev.bit to indicate individual faults. HID GUI uses Prev.Bit to test, turn LED widgets red or green.

    What that has to do with enabling GPIO CMD switch in project build is baffling.

    // Motor Startup Failed
    if( (obj->Is_A < objSets->stallCurrentSet_A)
    && (obj->speedAbs_Hz < objSets->speedFailMinSet_Hz))
    {
       if(obj->startupFailTimeCnt > objSets->startupFailTimeSet)
    {
    obj->faultMtrNow.bit.startupFailed = 1;
    obj->startupFailTimeCnt = 0;
    /* set fault flag */
      bFaultSet = true;
    }
    else
    {
      obj->startupFailTimeCnt++;
    }
    }
    else if(obj->startupFailTimeCnt > 0)
    {
      obj->startupFailTimeCnt--;
    /* clear fault flag */
      bFaultSet = false;
    }

       

  • Hello,

    Addressing your posts and queries in no particular order:

    • FaultMtrNow is the the active monitor. FaultMtrPrev is a latch that indicates whether or not a selected fault has ever happened- this is also useful information long-term, but isn't necessarily going to be helpful debugging individual faults, and further is never actually reset.

    • Note that generally, 'disabling' the PWM is typically performed in the labs in this SDK (and in most implementations overall, in my experience) by setting a trip to disable the final output. When a trip occurs, the PWM does not stop running, the ADC (triggered by the PWM) therefore does not stop triggering, and the ISR (triggered by the ADC) therefore does not stop running.

    • I had not realized you were also referencing the MotorWare InstaSPIN examples- good to know. It's definitely important to check the differences between those examples and the newer, more up-to-date Universal Lab before implementing the concepts they utilize.

    • I find that in these examples, while the system waits for the user to set a flag to begin actively responding, the peripherals and interrupts typically continue to execute and the output or action is simply blocked from propagating.

    Regards,
    Jason Osborn

  • Hello again,

    Forgot to mention one thing. In addition to FaultMtrPrev and FaultMtrNow, you'll notice that there's FaultMtrUse and FaultMtrMask.

    Not every fault actually stops the motor from running. With Boolean logic, FaultMtrUse = (FaultMtrNow & FaultMtrMask). The rest of the FOC code looks at FaultMtrUse when determining if a fault has occurred.

    So, in summary;

    • FaultMtrNow is a list of all currently active faults
    • FaultMtrPrev is a list of every fault that has ever happened since we started executing the code
    • FaultMtrMask is a constant bit mask over the faults struct, allowing us to only use a selected subset
    • FaultMtrUse = FaultMtrNow & FaultMtrMask, meaning it's every currently active fault from our selected subset only.

    Regards,
    Jason Osborn

  • FaultMtrPrev is a list of every fault that has ever happened since we started executing the code

    Odd though many of the motor scan faults use FaultMtrPrev for debug expressions drop down list box also sets my added bool switch bFaultSet = true or false. That is what sets the HID fault widget indicators and immediately was setting Starup fault when switch CMD is compiled into the project.

    The last thing my HID initialization code does is clear all motor scan faults in main.c shortly after SCI TXFIFO ISR is enabled prior to entering the first while loop and later forever loop. Setup in the same way SDK4.0 or the ADC mainISR() would lock up. So it is purposefully disabled until the SCI TXFIFO has been enabled and after SCIRXFIFO enabled in both projects.

    /* Clear all fault flags */
    motorVars_M1.flagClearFaults = true;

  • Hello,

    Sorry, I'm uncertain- are you saying that the issue is or is not still present, accounting for instances of 'FaultMtrPrev' being changed to 'FaultMtrUse' in error handling functions?

    Regards,
    Jason Osborn

  • Hi Jason,

    of 'FaultMtrPrev' being changed to 'FaultMtrUse' in error handling functions?

    Doing variable change in the HID code makes the faulting problems progressively worse even without CMD switch being enabled. Never changed runMotorMonitor() fault scan loop from Now into Use. Is the later what you were suggesting to try? It seems ok for the HID to use Prev as it only reports to the user what fault condition occurred of 8 tested.

  • Hello,

    To clarify what I was trying to say,

    • runMotorMonitor() sets FaultMtrNow
    • runMotor1Control() uses FaultMtrNow to set FaultMtrUse
    • runMotor1Control() also uses FaultMtrUse to determine whether or not to stop the motor

    I do have another question for you.

    What is the full list of predefines you have enabled? i.e. if I import one of the labs and navigate to {Project Properties} -> CCS Build -> C2000 Compiler -> Predefined Symbols, I might see something like this:

    What does you list look like?

    Regards,
    Jason Osborn

  • The only one noticed being different (MOTOR_ESMO) from UMC 4.0 when disabled (MOTOR_ESMO_N) motor will not run as I recall.