Skip to content
deebot edited this page Sep 3, 2020 · 27 revisions

Parallel Bidirectional Communication between ARM and PRU using GPIO interface

GSoC 2020 project under BeagleBoard.org

Student Name: Deepankar Maithani 
Mentors: Saketh,Jason kridner,Abhishek Kumar, Hunyue, Drew Fustini , RMA
Organisation: Beaglebone.org

Table of contents

Introduction

Beaglebone boards have two main subsystems namely ARM and PRU. The ARM allows us to run a linux OS and utilize the plethora of already existing code and libraries out of the box, however running a linux also has its downsides.As it is a non premtive OS so it is not suitable for situations where we need to perform tasks in real time. This is where PRU comes in picture, using the two 200MHz PRU on a beaglebone one can offload the time critical tasks to the PRU and can fetch the final results on the ARM side. Thus creating a solution which has best of both the worlds.

This project is aimed at implementing bidirectional communication between PRU and ARM through sysfs/chardev interface ,further firmware is implemented to interface a Universal shift register which helps extend the no of i/o which do not have the OS induced overhead. This might be used in situations for example when interfacing a LED matrix, where all the time critical bitbanging is done using PRU or when connecting a lot of inputs like in case of Keypads and joysticks. So all the time critical processing can be done inside the PRU. But the instructions from ARM and data fetched from connected peripherals can travel back and forth according to the requirement of application.

Block Diagram

The block diagram below shows the overview of the process involved in sharing data between the PRU and ARM Image

The three main software components that enables this communication are:

  • Gpiochip driver
  • PRU firmware
  • User space Code

As can be seen in the diagram on the left the user-space application accesses the GPIOchip driver to send/receive data. The GPIOchip created by the driver has 9 lines. In the ARM to PRU communication scenario, the userspace application grabs the lines and set them as output. As mentioned earlier there are lines 0 to 8. The value on line no 0 determines the mode of the shift register. The rest of the 8 lines are used to create 8 bit of data. Once all the 9 lines are assigned a value driver creates a RPMSG payload/message and sends it over to the PRU side. The PRU firmware continuously keeps looking for mailbox interrupt, when a new message is received interrupt is triggered. Then PRU reads the buffer which has the data. The first data bit in payload is analyzed and accordingly the PRU configures the shift register in SIPO and PISO mode. If in the SIPO mode the rest of the 8 bits are grabed one by one from the payload/message and shifted in the shift register.This process is discussed in detail in the later sections. If first bit in the payload is 1 then the rest of the 8 bits are discarded and the PRU configures the shift register in PISO mode and after that reads in the 8 inputs, creates a rpmsg payload and sends it back to the ARM side from where the user-space code can read the value by setting the gpio lines as input and then reading the state.

Code and Usage

To access the code, dependencies, ReadMe file, description of folder contents and wiring diagrams. Visit the link below

Repository Link

Usage Guide

The folder contains Readme files which explains how to setup everything to use the project. Basically there are following steps.

  • Connect the Hardware as shown in the diagram
  • Run the script to configure correct mode on the pins used
  • Build and run the code to test the hardware. Only need to be done first time when setting the hardware and to be sure that all the connections are connected correctly
  • Build and insert the driver.
  • Build and load the correct PRU firmware.
  • Build and run the userspace code to read or write.

Check out the folder Description section in the Repository link above for detailed README files.

Pull Requests:

Added new example with Button input

Modified Make file to ease PRU firmware loading

Gpiochip driver for RPmsg

Digging Deeper

The technique/protocol used to implement the communication is called rpmsg,The RPMsg protocol was created as part of the Open Asymmetric Multi Processing (OpenAMP) framework project to provide a standard interface for communication between multiple cores in a heterogeneous multi-core system. There was already a character driver in the linux source for this implementation. But here a gpiochip driver is implemented which provides a new interface to deal with the rpmsg based communication. To understand this better, we need to understand the architecture at a little more deeper level. The TRM tells us that there are 4 general purpose i/o modules and each module provides 32 gpio pins. So the AM335X provides 32 X 4 gpio. This fact can also be corroborated by looking inside the /dev and running the gpiodetect command.

