BeagleBoard/GSoC/2020 Projects/PRU Improvements

=Proposal for Implement a REPL interpreter for PRU =

Student: Vedant Paranjape Mentors: Kumar Abhishek, Jason Kridner Code: [N/A] Wiki: https://elinux.org/BeagleBoard/GSoC/2020Proposal/VedantParanjape2 GSoC: [N/A]

=Status= This project is currently just a proposal.

=Proposal= Completed all the requirements listed on the ideas page. the code for the cross-compilation task can be found here submitted through the pull request #138.

About you
IRC: vedant16 Github: https://github.com/vedantparanjape/ School: Veermata Jijabai Technological Institute (VJTI) Country: India Primary language : English, Hindi, Marathi Typical work hours : 10AM - 7PM Indian Standard Time Previous GSoC participation: I find embedded pretty interesting, given I have experience with ESP32, I think I will be able to excel in this project. This is the first time i am participating in GSoC

About your project
Project name: Implement a REPL interpreter for PRU

Description

 * The PRU is a dual core micro-controller system present on the AM335x SoC which powers the BeagleBone. It is meant to be used for high speed jitter free IO control. Being independent from the linux scheduler and having direct access to the IO pins of the BeagleBone Bhilack, the PRU is ideal for offloading IO intensive tasks.


 * Programming the PRU is a uphill task for a beginner, since it involves several steps, writing the firmware for the PRU, writing a loader program. This can be a easy task for a experienced developer, but it keeps many creative developers away. So, I propose to implement a REPL based control of the PRU, hiding all the low level things behind the REPL and providing a clean interface to uses PRU.


 * This can be achieved by implementing a PRU firmware which only runs some specific user defined commands delivered by RPMSG, executes and then sends a appropriate response. This can be achieved by offloading major task like lexing, parsing to the linux core, and through RPMSG only certain set of commands will be run, the high level code will be converted to these set of commands, on the linux machine itself.

Deliverables:
 * 1) Implement a wrapper library to simplify tasks like writing to a pin, reading from a pin, delay, accessing memory.
 * 2) Solve issues on am335x_pru_package github.
 * 3) Update PRUSpeak to work with the latest kernel.
 * 4) Implement a REPL based control for PRU, uses RPMSG and RPROC

Implementation Details

 * Implement a wrapper library to simplify tasks like writing to a pin, reading from a pin, delay, accessing memory.


 * Writing to a pin: __R30 ^= (1 << 3). This can be replaced by a more intuitive command like GPO_set_level(pin, state)
 * Delay: __delay_cycles(100000000) to wait for 500ms, this is non intuitive, this can be replaced by a command like delay(TIME(in ms))

If we define functions to wrap around the existing function, it can increase the size of the firmware, to overcome this, we can use MACROS to define these functions.


 * Solve issues on am335x_pru_package github


 * Solve issue #44, #41, #49


 * Update PRUSpeak to work with the latest kernel.




 * Implement a REPL based control for PRU, uses RPMSG and RPROC


 * PRU will run a firmware which will basically run a while loop, which will evaluate certain specified commands sent to it through RPMSG. Accordingly it will execute the described commands on the PRU. After taking a look at PRUSpeak, its command set enables to do advance PRU control. So, proposed commands set will be
 * {| class="wikitable


 * SET_PWM || Sets PWM output
 * SET_OUT || Sets HIGH/LOW value of an output pin
 * READ_IN || Reads HIGH/LOW value of an input pin
 * SET_MEM || Sets specified value to specified memory location
 * READ_MEM || Reads value at the specified location
 * WAIT || Waits for given amount of clock cycles
 * CMP || Compares the two operands, returns 0 if equal, -1 if less than and +1 if greater than
 * ADD || Adds two operands.
 * SUB || Subtracts two operands
 * AND || ANDs the two operands
 * OR || ORs the two operands
 * NOT || NOTs the given operand
 * HALT || Stops program execution
 * }
 * ADD || Adds two operands.
 * SUB || Subtracts two operands
 * AND || ANDs the two operands
 * OR || ORs the two operands
 * NOT || NOTs the given operand
 * HALT || Stops program execution
 * }
 * NOT || NOTs the given operand
 * HALT || Stops program execution
 * }
 * HALT || Stops program execution
 * }


 * Commands will be sent through RPMSG to the PRU and a response, either SUCCESS or error a message, will be sent through RPMSG by the PRU to ARM.

