Official eQEP driver Support

2,656 views
Skip to first unread message

Strawson

unread,
Apr 17, 2014, 1:30:03 PM4/17/14
to beagl...@googlegroups.com
Hello all,

In an effort to make use of the eQEP modules on the beaglebone black we stumbled across the following encoder patch and were able to compile a loadable kernel module with the help of TI. Hopefully this will make its way to the "thirdparty" script in the debian build farm so the community can use this without recompiling



I would like to make known a bug we ran into with reading the eQEP module that resulted in position values not updating after exactly 1020 reads without closing the file pointer. If the file pointer is closed and re-opened for every read, the behavior is normal, but opening/closing the file is painfully slow. I unfortunately don't really know where to begin with finding and fixing this problem, but any insight would be appreciated.

Best,
J Strawson, C Briggs

Robert Nelson

unread,
Apr 17, 2014, 2:09:34 PM4/17/14
to Beagle Board
On Thu, Apr 17, 2014 at 12:30 PM, Strawson <jstr...@gmail.com> wrote:
> Hello all,
>
> In an effort to make use of the eQEP modules on the beaglebone black we
> stumbled across the following encoder patch and were able to compile a
> loadable kernel module with the help of TI. Hopefully this will make its way
> to the "thirdparty" script in the debian build farm so the community can use
> this without recompiling
>
> https://github.com/Teknoman117/beaglebot/tree/master/encoders

It looks pretty self-contained, i have no problem adding to the
current kernel patches..

> I would like to make known a bug we ran into with reading the eQEP module
> that resulted in position values not updating after exactly 1020 reads
> without closing the file pointer. If the file pointer is closed and
> re-opened for every read, the behavior is normal, but opening/closing the
> file is painfully slow. I unfortunately don't really know where to begin
> with finding and fixing this problem, but any insight would be appreciated.


yikes, it still needs a little work then..

Regards,

--
Robert Nelson
http://www.rcn-ee.com/

William Hermans

unread,
Apr 17, 2014, 2:46:32 PM4/17/14
to beagl...@googlegroups.com
Strawson, best thing I personally can think of, would be to use two or more pointers to the same file, and rotate between them. Closing one down while the other continues operating.



--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Giuseppe Iellamo

unread,
Apr 18, 2014, 2:51:42 AM4/18/14
to beagl...@googlegroups.com
I'm using it but in order to be fast ( I know it's not very linux style ... but )

Set up

#ifdef __arm__

#define MAP_SIZE 4096UL //< Constant used for the memory mapping of the eqep
#define MAP_MASK (MAP_SIZE - 1)

    // mmaping device register in order to speed up things
    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
    {
        LOG(logFATAL) << " Unable to open /dev/mem";
        exit(-1);
    }

    map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
                    (eqepMap.at(channel).phAddress) & ~MAP_MASK );
    if(map_base == (void *) -1) {
        LOG(logFATAL) << " Unable to mmap eqep";
        exit(-1);
    }

    virt_addr = map_base + ((eqepMap.at(channel).phAddress) & MAP_MASK);
#endif

Read Position

inline int32_t get_position_fast() { return *((int32_t *) virt_addr); } ///< not really clean but performing


Strawson

unread,
Apr 26, 2014, 4:46:50 AM4/26/14
to beagl...@googlegroups.com
Thank you Guiseppe. I had tried an failed in the past to use mmap, but I see your solution to the error I had before is to mmap starting at the base address of the PWM peripheral instead of just at eQEP with (target&~MAP_MASK). Since ~MAP_MASK is 0xFFFFFFFFF000, the mmap starts at address 0x48300000 instead of 0x48300180 (for eqep0). Then you seem to be getting back to the base eQEP position register by adding target&MAP_MASK (0x180)  back onto the virt_addr. Why the mmap function call fails without using the MAP_MASK is not entirely clear to me, but I won't worry about it.

While my mmap errors are gone, I'm still only ever reading 0x83 when accessing the position value pointed to by virt-addr. If I try to access other parts of the eqep module I only get 0. For example the eqep hardware revision code which is at offset 0x5C according to the AM335xx reference manual returns 0 but should contain a value.

My test code is below. Any thoughts?

Thank you all,
Strawson

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
#define EQEP0_BASE 0x48300180
#define EQEP1_BASE 0x48302180
#define EQEP2_BASE 0x48304180


