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.

TMS320F280049C-Q1: tms320f280049c

Part Number: TMS320F280049C-Q1
Other Parts Discussed in Thread: C2000WARE, CONTROLSUITE, MOTORWARE, INA240

Hi,

 I  am doing PMSM motor control with hall effect sensor . 

Which is best method for calculation angle and speed for Hall effect sensor.

How to integrate FAST loop in sensored motor control.

sample code for same.

Regards,

  • Hi,

    The subject matter expert is on leave today. Please expect a response in 2 days.

    Regards,

    Veena

  • Hi Sagar, you may refer to Universal motor control lab documentation and the hall sensor example - C2000Ware_MotorControl_SDK_4_00_00_00\solutions\universal_motorcontrol_lab\doc

  • Hi,

     Thank you for reply.

    How to integrate estimator in my SW

    EST_run(obj->estHandle, &obj->estInputData, &obj->estOutputData); //ssy

    I want detailed information regarding the same which will help me to integrate in my SW.

    Regards,

  • Sagar, you can include the fast_full_lib.lib and est.h you find under src_lib of the universal_motorcontrol_lab. The source code of the estimator is protected.

  • It's been more than 2 weeks since we heard from you,  so I am assuming you no longer need clarification for your question that will be marking this thread as closed. You can reply with a post or create a new thread if you have any further question on this topic. Thanks.

  • Hi Navaneeth Narayanswamy

    we also stuck in EST_run,EST_getFm_lp_Hz,how we get definitions of this funtions or est.c file.

  • You can refer to the reference of these two functions in est.h, and call these two functions from the FAST library. TI doesn't provide the source codes for the API functions in FAST library. You can refer to the Universal lab to call these functions for motor control without the source codes.

  • Hi Navaneeth,

    I had a look at universal motor control lab PDF configured mostly for X25 MCU that does not have any kind of CMPDAC peripheral ePWM trip fault mitigation the x49 has. Also noticed new kind of FAST estimator (eSMO) that is not elaborated anywhere in the universal PDF document search, would be nice to eSMO added to x49c future silicon revisions too. 

    Wondering is x25 launch pad eSMO estimator required to produce minimal SVM mode and does it work better with HALLs versus sensorless FOC?

  • You can refer to the Technical Reference Manual of F28002x and F28004x about how to set the CMPSS and ePWM trip fault. The CMPSS and ePWM peripheral are the same type on both F28002x and F28004x.

    The eSMO has been already supported on C2000 devices in controlSUITE, we ported the algorithm to floating point version with open source and get it into the Universal lab in MCSDK. The algorithm can be implemented any newer C2000 devices including F28004x.

    The eSMO is still an estimator algorithm for sensorless-FOC that is not related to the hardware and SVM mode.

  • from  cmpss 7  can I trip  PWM 1,2&3 .

  • Yes. You can use any CMPSS to trip the PWM. Please configure the CMPSS and link the output to the EPWM according to your hardware.

  • Hi Yanming,

    The algorithm can be implemented any newer C2000 devices including F28004x.

    The eSMO is still an estimator algorithm for sensorless-FOC that is not related to the hardware and SVM mode.

    Perhaps good to know since I can't after weeks trying many different schemes to get other ePIE interrupts to work with FAST estimator asserting. Other ePIE INTS rudely interrupt FAST estimator by slower interrupt sources, either CPU_timer0, SCI TX interrupt or even with no TX interrupt enabled.

    Adjusting (user.h) USER_NUM_PWM_TICKS_PER_ISR_TICK (6 ticks) stalls ADCA1 interrupts, parameters refuse to load in debug. Will upload private video of the motor run condition conditions. Yet it didn't matter what ePIE interrupt was running, Instaspin execution time required the entire CPU time to run motor correctly. Hence the reason to check on the x25 with universal motor SDK that seems nicely done too.

  • The execution time FAST estimator is about 11.7us, and the execution time of the whole FOC in this lab is about 22.0us. 

    If you haven't had a chance to look at the workshop material, I think this will help demystify some of the terminology and architecture, and learn about C2000 MCU to get started developing as well.

    https://dev.ti.com/tirex/explore/node?node=AOXFCHdD4iiPtd8.R6R0Tw__jEBbtmC__LATEST

  • The execution time FAST estimator is about 11.7us, and the execution time of the whole FOC in this lab is about 22.0us. 

    There is no demystifying what seem to be failure ePIE core priority silicon logic area. Already developing many codes that jam other pending INT's prior to ADCA1 group 1 clear ACK with FAST estimator run time in group1 and group9 core priority.

    Note SDK (FOC)  ePWM module CMPD (hal.c) is configured 250us ADC trigger source. My execution time of mainISR() is roughly (active FAST, 125µs) @3 PWM ticks, inactive FAST, 75µs using GPIO markers for Instaspin decimation times via scope capture.

    // set EPWM1 trigger pulse, 
    EPWM_setADCTriggerSource(obj->pwmHandle[0],
    EPWM_SOC_A,
    EPWM_SOC_TBCTR_D_CMPD);

    // write value for ADC trigger (20KHz SOC_Int*5TBCTR=250µs, 1period=50µs)
    EPWM_setCounterCompareValue(obj->pwmHandle[0],
    EPWM_COUNTER_COMPARE_D,
    5);

  • Generally, the ADC trigger frequency equals to the PWM or controller frequency, the default frequency is 10KHz, 15KHz or 20KHz in MCSDK. Just use the CMPD to trigger the ADC at a time point in a PWM period, the event with CMPD will be generated every PWM period.

  • the event with CMPD will be generated every PWM period.

    Yet 20KHz modulation the ADC trigger period is set 5x50µs or 250µs for mainISR() IRQ. Instaspin GPIO decimation time (idle ready) period is 150µs or two PWM periods. That seems to be a very fast IRQ since it gets even faster 75µs during calls to fast estimator and other functions in mainISR() run time.

    Point being the Instaspin decimation time requires nearly all CPU execution bandwidth to run without causing motor control issues when additional slower ePIE groups are added to MCSDK. Seemingly it could use 3 separate ADC SOC sources (16 total) slower sample speed for inductive current. And split voltage (Clarke) and current controller (Clarke) samples between 3 ADC_Trigger_ePwm_Soc sources, (16 total) to choose from. Perhaps hardware task distribution could benefit MCSDK CPU execution times for other ePIE group events. Any thoughts if that could improve MCSDK throughput?

    The MCSDK motor control example must allow more CPU bandwidth for other peripherals to use free ePIE group vectors that run slower than motor control without CCS debug real time *.js monitors. Seemingly MCSDK is more than just an example and rather more of a flight plan for industrial SVM motor commutation purposes, is it not?

  • GI Quote "Seemingly it could use 3 separate ADC SOC sources (16 total) perhaps slower sample speed for inductive current. And split voltage (Clarke) and current controller (Clarke) samples between 3 ADC_Trigger_ePwm_Soc sources, (16 total) to choose from." 

    So I tested HW distribution idea using multiple SOC's and ePWM ADC trigger sources. The ePWM failed to trigger ADCA, ADCB, or ADCC via CPMD of individual ePWM-A generator sources. There was no ETSOPCPS trigger activity via CCS debug Register view (refreshed) ePWM peripherals. The HAL of MCSDK ADC uses ePWM1, ePWM4, ePWM2 in that order and mirrored over to each ADC peripheral, matching source to destination trigger points (respectively) failed to work. This condition points to ADC module having some kind of errata other than corrected by continuous IRQ patch being applied.

    BTW: Manual search of UVMC-SDK (guide PDF) later to find eSMO stands for "Enhance Sliding Mode Observer" (eSMO) for sensorless-FOC. Also wondering if ePWM multiple SOC ADC triggers via CMPD counts give any better results for 2-12bit ADC's (F2800x25c) than does the F2800x49c with 3-12 bit ADC's? Perhaps some laboratory benchmark testing between each SDK and MCU (x25c versus x49c) would shed more light on the subject. 

  • Yet 20KHz modulation the ADC trigger period is set 5x50µs or 250µs for mainISR() IRQ

    The entering frequency of mainISR() equal to the PWM frequency (USER_M1_PWM_FREQ_kHz=15kHz)  /  (USER_M1_NUM_PWM_TICKS_PER_ISR_TICK=1), so the default frequency is 15kHz.

    The CMPA/B/C/D can be used to generate the event when the time is incrementing or decrementing, and generate the interrupt or trigger the ADC every 1~15 event. And the event can be as ADC SOC trigger to trigger any channels in any ADC module.

    More details about this, you may take a look at the chapter about EPWM and ADC in the F28002x/4x technical manual.

  • The entering frequency of mainISR() equal to the PWM frequency (USER_M1_PWM_FREQ_kHz=15kHz)  /  (USER_M1_NUM_PWM_TICKS_PER_ISR_TICK=1), so the default frequency is 15kHz

    The instaspin runtime decimation is roughly 13KHz with 20KHz modulation via 3 ePWM ticks. Though much faster than slower data throughput such as SCIB peripheral IRQ's. When I try to slow down Instaspin decimation >3 ePWM ticks the (motor.params) fail to load CCS debug java script and LED stays on, never flashes.

    The CMPA/B/C/D can be used to generate the event when the time is incrementing or decrementing, and generate the interrupt or trigger the ADC every 1~15 event.

    Yet configuring multiple ePWM SOCA triggers for ADC-A,B,C fail to load any CMPD values at all. I thought it might be due to ADC SOC's not matching the ePWM triggers. Wrong again, even configured 3 IRQ's vectors for mainISR() from each ADC, still CMPD would not configure or show count value via CCS debug register view. It would seem more robust to let each ePWM SOCA trigger each ADC inputs but it does not work, only 1 SOCA can be configured. 

    EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_A);  

    EPWM_enableADCTrigger(obj->pwmHandle[cnt], EPWM_SOC_A);  

  • The instaspin runtime decimation is roughly 13KHz with 20KHz modulation via 3 ePWM ticks.

    That depends on the settings in user.h, you can sue the every 1~15 PWM ticks in MCSDK, every 1~3 ticks in MotorWare. Recommend the ISR/Controller as fast as possible according to the inverter or motor. Make sure that every IST doesn't occupy too much CPU bandwidth to cause the overflow issue.

    Each PWM supports two SOC hat can be triggered by CMPA/B/C/D. Each SOC can trigger one or multiple ADC.

  • Each PWM supports two SOC hat can be triggered by CMPA/B/C/D. Each SOC can trigger one or multiple ADC.

    As you can see above it does not trigger SOC at all but only from ePWM1. I suspect the R3 silicon ePWM module is damaged, was never reported as R1 errata. Better check it out prior to manufacturing more x49c when MCU production resumes. I personally reported several silicon issues TM4C R1 silicon PWM module failed ADC trigger sources were then fixed in R2 silicon. Things get overlooked or even dust got into the imaging optics, the machines to make silicon die are highly complex cost >500 million USD.

    That depends on the settings in user.h, you can sue the every 1~15 PWM ticks in MCSDK, every 1~3 ticks in MotorWare

    Again any PWM ticks greater than 3 seem to lock up EOC pules fail to trigger ePIE so mainISR() locks up. There is no overrun more like incorrect ISR core priority handling, mainISR is being stomped on by lower priority INT9.4.

    Friday, I reported a file missing C2000ware DSK folder needed for ePIE priority group masking. All x49c examples are missing the file that controls ePIE core priority of peripherals.

  • Please post all of the configuration codes you used that could help us to understand and find the issue you mentioned.

  • The ADC triggers via 3 different SOCA's was later added to give trigger endpoint for the ePWM module in silicon. As I recall not even ePWM1 CMPD has count 5 loaded CCS debug registers. Why did the FE only configure ePWM1 CMPD when it could have 3 ADC trigger sources. My guess is he did at first [cnt] then saw it didn't work so he forced ePWM1 SOC trigger via (obj->pwmHandle[0].

  • You need to put the following codes into the above "for" loop to set the SOC for each PWM module.

    // disable ePWM module interrupts
    EPWM_disableInterrupt(obj->pwmHandle[cnt]);//0
    // set EPWM1 trigger pulse, TBCTR=50µs*5 250µs or 25µs*1 CMPD-D
    EPWM_setADCTriggerSource(obj->pwmHandle[cnt],//0
    EPWM_SOC_A,
    EPWM_SOC_TBCTR_D_CMPD);
    //EPWM_SOC_TBCTR_ZERO, EPWM_SOC_TBCTR_PERIOD, EPWM_SOC_TBCTR_D_CMPD

    // Enable EPWM1 to trigger ADCA,ADCB,ADCC sample event
    EPWM_enableADCTrigger(obj->pwmHandle[cnt], EPWM_SOC_A);//0

    // setup the Event Trigger Prescale Register (ETPS)
    if(numPWMTicksPerISRTick > 15)
    {
    EPWM_setInterruptEventCount(obj->pwmHandle[cnt], 15);//0
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[cnt], EPWM_SOC_A, 15);//0
    }
    else if(numPWMTicksPerISRTick < 1)
    {
    EPWM_setInterruptEventCount(obj->pwmHandle[cnt], 1); //0
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[cnt], EPWM_SOC_A, 1);//0
    }
    else
    {
    EPWM_setInterruptEventCount(obj->pwmHandle[cnt], numPWMTicksPerISRTick);//0,0
    EPWM_setADCTriggerEventPrescale(obj->pwmHandle[cnt],
    EPWM_SOC_A,
    numPWMTicksPerISRTick);
    }

    // setup the Event Trigger Clear Register (ETCLR)
    EPWM_clearEventTriggerInterruptFlag(obj->pwmHandle[cnt]);//0
    EPWM_clearADCTriggerFlag(obj->pwmHandle[cnt], EPWM_SOC_A);//0


    // write value for ADC trigger (20KHz SOC_Int*5TBCTR=250µs, 1period=50µs)
    EPWM_setCounterCompareValue(obj->pwmHandle[cnt],
    EPWM_COUNTER_COMPARE_D,
    5);

  • Yanming,

    Why you just copy my same SOCA trigger code (hal.c) that does not work to configure any ePWM-An CMPD Thinking. Did you check CCS debug that each ePWM generator has CMPD count of 5? This configuration fails to execute when more than one ePWMA CMPD is configured, why?

  • Place the configuration code for SOCA in the "for" loop. If not, you only configure the third EPWM SOCA using CMPD.

    Yes, it works without any issue as you mentioned above.

  • Yes, it works without any issue as you mentioned above.

    Only on 1st CMPD no others will configure in the for loop, how you can't get that from what Is explained above? Please try to configure all 3 ADC triggers together inside the for loop on your x49c launch pad, it don't configure any at all on my launch pad.

    If not, you only configure the third EPWM SOCA using CMPD.

    ePWM_SOCA_Trigger[0] is 1st ePWM SOCA on x49c with DRV8320RS. I try your 3rd ePWM CMPD test, might be the driver lib call has an issue in for loop.

  • I try your 3rd ePWM CMPD test, might be the driver lib call has an issue in for loop.

    It did configure only ePWM4Regs CMPD 5. So, several driver lib calls are not allowing more than 1 ADC SOCA trigger source in for loop by variable (cnt). That makes for longer HAL_SetupPWMs() call, each driverlib function called 3x; SOCATrigger[0], SOCATrigger[1], SOCATrigger[2]. 

  • To simplify this, questions, you may take a look at the following code and test it on your project. Also you can just use the SOCAs by generated from CMPD  for the voltage sampling.

    void HAL_setupPWMs(HAL_Handle handle,
                       const float32_t systemFreq_MHz,
                       const float32_t pwmPeriod_usec,
                       const uint_least16_t numPWMTicksPerISRTick)
    {
        HAL_Obj   *obj = (HAL_Obj *)handle;
        uint16_t  halfPeriod_cycles = (uint16_t)(systemFreq_MHz *
                                      pwmPeriod_usec / (float32_t)2.0);
        uint16_t  cnt, numPWMPerISRTick;
    
        // disable the ePWM module time base clock sync signal
        // to synchronize all of the PWMs
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
        // turns off the outputs of the EPWM peripherals which will put the power
        // switches into a high impedance state.
        EPWM_forceTripZoneEvent(obj->pwmHandle[0], EPWM_TZ_FORCE_EVENT_OST);
        EPWM_forceTripZoneEvent(obj->pwmHandle[1], EPWM_TZ_FORCE_EVENT_OST);
        EPWM_forceTripZoneEvent(obj->pwmHandle[2], EPWM_TZ_FORCE_EVENT_OST);
    
        if(numPWMTicksPerISRTick > 15)
        {
            numPWMPerISRTick = 15;
        }
        else if(numPWMTicksPerISRTick < 1)
        {
            numPWMPerISRTick =1;
        }
        else
        {
            numPWMPerISRTick = numPWMTicksPerISRTick;
        }
    
        for(cnt=0;cnt<3;cnt++)
        {
            // setup the Time-Base Control Register (TBCTL)
            EPWM_setTimeBaseCounterMode(obj->pwmHandle[cnt],
                                        EPWM_COUNTER_MODE_UP_DOWN);
            EPWM_disablePhaseShiftLoad(obj->pwmHandle[cnt]);
            EPWM_setPeriodLoadMode(obj->pwmHandle[cnt], EPWM_PERIOD_DIRECT_LOAD);
            EPWM_setSyncOutPulseMode(obj->pwmHandle[cnt],
                                     EPWM_SYNC_OUT_PULSE_ON_SOFTWARE);
            EPWM_setClockPrescaler(obj->pwmHandle[cnt], EPWM_CLOCK_DIVIDER_1,
                                     EPWM_HSCLOCK_DIVIDER_1);
            EPWM_setCountModeAfterSync(obj->pwmHandle[cnt],
                                       EPWM_COUNT_MODE_UP_AFTER_SYNC);
            EPWM_setEmulationMode(obj->pwmHandle[cnt], EPWM_EMULATION_FREE_RUN);
    
            // setup the Timer-Based Phase Register (TBPHS)
            EPWM_setPhaseShift(obj->pwmHandle[cnt], 0);
    
            // setup the Time-Base Counter Register (TBCTR)
            EPWM_setTimeBaseCounter(obj->pwmHandle[cnt], 0);
    
            // setup the Time-Base Period Register (TBPRD)
            // set to zero initially
            EPWM_setTimeBasePeriod(obj->pwmHandle[cnt], 0);
    
            // setup the Counter-Compare Control Register (CMPCTL)
            EPWM_setCounterCompareShadowLoadMode(obj->pwmHandle[cnt],
                                                 EPWM_COUNTER_COMPARE_A,
                                                 EPWM_COMP_LOAD_ON_CNTR_ZERO);
    
            EPWM_disableCounterCompareShadowLoadMode(obj->pwmHandle[cnt],
                                                 EPWM_COUNTER_COMPARE_B);
    
                                                       //
            EPWM_disableCounterCompareShadowLoadMode(obj->pwmHandle[cnt],
                                                 EPWM_COUNTER_COMPARE_C);
    
            //
            EPWM_disableCounterCompareShadowLoadMode(obj->pwmHandle[cnt],
                                                 EPWM_COUNTER_COMPARE_D);
    
            // setup the Action-Qualifier Output A Register (AQCTLA)
            EPWM_setActionQualifierAction(obj->pwmHandle[cnt],
                                          EPWM_AQ_OUTPUT_A,
                                          EPWM_AQ_OUTPUT_HIGH,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    
            EPWM_setActionQualifierAction(obj->pwmHandle[cnt],
                                          EPWM_AQ_OUTPUT_A,
                                          EPWM_AQ_OUTPUT_LOW,
                                          EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
    
            // setup the Action-qualifier Continuous Software Force Register
            // (AQCSFRC)
            EPWM_setActionQualifierContSWForceAction(obj->pwmHandle[cnt],
                                                     EPWM_AQ_OUTPUT_B,
                                                     EPWM_AQ_SW_OUTPUT_HIGH);
    
            // setup the Dead-Band Generator Control Register (DBCTL)
            EPWM_setDeadBandDelayMode(obj->pwmHandle[cnt], EPWM_DB_RED, true);
            EPWM_setDeadBandDelayMode(obj->pwmHandle[cnt], EPWM_DB_FED, true);
    
            // select EPWMA as the input to the dead band generator
            EPWM_setRisingEdgeDeadBandDelayInput(obj->pwmHandle[cnt],
                                                 EPWM_DB_INPUT_EPWMA);
    
            // configure the right polarity for active high complementary config.
            EPWM_setDeadBandDelayPolarity(obj->pwmHandle[cnt],
                                          EPWM_DB_RED,
                                          EPWM_DB_POLARITY_ACTIVE_HIGH);
            EPWM_setDeadBandDelayPolarity(obj->pwmHandle[cnt],
                                          EPWM_DB_FED,
                                          EPWM_DB_POLARITY_ACTIVE_LOW);
    
            // setup the Dead-Band Rising Edge Delay Register (DBRED)
            EPWM_setRisingEdgeDelayCount(obj->pwmHandle[cnt],HAL_PWM_DBRED_CNT);
    
            // setup the Dead-Band Falling Edge Delay Register (DBFED)
            EPWM_setFallingEdgeDelayCount(obj->pwmHandle[cnt],HAL_PWM_DBFED_CNT);
    
            // setup the PWM-Chopper Control Register (PCCTL)
            EPWM_disableChopper(obj->pwmHandle[cnt]);
    
            // setup the Trip Zone Select Register (TZSEL)
            EPWM_disableTripZoneSignals(obj->pwmHandle[cnt],
                                        EPWM_TZ_SIGNAL_CBC1 |
                                        EPWM_TZ_SIGNAL_CBC2 |
                                        EPWM_TZ_SIGNAL_CBC3 |
                                        EPWM_TZ_SIGNAL_CBC4 |
                                        EPWM_TZ_SIGNAL_CBC5 |
                                        EPWM_TZ_SIGNAL_CBC6 |
                                        EPWM_TZ_SIGNAL_DCAEVT2 |
                                        EPWM_TZ_SIGNAL_DCBEVT2 |
                                        EPWM_TZ_SIGNAL_OSHT1 |
                                        EPWM_TZ_SIGNAL_OSHT2 |
                                        EPWM_TZ_SIGNAL_OSHT3 |
                                        EPWM_TZ_SIGNAL_OSHT4 |
                                        EPWM_TZ_SIGNAL_OSHT5 |
                                        EPWM_TZ_SIGNAL_OSHT6 |
                                        EPWM_TZ_SIGNAL_DCAEVT1 |
                                        EPWM_TZ_SIGNAL_DCBEVT1);
    
            // setup the Event Trigger Selection Register (ETSEL)
            EPWM_setADCTriggerSource(obj->pwmHandle[cnt],
                                     EPWM_SOC_A,
                                     EPWM_SOC_TBCTR_D_CMPD);
    
            EPWM_setADCTriggerSource(obj->pwmHandle[cnt],
                                     EPWM_SOC_B,
                                     EPWM_SOC_TBCTR_U_CMPC);
    
            EPWM_enableADCTrigger(obj->pwmHandle[cnt], EPWM_SOC_A);
            EPWM_enableADCTrigger(obj->pwmHandle[cnt], EPWM_SOC_B);
    
            // setup the interrupt Event Trigger Prescale Register (ETPS)
            EPWM_setADCTriggerEventPrescale(obj->pwmHandle[cnt],
                                            EPWM_SOC_A,
                                            numPWMPerISRTick);
    
            EPWM_setADCTriggerEventPrescale(obj->pwmHandle[cnt],
                                            EPWM_SOC_B,
                                            numPWMPerISRTick);
    
            // setup the Event Trigger Clear Register (ETCLR)
            EPWM_clearADCTriggerFlag(obj->pwmHandle[cnt], EPWM_SOC_A);
            EPWM_clearADCTriggerFlag(obj->pwmHandle[cnt], EPWM_SOC_A);
        }
    
        // setup the Event Trigger Selection Register (ETSEL)
        EPWM_disableInterrupt(obj->pwmHandle[0]);
    
        // setup the interrupt Event Trigger Prescale Register (ETPS)
        EPWM_setInterruptEventCount(obj->pwmHandle[0], numPWMPerISRTick);
    
        // setup the Event Trigger Clear Register (ETCLR)
        EPWM_clearEventTriggerInterruptFlag(obj->pwmHandle[0]);
    
        // since the PWM is configured as an up/down counter, the period register is
        // set to one-half of the desired PWM period
        EPWM_setTimeBasePeriod(obj->pwmHandle[0], halfPeriod_cycles);
        EPWM_setTimeBasePeriod(obj->pwmHandle[1], halfPeriod_cycles);
        EPWM_setTimeBasePeriod(obj->pwmHandle[2], halfPeriod_cycles);
    
          // write the PWM data value  for ADC trigger
        EPWM_setCounterCompareValue(obj->pwmHandle[0],
                                    EPWM_COUNTER_COMPARE_C,
                                    10);
    
        EPWM_setCounterCompareValue(obj->pwmHandle[0],
                                    EPWM_COUNTER_COMPARE_D,
                                    5);
    
        EPWM_setCounterCompareValue(obj->pwmHandle[1],
                                    EPWM_COUNTER_COMPARE_C,
                                    10);
    
        EPWM_setCounterCompareValue(obj->pwmHandle[1],
                                    EPWM_COUNTER_COMPARE_D,
                                    5);
    
    
        EPWM_setCounterCompareValue(obj->pwmHandle[2],
                                    EPWM_COUNTER_COMPARE_C,
                                    10);
    
        EPWM_setCounterCompareValue(obj->pwmHandle[2],
                                    EPWM_COUNTER_COMPARE_D,
                                    5);
    
        // enable the ePWM module time base clock sync signal
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
        return;
    }  // end of HAL_setupPWMs() function

    void HAL_setupADCs(HAL_Handle handle)
    {
        HAL_Obj *obj = (HAL_Obj *)handle;
    
        SysCtl_delay(100U);
        ADC_setVREF(obj->adcHandle[2], ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
        ADC_setVREF(obj->adcHandle[1], ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
        ADC_setVREF(obj->adcHandle[0], ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
        SysCtl_delay(100U);
    
        // Configure internal reference as 1.65V*2 = 3.3V
        ASysCtl_setAnalogReference1P65(ASYSCTL_VREFHIA |
                                       ASYSCTL_VREFHIB |
                                       ASYSCTL_VREFHIC);
    
        // Enable internal voltage reference
        ASysCtl_setAnalogReferenceInternal(ASYSCTL_VREFHIA |
                                           ASYSCTL_VREFHIB |
                                           ASYSCTL_VREFHIC);
    
        // Set main clock scaling factor (50MHz max clock for the ADC module)
        ADC_setPrescaler(obj->adcHandle[0], ADC_CLK_DIV_2_0);
        ADC_setPrescaler(obj->adcHandle[1], ADC_CLK_DIV_2_0);
        ADC_setPrescaler(obj->adcHandle[2], ADC_CLK_DIV_2_0);
    
        // set the ADC interrupt pulse generation to end of conversion
        ADC_setInterruptPulseMode(obj->adcHandle[0], ADC_PULSE_END_OF_CONV);
        ADC_setInterruptPulseMode(obj->adcHandle[1], ADC_PULSE_END_OF_CONV);
        ADC_setInterruptPulseMode(obj->adcHandle[2], ADC_PULSE_END_OF_CONV);
    
        // enable the ADCs
        ADC_enableConverter(obj->adcHandle[0]);
        ADC_enableConverter(obj->adcHandle[1]);
        ADC_enableConverter(obj->adcHandle[2]);
    
        // set priority of SOCs
        ADC_setSOCPriority(obj->adcHandle[0], ADC_PRI_ALL_HIPRI);
        ADC_setSOCPriority(obj->adcHandle[1], ADC_PRI_ALL_HIPRI);
        ADC_setSOCPriority(obj->adcHandle[2], ADC_PRI_ALL_HIPRI);
    
        // delay to allow ADCs to power up
        SysCtl_delay(1000U);
    
    #if (BOOST_to_LPD == BOOSTX_to_J1_J2)
        // configure the interrupt sources
        // configure the ample window to 15 system clock cycle wide by assigning 14
        // to the ACQPS of ADCSOCxCTL Register.
        // RB2/B1
        ADC_setInterruptSource(obj->adcHandle[1], ADC_INT_NUMBER1, ADC_SOC_NUMBER2);
    
        // configure the SOCs for hvkit_rev1p1
        // ISENA - PGA5->A14->RA0
        ADC_setupSOC(obj->adcHandle[0], ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM6_SOCA,
                     ADC_CH_ADCIN14, HAL_ADC_SAMPLE_WINDOW);
    
        // ISENB - PGA3->C7->RC0
        ADC_setupSOC(obj->adcHandle[2], ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM5_SOCA,
                     ADC_CH_ADCIN7, HAL_ADC_SAMPLE_WINDOW);
    
        // ISENC - PGA1->B7->RB0
        ADC_setupSOC(obj->adcHandle[1], ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM3_SOCA,
                     ADC_CH_ADCIN7, HAL_ADC_SAMPLE_WINDOW);
    
        // VSENA - A5->RA1
        ADC_setupSOC(obj->adcHandle[0], ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM6_SOCB,
                     ADC_CH_ADCIN5, HAL_ADC_SAMPLE_WINDOW);
    
        // VSENB - B0->RB1
        ADC_setupSOC(obj->adcHandle[1], ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM5_SOCB,
                     ADC_CH_ADCIN0, HAL_ADC_SAMPLE_WINDOW);
    
        // VSENC - C2->RC1
        ADC_setupSOC(obj->adcHandle[2], ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM3_SOCB,
                     ADC_CH_ADCIN2, HAL_ADC_SAMPLE_WINDOW);
    
        // VSENVM - B1->RB2. hvkit board has capacitor on Vbus feedback, so
        // the sampling doesn't need to be very long to get an accurate value
        ADC_setupSOC(obj->adcHandle[1], ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM6_SOCA,
                     ADC_CH_ADCIN1, HAL_ADC_SAMPLE_WINDOW);
    
        // Vthrottle - B3->RB3. hvkit board has capacitor on Vbus feedback, so
        // the sampling doesn't need to be very long to get an accurate value
        ADC_setupSOC(obj->adcHandle[1], ADC_SOC_NUMBER3, ADC_TRIGGER_EPWM6_SOCB,
                     ADC_CH_ADCIN3, HAL_ADC_SAMPLE_WINDOW);
    #endif
    
    #if (BOOST_to_LPD == BOOSTX_to_J5_J6)
        // configure the interrupt sources
        // configure the ample window to 15 system clock cycle wide by assigning 14
        // to the ACQPS of ADCSOCxCTL Register.
        // RC2/C1
        ADC_setInterruptSource(obj->adcHandle[2], ADC_INT_NUMBER1, ADC_SOC_NUMBER2);
    
        // configure the SOCs for hvkit_rev1p1
        // ISENA - PGA2->B9->RB0
        ADC_setupSOC(obj->adcHandle[1], ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA,
                     ADC_CH_ADCIN9, HAL_ADC_SAMPLE_WINDOW);
    
        // ISENB - PGA4->A15->RA0
        ADC_setupSOC(obj->adcHandle[0], ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA,
                     ADC_CH_ADCIN15, HAL_ADC_SAMPLE_WINDOW);
    
        // ISENC - PGA1->C9->RC0
        ADC_setupSOC(obj->adcHandle[2], ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA,
                     ADC_CH_ADCIN9, HAL_ADC_SAMPLE_WINDOW);
    
        // VSENA - A6->RA1
        ADC_setupSOC(obj->adcHandle[0], ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM1_SOCA,
                     ADC_CH_ADCIN6, HAL_ADC_SAMPLE_WINDOW);
    
        // VSENB - B6/A2->RB1
        ADC_setupSOC(obj->adcHandle[1], ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM1_SOCA,
                     ADC_CH_ADCIN6, HAL_ADC_SAMPLE_WINDOW);
    
        // VSENC - C14->RC1
        ADC_setupSOC(obj->adcHandle[2], ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM1_SOCA,
                     ADC_CH_ADCIN14, HAL_ADC_SAMPLE_WINDOW);
    
        // VSENVM - C1->RC2. hvkit board has capacitor on Vbus feedback, so
        // the sampling doesn't need to be very long to get an accurate value
        ADC_setupSOC(obj->adcHandle[2], ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM1_SOCA,
                     ADC_CH_ADCIN1, HAL_ADC_SAMPLE_WINDOW);
    #endif
    
      return;
    } // end of HAL_setupADCs() function
    

  • Yanming,

    The point of further posting was for you to inform TI programmers there is an issue with the driverlib call to set more than one ePWM trigger source. The CMPx trigger and load calls should be able to input the base address of each register in x49c. Suspect object-> adcHandle[n] may be to blame for not passing the register base address.

    BTW: You used the same ADC_TRIGGER_EWPM1_SOCA source for all ADC channel inputs. That is defeating the purpose to isolate each trigger to specific ADC channel input 1 to 1 sequence into each Clarke function. Purpose was to improve SW throughput for perceived FOC position timing issues being offloaded down to device layer in hardware. 

    Thanks for looking into this issue Grinning

  • BTW: You used the same ADC_TRIGGER_EWPM1_SOCA

    I made each ADC channel group a sperate ePWM trigger source (1,2,4 respectively) and it worked. Still only 1 IRQ for mainISR() though suspect SW could branch into 3 IRQ's, one for each ADC with Group1 shared INT nesting.

    Perhaps an easier less complicated HW distribution could also assign individual SOCn to each ADC channel, still retain 1 IRQ for mainISR().    

  • That's different settings and concept. Why do you need 3 IRQs for motor control ISR, mainISR? That doesn't make sense. Of course, you can enable the IRS for each PWM SOC or ADC EOC if you want, just need to configure the related registers. You may take a look at the technical manual about this. 

  • That's different settings and concept. Why do you need 3 IRQs for motor control ISR, mainISR?

    Seemingly you're missing the bigger point, each ADC trigger starts sampling synchronously with each ePWM generator periods. Direct loading the period is considered to cause electrical glitches and Master Slave sync mode is not a default in C2000 ePWM modules. Seeminly why shadow loading was developed, especially since global updates sync mode does not work at all with the runSVM() call.

    Of course, you can enable the IRS for each PWM SOC or ADC EOC if you want, just need to configure the related registers

    Yet the ISR is not registered but to one vector, so I don't think the SVM code is designed to handle 3x different vector addresses. Perhaps it could be the INT source for each CMPD count and the vector table registered with 3 mainISR() (hal.h) but can the CPU keep up with clear ACK's of 3 ADC interrupts the bigger question.

    Below is how it works now but it might give better samples for position and current control with individual SOCn 0,1,2 for each Clarke ADC channel input. That was why I mentioned some time ago to use PPB as x69m was configured in motorware control suite.

    #ifdef INA240A1
    // ISENB - PGA4_OF ADCC8->RC0 INA240(J5-46)/RC-filter
    ADC_setupSOC(obj->adcHandle[2], ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM4_SOCA,
    ADC_CH_ADCIN8, HAL_ADC_PGAxABC_SAMPLE_WINDOW);//140ns window

    // ISENC - PGA6_OF ADCA8->RA0 J3-24(B0)INA240(J5-45)/RC-filter
    ADC_setupSOC(obj->adcHandle[0], ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA,
    ADC_CH_ADCIN8, HAL_ADC_PGAxABC_SAMPLE_WINDOW);//140ns

    // ISENA - PGA2_OF ADCB8->RB0 INA240(J5-48)/RC-filter
    ADC_setupSOC(obj->adcHandle[1], ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM2_SOCA,
    ADC_CH_ADCIN8, HAL_ADC_PGAxABC_SAMPLE_WINDOW);//140ns
    #endif

    // VSENA - A6->RA1 J7-63
    ADC_setupSOC(obj->adcHandle[0], ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM1_SOCA,
    ADC_CH_ADCIN6, HAL_ADC_SAMPLE_WINDOW);

    // VSENC - B6/A2->RB1 J7-64
    ADC_setupSOC(obj->adcHandle[1], ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM2_SOCA,
    ADC_CH_ADCIN6, HAL_ADC_SAMPLE_WINDOW);

    // VSENB - C14->RC1 J7-65
    ADC_setupSOC(obj->adcHandle[2], ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM4_SOCA,
    ADC_CH_ADCIN14, HAL_ADC_SAMPLE_WINDOW)

  • You can configure the ADC trigger time point as you want by setting the eWPM, CPU timer or other events. The examples are just an reference, not limit you must use it on all of the case. The user can change it according to the system and ADC modules.

    Thanks for your suggestion. Seems like you can get  it done as you want.

  • Thanks for your suggestion. Seems like you can get  it done as you want.

    I was mostly thinking more about all the forum complaints of high speed instability might be ADC time related issue.

  • Thanks, we'll check and have a try. Let's you know if have any updates.