High speed encoder input capability of BBB?

I have a fairly simple motion control project I was planning on using an Arduino for, but my understanding is that the arduino’s 16Mhz clock won’t keep up with my encoder pulses. I will need to process a max of 10,000 pulses per second. The project is to control 1 reciprocating pneumatic cylinder and to simply monitor the position and change direction at a programmable in/out position. Is this within the capabilities of the BBB?

On Sat, 10 Sep 2016 15:04:23 -0700 (PDT), beezerlm
<beezerlm@netzero.net> declaimed the following:

    I have a fairly simple motion control project I was planning on using
an Arduino for, but my understanding is that the arduino's 16Mhz clock
won't keep up with my encoder pulses. I will need to process a max of
10,000 pulses per second. The project is to control 1 reciprocating
pneumatic cylinder and to simply monitor the position and change direction
at a programmable in/out position. Is this within the capabilities of the
BBB?

  Rather fast for a motion encoder... I think my Kenwood transceivers
only produce 1000 pulses per rotation (well, maybe twice that to account
for direction), and spinning that dial faster than 1 rotation per second is
difficult.

  Using the /sys filesystem access is highly unlikely to keep up. Memory
mapping the GPIO block might, or writing code for the PRUs (200MHz -- an
input loop using 100 instructions is still around 2MHz vs 10kHz)

  OTOH: you may be looking at the matter from the wrong side.

  If you need to catch just a position to command some valves... Perhaps
all you need is a simple hardware counter using the pulse stream as an
input. Full counter range scaled to the full encoder range, trigger set for
the specific count at the position to activate. Hardware counter is
probably much faster than a software loop. Getting to the counter from
plain Arduino may take some experimenting (I've not looked for a preset
library function)
https://sites.google.com/site/qeewiki/books/avr-guide/counter-atmega328 ->
CTC mode on counter 1 (16-bit) might be the type of operation you need.

  The BBB may have something similar, but a quick Google didn't blind me
with anything obvious. Granted, to date the most ambitious thing I've done
is to prove that a DHT-11 humidity/temp sensor can not be read from Python
using the /sys filesystem access, nor from a C program using that mode
either. [Oh... And running the old HINT benchmark -- which, contrary to the
authors' expectations, didn't really scale well over 20 years: had to cut
the RUNTM parameter from 1.0 seconds to 0.001 seconds, and still got a
warning that the 16-bit integer benchmark was too fast for precision]

There is an eCAP module in the processor that perhaps could be controlled via a PRU . . . but I have limited knowledge of that peripheral module, and no hands on . . .

The hardware eCAP encoder inputs on the BBB can easily keep up with
this rate and much faster. The main issue you are likely to run into
is latency and jitter on the ARM side running the control software.

If your application is simple enough, you can write PRU code to run it
and not have to worry about any ARM side system latency with Linux.

If your application is more complex and you need easy access to system
resources, you might consider using the Machinekit distribution. It's
already setup with a hard-real-time kernel and HAL layer that has
drivers for the BBB's eQEP hardware encoders. It should be fairly
simple to craft a HAL file (which is basically a netlist or text
version of a schematic design) using stock components that will
twiddle pins based on the current encoder position.

I did a little reading on the BBB’s PRU and that looks great for Motion control projects with it’s ability to perform tasks at very low latency. I would be interested to find out if it has full access to using the eQEP module while maintaining low latency. That looks to be just what I need, but I am wondering if it would be a bit over my head since I have no experience with the BBB and PRU programming.

As far as the counters go, I agree that may be a better solution. I assume they would be able to count up and down when direction is changed without losing count, but would the operator be able to change the value of the stroke’s upper or lower limit on the fly without losing position? This is a bit new to me.

I also find some nice IC’s from sold by US digital they may help with this task:

http://www.usdigital.com/products/interfaces/ics

http://cdn.usdigital.com/assets/general/LS7366R.pdf