int main(){
int fd;
volatile unsigned long *virt_addr;
volatile unsigned long *map_base;
unsigned long read_result;
int i;
for(i=0;i<10000;i++){
unsigned long target=EQEP2_BASE;
//O_SYNC makes the memory uncacheable
if ((fd = open("/dev/mem", O_RDWR | O_SYNC))==-1) {
 printf("Could not open memory\n");
 return 0;
}
//printf("opened /dev/mem \n");
//EQEP0_BASE&~MAP_MASK truncates the last 12 bits of the target address
map_base=(ulong*)mmap(0, 4096, PROT_READ|PROT_WRITE,MAP_SHARED,fd, target&~MAP_MASK);
if(map_base == (void *) -1) {
printf("Unable to mmap eqep\n");
exit(-1);
}
//add the last 12 bits (0x180 for eqep) back onto to the address
//also add 0x5C to offset to hardware revision code
virt_addr = map_base + (target & MAP_MASK)+0x5C;
read_result = *((unsigned long *) virt_addr);
   printf("\rValue at addr: 0x%lX (%p): 0x%lX  ", map_base, virt_addr, read_result); 
close(fd);
usleep(10000);
}
close(fd);
return 0;
}

 

John Syn

unread,
Apr 26, 2014, 1:55:40 PM4/26/14
to beagl...@googlegroups.com

From: Strawson <jstr...@gmail.com>
Reply-To: <beagl...@googlegroups.com>
Date: Saturday, April 26, 2014 at 1:46 AM
To: <beagl...@googlegroups.com>
Subject: Re: [beagleboard] Official eQEP driver Support

Thank you Guiseppe. I had tried an failed in the past to use mmap, but I see your solution to the error I had before is to mmap starting at the base address of the PWM peripheral instead of just at eQEP with (target&~MAP_MASK). Since ~MAP_MASK is 0xFFFFFFFFF000, the mmap starts at address 0x48300000 instead of 0x48300180 (for eqep0). Then you seem to be getting back to the base eQEP position register by adding target&MAP_MASK (0x180)  back onto the virt_addr. Why the mmap function call fails without using the MAP_MASK is not entirely clear to me, but I won't worry about it.

While my mmap errors are gone, I'm still only ever reading 0x83 when accessing the position value pointed to by virt-addr. If I try to access other parts of the eqep module I only get 0. For example the eqep hardware revision code which is at offset 0x5C according to the AM335xx reference manual returns 0 but should contain a value.
Take a look at this E2E posting:


I think the address you need is 0xFA300180

I have attached a printout of the MMU translations. Hopefully this helps. 

Regards,
John
--
MMU Translation.txt

Strawson

unread,
Apr 27, 2014, 11:46:46 PM4/27/14
to beagl...@googlegroups.com
Cheers, John! Your suggestion of 0xFA300180 matches the MMU translations and places it in the linux-arm map range: vmalloc : 0xf0000000 - 0xff000000. This address does return values at both the base and the hardware revision offset, but not correct ones :-/

A little more stumbling on the internet turned up the below example of mmapping the GPIO peripheral at GPIO1_START_ADDR 0x4804C000 which matches exactly to the address in page 159 of the AM335x Technical Reference Manual.


I'm not sure why this would work for GPIO but not the eQEP module. Guiseppe, do you mind sharing the output of your physical address function call?  eqepMap.at(channel).phAddress 

Just to confirm, I have the PWM and eQEP modules enabled, pinmux set correctly, and correct encoder readings being displayed with the eqep driver in the original post.

Thanks for any further input,
Strawson

James Zapico

unread,
Apr 28, 2014, 12:43:16 AM4/28/14
to beagl...@googlegroups.com
mmapping must be aligned with memory pages. It just so happens that the GPIO module is already aligned, but since the eQEP is a subset of the PWM module, the eQEP base address is not page aligned.

I chose to page align mmap in a more dynamic way to try to avoid some of that confusion later. getpagesize() is included with the unistd.h header. eQEP_address_ is one of the eQEP addresses you expect ending in 180:

  int masked_address = eQEP_address_ & ~(getpagesize()-1);
  pwm_addr = (void *) mmap(NULL, PWM_BLOCK_LENGTH,
    PROT_READ | PROT_WRITE, MAP_SHARED, eQEPFd, masked_address);

  int offset = eQEP_address_ & (getpagesize()-1);
  position_p = (uint32_t *) ((uint8_t *)pwm_addr + QPOSCNT  + offset);
  pos_init_p = (uint32_t *) ((uint8_t *)pwm_addr + QPOSINIT + offset);
  max_pos_p  = (uint32_t *) ((uint8_t *)pwm_addr + QPOSMAX  + offset);

