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/TM4C1294NCPDT: How to obtain QEI velocity

Part Number: TM4C1294NCPDT

Tool/software: Code Composer Studio

Hi

Hoping to get some help on how to correctly configure the QEI module in TM4C to obtain the speed reading in meters/min .

I have the below initialzation and run-time function which will periodically refresh the variable for the RPM.

The correct RPM measured using a Tachometer is 668rpm but my computed result is 120rpm .

Seems the correct result is 5.6x higher than the computation.

void RunTime(){

volatile uint32_t qeiVelocity,rpm;

uint16_t cyclePerRevolution = 1024;

uint32_t numerator,denominator,loadValue,systemClk,capMode,edges;

qeiVelocity=QEIVelocityGet(QEI0_BASE);

loadValue=(HWREG(QEI0_BASE + QEI_O_LOAD))+1;

capMode=(HWREG(QEI0_BASE + QEI_O_CTL) & QEI_CTL_CAPMODE);
edges = (capMode == 0x00000000) ? 2 : 4 ;
systemClk = MAP_SysCtlClockGet();
systemClk = systemClk/100; //scale down to prevent 32bit overflow
loadValue = loadValue/100; //scale down to prevent 32bit overflow

numerator=(systemClk*qeiVelocity*60);

denominator=(loadValue*cyclePerRevolution*edges);

        rpm = numerator/denominator;

}

static void ConveyorInverterCtrl_initQEI(void)
{

// Enable QEI Peripherals

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);

SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI0);

//Unlock GPIOD7 - Like PF0 its used for NMI - Without this step it doesn't work
HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; 
HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |= 0x80;
HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = 0;

//Set Pins to be PHA0 and PHB0
GPIOPinConfigure(GPIO_PL1_PHA0);
GPIOPinConfigure(GPIO_PL2_PHB0);

//Set GPIO pins for QEI. PhA0 -> PD6, PhB0 ->PD7. I believe this sets the pull up and makes them inputs
GPIOPinTypeQEI(GPIO_PORTL_BASE, GPIO_PIN_1 | GPIO_PIN_2);

//DISable peripheral and int before configuration
QEIDisable(QEI0_BASE);
QEIIntDisable(QEI0_BASE,QEI_INTERROR | QEI_INTDIR | QEI_INTTIMER | QEI_INTINDEX);

// Configure quadrature encoder, use an arbitrary top limit of 1000
QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_NO_RESET | QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), 1000);

QEIVelocityConfigure(QEI0_BASE, QEI_VELDIV_1, 200e3);
QEIVelocityEnable(QEI0_BASE);

// Enable the quadrature encoder.
QEIEnable(QEI0_BASE);