While this is somewhat of a simple task (not simple for me I guess), it is part of a larger project I am working on. I am retrofitting (for the second time now) a Moore G18 CNC Jig grinding machine. I did a partial retrofit about 6 years ago with using Mach3 motion control software which made the machine a hybrid of the new control and the old 1982 GE control. This time I am using Mach4 software and trying to eliminate the old control completely. The Mach4 software is doing a good job of controlling the X&Y axis Motion (via external PMDX-424 Motion controller) but it doesn’t seem like a good setup for this particular task due to latency. The software has an internal PLC loop that runs every 50ms which creates overshoot of the set limits. This is not a big deal because we can set hard stops, the problem is that the latency seems inconsistent and I am getting odd behavior such as changing direction halfway through a stroke as seen in this video on the 3rd or 4th stroke:

https://www.youtube.com/watch?v=L82Gi7fmf28&feature=youtu.be

What ever my end solution is, The operator needs the ability to change the upper or lower stroke limit quickly and easily on the fly. The PLC loop is working great for that, it just isn’t very responsive or consistent. It looks like there are a lot of different ways to approach this, I am just trying to figure out which would be the simplest method to integrate with the existing motion control software.

I think my project would be simple enough to run through the PRU. My current PLC loop I am running in the motion control software is just a few ifElse statements that monitor position and change direction. Does the PRU have access to the eQEP without adding latency?

It’s been a long time since I worked with a linux real time kernel and HAL. I did a similar project a long time ago using linuxCNC to control a Moog hydraulic servo-valve on an old Heald ID grinding machine. That was pretty cool to see linux handle a Hydraulic cylinder on a PID loop. Here is a quick vid of it:

https://www.youtube.com/watch?v=NMkNCSUJBvs

The machinekit distro looks very similar but more streamlined and with better hardware than what I had. I will have to dig into that a little more.

Hello beezerim!

Is this within the capabilities of the BBB?

Yes, it is.

As Charles mentioned, the BBB CPU has three PWM subsystems. Each of them contains one eQEP module. The modules are clocked at 100 MHz, so they can count a pulse train up to 50 MHz.

  • With one input signal they measure the speed.
  • With two input signals - 1/4 phase shift - they measure speed and position.
  • A third input can get used as reset impuls in order to compensate misscounting.
    All you need is software to set some registers enabling the subsystems and then read the results from the submodules. If you don’t have close real time requirements (controller loop less than 10 kHz) I can provide a new libpruio version that handles the registers for you.

Regards

I think my project would be simple enough to run through the PRU. My current
PLC loop I am running in the motion control software is just a few ifElse
statements that monitor position and change direction. Does the PRU have access
to the eQEP without adding latency?

No and yes. :slight_smile:

No: Everything adds latency, even reading the PRU's direct inputs
(although that only takes one clock cycle or 5 nS).

Yes: Reading the eQEP from the PRU will only take a few hundred nS
(during which time the PRU will be stalled), and the timing jitter
will be fairly low. Unless you have particularly critical timing
issues you didn't mention, the PRU can easily perform a few reads of
the eQEP module while running whatever other control routines you need.

It's been a long time since I worked with a linux real time kernel and HAL. I
did a similar project a long time ago using linuxCNC to control a Moog hydraulic
servo-valve on an old Heald ID grinding machine. That was pretty cool to see
linux handle a Hydraulic cylinder on a PID loop. Here is a quick vid of it:

https://www.youtube.com/watch?v=NMkNCSUJBvs

The machinekit distro looks very similar but more streamlined and with better
hardware than what I had. I will have to dig into that a little more.

If you're already somewhat familiar with HAL, this could be a good way
to go. As I mentioned there are already eQEP and I/O drivers
available, as well as building blocks like PID controllers,
comparators, and even a classic ladder-logic control if you want to
just port your PLC application. You can test things easily with the
pre-built Machinekit uSD card image...just pop out the uSD if you
decide you don't like using Machinekit:

http://elinux.org/Beagleboard:BeagleBoneBlack_Debian#BBW.2FBBB_.28All_Revs.29_Machinekit

Hi TJF,

So basically the libpruio is a driver that makes it easier to access the PRU and assign I/O and create a subsystem program loop? Is that correct? What would be the downside of using this driver? Added Latency?

I am going to order a BBB today so I can familiarize myself with it a bit more.