-
James

John Syn

unread,
Apr 28, 2014, 1:03:43 AM4/28/14
to beagl...@googlegroups.com
From: Strawson <jstr...@gmail.com>
Reply-To: <beagl...@googlegroups.com>
Date: Sunday, April 27, 2014 at 8:46 PM

To: <beagl...@googlegroups.com>
Subject: Re: [beagleboard] Official eQEP driver Support

Cheers, John! Your suggestion of 0xFA300180 matches the MMU translations and places it in the linux-arm map range: vmalloc : 0xf0000000 - 0xff000000. This address does return values at both the base and the hardware revision offset, but not correct ones :-/

A little more stumbling on the internet turned up the below example of mmapping the GPIO peripheral at GPIO1_START_ADDR 0x4804C000 which matches exactly to the address in page 159 of the AM335x Technical Reference Manual.

This example is using mmap() which is adding the translation between virtual and physical address. If you do not use mmap(), you must use the virtual address based on the MMU translations. Are you sure the PWM subsystem is enabled? Check that the PWM is not in IDLE or Standby mode and the clock is enabled. 

Regards,
John 

Strawson

unread,
Apr 28, 2014, 5:49:16 AM4/28/14
to beagl...@googlegroups.com
Thank you James, it works now! getpagesize() returns 4096, this matches the previous map_size which is a nice sanity check. I like that this would dynamically change with different modules as some are 1 or 2k. 

The difference that made this work is casting the virtual address (pwm_addr in your code) as a uint8_t*. I do not understand why the pointer should change based on the type it is pointing to. To demonstrate this, the below code prints both addresses to the console to show the same result.

Also of note is that reading in this manner seems to take ~.36 us. Not PRU fast, but I presume this is as fast as we can get it in userspace land.

I apologize for the long code snipped but I wanted to post a complete solution here for anyone curious.

#include <stdio.h>
#include <stdio.h>
#include <stdint.h>

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#define QPOSCNT    0x0000
#define EQEP0_BASE   0x48300180
#define QREVID       0x005C

int main(){
 
int fd;
 
volatile unsigned long *map_base;
 
unsigned long target=EQEP0_BASE;
 
long eqep0_pos, revid;
 
struct timeval tv1, tv2;
 
unsigned long map_size = getpagesize();
 
unsigned long map_mask = map_size-1;


 
//O_SYNC makes the memory uncacheable
 
if ((fd = open("/dev/mem", O_RDWR | O_SYNC))==-1) {

   printf
("Could not open /dev/mem\n");
   
return 0;
 
}
 printf
("opened /dev/mem\n");
 
 
//&~map_mask truncates the address to the base of the 4K Page
 map_base
=(uint8_t*)mmap(0, map_size, PROT_READ|PROT_WRITE,MAP_SHARED,fd, target&~map_mask);

 
if(map_base == (void *) -1) {
 printf
("Unable to mmap eqep\n");
 
exit(-1);
 
}

 
//&map_mask adds the position within the page to the address, this is 0x180 for eEQP0
 
unsigned long* eqep0_addr = (uint8_t *)map_base + (target&map_mask);
 
 
//time a read-loop to assess speed
 
int num_reads = 1000000;
 
int i;
 gettimeofday
(&tv1,NULL);
 
for(i=0;i<num_reads;i++){
  eqep0_pos
= *((uint8_t *)eqep0_addr + QPOSCNT);
 
}
 gettimeofday
(&tv2,NULL);
 revid
= *(uint32_t *)((uint8_t *)eqep0_addr+QREVID);
 
 
 
//find difference between start and end time
 
unsigned long dt_micros = (1000000 * tv2.tv_sec + tv2.tv_usec)-(1000000 * tv1.tv_sec + tv1.tv_usec);
 
float time_per_read = (float)dt_micros/num_reads;
 
 printf
("last position %ld\n", eqep0_pos);
 printf
("micros per read %f\n", time_per_read);
 printf
("pagesize %d\n", getpagesize());
 printf
("map_base 0x%lX\n",map_base);
 printf
("(uint8_t *)map_base 0x%lX\n", (uint8_t *)map_base);
 printf
("target&map_mask 0x%lX\n",target&map_mask);
 printf
("revid 0x%lX (should read 44D31103)\n",revid);
 close
(fd);
 
return 0;
}

