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/TMS320F28375D: QEP QPOSCNT accumulation issue

Part Number: TMS320F28375D

Tool/software: Code Composer Studio

Hi, I have an application where I have a quadrature encoder mounted to a motor and I need to very accurately represent position in single turn and multi turn.  Ideally it would be best if I could configure the EQEP module to represent position in both ways.  In single turn the QPOSCNT would be reset either by the index event or when QPOSCNT reaches the max ticks of the encoder.  In multi turn the QPOSCNT would continue to accumulate position throughout multiple encoder rotations.

I'm not seeing a way to support this functionality in hardware.  So my options seem to be either 1) connect the quadrature signals to two different EQEP modules and have one handle the single turn case and the other handle the multiple turn case.  This doesn't work for my current application since the hardware was not designed to accomodate this.

The second option the the approach I'm currently using is to look for overflow or underflow events in software and manually keep track of adding or subtracting MAX_ENCODER_TICKS when this occurs.  This works ok, but sometimes the PCU/PCO (under/overflow) flags are not synchronized with the QPOSCNT register.  What I mean by this is that I'll detect an overflow or underflow event in the foreground but don't see the corresponding jump in QPOSCNT, or vice versa.  While i'm checking the over/underflow flags in the foreground, i've tried disabling the PCO/PCU interrupts in the QEINT register during the critical section where I read the flag values and the QPOSCNT value, but this didnt appear to help.