Image

However not all of these gpios are accessible on the headers available on the beaglebone board. Now the interesting part is that after we insmod our GPIO driver the linux system thinks it has another gpio module which consists of 9 gpio lines. However these lines are virtual and there is no actual hardware pins corresponding to these lines inside the linux subsystem.

image

The data that is sent using the chardev interface is packaged in a char array and then send over to the PRU where this data is pushed to the i/o of the shift register.Similarly a gpio line can also be used to read input. So this data can also be read using the sysfs interface. This is a more intuitive interface as compared to using a char driver when any project involves controlling multiple i/o on the PRU side. Also this comes with another advantage that now one can use the libgpiod library to send and receive i/o state as if these are a part of gpio modules on the ARM.

Sysfs and libgpiod

sysfs is a pseudo file system provided by the Linux kernel that exports information about various kernel subsystems, hardware devices, and associated device drivers from the kernel's device model to user space through virtual files.[1] In addition to providing information about various devices and kernel subsystems, exported virtual files are also used for their configuration. Our field of interest was gpio class which can be acesses at /sys/class/gpio.User-mode GPIO has historically been performed via the legacy “integer-based”sysfs pseudo file system. For example our gpiochip driver has a interface in the sysfs and can be accessed as following:

Image

In the image above we can see the gpiochip interface exported by our driver is 'gpiochip593'. When we cat the label and ngpio we see that the label is "channel 30" as we have set in the PRU firmware and the ngpio number is 9 as we have set in out gpiochip driver.Now to use the lines we need to export them and then use them as we use any other gpio line available on the beaglebone header using the sysfs.The figure below shows how we can export lines from the gpiochip503. Here as an example two lines namely gpio503 and gpio504 are exported. You would notice that there are two folders gpio503 and gpio504 which have interfaces to control these lines. This gpiochip503 have 9 lines which go from gpio503 to gpio513.

image

Further the screenshot below shows the process of setting the direction of the pin and then assigining a value to it.

image

It is also worth mentioning that the userspace examples in the repo uses the new recomended way of using GPIO via the “descriptor-based” character device ABI (Application Binary Interface). The interface is exposed at /dev/gpiochipN as shown in the previous section. But for the sake of complete understanding this document has also explained the sysfs interface.

To use the chardev gpio interface there is a library called libgpiod which provide us with APIs using which we can easily access the gpio lines. There are userspace examples that you can find in the repository but you can follow thislink to understand the API better and write your own userspace code. The library is in C but there are bindings for other languages like C++ and Python. Also if one wants to use it through the terminal one can follow as shown below.

gpioinfo: It prints information about the GPIO lines of a specific gpiocontroller. Here in the example wr are printing for our controller 4.

gpioset: It sets a gpio line as HIGH or LOW. Ex gpioset <line no,>=<1 or 0>

gpioget: It is used to read value of a line. Ex gpioget

Understanding the Shift Registers

Shift Registers are sequential logic circuits, capable of storage and transfer of data. They are made up of Flip Flops which are connected in such a way that the output of one flip flop could serve as the input of the other flip-flop In the project here two different ICs are used to demonstrate bidirectional communication and provide additional i/o. First IC is 74HC595 which is can work in SIPO (Serial Input and Parallel Output Mode) and the second IC is 74HC299 which can work in SIPO, PISO (Parallel Input Serial Output) , Shift left and shift Right modes.

The image below shows block diagram of a shift register in SIPO mode. As you can see to shift in n bits of data n flipflops are required and n number of clock pulses are required. Once the serial data is loaded the parallel output can be obtained without any further clock. Further the time required to input the data will be n x time period of clock.

alt text

Further in the PISO mode the data is loaded in the shift register in 1 clock pulse and the data is read out serially using n-1 pulses. The value of shift/load as shown in the figure decides if shifting will happen or loading of new parallel data will take place.

alt text

Quick Overview of using shiftregister IC