output:

opened /dev/mem
last position 71
micros per read
0.389692
pagesize
4096
map_base
0xB6FF1000
(uint8_t *)map_base 0xB6FF1000
target
&map_mask 0x180
revid
0x44D31103 (should read 44D31103)

Strawson

unread,
May 9, 2014, 10:25:33 PM5/9/14
to beagl...@googlegroups.com
it seems my excitement was short-lived. While reading the position with the previous (and attached) code does work, it only does so when Teknoman's eqep driver is loaded. I've added writes to set up the PWMSS and eQEP configuration registers and have confirmed by reading them back that they are set up the same as the driver does. Any ideas on what I'm missing?

// Write the decoder control settings
*(unsigned short*)(pwm_map_base[0]+EQEP_OFFSET+QDECCTL) = 0;
// set maximum position to two's compliment of -1, aka UINT_MAX
*(unsigned long*)(pwm_map_base[0]+EQEP_OFFSET+QPOSMAX)=-1;
// Enable interrupt
*(uint16_t*)(pwm_map_base[0]+EQEP_OFFSET+QEINT) = UTOF;
// set unit period register
*(unsigned long*)(pwm_map_base[0]+EQEP_OFFSET+QUPRD)=0x5F5E100;
// enable counter in control register
*(unsigned short*)(pwm_map_base[0]+EQEP_OFFSET+QEPCTL) = PHEN|IEL0|SWI|UTE|QCLM;

SYSCONFIG 0xC
CLKCONFIG
0x111
QEPCTL0  
0x9E
QDECCTL0  
0x0
QEINT0    
0x800
QUPRD0    
0x5F5E100
QPOSMAX0  
0xFFFFFFFF
QEPSTS0  
0xA0
eqep0
: -174 eqep1: 544 e^Cp2: 0


mmap_pwm.rar

James Zapico

unread,
May 10, 2014, 2:33:23 AM5/10/14
to beagl...@googlegroups.com
Strawson,

It looks like you're not turning the PWM EQEP clock on. There should be something to accomplish what this line from the kernel driver does:

  // Enable the clock to the eQEP unit
  status
= pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EQEPCLK_EN);

I haven't tried this out, but it should be something like
 *(unsigned long*)(pwm_map_base[0]+PWMSS_CLKCONFIG) = PWMSS_EQEPCLK_EN;

-
James

Strawson

unread,
May 10, 2014, 3:25:14 AM5/10/14
to beagl...@googlegroups.com
I believe it is enabled. From my last post:  the PWMSS clock config returns
CLKCONFIG 0x111 = 000100010001

According to pg 1492 of the reference manual, PWMSS_EQEP_EN is bit 4 in this register which appears to be true. Furthermore the interrupt timer register QUTMR 
is incrementing away just fine. Good idea, but no dice.

For good measure I will write this bit anyway, but with |= instead of = since some bits are not writable and I wouldn't want to erase the enable bits for pwm and ecap.

Teknoman117

unread,
May 13, 2014, 2:41:14 AM5/13/14
to beagl...@googlegroups.com
I'll certainly take a look at this next week.  Currently in the middle of finals and Maker Faire is this weekend.  And in all honesty, once i figure out whats going on with the driver, its still a good idea to use the kernel based implementation, mainly because you can take advantage of hardware interrupts and not have to busy wait.  I know there are sleep methods, but unless something like Xenomai is being used, you're at the mercy of the scheduler...  

Although, just to rule it out - are you still applying a device tree overlay?  The supplied DTS files do more than just initialize the driver, they setup the IO configuration, as the default board config doesn't bring out the eQEP lines. 

- Nathaniel Lewis

Strawson

unread,
May 13, 2014, 2:53:08 AM5/13/14
to beagl...@googlegroups.com
Hi Nathaniel. The correct device tree fragments are loaded, pins are multiplexed correctly, and all 3 eqep channels work perfectly with your driver. The supplied mmap code from my last post also works perfectly, but only if I insmod the compiled .ko kernel module first. Strange, I know.

Strawson

unread,
May 13, 2014, 4:55:00 AM5/13/14
to beagl...@googlegroups.com
Actually, let me be more specific. I use the pinmux lines and enable the PWM Subsystem as follows