Well as far as I can tell, a few hundred nanoseconds would be great! I just ordered a BBB so I can familiarize myself with it a bit.

I guess I wouldn’t consider myself proficient with the Linux HAL seeing as I have only used it one time to set up a machine. Wouldn’t latency and jitter be lower going direct through the PRU instead of utilizing the HAL assuming the PRU was capable of handling my logic loop?

I also ordered the TI PRU Cape to go on the BBB. I will be traveling to Chicago this week for the IMTS in chicago so I would like to bring the BBB along with my laptop and peripherals to work with during down time.

On Sun, 11 Sep 2016 06:55:28 -0700 (PDT), beezerlm
<beezerlm@netzero.net> declaimed the following:

As far as the counters go, I agree that may be a better solution. I assume
they would be able to count up and down when direction is changed without
losing count, but would the operator be able to change the value of the
stroke's upper or lower limit on the fly without losing position? This is
a bit new to me.

  Ah, now those are more requirements that weren't in the original
description.

  Typically a counter goes from 0 to maximum (triggering an overflow)...
but (depending on HW implementation) the overflow/interrupt can be
triggered at a set value, or one presets the counter so that the "set
value" of increments brings it to overflow state.

  Count-down might be an option -- one would have to study the
specification sheet for the counter. But would have to be set up by the
processor -- and at your obscenely high pulse rate you may have to
incorporate an offset based upon how many cycles the CPU takes to load the
registers. 10kHz could be radiating RF (and harmonics) that could fall
afoul of Part 15 FCC rules. (Low Frequency is considered 30-300 kHz, so the
second harmonic of your 10kHz pulse would be into the LF bands -- the
primary is in the VLF band Very low frequency - Wikipedia

  Instead I see the counter always counting upwards, but your software
keeps track of the direction, zeros the counter and preloads the comparison
(or preloads the counter for the type that only responds to max-overflow)
for the required number of pulses.

Yes, latency and jitter for anything running on the PRU will probably
be in the uS time-scale. A typical real-time HAL processes running on
the ARM core will have millisecond scale cycle rates with ~75 uS of
jitter. So the PRU is definitely much faster, but it will probably
require custom programming for your application The HAL solution
could be implemented with existing HAL components, so no programming
required (just HAL netlist wiring).

Not entirely correct. It doesn’t provide access to the PRU.

libpruio is a non-LINUX driver. Instead of one folder in sysfs for any subsystem, it provides one shared library driving many subsystems. Instead of reading lots of kernel docs, the user configures a feature for a header pin and is done. That makes it easy and fast (~10 times lower latency than kernel drivers) to access the CPU hardware (for digital IO and analog I). Additionally libpruio provides access to each hardware register, so it’s highly flexible. Therefor it uses SW running on one PRU and a shared library running on the ARM.

Downsides:

  • Its limited to ARM335x CPUs (BBW, BBB, BBG).
  • Just one PRU is free for your application.
    As far as I understand your target, a reciprocating pneumatic cylinder isn’t that fast and you should be happy with a main loop running in less than 5 kHz. This you can realise in a high level compiler language running on the ARM (as long as you don’t have high interrupt loads).

Often, I start my projects that way and when I learn in the concept phase that the project needs better real-time capabilities, I transform the controller loop from high-level language to PRU assembler. libpruio is designed for that process.

Regards

Well I have obtained a BBB along with the PRU cape. I soldered the Jtag header on and I purchased a blackhawk XDS100v2 JTAG Emulator. I istalled CCSv6 and I have completed the PRU labs 1 through 4 - found here: http://processors.wiki.ti.com/index.php/PRU_Training:_Hands-on_Labs#Hardware

I am trying to figure out where to go from here. Libpruio looks promising, but I would like to take the path that would offer the best overall determinism & latency characteristics for reading encoder input and controlling IO accordingly. I would think the best case scenario would be to program the PRU directly and skip linux altogether. This may be overkill for my current project, but it seems like it would be useful for more demanding applications I may cross in the future.

My current PLC loop just sets an “Upper” stroke limit and a “Lower” stroke limit. It then uses if statements to determine when the current position meets or exceeds one of those two settings which activates a solenoid to change direction. It also counts the strokes and writes to some registers for the “Automatic grinding cycle”. It is currently working, but the windows environment doesn’t keep up very well. I would think the best case scenario would be to program the PRU directly and skip linux altogether.

My understanding is that eQEP0 is the only eQEP that can directly interrupt the PRU’s. I think this should be fine because I only need to read 1 encoder.

It looks like the eQEP0 pins are on the P9 header as follows:

P9 - pin 25 - eQEP0_STROBE
P9 - pin 27 - eQEP0B_in
P9 - pin 41B - eQEP0B_index

P9 - pin 42B - eQEP0A_in

I have read through the AM3358 TRM ( wow that is huge ) but I am not quite sure were to start as far as Initializing the eQEP0 and getting readings from the encoder? Are there any tutorials out there for programming the PRU’s to read eQEP0 inputs, then use that information to trigger GPIO events?

PRU will give you the encoder data, but where do you go from there? If all
you need is some calculations and running simple actuators of the PWM kind,
and/or display to low-pixel-count LCD, you dont' need Linux---however, if
you need communication stacks such as Ethernet, BT or WiFi, it's probably a
bad idea to try to write them from scratch.

Hi beezerlm!

Well I have obtained a BBB along with the PRU cape. I soldered the Jtag header on and I purchased a blackhawk XDS100v2 JTAG Emulator. I istalled CCSv6 and I have completed the PRU labs 1 through 4 - found here: http://processors.wiki.ti.com/index.php/PRU_Training:_Hands-on_Labs#Hardware

I didn’t use JTag yet. And I don’t use the bloated TI tools. Instead I use the lightweight pasm assembler and uio_pruss driver.

I am trying to figure out where to go from here. Libpruio looks promising, but I would like to take the path that would offer the best overall determinism & latency characteristics for reading encoder input and controlling IO accordingly. I would think the best case scenario would be to program the PRU directly and skip linux altogether. This may be overkill for my current project, but it seems like it would be useful for more demanding applications I may cross in the future.

You can develop everything from scratch, the subsystem configuration and your controller loop. Or you can use the configuration from libpruio, use the high level API to set the registers in a convenient way and just add some individual controller loop code.

My current PLC loop just sets an “Upper” stroke limit and a “Lower” stroke limit. It then uses if statements to determine when the current position meets or exceeds one of those two settings which activates a solenoid to change direction. It also counts the strokes and writes to some registers for the “Automatic grinding cycle”. It is currently working, but the windows environment doesn’t keep up very well. I would think the best case scenario would be to program the PRU directly and skip linux altogether.

Your costomized code can run either on the ARM or at the other PRU.

My understanding is that eQEP0 is the only eQEP that can directly interrupt the PRU’s. I think this should be fine because I only need to read 1 encoder.

What is eQEP0? There’re three PWMSS (subsystems), each of them have one eQEP module with the same features. So there is PWMSS-0.eQEP, PWMSS-1.eQEP and PWMSS-2.eQEP. All of them have the same interrupt features. And you don’t need them. Better poll the current state for lower latency.

It looks like the eQEP0 pins are on the P9 header as follows:

P9 - pin 25 - eQEP0_STROBE
P9 - pin 27 - eQEP0B_in
P9 - pin 41B - eQEP0B_index

P9 - pin 42B - eQEP0A_in

The pin names are input A, input B, index and strobe. You could also use PWMSS-2 (@ P8_12, P8_11, P8_16). Or – when HDMI is disabled – PWMSS-1 (@ P8_35, P8_33, P8_31) or PWMSS-2 (@ P8_41, P8_42, P8_39).

I have read through the AM3358 TRM ( wow that is huge ) but I am not quite sure were to start as far as Initializing the eQEP0 and getting readings from the encoder? Are there any tutorials out there for programming the PRU’s to read eQEP0 inputs, then use that information to trigger GPIO events?

I also coudn’t find tutorials. I figured it out by trail and error. I have some trouble when dynamically switching between modes, see this thread. But TI couldn’t help. (This isn’t related to your use case.)

Regards

I didn’t use JTag yet. And I don’t use the bloated TI tools. Instead I use the lightweight pasm assembler and uio_pruss driver.

What do you mean by “bloated”? Do you think my CCSv6/Jtag approach is overly complicating this project?

I know very little about the pasm assembler language. Is there some good learning material for that?

You can develop everything from scratch, the subsystem configuration and your controller loop. Or you can use the configuration from libpruio, use the high level API to set the registers in a convenient way and just add some individual controller loop code.

I would love to complete this project using a “baremetal” approach, but I am beginning to feel like this may be a bit over my head at the moment. I have learned a lot with the hands on labs, but I have further to go and I can’t seem to find many entry level tutorials with the baremetal CCSv6 approach. I may have to throw in the towel on the baremetal and give libpruio a shot.

What is eQEP0? There’re three PWMSS (subsystems), each of them have one eQEP module with the same features. So there is PWMSS-0.eQEP, PWMSS-1.eQEP and PWMSS-2.eQEP. All of them have the same interrupt features. And you don’t need them. Better poll the current state for lower latency.

The TRM refers to the module registers as eQEP0, eQEP1 & eQEP2 under each PWM subsystem (Table 2-3 in the ARM memory map chapter) I understand the difference between interrupts and polling, but it seems like i have seen the PRU polling being referred to as interrupts somewhere.

Here is a thread I found discussing PRU interrupts for the eQEP modules. Do you know why the original poster is looking for interrupts on all 3 equip modules? This confused me a bit. - AM335x eQEP modules using PRU - Processors forum - Processors - TI E2E support forums

Thanks for help on this it is much appreciated.

You make a very good point. I will need communication to send the values of my “upper” and “lower” stroke registers from the Mach4 software (windows) to the BBB PRU loop. I know Mach4 has a Modbus plugin. I wonder if that would be the best method of communication to the BBB?

I didn’t use JTag yet. And I don’t use the bloated TI tools. Instead I use the lightweight pasm assembler and uio_pruss driver.

What do you mean by “bloated”? Do you think my CCSv6/Jtag approach is overly complicating this project?

There’s 8kB of instruction ram. This is a maximum of 2048 instructions. Why should anybody use a compiler, a linker and libraries to generate code for that small amount instruction ram?

I know very little about the pasm assembler language. Is there some good learning material for that?

Check out GitHub - beagleboard/am335x_pru_package.

I would love to complete this project using a “baremetal” approach, but I am beginning to feel like this may be a bit over my head at the moment. I have learned a lot with the hands on labs, but I have further to go and I can’t seem to find many entry level tutorials with the baremetal CCSv6 approach. I may have to throw in the towel on the baremetal and give libpruio a shot.

Hold your towel, for now. libpruio with QEP features isn’t published yet. I’d have to prepare a beta version for you. (Code should be OK, documentation isn’t finished. BTW: found some issues with PWMSS-PWM on kernel 4.x, so better use latest 3.8 kernel.)

What is eQEP0? There’re three PWMSS (subsystems), each of them have one eQEP module with the same features. So there is PWMSS-0.eQEP, PWMSS-1.eQEP and PWMSS-2.eQEP. All of them have the same interrupt features. And you don’t need them. Better poll the current state for lower latency.

The TRM refers to the module registers as eQEP0, eQEP1 & eQEP2 under each PWM subsystem (Table 2-3 in the ARM memory map chapter) I understand the difference between interrupts and polling, but it seems like i have seen the PRU polling being referred to as interrupts somewhere.

OK, lets say OEP0 is a short form of PWMSS-0.eQEP.

Here is a thread I found discussing PRU interrupts for the eQEP modules. Do you know why the original poster is looking for interrupts on all 3 equip modules? This confused me a bit. - https://e2e.ti.com/support/arm/sitara_arm/f/791/t/391174

Biser is a freindly person, but he isn’t very keen on hardware issues. You can configure up to 11 interrupt sources for each QEP module (TRM chapter 15.4.3.16). But it’s better to poll some registers. You’ll get the position. And you can compute the speed, in order to predict the next position.

Regards