In this section i will go through the process of using the actual 74HC595 and 74HC299 IC. I started with 74HC595 because it is very widely available and i didn't had access to 74HC299 due to the corona pandemic.However it can be a blessing in disguise as now my repo has code for 74hc595 which is way more popular among hobbyists so somebody can use it out of the box. However for bidirectional communication you would need 74HC299. Now i will go through the overview and you can look for the finer details in the respective data sheets.

image

As shown in the image above there are two main blocks inside the 74hc595 one is the shift register which shifts the data on every low to high clock transition and the other one is Latch block which receives the parallel input . A low−to−high transition on the latch clock pin input latches the shift register data. Now if the OE pin is LOW it allows the data from the latch to be presented on the output. When this pin is HIGH the output pins are in high impedance state and can be driven by some external circuit.

However in case of 74HC299 we have an extra step, first we need to configure the IC to be used as SIPO or a PISO. To configure in SIPO mode both OE1 and OE2 are pulled LOW and SO is set HIGH while S1 is pulled LOW.Once configured The serial data is loaded bit by bit through the DS0 pin.

To configure in PISO mode OE1 , OE2 are kept LOW S0 and S1 all are set HIGH. Then a left shift or right shift configuration is made . Q0 gives data with least significant first and Q7 gives serial data with most significant first.other details are evident in the datasheet and in the comments in the source code image

Understanding the R30 and R31 registers of PRU

Before you could understand the code that i wrote, another very important bit of information need to be understood. There are 2 32 bit resistors in the PRU namely R30 and R31. The R30 register controls the PRU pins output and R31 controls the input. In simple words it means if you have a pin which is set as output. You need to figure out which is the bit number that it corresponds to in the R30 register and then use bit wise operation to set it low or High. Similarly if you have set a pin as input, in order to read this pin you need to read the corresponding bit in R31. You can read about it in detail in my Blogpost. Also as i mentioned earlier when using rpmsg a interrupt is set high every time a new message arrives, one must keep in mind that when working with PRU0 interrupt on pin no 30 should be monitored and when the code is running on PRU1 interrupt on pin 31 is triggered. This is one important point to consider while porting a code that involves rpmsg from one PRU core to another. More about it can be read in my Blogpost

Blog Posts

On this journey as i was figuring out solutions to the hurdles, i had to look around various places to learn concepts that would help me accomplish the objectives of this project. To make it easier for others to understand this project and related concepts i have written some blog-posts which could help others grasp the concepts quickly.Below are the links

Video Links

Some videos about my project

Limitations/Future Improvements

  • At one point of time the Shift register pins can only act as input or output. There is no way to setup some of them as input and others as output. So this is half duplex communication.
  • The PRU is operating at 200MHz and can switch at a much higher rate then the 74HC299 (or 74HC595) can register.It has a typical operating frequency of 50MHz at VCC = 5V, CL = 15pF, TA = 25oC. Hence it is a bottleneck to the overall performance of this setup. However the same communication can be done faster if we can implement the shift register on a FPGA like lattice ICE40 which also has a opensource tool chain.
  • The driver can be further extended to automatically load the firmware
  • Initially the objective was to implement a bus for bidirectional communication, further development in this direction can use elements from this gpiochip based implementation.
  • A cape can be designed based on this design to teach about rpmsg and shift registers.

To Conclude

It has been a great learning experience. I have been playing around with boards like raspberrypi but before GSOC i had never had the chance to get my hands on Beagleboard. However I had broad awareness of this platform and was drawn by the fact that it is open source even at the hardware level and the PRUs has also fascinated me, that's why i chose to work with this particular project. Further, prior to GSOC my understanding of kernel modules was limited to simple hello world kernel modules and just an overview of what could be the advantages or disadvantages of writing a kernel module vs a user space implementation. But after this internship i am in a way better state to understand and write some custom kernel modules. Further as now i am quite familiar with the beaglebone hardware and infact have 2 different variants of beaglebone with me i am looking forward to improving this project and contributing to the community with other projects. I would also like to mention that i had great support from my mentors during the project , at times i was overwhelmed by the new information that i had to churn and make sense of but the support form my mentors helped me get through the hurdles. Thanks for the opportunity.

References

Following links and Books were very helpful in understanding the required concepts

Links

Books