fragment@0 {
       target = <&am33xx_pinmux>;
       __overlay__ {
            pinctrl_eqep0: pinctrl_eqep0_pins {
                    pinctrl-single,pins = <
                       0x1A8 0x21  /* P9_41 = GPIO3_20 = EQEP0_index, MODE1 */        
                       0x1AC 0x21  /* P9_25 = GPIO3_21 = EQEP0_strobe, MODE1 */  
                        0x1A0 0x31  /* P9_42 = GPIO3_18 = EQEP0A_in, MODE1 */      
                        0x1A4 0x31  /* P9_27 = GPIO3_19 = EQEP0B_in, MODE1 */      
                       >;
             };
       };
   };
   
   fragment@1 {
         target = <&epwmss0>;
           __overlay__ {
                  status = "okay";
       };
   };

I am not using the following fragment passing parameters to the kernel driver
fragment@2 {
           target = <&eqep0>;
     __overlay__ {
           pinctrl-names = "default";
           pinctrl-0 = <&pinctrl_eqep0>;
           
           count_mode = <0>;  /* 0 - Quadrature mode, normal 90 phase offset cha & chb.  1 - Direction mode.  cha input = clock, chb input = direction */
           swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
           invert_qa = <1>;   /* Should we invert the channel A input?  */
           invert_qb = <1>;   /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
           invert_qi = <0>;   /* Should we invert the index input? */
           invert_qs = <0>;   /* Should we invert the strobe input? */
           
        status = "okay";
       };
   };

This is for two reasons. Firstly, I don't see how this would change the behavior of the hardware if I'm setting the registers anyway. Secondly, it fails to load because eqep is not a part of the default am335x-boneblack.dtb located in /boot/uboot/dtbo in debian

When trying to load this, dmesg returns

[  523.086537] bone-capemgr bone_capemgr.9: slot #10: dtbo 'bone_eqep0-00A0.dtbo' loaded; converting to live tree
[  523.090030] of_resolve: Could not find symbol 'eqep0'
[  523.095581] bone-capemgr bone_capemgr.9: slot #10: Failed to resolve tree



In Angstrom, this file was located in /boot/am335x-boneblack.dtb. Attached is a modified version of this that was provided by TI and results in the eqep dts loading correctly in angstrom. This file has since changed in the Debian release and the fix no longer works. As stated in the first post in this thread, it would be nice if the correct eqep entries and your driver were included in the public image so that this functionality can be used out of the box like pwm.

am335x-boneblack.dtb

Robert Nelson

unread,
May 13, 2014, 8:07:23 AM5/13/14
to Beagle Board
> In Angstrom, this file was located in /boot/am335x-boneblack.dtb. Attached
> is a modified version of this that was provided by TI and results in the
> eqep dts loading correctly in angstrom. This file has since changed in the
> Debian release and the fix no longer works. As stated in the first post in
> this thread, it would be nice if the correct eqep entries and your driver
> were included in the public image so that this functionality can be used out
> of the box like pwm.

<cough>

Well it didn't make the time deadline for "2014-04-23"..

</cough>

But if you do:

cd /opt/scripts/tools
git pull
sudo ./update_kernel.sh

It'll pull something newer, as the (TIEQEP) was added in 3.8.13-bone48 release.

https://github.com/RobertCNelson/linux-dev/commit/b7bc988c048b69f03b71c72f7c544f2348f378d0

Although if you find a bug, i expect a patch. ;)

Teknoman117

unread,
May 14, 2014, 4:59:42 AM5/14/14
to beagl...@googlegroups.com
I don't believe that actually will change the I/O configuration.  For the pin ctrl entry to be adopted, it needs to be used by some driver.  Turns out there is a "pinmux helper" device.  Check out this blog post: http://hipstercircuits.com/enable-serialuarttty-on-beaglebone-black/.  More specifically, this section:

fragment@2 {
        target
= <&ocp>;
        __overlay__
{
            test_helper
: helper {
                compatible
= "bone-pinmux-helper";
                pinctrl
-names = "default";
                pinctrl
-0 = <&pinctrl_uart5>;
                status
= "okay";
           
};
       
};
   
};

- Nathaniel

Strawson

unread,
May 21, 2014, 11:25:23 PM5/21/14
to beagl...@googlegroups.com
Robert held true to his word: The 2014-5-14 debian image includes the tieqep driver and works correctly when teknoman's device tree overlays (or my own) are loaded. Thank you Thank you Thank you!

