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/TMS320F28379D: F28379 EQEP Pos-Speed example not registering index

Part Number: TMS320F28379D
Other Parts Discussed in Thread: C2000WARE

Tool/software: Code Composer Studio

Hi,

I'm having a problem with the software example:

eqep_pos_speed_cpu1 (v210, but tried with different versions)

 

I'm trying to use the example to use the encoder of the TI 2-MTR-Dyno package. The eQEP1A and eQEP1B are registered correctly, however, QEP1I is not registered under any circumstance. I tried:

- Connecting GPIO pin 4 to EQEP1I pin to simulate an index pulse

- Connecting the encoder to the pin header directly

- Directly connecting 3.3V to the EQEP1I pin to force an index detection

None of these seem to work, so once theta_raw overflows, it creates an erroneous generation of theta_mech rendering the encoder useless.

Information on my setup:

- Code Composer 10.0

- Compiler TI v20.2.1.LTS

Thanks for your help in advance!

  • Hi Rick,

    Are you using GPIO4 as EQEP1I? If you go through the data sheet, GPIO4 does not have connection to EQEP Index pin.

    You can use GPIO13 with mux option 5.

    Regards,

    Nirav

  • Hi Nirav,

    I'm not using GPIO4 as EqepI, I'm externally connecting it to the eqep1I pin of the eqep1 pin header. (This is also suggested by the example) As I've tried different methods to create an index pulse (and measuring with an oscilloscope to verify if de pulse is generated), I assume the pulse is nog registered by de controller, however I have no idea what is causing this.

    If I single out the code which is responsible for the processing of the interrupt:

    // Check an index occurrence
    //
    if(EQep1Regs.QFLG.bit.IEL == 1)
    {
      p->index_sync_flag = 0x00F0;
      EQep1Regs.QCLR.bit.IEL = 1;    // Clear __interrupt flag
    }

    When I place a breakpoint inside this code it is not reached, even with an external index pulse applied to GPIO23. (As also discussed in https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/634607?CCS-TMS320F28379D-Example-eqep-pos-speed-cpu01-index-signal-not-resetting-theta-raw)

    Update:

    Setup:


    I've tried the same thing with the example from C2000Ware, it still does not detect the index pulse. I've checked with an oscilloscope, the EQEPI pin does receive an index pulse. Is there anything else I can check?

    Regards,

    Rick

  • Hi,

    The current workarround I implemented is setting QPOSMAX to 4000, the same as the resolution of the encoder, however, this is not a proper solution as it does not use the index signal to mittigate any counting errors. I'm still trying to solve the problem where my index pulse is not registered. Some extra info on the settings of the GPIOs and EqepRegs: (the same as the example with changed max QPOSCNT)

    FILE: F2837xD_Eqep.c (system file)
    void InitEQep1Gpio(void)
    {
        EALLOW;
    
        //
        // Disable internal pull-up for the selected output pins
        // for reduced power consumption
        // Pull-ups can be enabled or disabled by the user.
        // Comment out other unwanted lines.
    
        GpioCtrlRegs.GPAPUD.bit.GPIO20 = 1;    // Disable pull-up on GPIO20 (EQEP1A)
        GpioCtrlRegs.GPAPUD.bit.GPIO21 = 1;    // Disable pull-up on GPIO21 (EQEP1B)
        GpioCtrlRegs.GPAPUD.bit.GPIO22 = 1;    // Disable pull-up on GPIO22 (EQEP1S)
        GpioCtrlRegs.GPAPUD.bit.GPIO23 = 1;    // Disable pull-up on GPIO23 (EQEP1I)
    
        //
        // Synchronize inputs to SYSCLK
        // Synchronization can be enabled or disabled by the user.
        // Comment out other unwanted lines.
        //
    
        GpioCtrlRegs.GPAQSEL2.bit.GPIO20 = 0;   // Sync GPIO20 to SYSCLK  (EQEP1A)
        GpioCtrlRegs.GPAQSEL2.bit.GPIO21 = 0;   // Sync GPIO21 to SYSCLK  (EQEP1B)
        GpioCtrlRegs.GPAQSEL2.bit.GPIO22 = 0;   // Sync GPIO22 to SYSCLK  (EQEP1S)
        GpioCtrlRegs.GPAQSEL2.bit.GPIO23 = 0;   // Sync GPIO23 to SYSCLK  (EQEP1I)
    
        //
        // Configure EQEP-1 pins using GPIO regs
        // This specifies which of the possible GPIO pins will be EQEP1 functional
        // pins.
        // Comment out other unwanted lines.
        //
    
        GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 1;    // Configure GPIO20 as EQEP1A
        GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 1;    // Configure GPIO21 as EQEP1B
        GpioCtrlRegs.GPAMUX2.bit.GPIO22 = 1;    // Configure GPIO22 as EQEP1S
        GpioCtrlRegs.GPAMUX2.bit.GPIO23 = 1;    // Configure GPIO23 as EQEP1I
    
        EDIS;
    }
    
    FILE: posspeed_example (example c2000Ware)
    //
    // POSSPEED_Init - Initialize EQEP1 configuration
    //
    void  Encoder_Init(void)
    {
        EQep1Regs.QUPRD = 2000000;            // Unit Timer for 100Hz at 200 MHz
                                              // SYSCLKOUT
        EQep1Regs.QDECCTL.bit.QSRC = 00;      // QEP quadrature count mode
        EQep1Regs.QEPCTL.bit.FREE_SOFT = 2;
        EQep1Regs.QEPCTL.bit.PCRM = 00;       // PCRM=00 mode - QPOSCNT reset on
                                              // index event
        EQep1Regs.QEPCTL.bit.UTE = 1;         // Unit Timeout Enable
        EQep1Regs.QEPCTL.bit.QCLM = 1;        // Latch on unit time out
        EQep1Regs.QPOSMAX = 0xFA0;
        EQep1Regs.QEPCTL.bit.QPEN = 1;        // QEP enable
        EQep1Regs.QCAPCTL.bit.UPPS = 5;       // 1/32 for unit position
        EQep1Regs.QCAPCTL.bit.CCPS = 6;       // 1/64 for CAP clock
        EQep1Regs.QCAPCTL.bit.CEN = 1;        // QEP Capture Enable
    }
    
    //
    // POSSPEED_Calc - Perform the position calculations
    //
    void Encoder_Update(EncoderState *p)
    {
        long tmp;
        unsigned int pos16bval,temp1;
        _iq Tmp1,newp,oldp;
    
        //
        // Position calculation - mechanical and electrical motor angle
        //
        p->DirectionQep = EQep1Regs.QEPSTS.bit.QDF;  // Motor direction:
                                                     // 0=CCW/reverse, 1=CW/forward
    
        pos16bval = (unsigned int)EQep1Regs.QPOSCNT; // capture position once
                                                     // per QA/QB period
        p->theta_raw = pos16bval+ p->cal_angle;      // raw theta = current pos. +
                                                     // ang. offset from QA
    
        if(p->theta_raw > 4000){
            p->theta_raw=p->theta_raw-4000;
        } else if(p->theta_raw < -4000){
            p->theta_raw=p->theta_raw+4000;
        }
    
        //
        // The following lines calculate
        // p->theta_mech ~= QPOSCNT/mech_scaler [current cnt/(total cnt in 1 rev.)]
        // where mech_scaler = 4000 cnts/revolution
        //
        tmp = (long)((long)p->theta_raw*(long)p->mech_scaler);   // Q0*Q26 = Q26
        tmp &= 0x03FFF000;
        p->theta_mech = (int)(tmp>>11);                          // Q26 -> Q15
        p->theta_mech &= 0x7FFF;
    
        p->th_rad = 2*M_PI-((double)p->theta_mech/32765)*2*M_PI;
        p->th_deg = 360-((double)p->theta_mech/32765)*360;
    
        if (p->th_deg<0){
            p->th_deg=p->th_deg;
        }
    
        //
        // The following lines calculate p->elec_mech
        //
        p->theta_elec = p->pole_pairs*p->theta_mech;             // Q0*Q15 = Q15
        p->theta_elec &= 0x7FFF;
    
        //
        // Check an index occurrence
        //
        if(EQep1Regs.QFLG.bit.IEL == 1)
        {
           p->index_sync_flag = 0x00F0;
           EQep1Regs.QCLR.bit.IEL = 1;    // Clear __interrupt flag
        }
    
        //
        // High Speed Calculation using QEP Position counter
        //
        // Check unit Time out-event for speed calculation:
        // Unit Timer is configured for 100Hz in INIT function
        //
        if(EQep1Regs.QFLG.bit.UTO == 1)    // If unit timeout (one 100Hz period)
        {
            //
            // Differentiator
            //
            // The following lines calculate
            // position = (x2-x1)/4000 (position in 1 revolution)
            //
            pos16bval = (unsigned int)EQep1Regs.QPOSLAT;   // Latched POSCNT value
            tmp = (long)((long)pos16bval*(long)p->mech_scaler); // Q0*Q26 = Q26
            tmp &= 0x03FFF000;
            tmp = (int)(tmp>>11);                               // Q26 -> Q15
            tmp &= 0x7FFF;
            newp = _IQ15toIQ(tmp);
            oldp = p->oldpos;
    
            if(p->DirectionQep==0)                     // POSCNT is counting down
            {
                if(newp>oldp)
                {
                    Tmp1 = - (_IQ(1) - newp + oldp);    // x2-x1 should be negative
                }
                else
                {
                    Tmp1 = newp -oldp;
                }
            }
            else if(p->DirectionQep == 1)              // POSCNT is counting up
            {
                if(newp<oldp)
                {
                    Tmp1 = _IQ(1) + newp - oldp;
                }
                else
                {
                    Tmp1 = newp - oldp;                 // x2-x1 should be positive
                }
            }
    
            if(Tmp1>_IQ(1))
            {
                p->Speed_fr = _IQ(1);
            }
            else if(Tmp1<_IQ(-1))
            {
                p->Speed_fr = _IQ(-1);
            }
            else
            {
                p->Speed_fr = Tmp1;
            }
    
            //
            // Update the electrical angle
            //
            p->oldpos = newp;
    
            //
            // Change motor speed from pu value to rpm value (Q15 -> Q0)
            // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
            //
            p->SpeedRpm_fr = _IQmpy(p->BaseRpm,p->Speed_fr);
    
            EQep1Regs.QCLR.bit.UTO=1;                   // Clear __interrupt flag
        }
    
        //
        // Low-speed computation using QEP capture counter
        //
        if(EQep1Regs.QEPSTS.bit.UPEVNT == 1)               // Unit position event
        {
            if(EQep1Regs.QEPSTS.bit.COEF == 0)             // No Capture overflow
            {
                temp1 = (unsigned long)EQep1Regs.QCPRDLAT; // temp1 = t2-t1
            }
            else   // Capture overflow, saturate the result
            {
                temp1 = 0xFFFF;
            }
    
            //
            // p->Speed_pr = p->SpeedScaler/temp1
            //
            p->Speed_pr = _IQdiv(p->SpeedScaler,temp1);
            Tmp1 = p->Speed_pr;
    
            if (Tmp1>_IQ(1))
            {
                p->Speed_pr = _IQ(1);
            }
            else
            {
                p->Speed_pr = Tmp1;
            }
    
            //
            // Convert p->Speed_pr to RPM
            //
            if(p->DirectionQep == 0)  // Reverse direction = negative
            {
                //
                // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
                //
                p->SpeedRpm_pr = -_IQmpy(p->BaseRpm,p->Speed_pr);
            }
            else                     // Forward direction = positive
            {
                //
                // Q0 = Q0*GLOBAL_Q => _IQXmpy(), X = GLOBAL_Q
                //
                p->SpeedRpm_pr = _IQmpy(p->BaseRpm,p->Speed_pr);
            }
    
            EQep1Regs.QEPSTS.all = 0x88; // Clear Unit position event flag
                                         // Clear overflow error flag
        }
    }

    Regards,

    Rick

  • Hi Rick,

    Apologies for delayed response. All your configuration looks fine, so I was trying to figure out why you are not able to see index pulse. Finally I think I may have found the problem. 

    Since you are using Launchpad, you must be connecting QEP signals to header J14 (eQEP1A, eQEP1B & eQEP1I). If you go through the schematic of Launchpad, you will find that eQEP1A and eQEP1B goes to GPIO20 and GPIO21 respectively, but eQEP1I goes to GPIO99 (not GPIO23). So, in you code you need to set GPIO99 with mux option 5.

    Please try that and let me know if you are still seeing any problems.

     Regards,

    Nirav

  • Hi Nirav,

    That indeed fixed the problem! Thank you! I'll be sure to double check the schematics of the Launchpad next time!

    Regards,

    Rick