Is there some way to guarantee that PCU/PCO flags are synchronized with the QPOSCNT register so that its not possible to read one before the other updates? 

  • Hi,

    The second approach to handle the single and multi-turn position sensing looks good to me. Although the synchronization issue that you have indicated regarding the position counter underflow/overflow events is not very clear. Once the underflow/overflow occurs, an interrupt event is generated and the position counter would get reset and starts counting again. So how exactly does this affects your calculations ? Also I think it would be helpful if you can share the code snippet for foreground ISR.

    If my reply answers your question please click on "This resolved my issue" button located at the bottom of my post.

    Regards

    Himanshu

  • Hi Himanshu, I've been able to write some code for my "foreground ISR" that seems to work so far (discovered this after my original post) although it hasnt been thoroughly tested.  This code runs at a frequency of 20khz and so only small (<10) changes in QPOSCNT typically occur between this code's execution. 

    This code is more complicated than it would need to be if the PTO/PTU events occurred at the same time as the QPOSCNT wrapping occurs.  But, as you can see by the checks I'm doing here, there are some cases where PTO/PTU is triggered but QPOSCNT hasn't wrapped yet, or QPOSCNT wraps before PTO/PTU is triggered.

    Here it is:

        //attempt to keep overflow/underflow flags from changing during this section, not sure if this works or not
        fclVars[0].ptrQEP->QEINT.bit.PCO = 0;
        fclVars[0].ptrQEP->QEINT.bit.PCU = 0;
    
        //save previous state
        numwraps_prev = fclVars[0].qep.numWraps;
        poscnt_prev = poscnt;
        fclVars[0].qep.cnts_unwrapped_prev = fclVars[0].qep.cnts_unwrapped;
    
        //update poscnt
        poscnt = fclVars[0].ptrQEP->QPOSCNT;
    
        if(poscnt - poscnt_prev < -100 && fclVars[0].ptrQEP->QFLG.bit.PCO) { //detected overflow event, 100 is a "large" number less than encoder ticks (4000)
          fclVars[0].ptrQEP->QCLR.bit.PCO = 1; //clear PCO flag
          fclVars[0].qep.numWraps++;
          fclVars[0].qep.cnts_unwrapped = fclVars[0].qep.numWraps * 4000 + poscnt;
          waitingForPCO = 0;
        }
        else if(poscnt - poscnt_prev > 100 && fclVars[0].ptrQEP->QFLG.bit.PCU ) { //detected underflow event
          fclVars[0].ptrQEP->QCLR.bit.PCU = 1;//clear PCU flag
          fclVars[0].qep.numWraps--;
          fclVars[0].qep.cnts_unwrapped = fclVars[0].qep.numWraps * 4000 + poscnt;
          waitingForPCU = 0;
        }
        else if((poscnt - poscnt_prev > 100 && !fclVars[0].ptrQEP->QFLG.bit.PCU) || waitingForPCU) { //qposcnt underflowed but no pcu event
          fclVars[0].qep.cnts_unwrapped = fclVars[0].qep.numWraps * 4000 + poscnt - 4000;
          waitingForPCU++; //poscnt has wrapped but PCU doesnt reflect this
        }
        else if((poscnt - poscnt_prev < -100 && !fclVars[0].ptrQEP->QFLG.bit.PCO) || waitingForPCO) { //qposcnt overflowed but no pco event
          fclVars[0].qep.cnts_unwrapped = fclVars[0].qep.numWraps * 4000 + poscnt + 4000;
          waitingForPCO++; //poscnt has wrapped but PCO doesnt reflect this
        } 
        else if(abs(poscnt - poscnt_prev) > 100) {
          unk_err++; //unknown error, this has not occurred so far 
        }
        else { 
          fclVars[0].qep.cnts_unwrapped = fclVars[0].qep.numWraps * 4000 + poscnt;
        } 
     
        //re-enable over/under flow flags 
        fclVars[0].ptrQEP->QEINT.bit.PCO = 1; 
        fclVars[0].ptrQEP->QEINT.bit.PCU = 1;

  • Hi,

    I looked at the above code snippet and has following questions :

    • If the expected change in counter value is already known as ~ 10 then for the test cases to compare the current and previous counter values >/< 100/-100, why is there a need to check for PCO/PCU at all ?  if(poscnt - poscnt_prev < -100) -> definitely overflow or if(poscnt - poscnt_prev > 100) -> definitely underflow.

    • Even if we decide to use the PCO/PCU flags, why they are disabled before reading the position counter value? What if the overflow/underflow was about to set exact the time reading so isn't it better to disable it after reading the value?

    • Is index signal also used in the above use-case? if yes then please note that there is an errata item related to eQEP: Position Counter Incorrectly Reset on Direction Change During Index so make sure this is proporly account in your use-case. More information on this and the workaround is documented as part of F2837x Errata document available on TI Product page.

    Finally, behavior of overflow/underflow is very clearly illustrated in the below diagram available as part of section "Position Counter Reset on Maximum Position" in TRM which should help you to analyze and debug your issue.

    If my reply answers your question please click on "This resolved my issue" button located at the bottom of my post.

    Regards

    Himanshu

  • Himanshu Chaudhary60 said:

    If the expected change in counter value is already known as ~ 10 then for the test cases to compare the current and previous counter values >/< 100/-100, why is there a need to check for PCO/PCU at all ?  if(poscnt - poscnt_prev < -100) -> definitely overflow or if(poscnt - poscnt_prev > 100) -> definitely underflow.

    Yes, I expect this would work too, but I don't like that this approach depends on a "magic number" and isn't guaranteed to work in all situations.

    Himanshu Chaudhary60 said:

    Even if we decide to use the PCO/PCU flags, why they are disabled before reading the position counter value? What if the overflow/underflow was about to set exact the time reading so isn't it better to disable it after reading the value?

    My thinking here was that a bug could be introduced if PCO/PCU or QPOSCNT changed after one of those values is read, but not the other.  But I suppose you're right in that PCO/PCU may not change but QPOSCNT could still change.  One thing I've also noticed is that the problem I'm seeing gets much worse if I use QPOSLAT, which is latched at a 10khz frequency.

    Himanshu Chaudhary60 said:

    Is index signal also used in the above use-case? if yes then please note that there is an errata item related to eQEP: Position Counter Incorrectly Reset on Direction Change During Index so make sure this is proporly account in your use-case. More information on this and the workaround is documented as part of F2837x Errata document available on TI Product page.

    The index is used to set QPOSCNT to QPOSINIT.  The errors I'm seeing are when the motor is spinning at high speed in one direction.  I suppose if there's any noise on the encoder signal that a falsely detected direction change could occur though. I'll look into this errata.

    Himanshu Chaudhary60 said:

    Finally, behavior of overflow/underflow is very clearly illustrated in the below diagram available as part of section "Position Counter Reset on Maximum Position" in TRM which should help you to analyze and debug your issue.

    Yes, I've looked at this diagram quite a bit and understand how it works.  It is the fact that I'm trying to "unwrap" the QPOSCNT value in software though that is the challenge, where timing and synchronization are harder to guarantee than in hardware.

  • Okay sure, please keep us posted if you are able to debug and resolve the issue based on the above discussed information and resources.

    If my reply answers your question please click on "This resolved my issue" button located at the bottom of my post.

    Regards

    Himanshu