I am still not sure why the mmap code I attached above only works with that driver, but I suppose I will never find out since it works out of the box on the 2014-5-14 debian image.

Thank you everyone for your help! 

Jason Kridner

unread,
May 22, 2014, 7:11:05 AM5/22/14
to beagl...@googlegroups.com
On Wed, May 14, 2014 at 4:59 AM, Teknoman117 <linux.r...@gmail.com> wrote:
I don't believe that actually will change the I/O configuration.  For the pin ctrl entry to be adopted, it needs to be used by some driver.  Turns out there is a "pinmux helper" device.  Check out this blog post: http://hipstercircuits.com/enable-serialuarttty-on-beaglebone-black/.  More specifically, this section:

fragment@2 {
        target
= <&ocp>;
        __overlay__
{
            test_helper
: helper {
                compatible
= "bone-pinmux-helper";
                pinctrl
-names = "default";
                pinctrl
-0 = <&pinctrl_uart5>;
                status
= "okay";
           
};
       
};
   
};

- Nathaniel

With cape-universal, I believe our new path is to include stuff like this in https://github.com/cdsteinkuehler/beaglebone-universal-io. In that case, you could simply do something like:
root@beaglebone:~# config-pin P8.16 qep
root@beaglebone:~# config-pin -q P8.16
P8_16 Mode: qep
root@beaglebone:~# cat /sys/devices/ocp.3/P8_16_pinmux.24/state 
qep

However, with HDMI enabled, I'm not able to find a valid set of pins to put together an entire eQEP. Further, the entries for an eqep don't seem to be in cape-universal. There has been some discussion if they are necessary, but I haven't been able to expose an eqep as of yet. I'll disable HDMI and reboot next, but can those with experience comment on if something like this is necessary:

