libpruio  0.6.8
Fast and easy Digital/Analog Input/Output for Beaglebones
Features

Here's some feedback about the libpruio project. lejan wrote:

Dear TJF,

I just wanted to thank you for sharing such a great library! I have
been using this in C for a robotics project and this library really
took the hassle out of a lot of the programming work. The Beaglebone is
not as well supported as Arduino or Rasp Pi so your library is very
much appreciated.

Peter

Thanks, for the feedback! It seems that the major goal is reached.

libpruio is designed to provide faster, more flexible (customizable) and more easy (single source) access to the TI AM335x CPU subsystems, compared to the methods provided by the kernel. Its features in short

  • run on PRU-0 or PRU-1 (default)
  • control subsystems at runtime (disable or enable and configure)
  • run in different run modes (IO, RB and MM)
  • configure header pins
  • get digital input (GPIO)
  • set digital output (GPIO)
  • analyse digital input train (CAP frequency and duty cycle)
  • set digital output train (PWM frequency and duty cycle)
  • get digital input from Quadrature Encoder (QEP position and speed)
  • get analog input (ADC)
  • apply samples bit encoding (12 to 16 bit)
  • configure ADC settings (input channel, timing, averaging)
  • perform high-speed measurements (up to 200 kSamples/s)
  • start measurement by trigger events (up to 4)
  • trigger on analog (single or all) or digital (GPIO) lines
  • perform a pre-trigger that starts measurement before the trigger event happens

It's designed for BeagleBone boards with a type of TI AM335x CPU

  • with 2x46 headers (White, Green, Black)
  • with 3x36 headers (Pocket)
  • with individual connectors (Blue)

and runs on all kernel versions above 3.8 (including 4.x, 5.x).

PRUSS

The TI AM335x CPU on Beaglebone hardware contains beside the main ARMv7 processor also two PRU subsystems. libpruio runs software on the host system (ARM) and in parallel on a Programable Realtime Unit SubSystem (PRUSS), either on PRU-0 or PRU-1 (the later is the default). Due to the PRU support the work load on the ARM is very low. Even complex controllers can operate at reasonable speed. The second PRU is free for any custom firmware, ie. a controller working in real-time, and using libpruio measurement configuration and data.

Operation

libpruio controls the following subsystems on the TI AM335x CPU

  • TSC_ADCSS (Touch Screen Controler and Analog to Digital Converter SubSystem)
  • GPIO (4x General Purpose Input Output subsystem)
  • PWMSS (3x Pulse Width Modulation SubSystem, containing modules PWM, CAP and QEP)
  • TIMERSS (4x Timer and PWM features)

Therefor the user application (ARM) executes a sequence of these three steps

  1. Create a PruIo structure, read initial subsystems registers configuration (constructor PruIo::PruIo() ).
  2. Upload customized configuration to the subsystems registers (function PruIo::config() ) and start the main loop operations (possibly by functions PruIo::rb_start() or PruIo::mm_start() ).
  3. Finally, restore original register configuration and destroy the PruIo structure (destructor PruIo::~PruIo() ).
Note
Create and use just one PruIo structure at a time.

libpruio offers a set of API functions to do simple IO task at a reasonable speed. They may be inefficient in case of advanced requirements. Therefor libpruio allows direct access to all register configurations of the subsystems. This is for experts only. Further customization of the subsystems configuration for analog and digital lines can get done by adapting the subsystem registers before step 2.

Note
It's save to control the Beaglebone hardware by the libpruio API functions. In contrast accessing the register sets directly is for experts only and may cause non-revisible hardware damages.

Run Modes

libpruio supports three run modes. They differ in the priority of the timing of the ADC subsystem (restarts of the sequencer):

  1. IO mode (inaccurate ADC timing): the PRU is running in an endless loop and handles input and output lines of all subsystems at the same priority. Depending on the number of enabled subsystems, their usage and the ADC step configuration, there may be some latency (< 1 µs) before the next ADC sampling sequence.
  2. RB mode (accurate ADC timing): the PRU is running in an endless loop and handles restarts of the ADC subsystem at prefered priority. Digital input and output gets only handled when the PRU is waiting for the next ADC restart. This may cause some delay (< 1 µs) before a digital output line gets set or a digital value gets in.
  3. MM mode (accurate ADC timing): the PRU waits for a start command and performs a single measurement. It handles analog samples only (no digital IO available).