//Set position to a middle value so we can see if things are working
QEIPositionSet(QEI0_BASE, 500);
}

  • Greetings,

    Had you noted that your MCU (part of the TM4C129 family) has a much more sophisticated (& complex) 'Clock domain' than the (older) & slower TM4C123 MCU family?     It is suspected that the code you (may) have referenced was written prior to the TM4C129's release.

    In particular - this assignment, "systemClk = MAP_SysCtlClockGet();" employs the function "SysCtlClockGet()" which is not 'legal' for your '129 family device!    (From the '123 MCU Manual, "This function  'SysCtlClockGet()'  can only be called on TM4C123 devices.    For TM4C129 devices, the return value from SysCtlClockFreqSet() indicates the system clock frequency.)

    In addition - your configuration of the MCU's System Clock may also (improperly) model that of the '123 family MCU - which is (also) improper for the '129.     The correct call for your '129 is: "SysCtlClockFreqSet()"

    You should be able to locate 'code examples' dedicated to the '129 family' - and those should enable you to configure the MCU's system clock properly.   That's believed to be the, 'Clear first step' - other actions may be required as well...    (KISS demands that the 'obvious' receive first attention - then you, 'Proceed by Refinement.')

  • Hi cb1_mobile

    Thanks for highlighting this deprecated function for TM4C129 series.

    I had modified my systemClk variable to obtain 120,000,000 hz.

    The function as follows :

    systemClk = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);

    After this modification, I now obtain 421rpm. Its now nearer to the measurement but is still off by about 240 rpm. 

    I am guessing it has something to do with this line :   QEIVelocityConfigure(QEI0_BASE, QEI_VELDIV_1, 200e3);   ?

  • Hello again,

    Firm & I are 'BIG Believers' in 'KISS' - we've broken down your postings to illustrate the (many) advantages afforded by 'KISS.'

    Kindly take, 'None of this personally' - this serves as a (proven) Diagnostic Method/Teaching Moment - which 'unmasks the (span of insights) required' - to 'Diagnose above & beyond the 'MCU Only!'     Most always VITAL in the Real World!

    Follows our key breakdown (which best enables high/selective focus - especially by a division of staff - each attacking one area)

    • poster history   We know 'nothing' of your background - this complicates (& extends) our (and other's) response
    • the 'critical value' returned by QEIVelocityGet() has not been presented  (or is very well camouflaged)
    • we are in disagreement w/ the formulas you presented for (both) numerator & denominator.   In addition - no 'units' have been specified.
    • the active 'Time Period of the QEI Operational Window' was set to: (0.2/120 = 1/600 Second!)    Unexplained - and so (very) short!
    • Tach employed - yet (unknown):  Accuracy, time of last calibration etc.
    • multiple comments unmatched to updated functions - several (exacting) 'Pin Releases from 'NMI' - yet (apparently) unused by your code.

    QEIVelocityGet() of course - proves of great interest & value - yet was not provided.   KISS directs that, 'Single Steps - most always - prove most instructive, accurate & SAFE!'

    The formulas you presented 'Num & Denom' are, 'outside our understanding' and apparently differ from those present w/in the MCU Manual.   Follows a direct quote: "QEIVelocityGet() can be multiplied by the number of time periods per second and divided by the number of pulses per revolution to obtain the number of revolutions per second.   We note that 'neither' of your formulas match that guidance AND in addition -  no 'Units' were presented!

    numerator=(systemClk*qeiVelocity*60);
    denominator=(loadValue*cyclePerRevolution*edges);

    Active 'Time Period of the QEI Operational Window' - you 'feared' overflowing a 'uint32_t' - yet that extends to, "4.294B" - does it not?   1/600 of a Second is 'almost surely' too short a duration to enable a proper QEI processed measurement...   We suggest - instead - the hard-coding of 30 million (1/4 Sec at 120MHz SysClk) to (better) serve as, ' QEIVelocityConfigure()'s final parameter.'    (the clock in question here is listed as, 'System Clock.')

    Tach employed: Neither we (nor Sergeant Schultz) 'No Nothing' of this Tach.   As it serves as your 'standard' - should not (some) background be supplied?   Further - (some) such Tachs provide, 'Clock & Direction Bits' - which demands a 'different parameter' w/in the QEI Configuration.    And thus - may lead to flawed QEI operation.    All solved via a direct link to the Tach...

    Unmatched and/or 'never utilized' functions' (causing code bloat/diverting attention) should be removed!   (prior to 'exercising helpers!')

    //Set GPIO pins for QEI. PhA0 -> PD6, PhB0 ->PD7. I believe this sets the pull up and makes them inputs
    GPIOPinTypeQEI(GPIO_PORTL_BASE, GPIO_PIN_1 | GPIO_PIN_2);

    Conclusions:

    • Even though - especially though - the MCU is often, 'Judged as Guilty' - such finding is 'too often' premature and/or incorrect.    All relevant 'outside influences' must be considered - and analyzed individually.
    • Large complex tasks should be reduced to their most  elemental/basic  parts.   Always strive for the identification of a 'meaningful result' - which can then be tested/measured.   W/out such 'measurement' - the reliability of such 'findings' - is always suspect.
    • Multiple functions should be 'First - individually probed & test/verified' - well before they are 'Used in Combination.'   Once so combined - it proves likely that a 'new test' must be devised.
    • When & wherever possible - employ the API - it has, 'Stood the test of time' - your (and our group's) unique 'enhancements/modifications' enjoy, 'No such assurance' - and must remain suspect - till (really & conclusively Proven!)    (i.e. in some 'future life!)
    • Provide 'Safety Factors' - avoid testing at the 'ragged edges' - and insure that ALL external equipment - attaching to the MCU - has been 'well tested/measured' in advance - and (ALWAYS) remains w/in the MCU's specifications.    (Hate it when the alleged, 'Test' (instead) "Murders the MCU!")

    If you'd 'Be so good' as to supply the result returned by: "QEIVelocityGet()" when employing the (suggested) parameter (30 million) - hard coded (i.e. 30000000) to avoid (potential) compiler miscues -  we can (then) best & further proceed...   

    This writing is the combined work of both (primarily young staff & myself) and was intended as, 'Constructive' - applicable both to you - yet also 'many others.'

  • Hi cb1_mobile

    To appease the dislike for the numerator and denominator thingy, I am willing to convert to the following :

    rpm = (systemClk*qeiVelocity*60)/(loadValue*cyclePerRevolution*edges);

    So now it appears quite similar to the formula in Page 1752 of TM4C2194NCPDT datasheet.

    rpm = (clock * (2 ^ VELDIV) * SPEED * 60) ÷ (LOAD * ppr * edges)

    Sorry if I have renamed some beyond recognition but there aren't anything which is a unique enhancement/modifications.

    At period set to 30 million (1/4 Sec at 120MHz SysClk), QEIVelocityGet() output is 7190. 

    Where is mentioned to meet 30 million (1/4 Sec at 120MHz SysClk)  ?

  • ronnie said:
    Where is mentioned to meet 30 million (1/4 Sec at 120MHz SysClk)  ?

    That number was chosen as, 'vastly superior' to the (overly brief) 200K.   It proves 'beyond unusual' to perform such a demanding QEI operation in 1/600th of a Second!   We chose (30 million) as the 250mS period (resulting for the QEI) - has worked (very) well for us - in multiple QEI Applications...

    ronnie said:
    At period set to 30 million (1/4 Sec at 120MHz SysClk), QEIVelocityGet() output is 7190

    That '7190' appears, 'FAR Too High' - thus unexpected!      I must plead, "Temporary Insanity" - as (much) younger staff (delights) in noting - my 'multi-tasking - while in transit - often proves (highly) suspect!

    Instead - would you believe:

    • by multiplying that '7190' (the result of 'VelocityGet()' by the number of 'time periods' w/in 1 Second (that's 4)  28,760 results
    • then by dividing by the number of 'pulses per motor's revolution' (believed to be 1024 * 4 = 4096)
    • 7.02148 results  (that's the number of QEI 'events/Sec. detected)
    • multiplying that by '60' yields  421.289

    And that is EXACTLY the 'RPM' you earlier reported!     (thus - do not (near) 'great minds' think alike?)     Do note - our systematic formula is, 'FAR MORE DIRECT & SIMPLER'  (i.e. KISS blessed) than the (Ugh! pardon)  'Num/Denom monstrosity' (multiply by SysClk - good grief!) - past presented!  

    These duplicate (QEI '421 RPM' readings) suggest - if we can 'believe' your (still undescribed) Tach:  (one or more of the below)

    • an improper configuration of the  MCU's QEI module
    • an MCU System Clock set to 'other than' 120MHz
    • lost pulse edges emitted by your 'QEI based' encoder (still unknown)  and/or an 'ineffectual common Gnd.'

    Also - your motor's speed should have been noted - which gave rise to such measurement.   (it 'appears' that you (properly) matched it to the original speed - 668 RPM, iirc)

    As a 'sanity check' might you:

    • first double your motor's speed - reporting results  (those achieved via 'VelocityGet()' please)
    • then half your motor's speed - again reporting   (in each case - perform the operation based upon the ~668 RPM earlier listed)

    We seek to determine if the QEI's measure maintains the expected 'linearity' - based upon motor speed.

    It is important to note that you must, 'Command such Measure' ... ONLY when the motor has reached (and maintains) a steady speed.   (i.e. no Accel nor Decel)

    Now - (both) your earlier & my current '421 RPM' results are 63% of that rendered by your Tach.    That (should) prove a 'strong clue' -  what variable is (then) 'most likely' to enable such 37% ERROR?    (that's first-cabin Problem Analysis/Solving - is it not?)     You, my group, (less than responsive 'others') should direct their focus there - is that not true?

    There's no mention (ID) of your 'Tach' - its Accuracy - & Date of last calibration.

    As earlier requested - your linking to the Spec for your Encoder would (also) prove highly useful.   

    Traveling today - may not be until way late - and after you've answered (list above) - that I can respond further.

  • The Tach is indeed the source of the error due to it dependent on a dimension which was provided with incorrect information.

  • Thank you for your confirmation of my young team's 'skilled analysis' - such is always appreciated.

    And you are the 2nd this (early) day - to properly award the (actual) Resolving Post - rather than, 'succumb to the horrid 'Verify' - which sets new records for 'Vagueness!'     (too many posters 'Self-Award' (their own 'Confirming post) rather than that post(s) which actually identified & resolved, poster's issue.

    Staff suggests that you acquire 'several Tachs' (ideally of different technology) - confirmation via 'several sources' ALWAYS trumps that obtained from 'just one!'    

    Brushed Motors most always 'demand' use of an Encoder or Tach to confirm their Speed.     As (likely when) you migrate to Brushless (BLDC) your measure of the hall sensor frequency and/or the 'pulses sent to one or all motor phase(s)' - (almost) eliminates the requirement for a robust & accurate Tach.   (still they provide value - although (often) as only a, 'Sanity Check.')