diff --git a/cape-universal-00A0.dts b/cape-universal-00A0.dts
index ad5b388..bc6c005 100755
--- a/cape-universal-00A0.dts
+++ b/cape-universal-00A0.dts
@@ -602,7 +602,7 @@
             P9_27_gpio_pd_pin: pinmux_P9_27_gpio_pd_pin {
                 pinctrl-single,pins = <0x1a4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
             P9_27_qep_pin: pinmux_P9_27_qep_pin {
-                pinctrl-single,pins = <0x1a4  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+                pinctrl-single,pins = <0x1a4  0x31>; };     /* Mode 1, Pull-Up, RxActive */
             P9_27_pruout_pin: pinmux_P9_27_pruout_pin {
                 pinctrl-single,pins = <0x1a4  0x25>; };     /* Mode 5, Pull-Down, RxActive */
             P9_27_pruin_pin: pinmux_P9_27_pruin_pin {
@@ -752,7 +752,7 @@
             P9_92_gpio_pd_pin: pinmux_P9_92_gpio_pd_pin {
                 pinctrl-single,pins = <0x1a0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
             P9_92_qep_pin: pinmux_P9_92_qep_pin {
-                pinctrl-single,pins = <0x1a0  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+                pinctrl-single,pins = <0x1a0  0x31>; };     /* Mode 1, Pull-Up, RxActive */
             P9_92_pruout_pin: pinmux_P9_92_pruout_pin {
                 pinctrl-single,pins = <0x1a0  0x25>; };     /* Mode 5, Pull-Down, RxActive */
             P9_92_pruin_pin: pinmux_P9_92_pruin_pin {
@@ -1727,4 +1727,24 @@
         };
     };
 
+
+    /************************/
+    /* eQEP                 */
+    /************************/
+
+    fragment@41 {
+    	target = <&eqep0>;
+    	__overlay__ {
+	        status = "okay";
+            pinctrl-names = "default";
+            pinctrl-0 = <>;
+            
+            count_mode = <0>;  /* 0 - Quadrature mode, normal 90 phase offset cha & chb.  1 - Direction mode.  cha input = clock, chb input = direction */
+            swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
+            invert_qa = <1>;   /* Should we invert the channel A input?  */
+            invert_qb = <1>;   /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
+            invert_qi = <0>;   /* Should we invert the index input? */
+            invert_qs = <0>;   /* Should we invert the strobe input? */
+    	};
+    };
 };
 

Nathaniel Lewis

unread,
May 22, 2014, 8:43:01 PM5/22/14
to beagl...@googlegroups.com
Damn, now that its in the kernel i'm going to have to maintain backwards compatibility =P.

As far as eQEP goes, I think you can enable eQEP 0 without any conflictions. (P9.42 = eQEP0A_in, P9.27 = eQEP0B_in, P9.25 = eQEP0_strobe, and P9.41 = eQEP0_index -> all at mode 1).  I read above someone wanted to see the eQEP hardware in the angstrom device tree - here's a patch just for the device tree file.

- Nathaniel Lewis
0001-Patch-am33xx.dtsi-to-include-device-tree-nodes-for-the-eQEP-units-in-the-SoC.patch

James Zapico

unread,
May 22, 2014, 11:16:27 PM5/22/14
to beagl...@googlegroups.com
eQEP2 is connected to two sets of pins, one of which may also be exposed without disabling the HDMI. Here are the pins:

               0x038 0x24  /* P8_16 = GPIO2_12 = EQEP2_index, MODE4 */
               0x03C 0x24  /* P8_15 = GPIO2_13 = EQEP2_strobe, MODE4 */
               0x030 0x34  /* P8_12 = GPIO2_10 = EQEP2A_in, MODE4 */
               0x034 0x34  /* P8_11 = GPIO2_11 = EQEP2B_in, MODE4 */
- James Zapico

Mark A. Yoder

unread,
Jun 23, 2014, 4:21:04 PM6/23/14
to beagl...@googlegroups.com
James:
  Thanks.  That works for me.  Can this be included in the next debian release?

--Mark

Whissmerhil

unread,
Jun 24, 2014, 12:25:21 PM6/24/14
to beagl...@googlegroups.com
Hello,
 
I'm a bit stuck with your driver and cannot seem to get it working...
 
I've done everything adviced in this discussion and on your "readme" files but whereas the device tree applies itself when I echo, the 4 sysfs entries don't appear, I just get the usual "modalias  power  subsystem  uevent" entries.
 
I must have done something wrong but I honnestly don't see what it could be, does anyone have any idea? =/
 
ps: I'm running on Angström with the 3.8 kernel modified with your patch and with HDMI disabled.

r.mcn...@gmail.com

unread,
Apr 10, 2015, 11:43:24 AM4/10/15
to beagl...@googlegroups.com
I have got the eqep2b working fine and dandy, but when I try to add a second encoder using eqep0 i follow the same device tree configurations, and when I go to read the position of eqep0 hooked up to p9.27 and 9.42 I get a position of 0, always! Do you know what could be causing this? Or point me in the direction of someone who has gotten two encoders working at the same time using two eqep modules?

Thanks ya!

Charles Steinkuehler

unread,
Apr 10, 2015, 2:35:34 PM4/10/15
to beagl...@googlegroups.com
Some folks have gotten all three encoders working with Machinekit.

Just guessing, I'd say review your device tree file and make sure you've
got the pin mux settings correct. Note that some encoder input pins
appear on more than one CPU pad...make sure only one of these pins is
set for eQEP usage or you get undefined behavior.

Also, since you're using P9.42, make sure the mux value for both CPU
pads tied to this one pin are setup so they don't conflict (ie: the
unused pin should be set to be a GPIO input or similar.

On 4/9/2015 10:13 PM, r.mcn...@gmail.com wrote:
> I have got the eqep2b working fine and dandy, but when I try to add a
> second encoder using eqep0 i follow the same device tree configurations,
> and when I go to read the position of eqep0 hooked up to p9.27 and 9.42 I
> get a position of 0, always! Do you know what could be causing this? Or
> point me in the direction of someone who has gotten two encoders working at
> the same time using two eqep modules?
>
> Thanks ya!
>
> On Thursday, April 17, 2014 at 1:30:03 PM UTC-4, Strawson wrote:
>>
>> Hello all,
>>
>> In an effort to make use of the eQEP modules on the beaglebone black we
>> stumbled across the following encoder patch and were able to compile a
>> loadable kernel module with the help of TI. Hopefully this will make its
>> way to the "thirdparty" script in the debian build farm so the community
>> can use this without recompiling
>>
>> *https://github.com/Teknoman117/beaglebot/tree/master/encoders
>> <https://github.com/Teknoman117/beaglebot/tree/master/encoders>*
>>
>>
>> I would like to make known a bug we ran into with reading the eQEP module
>> that resulted in position values not updating after exactly 1020 reads
>> without closing the file pointer. If the file pointer is closed
>> and re-opened for every read, the behavior is normal, but opening/closing
>> the file is painfully slow. I unfortunately don't really know where to
>> begin with finding and fixing this problem, but any insight would be
>> appreciated.
>>
>> Best,
>> J Strawson, C Briggs
>>
>


--
Charles Steinkuehler
cha...@steinkuehler.net

dickelbeck

unread,
Nov 13, 2015, 12:41:59 PM11/13/15
to BeagleBoard
> I would like to make known a bug we ran into with reading the eQEP module that resulted in position values not updating after exactly 1020 reads without closing the file pointer.

Of course you are using a low level read function, not buffered userspace IO like fscanf(). 
That is, use read() not fscanf().  Then try using seek() back to file begin, offset 0, in between reads.

HTH,

Dick


fisher...@gmail.com

unread,
Apr 20, 2017, 3:53:30 PM4/20/17
to BeagleBoard, di...@softplc.com
Hi all,

I'm trying to use the eQEP Linux driver.  I can get it to load by adding a device tree overlay, but it doesn't increment much.  I can see that its loaded (called tieqep) with lsmod etc.

I've never used a quadrature encoder before, so I question if I just havn't connected it correctly.

At times it doesn't increment (reading Position file in /sys/device/ocp/epwmss48...... folder), other times it increments or decrements 2 or 3 positions.

If I jiggle the wheel back and forth a small a amount, it counts a lot.  The dual hall effect sensor outputs clean and clear waveforms at 3.3v, 90 degrees out of phase, switches phase when change wheel direction just as I expected.

I'm only using channels A and B, did not touch other connections.

I've tried using all 3 eQEPs separately (including the 2b overlay for alternate pins of eQEP2).  I've used Derek Molloy's P9 and P8 header files.

Currently have proto-cape with pins 35 (A input)and 33 (B input)on P8 header for eQEP1.

Other eQEPs have same behaviour.  I've also swapped the beaglebone black board with a new one.

I'm using kernel 4.4.9-ti-rt-r25 but with old llibraries and system from like 2015 I think as Simulink doesn't officially support anything higher.  I only upgraded the kernel.

Please let me know if anyone has any advice.

Thanks,
Fisher

Drew Fustini

unread,
Apr 22, 2017, 7:23:27 PM4/22/17
to Beagle Board, di...@softplc.com
I've been using a rotary encoder successfully with the tieqep driver:
https://blog.oshpark.com/2017/04/05/rotary-encoder-breakout-with-pull-up-resistors/

I'm running 4.4.47-ti-r87 on Debian 8.7. I've got it connected to
P8.11 and P8.12. I'm using config-pin to set the mode on those pins.
Details here:
https://github.com/adafruit/adafruit-beaglebone-io-python/blob/eqep/doc/rotary-encoder-eqep-test.md

The position does accurately reflect how many increments I turn the
encoder knob. However, this is at a relatively low rate of speed as I
can not turn the knob as fast a motor with an encoder.

You could try using the Strawson library as an alternative to the
kernel driver. I believe it has support for the encoders:
http://www.strawsondesign.com/#!manual-encoders

regards,
drew

fisher...@gmail.com

unread,
May 2, 2017, 8:01:19 AM5/2/17
to BeagleBoard, di...@softplc.com
Hi Drew,

Thanks very much for your reply and info, I've previously seen your 2 YouTube videos showing your setup from a few years ago which gave me some clues and I downloaded the same image you used then and saw it worked fine.

I had made a mistake by using 5v on the hall sensor as the datasheet claimed it only worked above 5v. I didn't add anything to reduce its output A and B channels, so I wondered if I damaged QEP 2b or the whole eQEP system.

Thankfully, the board is fine and I've found that the issue is actually the wrong mode values in the newer eQEP overlay files.

Nathaniel Lewis originally used modes 0x24 for the index and strobe pins, and 0x34 for channels A and B.  It seems that all or most updated images use modes 0x2c for all pins and so it seems that the driver doesn't work, when its just to do with pull-down resistors being enabled.

So, one doesn't have to use the Cape-Universal overlay if you don't want to.

I prefer to use separate overlays at the moment as I'm trying to get Simulink support for eQEP working as well as upgrading Simulink support to work with the newer images (kernel 4 and above as the slots path has changed etc).

Fisher
Reply all
Reply to author
Forward
0 new messages