The run mode gets specified by parameter Samp in the call to function PruIo::config()

  • Samp = 1 for IO mode, starting immediately, running endless.
  • Samp > 1 for RB mode, starting by a call to function PruIo::rb_start(), running endless.
  • Samp > 1 for MM mode, starting by a call to function PruIo::mm_start(), stopping after a single measurement is done.

To stop an endless mode (IO or RB) call function PruIo::config() again. Or destroy the libpruio structure when done by calling the destructor PruIo::~PruIo().

Pinmuxing

Most digital lines of the TI AM335x CPU support several features and need to be configured before use (see section Pinmuxing for details). libpruio checks the pin configuration at run-time, and tries to adapt it if necessary.

libpruio supports multiple pinmuxing methods. Depending on the kernel version and the system configuration pinmuxing at run-time may require administrator privileges. The most advanced method is the loadable kernel module, described in section LKM. Or you can run your application with user privileges by making sure that digital lines are in the required state (configuration) before executing the code.

GPIO

General Purpose Input Output is available by the GpioUdt member functions (in IO and RB mode, for all header pins). See section GPIO for further info.

Furthermore, multi lines can get accessed simultameously by direct access to the PRU interface (experts only).

CAP

Capture And Analyse a digital Pulse train is available by the member functions of class CapMod (in IO and RB mode). The frequency and duty cycle of a pulse train can get measured. See section CAP for further info.

A minimal frequency can get specified to limit the reaction time in case of no input.

PWM

Generating a Pulse Width Modulated output is available by the PwmMod member functions (in IO and RB mode). Therefor libpruio uses different subsystems: the PWM modules and the CAP modules in the PWMSS subsystems, as well as the TIMER [4-7] subsystems. All modules are supported in a transparent API. See section PWM for further info.

  • Function PwmMod::setValue() sets the frequncy and duty cycle (and configure the pin, if necessary).
  • Function CapMod::Value() gets the current frequency and/or duty cycle (they may differ from the required values).

Furthermore advanced features of the PWMSS subsystems can be used by direct access to the register configuration and PRU interface, ie. syncronizing multiple PWM outputs (experts only).

TIMER

Generating a pulse train on output line[s]. The time period until the pulse starts and its duration gets specified. See section TIMER for details.

  • Function TimerUdt::setValue() sets the duration or stops a running TIMER (and configure the pin, if necessary).
  • Function TimerUdt::Value() gets the current durations (those may differ from the required values).

QEP

Reading and analysing signals from incremental Quadrature Encoder Pulse Trains. Those encoders generate pulses by two (mostly light barriers) sensors, scanning a regular grid (bar code), while both sensors are out of phase by 90 degrees. By analysing those signals, the position (angle) and the speed of the movement can get detected.

libpruio supports multiple measurement configurations:

  • single pin (speed only)
  • double pin (speed and position)
  • tripple pin (speed and position, accurate reset by index pin)

The mode gets specified by the call to function QepMod::config(). See section QEP for further info.

ADC

In all run modes (IO, RB and MM) Analog Digital Converted input can get sampled by the AdcUdt member functions, controling the Touch Screen Controler and Analog to Digital Converter SubSystem (TSC_ADC_SS). It samples analog data on eight input lines (AIN-0 to AIN-7).

Note
On Beaglebone hardware line AIN-7 is hard wired by a voltage divider on board to the 3V3 power supply.

The ADC subsystem can use up to 16 step configurations (and an additional charge step) to perform a measurement. libpruio pre-configures steps 1 to 8 by default to sample lines AIN-0 to AIN-7.

  • Function PruIo::config() sets the run mode, the step mask, the measurement timing and the bit encoding.
  • Function AdcUdt::setStep() customizes a step configuration (optional).
  • Array AdcUdt::Value holds the sampled values. The context depends on the run mode of libpruio, specified by the parameter Samp in the most recent call to function PruIo::config().