Since PRU is 32 bit, OPCODE will be 8-bit and PARAMS will be 32-bit


 * Command format


 * OPCODE PARAM1 PARAM2


 * One word commands


 * {|class = "wikitable"


 * Command || OPCODE || PARAM1 || PARAM2 || Example || Usage
 * HALT || 0x00 || N/A || N/A || HALT || Halts the processor
 * }
 * }


 * Two word commands


 * {|class = "wikitable"


 * Command || OPCODE || PARAM1 || PARAM2 || Example || Usage
 * READ_IN || 0x01 || Pin Number (Hex format) || N/A || READ_IN 0x00000007 || Reads input at the given input pin.
 * READ_MEM || 0x02 || Memory Address || N/A || READ_MEM 0x80000000 || Reads from a given memory location.
 * WAIT || 0x03 || Ticks to wait || N/A || WAIT 0x01113010 || Waits for specified ticks
 * NOT || 0x0B || register( result stored here) || N/A || NOT 0x00000007 || NOTs the given binary value
 * }
 * WAIT || 0x03 || Ticks to wait || N/A || WAIT 0x01113010 || Waits for specified ticks
 * NOT || 0x0B || register( result stored here) || N/A || NOT 0x00000007 || NOTs the given binary value
 * }
 * }


 * Three word commands
 * {|class = "wikitable"

Compares A with B gives output:
 * Command || OPCODE || PARAM1 || PARAM2 || Example || Usage
 * SET_PWM || 0x04 || PIN Number (Hex format) || Duty Cycle (Hex format) || SET_PWM 0x00000007 0x0000005A (SET_PWM 7 90) || Output PWM pulse on a given pin with specified pulse width.
 * SET_OUT || 0x05 || PIN Number (Hex format) || HIGH/LOW Value (Hex format) || SET_OUT 0x00000007 0x00000001 (SET_OUT 7 1) || Sets high/low to the specified pin.
 * CMP || 0x06 || Variable A/Constant (Hex format) || Variable B/Constant (Hex format) || CMP 0x00000008 Ox00000002 ||
 * SET_OUT || 0x05 || PIN Number (Hex format) || HIGH/LOW Value (Hex format) || SET_OUT 0x00000007 0x00000001 (SET_OUT 7 1) || Sets high/low to the specified pin.
 * CMP || 0x06 || Variable A/Constant (Hex format) || Variable B/Constant (Hex format) || CMP 0x00000008 Ox00000002 ||
 * CMP || 0x06 || Variable A/Constant (Hex format) || Variable B/Constant (Hex format) || CMP 0x00000008 Ox00000002 ||
 * 0x00000000 if A = B
 * 0x00000001 if A > B
 * 0x00000002 if A < B
 * ADD || 0x07 || Register (result will be stored here) || Register/Constant || ADD 0x00000001 0x20202020 || Adds two numbers.
 * SUB || 0x08 || Register (result will be stored here) || Register/Constant || SUB 0x00000001 0x20202020 || Subtracts two numbers.
 * AND || 0x09 || Register (result will be stored here) || Register/Constant || AND 0x00000001 0x20202020 || ANDs two binary values.
 * OR || 0x0A || Register (result will be stored here) || Register/Constant || OR 0x00000001 0x20202020 || ORs two binary values.
 * SET_MEM || 0x0C || Memory Address || Binary data to be written || SET_MEM 0x80000000 0x00000011 || Writes to a given memory location.
 * }
 * OR || 0x0A || Register (result will be stored here) || Register/Constant || OR 0x00000001 0x20202020 || ORs two binary values.
 * SET_MEM || 0x0C || Memory Address || Binary data to be written || SET_MEM 0x80000000 0x00000011 || Writes to a given memory location.
 * }
 * SET_MEM || 0x0C || Memory Address || Binary data to be written || SET_MEM 0x80000000 0x00000011 || Writes to a given memory location.
 * }

Experience and approach
I have decent experience in C++, C and Python. I have done several projects involving embedded systems like ESP32, I well-versed with freeRTOS. I recently did a project on ESP32, in which I used ESP to control and plot PID loop running on the embedded device, plotting the values on a python GUI. Other than that I have developed firmware for a 3 DOF arm based on a ESP32 custom board. I did a internship with a embedded deviced startup, where I built:
 * 1) Built TCP network stack for embedded IoT Devices
 * 2) Implemented Synchronous TCP server using Boost.Asio(C++) and Boost.Thread(C++)
 * 3) Implemented a tool to calculate round trip time(RTT) of tcp packets

I actively contribute to open source and do a lot of mini projects throughout the year, you can find my several more interesting projects at my github page

Contingency
I believe that if I get stuck on my project and my mentor isn’t around, I will use the resources that are available to me. Some of those information portals are listed below.
 * 1) https://git.ti.com/pru-software-support-package
 * 2) https://processors.wiki.ti.com/index.php/PRU_Training:_Hands-on_Labs PRU Guide
 * 3) https://markayoder.github.io/PRUCookbook/ Mark Yoder's cookbook is a excellent guide
 * 4) Derek Molly's beagle bone guide provides all the information needed for getting up and running with my beagle.
 * 5) The technical reference manuals provided by TI on am3358 and am5729 are the best source
 * 6) Processor SDK Linux Software Guide is a good reference material

Benefit

 * Currently interfacing with the PRU requires a lot of makefile manipulation, kernel drivers and stuff. There's no working around that for more advanced applications but if you can get something simple up and running quickly with a REPL, that'd be great.
 * -Abhishek Kumar