Shop OBEX P1 Docs P2 Docs Learn Events
Reading Encoder strip values in P2 — Parallax Forums

Reading Encoder strip values in P2

chintan_joshichintan_joshi Posts: 135
edited 2022-09-06 10:31 in C/C++

Hello,

I am creating sample code in c++ to read encoder strip values.

This is used for calculate motor steps for DC motor.

previously i was using QEI library for Nucleo 144(https://os.mbed.com/teams/IoTKitV3/code/QEI/docs/tip/QEI_8cpp_source.html).

And using QEI lib with X2_ENCODING macro i am getting proper values in Nucleo144 board.

So i am creating similar support for P2. In QEI lib there is ISR which is continuously checking pulses for Forward and reverse directions.

So for P2 i have created this function to run on another cog to monitor pins.

But i am not getting proper values in P2. for forward direction its taking both forward and reverse pulses and same for backward direction also.

And i am sure that its not about calculation(ISR in QEI lib code) because same calculation works in Nucleo 144 board. So not sure whats wrong here. attaching my sample code for P2.

Comments

  • Not needed...all P2 pins are capable of QEI with zero processor overhead. Search the forum for quadrature encoder.

    Craig

  • evanhevanh Posts: 15,126
    edited 2022-09-06 15:27

    Try this:

    #include <stdio.h>
    #include <stdint.h>
    
    void  main( void )
    {
        _waitms( 200 );
        printf( "\n   clkfreq = %d   clkmode = 0x%x\n", _clockfreq(), _clockmode() );
    
        //_pinstart(int pin, uint32_t mode, uint32_t xval, uint32_t yval);
        _pinstart( 25, P_QUADRATURE | 1<<24, 0, 0);  // SmartB input is P26 (base+1 as per encoded mode)
    
        while(true)
        {
            //uint32_t _rdpin(int pin);
            printf("pulses = %d  \r",_rdpin(25));
            //_waitms(10);
        }
    }
    
  • JonnyMacJonnyMac Posts: 8,912
    edited 2022-09-06 16:20

    As others have indicated, you can use P2 smart pins to handle encoder input without using a spare cog. Note, though, that you cannot preset the S/P encoder value to anything but zero, and there are no built-in end limits. In my Spin object I have user variables for a preset value (which becomes an offset from the physical encoder read) and low and high limit values.

    Ideas (translated from my Spin code):

    int setEncoder(preset)
    {
        if (preset < encLo) preset = encLo;                         // force preset into range
        if (preset > encHi) preset = encHi;
    
        encOffset = preset;                                         // save as offset
    
        _pinf(encA);                                                // reset S/P encoder
        _pinl(encA);
    
        return preset; 
    }
    
    int readEncoder()
    {
        int result = _rdpin(encA) + encOffset;
    
        if (result < encLo) return setEncoder(encLo);
        if (result > encHi) return setEncoder(encHi);
    
        return result;
    }
    

    One of my clients makes camera control platforms so we get a lot of use out of encoders.

  • Sample Quadrature code using smart pin to count the pulses:

    /**
     * @brief Test Quadrature decode
     * @date December 26, 2020
     * @version 1.0
     * 
    */
    
    #include <stdio.h>
    #include <propeller.h>
    #include <smartpins.h>
    
    
    #define QUADA 21
    #define QUADB 22
    
    
    int main()
    {
        int i, j;
    
        _pinstart(QUADA, P_PLUS1_B | P_QUADRATURE, 0, 0);
    //  _dirl(QUADA);
    //  _wrpin(QUADA, 0x01000016); //Quadrature input
    //  _wxpin(QUADA, 0);
    //  _dirh(QUADA);
    
        while (1)
        {
            i = _rdpin(QUADA) >> 2;
            printf("i: %d\n", i);
            _waitms(1000);
        }
    }
    

    The code requires that you use two pins next to each other and greater. In this case pin 21 and plus 1 is 22.

    The commented code is what the "_pinstart" does for you.

    Mike

  • chintan_joshichintan_joshi Posts: 135
    edited 2022-09-07 08:58

    @JonnyMac said:
    As others have indicated, you can use P2 smart pins to handle encoder input without using a spare cog. Note, though, that you cannot preset the S/P encoder value to anything but zero, and there are no built-in end limits. In my Spin object I have user variables for a preset value (which becomes an offset from the physical encoder read) and low and high limit values.

    Ideas (translated from my Spin code):

    int setEncoder(preset)
    {
        if (preset < encLo) preset = encLo;                         // force preset into range
        if (preset > encHi) preset = encHi;
    
        encOffset = preset;                                         // save as offset
    
        _pinf(encA);                                                // reset S/P encoder
        _pinl(encA);
    
        return preset; 
    }
    
        
    
    int readEncoder()
    {
        int result = _rdpin(encA) + encOffset;
    
        if (result < encLo) return setEncoder(encLo);
        if (result > encHi) return setEncoder(encHi);
    
        return result;
    }
    
        
    

    One of my clients makes camera control platforms so we get a lot of use out of encoders.

    Hello @JonnyMac what is encLo and encHi variables? and what will be their default values?
    i am taking encA as pin 25. and have created volatile int encOffset = 0,

    also can i take preset variable as volatile int?

    Right now i have created this variables

    volatile int encOffset = 0;
    int encLo = 0;
    int encHi = 1500;
    int preset = 0;

    encHi as maximum 1500 encoder steps.

    Is this correct as per your description?

  • @evanh said:
    Try this:

    #include <stdio.h>
    #include <stdint.h>
    
    void  main( void )
    {
      _waitms( 200 );
      printf( "\n   clkfreq = %d   clkmode = 0x%x\n", _clockfreq(), _clockmode() );
    
      //_pinstart(int pin, uint32_t mode, uint32_t xval, uint32_t yval);
      _pinstart( 25, P_QUADRATURE | 1<<24, 0, 0);  // SmartB input is P26 (base+1 as per encoded mode)
    
      while(true)
      {
          //uint32_t _rdpin(int pin);
          printf("pulses = %d  \r",_rdpin(25));
          //_waitms(10);
      }
    }
    

    Thank you very much @evanh , this is really great.

    But where can i find smart pin configuration details? any link or manual?

  • chintan_joshichintan_joshi Posts: 135
    edited 2022-09-07 09:02

    @iseries said:
    Sample Quadrature code using smart pin to count the pulses:

    /**
     * @brief Test Quadrature decode
     * @date December 26, 2020
     * @version 1.0
     * 
    */
    
    #include <stdio.h>
    #include <propeller.h>
    #include <smartpins.h>
    
    
    #define QUADA 21
    #define QUADB 22
    
    
    int main()
    {
        int i, j;
        
        _pinstart(QUADA, P_PLUS1_B | P_QUADRATURE, 0, 0);
    //    _dirl(QUADA);
    //    _wrpin(QUADA, 0x01000016); //Quadrature input
    //    _wxpin(QUADA, 0);
    //    _dirh(QUADA);
        
        while (1)
        {
            i = _rdpin(QUADA) >> 2;
            printf("i: %d\n", i);
            _waitms(1000);
      }
    }
    

    The code requires that you use two pins next to each other and greater. In this case pin 21 and plus 1 is 22.

    The commented code is what the "_pinstart" does for you.

    Mike

    @iseries , really appreciate your help. I have used your code on pin 25 26 and its counting pulses. but when i read pulses from QEI lib in Nucleo 144 i was getting around 1500 count, and with this smart pin code i am getting 930 steps. So is there possibility we can increase count resolution? seems like pulses are missing?

    Also where you have find smart pin configuration details for P2 in c++? any link or manual available for it?

  • @chintan_joshi

    It simply decodes the quadrature. How are you physically generating the pulses....rotary/linear encoder? Presumably a 5v device. How are you interfacing to the P2?.

    Craig

  • chintan_joshichintan_joshi Posts: 135
    edited 2022-09-07 09:28

    @Mickster said:
    @chintan_joshi

    It simply decodes the quadrature. How are you physically generating the pulses....rotary/linear encoder? Presumably a 5v device. How are you interfacing to the P2?.

    Craig

    I am using linear optical encoder which used by printers.

    this is standard circuit which nedds to be placed in between encoder pins and controller pins.


  • evanhevanh Posts: 15,126

    @chintan_joshi said:

    @iseries said:
    Sample Quadrature code using smart pin to count the pulses:

    @iseries , really appreciate your help. I have used your code on pin 25 26 and its counting pulses. but when i read pulses from QEI lib in Nucleo 144 i was getting around 1500 count, and with this smart pin code i am getting 930 steps. So is there possibility we can increase count resolution? seems like pulses are missing?

    Mike's code does a divide by 4 (right-shift 2). You're one did a divide by 2. And mine didn't do any dividing.

  • evanhevanh Posts: 15,126
    edited 2022-09-07 09:58

    Hardware details are all in the Silicon Document - https://www.parallax.com/propeller-2/documentation/
    It's a very terse document but the details are all there.

  • @evanh said:

    @chintan_joshi said:

    @iseries said:
    Sample Quadrature code using smart pin to count the pulses:

    @iseries , really appreciate your help. I have used your code on pin 25 26 and its counting pulses. but when i read pulses from QEI lib in Nucleo 144 i was getting around 1500 count, and with this smart pin code i am getting 930 steps. So is there possibility we can increase count resolution? seems like pulses are missing?

    Mike's code does a divide by 4 (right-shift 2). You're one did a divide by 2. And mine didn't do any dividing.

    Oh yes, understood. to make it divide by two i have to make >>1.
    Now getting double pulses around 1800.

    Thank you.

  • @evanh said:
    Hardware details are all in the Silicon Document - https://www.parallax.com/propeller-2/documentation/
    It's a very terse document but the details are all there.

    Yes after looking smart pin sample code for Quadrature read, i think its worth to explore other capability of P2 smart pins. :)

  • evanhevanh Posts: 15,126
    edited 2022-09-07 12:06

    You'll like them. :)

    On that note, the low level pin drive config is capable of performing pull-up function for inputs where you've got PNP or NPN (like above) sensors.

    The 100 kR resistors I wouldn't bother with. The 3k3 pull-ups can be replaced by driving output high with, say, 1.0 mA setting.

        _pinstart( 25, P_QUADRATURE | P_PLUS1_B | P_OE | P_HIGH_1MA | P_LOW_FLOAT | P_INVERT_OUTPUT, 0, 0) ;  // Start smartpin and config pin mode to suit NPN sensor
        _wrpin( 26, P_HIGH_1MA | P_LOW_FLOAT );   // Config pin mode to suit NPN sensor
        _drvh( 26 );  // Set pin high to drive the pull-up
    

    PS: I guess the 100 kR resistors were there to prevent saturation spikes from bouncing off the input protection diodes. I don't know for sure but I'd guess the 1 mA drive circuit will peter out a little below VIO supply volts and thereby perform the same job of preventing saturation spikes also.

    PPS: On the other hand, the capacitors should prevent any bouncing in the first place. The 100 kR resistors just seem overkill.

  • Hello @JonnyMac what is encLo and encHi variables? and what will be their default values?
    i am taking encA as pin 25. and have created volatile int encOffset = 0,

    also can i take preset variable as volatile int?

    Right now i have created this variables

    volatile int encOffset = 0;
    int encLo = 0;
    int encHi = 1500;
    int preset = 0;

    encHi as maximum 1500 encoder steps.

    Is this correct as per your description?

    In my Spin code, the values of encLo and encHi are passed via the start method (along with the encoder a and b pins and other configuration values). The variables encLo, encHi, and encOffset are global to the module; preset is a local parameter and does not have to be declared in the variable space.

    In other threads you seemed disinterested in looking as Spin, but I'm attaching my encoder object for your reference -- it will help you make sense of the scope of variables.

  • Hi Jon,

    I didn't want to muddy the water and so waited for you to reply but I interpret encLo/encHi to be "soft limit switches" (I do similar) :smile:

    Craig

  • @evanh said:
    Mike's code does a divide by 4 (right-shift 2). You're one did a divide by 2. And mine didn't do any dividing.

    So, IOW, we have the equivalent of X1, X2, X4 line-count multiply, like a dedicated quad-counter device?..... :sunglasses::+1:

    Craig

  • JonnyMacJonnyMac Posts: 8,912
    edited 2022-09-07 15:19

    @Mickster said:
    Hi Jon,

    I didn't want to muddy the water and so waited for you to reply but I interpret encLo/encHi to be "soft limit switches" (I do similar) :smile:

    Craig

    Yes, sort of. Think of the volume control on your car radio. You can spin the knob clockwise forever, but the max volume is 100; anti-clockwise will stop changing at 0. This is how those low and high limit values work with the encoder object. In an application that requires actual limits, those should be handled by the application (I did this with a moving target on a rope project for JonyJib).

  • @JonnyMac said:

    Hello @JonnyMac what is encLo and encHi variables? and what will be their default values?
    i am taking encA as pin 25. and have created volatile int encOffset = 0,

    also can i take preset variable as volatile int?

    Right now i have created this variables

    volatile int encOffset = 0;
    int encLo = 0;
    int encHi = 1500;
    int preset = 0;

    encHi as maximum 1500 encoder steps.

    Is this correct as per your description?

    In my Spin code, the values of encLo and encHi are passed via the start method (along with the encoder a and b pins and other configuration values). The variables encLo, encHi, and encOffset are global to the module; preset is a local parameter and does not have to be declared in the variable space.

    In other threads you seemed disinterested in looking as Spin, but I'm attaching my encoder object for your reference -- it will help you make sense of the scope of variables.

    Thank you for spin2 file.

Sign In or Register to comment.