Bit Encoding

The Beaglebone ADC subsystem samples 12 bit values in the range of 0 to 4095. Most other devices (ie. like sound cards) use 16 bit encoding (in the range of 0 to 65535) and the values cannot get compared directly. Therefor libpruio can left shift the samples internaly. By default the output is 16 bit encoded (range 0 to 65520).

Ring Buffer

In Ring Buffer (RB) mode the samples from the ADC subsystem continuously get stored in the external memory. The calling software has to make sure that only valid values get read. Therefor the value of PruIo::DRam [0] contains the most recent write position (UInt32 index).

In order to run RB mode, specify the size of the ring buffer by the number of samples (> 1) in the call to PruIo::config() and then start measurement by calling function PruIo::rb_start(). Read samples as AdcUdt::Value[index] and make sure that index is always behind the counter PruIo::DRam [0] (at the end of the ring buffer memory, the index counter jumps to 0 (zero)). Find examples in rb_file.bas (rb_file.c) or rb_oszi.bas.

Measurement Mode and Triggers

In Measurement Mode (MM mode) the start of a measurement is either immediately, or the start can get triggered by up to four events. When the first event happens, the second trigger gets started, and so on. The last specified trigger starts the measurement.

A trigger event may be a digital line reaching a certain state or an analog line reaching a certain voltage. The voltage can get specified as an absolute voltage or as a difference related to the measured voltage at trigger start.

Post-triggers may delay the measurement start or the start of the next trigger for a certain time.

A pre-trigger can be used to start the measurement before the event happens. Only one pre-trigger is allowed, it's always the last trigger.

Call function

Pass the trigger specification[s] to function PruIo::mm_start() to activate them. Read the samples as AdcUdt::Value[index] and make sure that the index doesn't leave the range specified by the number of samples in the call to RruIo::config(). Find am exmple in file triggers.bas.

Subsystem Control

libpruio controls several subsystems, listed in section Operation. Each of these subsystems can either

  • get configured and used (the default), or
  • get switched of (ie. to reduce power consumption), or
  • get ignored (no subsystem access, just evaluate the initial state).

To ignore a subsystem, clear its status bit in parameter Act when calling the constructor PruIo::PruIo(). Each subsystem gets controlled by its own status bit. When a system is set to be ignored, libpruio cannot access it. There's no configuration data and there's no reset to the initial state for the subsystem by the destructor PruIo::~PruIo().

By default all subsystems are active (not ignored). All active subsystems are enabled after the constructor call (unless the hardware fails). Check

  • the subsystems initial clock value to find out if the subsystem was enabled before the constructor call (ie. AdcSet::ClVa or GpioSet::ClVa have values of 2 if enabled),
  • the subsystems version information to find out if the subsystem is enabled after the constructor call (ie. AdcSet::REVISION or PwmssSet::IDVER have values of 0 (zero) if wakeup failed).

libpruio stores a complete set of configuration data for active subsystems and restores their state by the destructor when finished. Active subsystems can get enabled or disabled at run-time. Each call to function PruIo::config() can change a subsystem state.

  • A set status bit in parameter Act for the constructor PruIo::PruIo() call enable the subsystem.
  • To disable a subsystem, set the clock value to 0 (zero), before calling function PruIo::config(). Ie. set PruIo->PwmSS->Conf(2)->ClVa = 0 to switch off the third PWMSS subsystem (PWMSS-2).
  • To re-enable a subsystem, set the clock value to 2, before calling function PruIo::config() again. Ie. set PruIo->Adc->Conf->ClVa = 2 to enable the ADC subsystem.

Overlays

The libpruio package contains in folder src/config tools to create, compile and install device tree overlays.

  • Either an overlay with fixed pin configuration. This overlay type configures the pins to a certain state before the libpruio code gets executed. The code can run with user privileges.
  • Or an universal overlay, that provide run-time pinmuxing capability. That means the pin mode and resistor / receiver configuration can get changed when the libpruio code is running. The later needs admin privileges.

In order to create a customized overlay adapt the source code, compile and execute it: