From 4b27daa52e8197b1b4991a14241af6a2f4edf55e Mon Sep 17 00:00:00 2001 From: Deepak Khatri <lorforlinux@beagleboard.org> Date: Sat, 3 Sep 2022 22:55:09 +0530 Subject: [PATCH] Update PRU Cookbook --- VERSION | 4 +- books/pru-cookbook/01case/case.rst | 279 +++--- books/pru-cookbook/02start/start.rst | 71 +- books/pru-cookbook/03details/details.rst | 99 ++- books/pru-cookbook/04debug/debug.rst | 99 +-- books/pru-cookbook/05blocks/blocks.rst | 518 ++++++----- books/pru-cookbook/06io/io.html | 1003 ---------------------- books/pru-cookbook/06io/io.rst | 67 +- books/pru-cookbook/07more/more.rst | 124 +-- books/pru-cookbook/08ai/ai.rst | 57 +- 10 files changed, 631 insertions(+), 1690 deletions(-) delete mode 100644 books/pru-cookbook/06io/io.html diff --git a/VERSION b/VERSION index 57bdc69b..25065008 100644 --- a/VERSION +++ b/VERSION @@ -1,5 +1,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 PATCHLEVEL = 8 -VERSION_TWEAK = 1 -EXTRAVERSION = beta +VERSION_TWEAK = 2 +EXTRAVERSION = diff --git a/books/pru-cookbook/01case/case.rst b/books/pru-cookbook/01case/case.rst index 8082060e..a647ff28 100644 --- a/books/pru-cookbook/01case/case.rst +++ b/books/pru-cookbook/01case/case.rst @@ -19,8 +19,8 @@ operation. But what if you have a project that needs the flexibility of an OS and the timing of a microcontroller? This is where the BeagleBoard excels since it has both -an ARM procssor running Linux and two footnote:[Four if you are on the BeagleBone AI]; -**P**rogrammable **R**eal-Time **U**nits (PRUs). +an ARM procssor running Linux and two [#]_ +**P**\ rogrammable **R**\ eal-Time **U**\ nits (PRUs). The PRUs have 32-bit cores which run independently of the ARM processor, therefore they can be programmed to respond quickly to inputs and produce very precisely timed @@ -40,9 +40,9 @@ Here we present: * `NeoPixels -- 5050 RGB LEDs with Integrated Drivers (Falcon Christmas) <http://falconchristmas.com>`_ * `RGB LED Matrix (Falcon Christmas) <http://falconchristmas.com>`_ * `simpPRU -- A python-like language for programming the PRUs`_ <https://github.com/VedantParanjape/simpPRU> -.. * `MachineKit <http://www.machinekit.io/>`_ -.. * `ArduPilot <http://ardupilot.org/>, <http://ardupilot.org/dev/docs/beaglepilot.html>`_ -.. * `BeagleScope <https://github.com/ZeekHuge/BeagleScope>`_ +* `MachineKit <http://www.machinekit.io/>`_ +* `BeaglePilot <http://ardupilot.org/dev/docs/beaglepilot.html>`_ +* `BeagleScope <https://github.com/ZeekHuge/BeagleScope>`_ The following are resources used in this chapter. @@ -55,7 +55,7 @@ The following are resources used in this chapter. Robotics Control Library -------------------------- +************************** Robotics is an embedded application that often requires both an SBC to control the high-level tasks (such as path planning, line following, communicating with the user) @@ -70,7 +70,7 @@ in :ref:`<case_blue>`. .. _case_blue: Blue balancing -~~~~~~~~~~~~~~~ +=============== .. figure:: figures/blue.png :align: center @@ -85,17 +85,17 @@ addition real-time encoder input. The following examples show how easy it is to use the PRU for robotics. Controlling Eight Servos -************************* +========================= Problem -~~~~~~~~ +-------- You need to control eight servos, but the Bone doesn't have enough pulse width modulation (PWM) channels and you don't want to add hardware. Solution -~~~~~~~~~ +--------- The Robotics Control Library provides eight additional PWM channels via the PRU that can be used out of the box. @@ -138,7 +138,7 @@ The ``-f 10`` says to use a frequency of 10 Hz and the ``-p 1.5`` says to set th rc_test_servo -c 1 -p 0.0 Discussion -~~~~~~~~~~~ +------------ The BeagleBone Blue sends these eight outputs to it's servo channels. The others use the pins shown in the :ref:`case__register_to_pin_table`. @@ -146,7 +146,7 @@ The BeagleBone Blue sends these eight outputs to it's servo channels. The other .. _case__register_to_pin_table: PRU register to pin table -~~~~~~~~~~~~~~~~~~~~~~~~~~ +--------------------------- .. table:: @@ -187,15 +187,15 @@ servos. All you have to do is run the command. .. [/opt/source/Robotics_Cape_Installer/pru_firmware/src/pru1-servo.asm] Controlling Individual Servos -****************************** +=============================== Problem -~~~~~~~~~ +-------- ``rc_test_servos`` is nice, but I need to control the servos individually. Solution -~~~~~~~~~ +--------- You can modify ``rc_test_servos.c``. You'll find it on the bone online at https://github.com/beagleboard/librobotcontrol/blob/master/examples/src/rc_test_servos.c. @@ -205,32 +205,32 @@ Just past line 250 you'll find a ``while`` loop that has calls to ``rc_servo_sen sets the width to an absolute time. Use whichever works for you. Controlling More Than Eight Channels -************************************* +===================================== Problem -~~~~~~~~~~ +-------- I need more than eight PWM channels, or I need less jitter on the off time. Solution -~~~~~~~~~~ +--------- This is a more advanced problem and required reprograming the PRUs. See :ref:`../05blocks/blocks.html#blocks_pwm, PWM Generator` for an example. Reading Hardware Encoders -************************** +========================== Problem -~~~~~~~~~~ +-------- I want to use four encoders to measure four motors, but I only see hardware for three. Solution -~~~~~~~~~~ +--------- -The forth encoder can be implemented on the PRU. If you run ``rc_test_encoders_eqep`` on the Blue, you will see the output of -encoders E1-E3 which are connected to the eEQP hardware. +The forth encoder can be implemented on the PRU. If you run ``rc_test_encoders_eqep`` +on the Blue, you will see the output of encoders E1-E3 which are connected to the eEQP hardware. .. code-block:: bash @@ -246,7 +246,8 @@ pins shown in :ref:`case_pin_mapping`. .. _case_pin_mapping: eQEP to pin mapping -~~~~~~~~~~~~~~~~~~~~ +-------------------- + .. table:: +----+--------+-----------+-----------+--------+--------+------------+-------------+ @@ -277,17 +278,18 @@ eQEP to pin mapping Reading PRU Encoder -********************* +===================== Problem -~~~~~~~~ +-------- I want to access the PRU encoder. Solution -~~~~~~~~~ +--------- The forth encoder is implemented on the PRU and accessed with `sudo rc_test_encoders_pru` + .. note:: This command needs root permission, so the `sudo` is needed. @@ -309,15 +311,15 @@ Here's what you will see BeagleLogic -- a 14-channel Logic Analyzer -------------------------------------------- +******************************************** Problem -******** +-------- I need a 100Msps, 14-channel logic analyzer Solution -********* +--------- `BeagleLogic <https://beaglelogic.readthedocs.io/en/latest/>`_ is a 100Msps, 14-channel logic analyzer that runs on the Beagle. @@ -335,8 +337,8 @@ Solution https://github.com/abhishek-kakkar/BeagleLogic/wiki -The quickest solution is to get the `no-setup-required image <https://github.com/abhishek-kakkar/BeagleLogic/wiki/BeagleLogic-%22no-setup-required%22-setup:-Introducing-System-Image!>`_. It points to an older image -(beaglelogic-stretch-2017-07-13-4gb.img.xz) but should still work. +The quickest solution is to get the `no-setup-required image <https://github.com/abhishek-kakkar/BeagleLogic/wiki/BeagleLogic-%22no-setup-required%22-setup:-Introducing-System-Image!>`_. +It points to an older image (beaglelogic-stretch-2017-07-13-4gb.img.xz) but should still work. If you want to be running a newer image, there are instructions on the site for `installing BeagleLogic <https://beaglelogic.readthedocs.io/en/latest/install.html>`_, but I had to do the additional steps in :ref:`case_installing_beaglelogic`. @@ -345,7 +347,7 @@ If you want to be running a newer image, there are instructions on the site for .. _case_installing_beaglelogic: Installing BeagleLogic -~~~~~~~~~~~~~~~~~~~~~~~ +======================= .. code-block:: bash @@ -366,7 +368,7 @@ Then click *Begin Capture* to capture your data, at up to 100 MHz! .. _case_beaglelogic_capture: BeagleLogic Data Capture -~~~~~~~~~~~~~~~~~~~~~~~~~ +========================== .. figure:: figures/beaglelogic_capture.png :align: center @@ -374,7 +376,7 @@ BeagleLogic Data Capture Discussion -************ +----------- BeagleLogic is a complete system that includes firmware for the PRUs, a kernel module and a web interface that create a powerful 100 MHz @@ -434,10 +436,10 @@ explaining how the PRUs get this type of performance. NeoPixels -- 5050 RGB LEDs with Integrated Drivers (Falcon Christmas) ----------------------------------------------------------------------- +*********************************************************************** Problem -********* +-------- You have an `Adafruit NeoPixel LED string <http://www.adafruit.com/products/1138>`_, `Adafruit NeoPixel LED matrix <http://www.adafruit.com/products/1487>`_ or @@ -448,7 +450,7 @@ and want to light it up. .. TODO Show how to drive ws2812's with FPP. Solution -********* +--------- If you are driving just one string you can write your own code (See :ref:`../05blocks/blocks.adoc#blocks_ws2812, WS2812 Driver`) @@ -460,7 +462,7 @@ set up for the integrated drive and in the next section the no driver LEDs will show. Hardware -********* +---------- For this setup we'll wire a single string of NeoPixels to the Beagle. I've attached the black wire on the string to ground on the Beagle @@ -475,7 +477,7 @@ line 27. It's the 20th entry in the list. You could pick any of the others if you'd rather. Software Setup -*************** +--------------- Assuming the PocketBeagle is attached via the USB cable, on your host computer browse to <http://192.168.7.2/> and you will see @@ -483,35 +485,32 @@ on your host computer browse to <http://192.168.7.2/> and you will see .. _case_fpp_program_control2: -Falcon Play Program Control -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_program_control.png :align: center :alt: Falcon Play Program Control + Falcon Play Program Control + You can test the display by first setting up the Channel Outputs and then going to *Display Testing*. :ref:`case_channel_outputs_menu2` shows where to select Channel Outputs and :ref:`case_channel_outputs2` shows which settings to use. .. _case_channel_outputs_menu2: -Selecting Channel Outputs -~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_channel_outputs_menu.png :align: center :alt: Selecting Channel Outputs -.. _case_channel_outputs2: + Selecting Channel Outputs -Channel Outputs Settings -~~~~~~~~~~~~~~~~~~~~~~~~~ +.. _case_channel_outputs2: .. figure:: figures/fpp_channel_outputs_strings.png :align: center :alt: Channel Outputs Settings + Channel Outputs Settings + Click on the *Pixel Strings* tab. Earlier we noted that *P1.31* is attached to port 20. Note that at the bottom of the screen, port 20 has a PIXEL COUNT of 24. We're telling FPP our string has 24 NeoPixels and they are attached @@ -524,13 +523,12 @@ Next we need to test the display. Select **Display Testing** shown in .. _case_display_testing_menu2: -Selecting Display Testing -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_display_testing_menu2.png :align: center :alt: Selecting Display Testing + Selecting Display Testing + Set the *End Channel* to *72*. (72 is 3*24) Click *Enable Test Mode* and your matrix should light up. Try the different testing patterns shown in :ref:`case_display_testing2`. @@ -544,13 +542,12 @@ testing patterns shown in :ref:`case_display_testing2`. .. _case_display_testing2: -Display Testing Options -~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_display_testing2.png :align: center :alt: Display Testing Options + Display Testing Options + You can control the LED string using the E1.31 protocol. (https://www.doityourselfchristmas.com/wiki/index.php?title=E1.31_(Streaming-ACN)_Protocol) First configure the input channels by going to Channel Inputs as shown in @@ -558,54 +555,52 @@ First configure the input channels by going to Channel Inputs as shown in .. _case_channel_inputs: -Going to Channel Inputs -~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_channel_inputs.png :align: center :alt: Going to Channel Inputs + Going to Channel Inputs + Tell it you have 72 LEDs and enable the input as shown in :ref:`case_set_inputs`. .. _case_set_inputs: -Setting Channel Inputs -~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_inputs_setup2.png :align: center :alt: Setting Channel Inputs + Setting Channel Inputs + Finally go to the Status Page as shown in :ref:`case_status`. .. _case_status: -Watching the status -~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_status.png :align: center :alt: Watching Status + Watching the status + Now run a program on another computer that generated E1.31 packets. :ref:`case_1.31_example` is an example python program. .. _cse_e1.31_example: -.e1.31-test.py -~~~~~~~~~~~~~~ +.. literalinclude:: code/e1.31-test.py + :caption: e1.31-test.py -Example of generating packets to control the NeoPixels + :linenos: -:downlod:`e1.31-test.py <code/e1.31-test.py>`- Example of generating packets to control the NeoPixels +:download:`e1.31-test.py <code/e1.31-test.py>` .. TODO document the code .. _case_rgb_matrix: RGB LED Matrix -- No Integrated Drivers (Falcon Christmas) ------------------------------------------------------------ +************************************************************ Problem -************************* +-------- You want to use a RGB LED Matrix display that doesn't have integrated drivers such as the @@ -615,19 +610,17 @@ shown in :ref:`case_adfruit_matrix`. .. _case_adfruit_matrix: Adafruit LED Matrix -~~~~~~~~~~~~~~~~~~~~~ +===================== .. figure:: figures/ledmatrix.jpg :align: center :alt: Adafruit LED Matrix Solution -************************* +--------- -`Falcon Christmas <http://falconchristmas.com>`_ makes a software package -called -`Falcon Player <http://falconchristmas.com/forum/index.php/board,8.0.html>`_ (FPP) which can drive -such displays. +`Falcon Christmas <http://falconchristmas.com>`_ makes a software package called +`Falcon Player <http://falconchristmas.com/forum/index.php/board,8.0.html>`_ (FPP) which can drive such displays. .. admonition:: information: @@ -642,7 +635,7 @@ such displays. http://www.falconchristmas.com/wiki/FPP:FAQ#What_is_FPP.3F Hardware -~~~~~~~~~ +--------- The Beagle hardware can be either a BeagleBone Black with the `Octoscroller Cape <https://oshpark.com/shared_projects/7mSHNZcD>`_, or a @@ -658,20 +651,18 @@ to full white at the same time you will need at least a 4A supply. .. _case_pocket: -Pocket Beagle Driving a P5 RGB LED Matrix via the PocketScroller Cape -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/pocketscroller.jpg :align: center :alt: Pocket Beagle Driving a P5 RGB LED Matrix via the PocketScroller Cape + Pocket Beagle Driving a P5 RGB LED Matrix via the PocketScroller Cape Software -~~~~~~~~~~ +--------- The FPP software is most easily installed by downloading the -`current FPP release <https://github.com/FalconChristmas/fpp/releases/>`_, flashing an SD card and -booting from it. +`current FPP release <https://github.com/FalconChristmas/fpp/releases/>`_, +flashing an SD card and booting from it. .. tip:: @@ -698,53 +689,48 @@ select Channel Outputs and :ref:`case_channel_outputs` shows which settings to u .. _case_channel_outputs_menu: -Selecting Channel Outputs -~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_channel_outputs_menu.png :align: center :alt: Selecting Channel Outputs -.. _case_channel_outputs: + Selecting Channel Outputs -Channel Outputs Settings -~~~~~~~~~~~~~~~~~~~~~~~~~ +.. _case_channel_outputs: .. figure:: figures/fpp_channel_outputs.png :align: center :alt: Channel Outputs Settings -Click on the **LED Panels** tab and then the only changes I made was -to select the **Single Panel Size** to be -*64x32* and to check the **Enable LED Panel Output**. + Channel Outputs Settings + +Click on the **LED Panels** tab and then the only changes I made was to select the +**Single Panel Size** to be *64x32* and to check the **Enable LED Panel Output**. Next we need to test the display. Select *Display Testing* shown in :ref:`case_display_testing_menu`. .. _case_display_testing_menu: -Selecting Display Testing -~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_display_testing_menu.png :align: center :alt: Selecting Display Testing + Selecting Display Testing + Set the **End Channel** to **6144**. (6144 is 3*64*32) Click **Enable Test Mode** and your matrix should light up. Try the different testing patterns shown in :ref:`case_display_testing`. .. _case_display_testing: -Display Testing Options -~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_display_testing.png :align: center :alt: Display Testing Options + Display Testing Options + xLights - Creating Content for the Display -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +=========================================== Once you are sure your LED Matrix is working correctly you can program it with a sequence. @@ -776,13 +762,12 @@ Run xLights and you'll see :ref:`case_xlights_setup`. .. _case_xlights_setup: -xLights Setup -~~~~~~~~~~~~~~ - .. figure:: figures/xlights_setup.png :align: center :alt: xLights Setup + xLights Setup + We'll walk you through a simple setup to get an animation to display on the RGB Matrix. xLights can use a protocol called E1.31 to send information to the display. Setup xLights by clicking on *Add Ethernet* and entering the values @@ -790,13 +775,12 @@ shown in :ref:`case_xlights_setup_e1_31`. .. _case_xlights_setup_e1_31: -Setting Up E1.31 -~~~~~~~~~~~~~~~~~ - .. figure:: figures/xlights_setup_e1_31.png :align: center :alt: Setting Up E1.31 + Setting Up E1.31 + The **IP Address** is the Bone's address as seen from the host computer. Each LED is one channel, so one RGB LED is three channels. The P5 board has 3*64*32 or 6144 channels. These are grouped into universes of 512 @@ -809,37 +793,34 @@ Your setup should look like :ref:`case_xlights_setup_done`. Click the .. _case_xlights_setup_done: -xLights setup for P5 display -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/xlights_setup_done.png :align: center :alt: xLights setup for P5 display + xLights setup for P5 display + Next click on the **Layout** tab. Click on the *Matrix* button as shown in :ref:`case_xlights_matrix`, then click on the black area where you want your matrix to appear. .. _case_xlights_matrix: -Setting up the Matrix Layout -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/xlights_layout.png :align: center :alt: Setting up the Matrix Layout + Setting up the Matrix Layout + :ref:`case_xlights_layout_details` shows the setting to use for the P5 matrix. .. _case_xlights_layout_details: -Layout details for P5 matrix -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/xlights_layout_details.png :align: center :alt: Layout details for P5 matrix + Layout details for P5 matrix + All I changed was **# Strings**, **Nodes/String**, **Starting Location** and most importantly, expand **String Properties** and select at **String Type** of **RGB Nodes**. Above the setting you should see that **Start Chan** is 1 and @@ -851,19 +832,18 @@ Now click on the *Sequencer* tab and then click on the **New Sequence** button .. _case_seq_new: -Starting a new sequence -~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/xlights_seq_new.png :align: center :alt: Starting a new sequence + Starting a new sequence + Then click on **Animation**, **20fps (50ms)**, and **Quick Start**. Learning how to do sequences is beyond the scope of this cookbook, however I'll shown you how do simple sequence just to be sure xLights is talking to the Bone. Setting Up E1.31 on the Bone -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +============================== First we need to setup FPP to take input from xLights. Do this by going to the *Input/Output Setup* menu and selecting *Channel Inputs*. Then @@ -872,13 +852,12 @@ enter *12* for *Universe Count* and click *set* and you will see .. _case_inputs_setup: -E1.31 Inputs -~~~~~~~~~~~~~ - .. figure:: figures/fpp_inputs_setup.png :align: center :alt: .E1.31 Inputs + E1.31 Inputs + Click on the **Save** button above the table. Then go to the **Status/Control** menu and select **Status Page**. @@ -887,15 +866,14 @@ Then go to the **Status/Control** menu and select **Status Page**. .. _case_mode_bridge: -Bridge Mode -~~~~~~~~~~~~~ - .. figure:: figures/fpp_mode_bridge.png :align: center :alt: Bridge Mode + Bridge Mode + Testing the xLights Connection -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +=============================== The Bone is now listening for commands from xLights via the E1.31 protocol. A quick way to verify everything is t o return to xLights and go to the @@ -903,28 +881,26 @@ A quick way to verify everything is t o return to xLights and go to the .. _case_xlights_test: -xLights test page -~~~~~~~~~~~~~~~~~~ - .. figure:: figures/xlights_test.png :align: center :alt: xLights test page + xLights test page + Click the box under **Select channels...**, click **Output to lights** and select **Twinkle 50%**. You matrix should have a colorful twinkle pattern (:ref:`case_xlights_twinkle`). .. _case_xlights_twinkle: -xLights Twinkle test pattern -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/xlights_twinkle.jpg :align: center :alt: xLights Twinkle test pattern + xLights Twinkle test pattern + A Simple xLights Sequence -~~~~~~~~~~~~~~~~~~~~~~~~~~ +========================== Now that the xLights to FPP link is tested you can generate a sequence to play. Close the Test window and click on the **Sequencer** tab. Then drag @@ -935,19 +911,18 @@ toolbar. Your matrix should now be displaying your effect. .. _case_seq_drag: -Drag an effect to the timeline -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/xlights_seq_drag.png :align: center :alt: Drag an effect to the timeline + Drag an effect to the timeline + The setup requires the host computer to send the animation data to the Bone. The next section shows how to save the sequence and play it on the Bone standalone. Saving a Sequence and Playing it Standalone -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +============================================ In xLights save your sequence by hitting Ctrl-S and giving it a name. I called mine *fire* since I used a fire effect. Now, switch back to FPP and select @@ -957,13 +932,12 @@ the *Content Setup* menu and select *File Manager*. Click the black .. _case_file_manager: -FPP file manager -~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_file_manager.png :align: center :alt: FPP file manager + FPP file manager + Once your sequence is uploaded, got to **Content Steup** and select **Playlists**. Enter you playlist name (I used **fire**) and click **Add**. Then click **Add a Sequence/Entry** and select **Sequence Only** @@ -971,13 +945,12 @@ Enter you playlist name (I used **fire**) and click **Add**. Then click .. _case_playlist: -Adding a new playlist to FPP -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_playlist.png :align: center :alt: Adding a new playlist to FPP + Adding a new playlist to FPP + Be sure to click **Save Playlist** on the right. Now return to **Status/Control** and **Status Page** and make sure **FPPD Mode:** is set to **Standalone**. You should see your playlist. Click the **Play** @@ -985,19 +958,18 @@ button and your sequence will play. .. _case_playlist_status: -Adding a new playlist to FPP -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/fpp_playlist_status.png :align: center :alt: Playing a playlist + Adding a new playlist to FPP + The beauty of the PRU is that the Beagle can play a detailed sequence at 20 frames per second and the ARM procossor is only 15% used. The PRUs are doing all the work. simpPRU -- A python-like language for programming the PRUs ------------------------------------------------------------ +=========================================================== `simpPRU <https://github.com/VedantParanjape/simpPRU>`_ is a simple, python-like programming languge designed to make programming the PRUs easy. @@ -1029,8 +1001,9 @@ Now, suppose you wanted to run the `LED blink <https://simppru.readthedocs.io/en/latest/examples/led_blink/>`_ example which is reproduced here. -LED Blink (blink.sim) -~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/blink.sim + :caption: LED Blink (blink.sim) + :linenos: :download:`blink.sim <code/blink.sim>` @@ -1046,7 +1019,7 @@ Just run simppru Current mode for P1_31 is: pruout Detected TI AM335x PocketBeagle --------------------------------- +================================ The +--load+ flag caused the compiled code to be copied to +/lib/firmware+. To start just do: @@ -1064,16 +1037,14 @@ Your LED should now be blinking. Check out the many examples (https://simppru.readthedocs.io/en/latest/examples/led_blink/). -simpPRU Examples -~~~~~~~~~~~~~~~~ - .. figure:: figures/LEDblink.png :align: center :alt: simpPRU Examples + simpPRU Examples MachineKit ------------ +=========== `MachineKit <http://www.machinekit.io/>`_ is a platform for machine control applications. It can control machine tools, robots, or other automated devices. It can control servo @@ -1120,3 +1091,7 @@ multi-copters, traditional helicopters, fixed wing aircraft and rovers. ArduPilo colleges and universities around the world. http://www.machinekit.io/about/ + +.. rubric:: Footnotes + +.. [#] Four if you are on the BeagleBone AI diff --git a/books/pru-cookbook/02start/start.rst b/books/pru-cookbook/02start/start.rst index dee7273d..1150f223 100644 --- a/books/pru-cookbook/02start/start.rst +++ b/books/pru-cookbook/02start/start.rst @@ -13,15 +13,15 @@ code (and the whole book) on the PRU Cookbook github site: https://github.com/MarkAYoder/PRUCookbook. Selecting a Beagle -==================== +******************** Problem ----------- +-------- Which Beagle should you use? Solution ----------- +--------- http://beagleboard.org/boards lists the many Beagles from which to choose. Here we'll give examples for the venerable `BeagleBone Black <http://beagleboard.org/black>`_, @@ -41,13 +41,12 @@ member of the open hardware Beagle family. .. _start_black: -BeagleBone Black -~~~~~~~~~~~~~~~~~ - .. figure:: figures/product_detail_black_sm.jpg :align: center :alt: BeableBone Black + BeagleBone Black + The Black has: * AM335x 1GHz ARM® Cortex-A8 processor @@ -71,13 +70,12 @@ The `Blue <http://beagleboard.org/blue>`_ is a good choice if you are doing robo .. _start_blue: -BeagleBone Blue -~~~~~~~~~~~~~~~~ - .. figure:: figures/beagle-blue.png :align: center :alt: BeagleBone Blue + BeagleBone Blue + The Blue has everything the Black has except it has no Ethernet or HDMI. But it also has: @@ -94,13 +92,12 @@ https://www.renaissancerobotics.com/eduMIP.html[EduMIP kit] as shown in .. _start_edumip: -BeagleBone Blue EduMIP Kit -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/edumip.png :align: center :alt: BeagleBone Blue EduMIP Kit + BeagleBone Blue EduMIP Kit + https://www.hackster.io/53815/controlling-edumip-with-ni-labview-2005f8 shows how to assemble the robot and control it from `LabVIEW <http://www.ni.com/en-us/shop/labview.html>`_. @@ -114,13 +111,12 @@ compatible with the other Beagles. .. _start_pocket: -PocketBeagle -~~~~~~~~~~~~~ - .. figure:: figures/PocketBeagle-size-compare-small.jpg :align: center :alt: PocketBeagle + PocketBeagle + The Pocket is based on the same processor as the Black and Blue and has: * 8 analog inputs @@ -130,19 +126,18 @@ The Pocket is based on the same processor as the Black and Blue and has: See http://beagleboard.org/pocket for more details. BeagleBone AI -~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~ If you want to do deep learning, try the `BeagleBone AI <http://beagleboard.org/ai>`_. .. _start_ai: -BeagleBone AI -~~~~~~~~~~~~~~ - .. figure:: figures/BB_AI_BeautyAngle_800px.jpg :align: center :alt: BeableBone AI + BeagleBone AI + The AI has: * Dual Arm® Cortex®-A15 microprocessor subsystem @@ -163,7 +158,7 @@ The AI has: Installing the Latest OS on Your Bone -====================================== +**************************************** Problem --------- @@ -185,17 +180,16 @@ one for all the other Beagles ( `AM3358 Debian 10.3 2020-04-06 4GB SD IoT <https://debian.beagleboard.org/images/bone-debian-10.3-iot-armhf-2020-04-06-4gb.img.xz>`_). Download the one for your Beagle. -Latest Debian images -~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/latest-images.png :align: center :alt: Latest Debian images + Latest Debian images + It contains all the packages we'll need. Flashing a Micro SD Card -========================= +************************* Problem --------- @@ -215,17 +209,16 @@ button and wait for it to finish. .. _start_etcher: -Etcher -~~~~~~~~ - .. figure:: figures/etcher.png :align: center :alt: Ether + Etcher + Once the SD is flashed, insert it in the Beagle and power it up. Cloud9 IDE -=========== +*********** Problem ------------ @@ -241,13 +234,12 @@ a web-based intergrated development environment (IDE) as shown in .. _start_c9: -Cloud9 IDE -~~~~~~~~~~~~ - .. figure:: figures/c9.png :align: center :alt: The Cloud9 IDE + Cloud9 IDE + Just point the browswer on your host computer to http://192.168.7.2 and start exploring. If you want the files in your home directory to appear in the tree structure click the settings gear and select *Show Home in Favorites* @@ -255,13 +247,12 @@ as shown in :ref:`start_c9_show_home`. .. _start_c9_show_home: -Cloud9 Showing Home files -~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/c9ShowHome.png :align: center :alt: Cloud9 showing home files + Cloud9 Showing Home files + If you want to edit files beyond your home directory you can link to the root file system by: @@ -277,7 +268,7 @@ If you want to edit files beyond your home directory you can link to the root fi Now you can reach all the files from Cloud9. Getting Example Code -==================== +********************** Problem --------- @@ -302,7 +293,8 @@ it on your Beagle and then look in the *docs* directory. 04debug/ 08ai/ common/ index.adoc notes.html style.html -Each chapter has its own directory and within that directory is a **code** directory that has all of the code. +Each chapter has its own directory and within that directory +is a **code** directory that has all of the code. .. code-block::bash @@ -313,7 +305,7 @@ Each chapter has its own directory and within that directory is a **code** direc Go and explore. Blinking an LED -================= +***************** Problem --------- @@ -330,8 +322,9 @@ is some code that blinks the ``USR3`` LED ten times using the PRU. .. _start_hello: -hello.pru0.c -~~~~~~~~~~~~~ +.. literalinclude:: code/hello.pru0.c + :caption: hello.pru0.c + :linenos: :download:`hello.pru0.c <code/hello.pru0.c>` diff --git a/books/pru-cookbook/03details/details.rst b/books/pru-cookbook/03details/details.rst index 24aa20a4..5bc99bbb 100644 --- a/books/pru-cookbook/03details/details.rst +++ b/books/pru-cookbook/03details/details.rst @@ -20,7 +20,7 @@ compile code and also start and stop the PRUs. Getting Example Code -===================== +********************** Problem --------- @@ -44,8 +44,7 @@ It's all on a GitHub repository. Compiling with clpru and lnkpru -================================ - +******************************** Problem --------- @@ -64,6 +63,7 @@ They are called ``clpru`` and ``lnkpru``. Do the following to see if ``clpru`` /usr/bin/clpru .. tip:: + If ``clpru`` isn't installed, follow the instructions at https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#TI_PRU_Code_Generation_Tools to install it. @@ -83,6 +83,7 @@ In fact there are PRU versions of many of the standard code generation tools. code tools ~~~~~~~~~~~ + .. code-block:: bash bone$ ls /usr/bin/*pru @@ -95,7 +96,7 @@ code tools See the `PRU Assembly Language Tools <http://www.ti.com/lit/ug/spruhv6b/spruhv6b.pdf>`_ for more details. Making sure the PRUs are configured -==================================== +************************************* Problem --------- @@ -130,7 +131,7 @@ Uncomment the ``uboot_overlay`` line as shown and then reboot. 0 lrwxrwxrwx 1 root root 33 Jul 29 16:12 pruss-core1 -> /sys/class/remoteproc/remoteproc2 Compiling and Running -====================== +********************** Problem --------- @@ -203,6 +204,7 @@ You can override the ``TARGET`` on the command line. Notice the ``TARGET`` doesn't have the ``.c`` on the end. You can also specify them when running ``make``. + .. code-block:: bash bone$ cp gpio.pru0.c gpio.pru1.c @@ -211,8 +213,10 @@ You can also specify them when running ``make``. The setup file also contains instructions to figure out which Beagle you are running and then configure the pins acordingly. -setup.sh -~~~~~~~~~ + +.. literalinclude:: code/gpio_setup.sh + :caption: gpio_setup.sh + :linenos: :download:`gpio_setup.sh <code/gpio_setup.sh>` @@ -240,7 +244,7 @@ The ``Makefile`` stops the PRU, compiles the file and moves it where it will be loaded, and then restarts the PRU. Stopping and Starting the PRU -============================== +******************************* Problem --------- @@ -278,7 +282,7 @@ If you want to control the other PRU use: .. _details_makefile: The Standard Makefile -===================== +********************** Problem --------- @@ -299,8 +303,9 @@ It's assumed you already know how Makefiles work. If not, there are many resources online that can bring you up to speed. Here is the local ``Makefile`` used throughout this book. -Local Makefile -~~~~~~~~~~~~~~~ +.. literalinclude:: code/Makefile + :caption: Local Makefile + :linenos: :download:`Makefile <code/Makefile>` @@ -312,7 +317,7 @@ Fortunately you shouldn't have to modify the `Makefile`. .. _detail_linker: The Linker Command File - am335x_pru.cmd -========================================= +****************************************** Problem @@ -328,8 +333,10 @@ where to put what for the BeagleBone Black and Blue, and the Pocket. The ``am57xx_pru.cmd`` does the same for the AI. Both files can be found in ``/var/lib/cloud9/common``. -am335x_pru.cmd -~~~~~~~~~~~~~~~~ + +.. literalinclude:: code/am335x_pru.cmd + :caption: am335x_pru.cmd + :linenos: :download:`am335x_pru.cmd <code/am335x_pru.cmd>` @@ -340,44 +347,44 @@ The cmd file for the AI is about the same, with appropriate addresses for the AI Discussion ----------- - The important things to notice in the file are given in the following table. AM335x_PRU.cmd important things ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .. table:: - +-----+-----------------------------------------------------------------------------------------+ - |Line | Explanation | - +=====+=========================================================================================+ - |16 | This is where the instructions are stored. See page 206 of the | + +-----+------------------------------------------------------------------------------------------------+ + |Line | Explanation | + +=====+================================================================================================+ + |16 | This is where the instructions are stored. See page 206 of the | | | `AM335x Technical Reference Manual rev. P <https://www.ti.com/lit/ug/spruh73p/spruh73p.pdf>`_ | - | | Or see page 417 of | - | | `AM572x Technical Reference Manual <http://www.ti.com/lit/pdf/spruhz6l>`_ for the AI. | - +-----+-----------------------------------------------------------------------------------------+ - |22 | This is where PRU 0's DMEM 0 is mapped. It's also where PRU 1's | - | | DMEM 1 is mapped. | - +-----+-----------------------------------------------------------------------------------------+ - |23 | The reverse to above. PRU 0's DMEM 1 appears here and PRU 1's DMEM 0 | - | | is here. | - +-----+-----------------------------------------------------------------------------------------+ - |26 | The shared memory for both PRU's appears here. | - +-----+-----------------------------------------------------------------------------------------+ - |72 | The `.text` section is where the code goes. It's mapped to `IMEM` | - +-----+-----------------------------------------------------------------------------------------+ - |73 | The ((stack)) is then mapped to DMEM 0. Notice that DMEM 0 is one bank | - +-----+-----------------------------------------------------------------------------------------+ - | | of memory for PRU 0 and another for PRU1, so they both get their own stacks. | - +-----+-----------------------------------------------------------------------------------------+ - |74 | The `.bss` section is where the **heap** goes. | - +-----+-----------------------------------------------------------------------------------------+ + | | Or see page 417 of | + | | `AM572x Technical Reference Manual <http://www.ti.com/lit/pdf/spruhz6l>`_ for the AI. | + +-----+------------------------------------------------------------------------------------------------+ + |22 | This is where PRU 0's DMEM 0 is mapped. It's also where PRU 1's | + | | DMEM 1 is mapped. | + +-----+------------------------------------------------------------------------------------------------+ + |23 | The reverse to above. PRU 0's DMEM 1 appears here and PRU 1's DMEM 0 | + | | is here. | + +-----+------------------------------------------------------------------------------------------------+ + |26 | The shared memory for both PRU's appears here. | + +-----+------------------------------------------------------------------------------------------------+ + |72 | The `.text` section is where the code goes. It's mapped to `IMEM` | + +-----+------------------------------------------------------------------------------------------------+ + |73 | The ((stack)) is then mapped to DMEM 0. Notice that DMEM 0 is one bank | + +-----+------------------------------------------------------------------------------------------------+ + | | of memory for PRU 0 and another for PRU1, so they both get their own stacks. | + +-----+------------------------------------------------------------------------------------------------+ + |74 | The `.bss` section is where the **heap** goes. | + +-----+------------------------------------------------------------------------------------------------+ Why is it important to understand this file? If you are going to store things in DMEM, you need to be sure to start at address 0x0200 since the **stack** and the **heap** are in the locations below 0x0200. Loading Firmware -================== +***************** Problem --------- @@ -441,7 +448,7 @@ Therefore you copy your ``.out`` file to ``/lib/firmware/am335x-pru0-fw``. .. _details_configure_servos: Configuring Pins for Controlling Servos -======================================== +**************************************** Problem --------- @@ -455,8 +462,10 @@ It depends on which Beagle you are running on. If you are on the AI or Blue, everything is already configured for you. If you are on the Black or Pocket you'll need to run the following script. -servos_setup.sh -~~~~~~~~~~~~~~~~ + +.. literalinclude:: code/servos_setup.sh + :caption: servos_setup.sh + :linenos: :download:`servos_setup.sh <code/servos_setup.sh>` @@ -470,7 +479,7 @@ assigns ``pins`` a list of pins to configure. Then the last part of the script .. _details_configure_encoders: Configuring Pins for Controlling Encoders -========================================== +********************************************* Problem --------- @@ -484,7 +493,9 @@ It depends on which Beagle you are running on. If you are on the AI or Blue, everything is already configured for you. If you are on the Black or Pocket you'll need to run the following script. -.encoder_setup.sh +.. literalinclude:: code/encoder_setup.sh + :caption: encoder_setup.sh + :linenos: :download:`encoder_setup.sh <code/encoder_setup.sh>` diff --git a/books/pru-cookbook/04debug/debug.rst b/books/pru-cookbook/04debug/debug.rst index 7887b96c..077951e3 100644 --- a/books/pru-cookbook/04debug/debug.rst +++ b/books/pru-cookbook/04debug/debug.rst @@ -13,7 +13,7 @@ Finally, using one of the UARTS to send debugging information out a serial port is shown. Debugging via an LED -===================== +********************** Problem --------- @@ -28,17 +28,16 @@ flash. :ref:`debug_LED` shows an LED attached to pin P9_29 of the BeagleBone Bla .. _debug_LED: -LED used for debugging P9_29 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/LED_bb.png :align: center :alt: LED used for debugging P9_29 + LED used for debugging P9_29 + Make sure you have the LED in the correct way, or it won't work. Discussion ---------- +----------- If your output is changing more than a few times a second, the LED will be blinking too fast and you'll need an oscilloscope or a logic analyzer to @@ -50,7 +49,7 @@ RAM is discussed in :ref:`debug_prudebug`. .. _dmesg_hw: dmesg Hw -========= +*********** Problem --------- @@ -60,16 +59,16 @@ when I load my code, but don't know what's causing it. Solution --------- + The command ``dmesg`` outputs useful information when dealing with the kernel. Simplying running ``dmesg -Hw`` can tell you a lot. The ``-H`` flag puts the dates in the human readable form, the ``-w`` tells it to wait for more information. Often I'll have a window open running ``dmesg -Hw``. -. Here's what ``dmesg`` said for the example above. dmesg -Hw -~~~~~~~~~~ +********** .. code-block:: bash @@ -83,7 +82,7 @@ to my code. .. _debug_prudebug: prudebug - A Simple Debugger for the PRU -========================================= +****************************************** Problem --------- @@ -200,10 +199,7 @@ restart back at the beginning. The ``dd`` command dumps the memory. Keep in mind the following. -Important memory locations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: Important memory locations +-------+---------------------------------------------------------------------------+ |Address|Contents | @@ -279,7 +275,7 @@ of how you can control where your vaiables are stored in memory. UART -====== +****** Problem --------- @@ -304,37 +300,32 @@ you can get such a cable from places such as .. _debug_ftdi: -FTDI cable -~~~~~~~~~~~ - .. figure:: figures/FTDIcable.jpg :align: center :alt: FTDI cable + FTDI cable + Discussion ---------- +----------- The Beagle side of the FTDI cable has a small triangle on it as shown in :ref:`debug_ftdi_connector` which marks the ground pin, pin 1. .. _debug_ftdi_connector: -FTDI connector -~~~~~~~~~~~~~~~~~ - .. figure:: figures/FTDIconnector.jpg :align: center :alt: FTDI connector + FTDI connector + The :ref:`debug_FTDI` table shows which pins connect where and :ref:`debug_ftdi_pins` is a wiring diagram for the BeagleBone Black. .. _debug_FTDI: -Wriing for FTDI cable to Beagle -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: Wriing for FTDI cable to Beagle +--------+------+---------+-------------+--------+------+---------+ |FTDI pin|Color |Black pin|AI 1 pin |AI 2 pin|Pocket|Function | @@ -348,15 +339,14 @@ Wriing for FTDI cable to Beagle .. _debug_ftdi_pins: -FTDI to BB Black -~~~~~~~~~~~~~~~~~ - .. figure:: figures/FTDIhookup_bb.png :align: center :alt: FTDI to BB Black + FTDI to BB Black + Details -~~~~~~~~ +-------- Two examples of using the UART are presented here. The first (:ref:`debug_uart1`) sends a character out the serial port then @@ -375,7 +365,7 @@ Once an ENTER appears the string is sent back. You need to set the pin muxes. config-pin -~~~~~~~~~~~ +----------- .. code-block:: bash @@ -402,15 +392,16 @@ For example .. * TODO - Add code for Blue. -uart1.pru1_0.c -~~~~~~~~~~~~~~~ +.. literalinclude:: code/uart1.pru1_0.c + :caption: uart1.pru1_0.c + :linenos: -Set the following variables so ``make`` will know what to compile. +:download:`uart1.pru1_0.c <code/uart1.pru1_0.c>` -make -~~~~~ +Set the following variables so ``make`` will know what to compile. .. code-block:: bash + :caption: make bone$ *make TARGET=uart1.pru0* /var/lib/cloud9/common/Makefile:29: MODEL=TI_AM335x_BeagleBone_Black,TARGET=uart1.pru0 @@ -433,19 +424,19 @@ In a terminal window on your host computer run It will initially display the first charters (``H``) and then as you enter characters on the keyboard, the rest of the message will appear. -uart1.pru0.c output -~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/uart1.pru0.png :align: center :alt: uart1.pru0.c output + uart1.pru0.c output + Here's the code (``uart1.pru1_0.c``) that does it. .. _debug_uart1: -uart1.pru1_0.c -~~~~~~~~~~~~~~~ +.. literalinclude:: code/uart1.pru1_0.c + :caption: uart1.pru1_0.c + :linenos: :download:`uart1.pru1_0.c <code/uart1.pru1_0.c>` @@ -472,15 +463,16 @@ receive register on the UART. These simple lines should be enough to place in your code to print out debugging information. -uart2.pru0.c -~~~~~~~~~~~~ +.. literalinclude:: code/uart2.pru0.c + :caption: uart2.pru0.c + :linenos: -If you want to try ``uart2.pru0.c``, run the following: +:download:`uart2.pru0.c <code/uart2.pru0.c>` -make -~~~~~ +If you want to try ``uart2.pru0.c``, run the following: .. code-block:: bash + :caption: make bone$ *make TARGET=uart2.pru0* /var/lib/cloud9/common/Makefile:29: MODEL=TI_AM335x_BeagleBone_Black,TARGET=uart2.pru0 @@ -495,13 +487,12 @@ make You will see: -uart2.pru0.c output -~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/uart2.pru0.png :align: center :alt: uart2.pru0.c output + uart2.pru0.c output + Type a few characters and hit ENTER. The PRU will playback what you typed, but it won't echo it as you type. @@ -514,8 +505,9 @@ wait for the FIFO to empty, which may cause your code to miss something. .. _debug_uart2: -uart2.pru1_0.c -~~~~~~~~~~~~~~~ +.. literalinclude:: code/uart2.pru1_0.c + :caption: uart2.pru1_0.c + :linenos: :download:`uart2.pru1_0.c <code/uart2.pru1_0.c>` @@ -524,11 +516,12 @@ More complex examples can be built using the principles shown in these examples. Copyright ========== -copyright.c -~~~~~~~~~~~~~ +.. literalinclude:: code/copyright.c + :caption: copyright.c + :linenos: :download:`copyright.c <code/copyright.c>` .. rubric:: Footnotes -.. [#debug1] FTDI images are from the BeagleBone Cookbook http://shop.oreilly.com/product/0636920033899.do +.. [#debug1] `FTDI images are from the BeagleBone Cookbook <http://shop.oreilly.com/product/0636920033899.do>`_ diff --git a/books/pru-cookbook/05blocks/blocks.rst b/books/pru-cookbook/05blocks/blocks.rst index e6de06e3..18adbe14 100644 --- a/books/pru-cookbook/05blocks/blocks.rst +++ b/books/pru-cookbook/05blocks/blocks.rst @@ -17,7 +17,7 @@ Resources * `WS2812 Data Sheet <https://cdn-shop.adafruit.com/datasheets/WS2812.pdf>`_ Memory Allocation -================== +****************** Problem @@ -35,13 +35,12 @@ shared memory (Shared RAM) as shown in :ref:`blocks_PRU_block_diagram`. .. _blocks_PRU_block_diagram: -PRU Block Diagram -~~~~~~~~~~~~~~~~~~ - .. figure:: figures/blockDiagram.png :align: center :alt: PRU Block diagram + PRU Block Diagram + Each PRU accesses it's own DRAM starting at location 0x0000_0000. Each PRU can also access the other PRU's DRAM starting at 0x0000_2000. Both PRUs access the shared RAM at 0x0001_0000. The compiler can control where each @@ -51,8 +50,9 @@ of these memories variables are stored. .. _blocks_shared: -shared.pro0.c - Examples of Using Different Memory Locations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/shared.pru0.c + :caption: shared.pro0.c - Examples of Using Different Memory Locations + :linenos: :download:`shared.pru0.c <code/shared.pru0.c>` @@ -62,8 +62,7 @@ Discussion Here's the line-by-line -Line-byline for shared.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. table:: Line-byline for shared.pru0.c +-------+---------------------------------------------------------------------------------------------------------+ |Line | Explanation | @@ -155,9 +154,7 @@ therefore placed on the stack at run time. The ``shared.map`` file shows the compile time allocations. We have to look in the memory itself to see what happen at run time. -Let's fire up ``prudebug`` -(:ref:`../04debug/debug.html#debug_prudebug, prudebug - A Simple Debugger for the PRU`) -to see where things are. +Let's fire up ``prudebug`` (:ref:`debug_prudebug`) to see where things are. .. code-block:: bash @@ -233,10 +230,10 @@ be sure if you are hand picking where things are put, not to put them in places used by the compiler. Auto Initialization of built-in LED Triggers -============================================= +********************************************* Problem ------------ +--------- I see the built-in LEDs blink to their own patterns. How do I turn this off? Can this be automated? @@ -312,8 +309,9 @@ the code work. Fortunately the Makefile always runs it. .. _blocks_write_init_pins: -write_init_pins.sh -~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/write_init_pins.sh + :caption: write_init_pins.sh + :linenos: :download:`write_init_pins.sh <code/write_init_pins.sh>` @@ -338,7 +336,7 @@ file contains everything needed to run the executable. .. _blocks_pwm: PWM Generator -============== +************** One of the simplest things a PRU can to is generate a simple signal starting with a single channel PWM that has a fixed frequency and @@ -365,8 +363,9 @@ for details on making it work. .. _blocks_pwm1: -pwm1.pru0.c -~~~~~~~~~~~~ +.. literalinclude:: code/pwm1.pru0.c + :caption: pwm1.pru0.c + :linenos: :download:`pwm1.pru0.c <code/pwm1.pru0.c>` @@ -385,7 +384,7 @@ On the Pocket run .. note:: - See :ref:`../08ai/ai.html#ai_device_tree, Configuring pins on the AI via device trees` + See :ref:`ai_device_tree` for configuring pins on the AI. Then, tell ``Makefile`` which PRU you are compiling for and what your target file is @@ -417,17 +416,17 @@ Discussion Since this is our first example we'll discuss the many parts in detail. -pwm1.pru0.c -~~~~~~~~~~~~ +.. literalinclude:: code/pwm1.pru0.c + :caption: pwm1.pru0.c + :linenos: + +:download:`pwm1.pru0.c <code/pwm1.pru0.c>` :ref:`blocks_pwm1_line_by_line` is a line-by-line expanation of the c code. .. _blocks_pwm1_line_by_line: -Line-by-line of pwm1.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: Line-by-line of pwm1.pru0.c +-----+-------------------------------------------------------------------------------------+ |Line | Explanation | @@ -446,15 +445,13 @@ Line-by-line of pwm1.pru0.c Here's what's in ``resource_table_empty.h`` -resource_table_empty.c -~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/resource_table_empty.h + :caption: resource_table_empty.c + :linenos: -:download:`resource_table_empty.h <code/resource_table_empty.h>` +:download:`resource_table_empty.c <code/resource_table_empty.h>` -Line-by-line (continuted) -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: Line-by-line (continuted) +-----+-----------------------------------------------------------------------------------------------------------------+ |Line | Explanation | @@ -483,10 +480,7 @@ Bit 0 is the LSB. .. _blocks_mapping_bits: -Mapping bit positions to pin names -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: Mapping bit positions to pin names +---+---+---------------------+-----------+ |PRU|Bit|Black pin |Pocket pin | @@ -550,16 +544,14 @@ Mapping bit positions to pin names .. note:: - See :ref:`../08ai/ai.html#ai_device_tree, Configuring pins on the AI via device trees` + See :ref:`ai_device_tree` for all the PRU pins on the AI. Since we are running on PRU 0, and we're using ``0x0001``, that is bit 0, we'll be toggling ``P9_31``. -Line-by-line (continued again) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. table:: +.. table:: Line-by-line (continued again) +-----+-----------------------------------------------------------------------+ |Line | Explanation | @@ -590,13 +582,13 @@ Line-by-line (continued again) When you run this code and look at the output you will see something like the following figure. -Output of pwm1.pru0.c with 100,000,000 delays cycles giving a 1s period -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. figure:: figures/pwm1.png :align: center :alt: pwm1.pru0.c output + Output of pwm1.pru0.c with 100,000,000 delays cycles giving a 1s period + Notice the on time (``+Width(1)``) is 500ms, just as we predicted. The off time is 498ms, which is only 2ms off from our prediction. The standard deviation is 0, or only 380as, which is 380 * 10^-18^!. @@ -604,13 +596,12 @@ The standard deviation is 0, or only 380as, which is 380 * 10^-18^!. You can see how fast the PRU can run by setting both of the ``pass:[__]delay_cycles`` to 0. This results in the next figure. -Output of pwm1.pru0c with 0 delay cycles -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/pwm2.png :align: center :alt: pwm1.pru0.c output with 0 delay + Output of pwm1.pru0c with 0 delay cycles + Notice the period is 15ns which gives us a frequency of about 67MHz. At this high frequency the breadboard that I'm using distorts the waveform so it's no longer a squarewave. The **on** time is 5.3ns and the **off** time is 9.8ns. That means **pass:[__]R30 |= gpio** @@ -622,29 +613,35 @@ We want a square wave, so we need to add a delay to correct for the delay of loo Here's the code that does just that. -pwm2.pru0.c -~~~~~~~~~~~~~ +.. literalinclude:: code/pwm2.pru0.c + :caption: pwm2.pru0.c + :linenos: :download:`pwm2.pru0.c <code/pwm2.pru0.c>` The output now looks like: -Output of pwm2.pru0.c corrected delay -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/pwm3.png :align: center :alt: pwm2.c corrected delay + Output of pwm2.pru0.c corrected delay + It's not hard to adjust the two ``pass:[__]delay_cycles`` to get the desired frequency and duty cycle. -### Controlling the PWM Frequency -#### Problem +Controlling the PWM Frequency +****************************** + +Problem +--------- + You would like to control the frequency and duty cycle of the PWM without recompiling. -#### Solution +Solution +---------- + Have the PRU read the **on** and **off** times from a shared memory location. Each PRU has is own 8KB of data memory (DRAM) and 12KB of shared memory (SHAREDMEM) that the ARM processor can also access. See :ref:`blocks_PRU_block_diagram`. @@ -692,15 +689,17 @@ the ARM can write values into the DRAM and change the PWM on and off times. .. _blocks_pwm4: -pwm4.pru0.c -~~~~~~~~~~~~ +.. literalinclude:: code/pwm4.pru0.c + :caption: pwm4.pru0.c + :linenos: :download:`pwm4.pru0.c <code/pwm4.pru0.c>` Here is code that runs on the ARM side to set the on and off time values. -pwm-test.c -~~~~~~~~~~~~ +.. literalinclude:: code/pwm-test.c + :caption: pwm-test.c + :linenos: :download:`pwm-test.c <code/pwm-test.c>` @@ -708,13 +707,12 @@ A quick check on the 'scope shows :ref:`blocks_pwm_arm_control`. .. _blocks_pwm_arm_control: -Four Channel PWM with ARM control -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/pwm4.png :align: center :alt: pwm4.png + Four Channel PWM with ARM control + From the 'scope you see a 1 cycle **on** time results in a 450ns wide pulse and a 3.06us period is 326KHz, much slower than the 10ns pulse we saw before. But it may be more than fast enough for many applications. For example, most servos run at 50Hz. @@ -722,39 +720,35 @@ may be more than fast enough for many applications. For example, most servos ru But we can do better. Loop Unrolling for Better Performance -====================================== +*************************************** Problem ------------ +--------- The ARM controlled PRU code runs too slowly. Solution ------------ +---------- -Simple loop unrolling can greatly improve the speed. ``pwm5.pru0.c`` is our unrolled -version. +Simple loop unrolling can greatly improve the speed. ``pwm5.pru0.c`` is our unrolled version. -pwm5.pru0.c Unrolled -~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/pwm5.pru0.c + :caption: pwm5.pru0.c Unrolled + :linenos: :download:`pwm5.pru0.c <code/pwm5.pru0.c>` The output of ``pwm5.pru0.c`` is in the figure below. -pwm5.pru0.c Unrolled version of pwm4.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/pwm5_no_loop.png :align: center :alt: pwm5.pru0.c Unrolled version of pwm4.pru0.c -It's running about 6 times faster than ``pwm4.pru0.c``. + pwm5.pru0.c Unrolled version of pwm4.pru0.c -pwm4.pru0.c vs. pwm5.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It's running about 6 times faster than ``pwm4.pru0.c``. -.. table:: +.. table:: pwm4.pru0.c vs. pwm5.pru0.c +---------+-----------------+-----------------+---------+-----------------------+---------+ |Measure |pwm4.pru0.c time |pwm5.pru0.c time |Speedup |pwm5.pru0.c w/o UNROLL |Speedup | @@ -786,7 +780,7 @@ it copies the code an then it's compiled. This unrolling gets us an impressive 6x speedup. Making All the Pulses Start at the Same Time -============================================= +********************************************** Problem ----------- @@ -802,16 +796,17 @@ in each channel starts about 15ns later than the channel above it. .. _blocks_zoomed: -pwm5.pru0 Zoomed In -~~~~~~~~~~~~~~~~~~~~~ .. figure:: figures/pwm5_zoomed.png :align: center :alt: pwm5.pru0 zoomed.png + pwm5.pru0 Zoomed In + The solution is to declare ``Rtmp`` (line 35) which holds the value for ``pass:[__]R30``. -pwm6.pru0.c Sync'ed Version of pwm5.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/pwm6.pru0.c + :caption: pwm6.pru0.c Sync'ed Version of pwm5.pru0.c + :linenos: :download:`pwm6.pru0.c Sync'ed Version of pwm5.pru0.c <code/pwm6.pru0.c>` @@ -824,16 +819,16 @@ Discussion The following figure shows the channel are sync'ed. Though the period is slightly longer than before. -pwm6.pru0 Synchronized Channels -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. figure:: figures/pwm6_synced.png :align: center :alt: pwm6.pru0 Synchronized Channels + pwm6.pru0 Synchronized Channels + Adding More Channels via PRU 1 -================================ +******************************* Problem ----------- @@ -857,15 +852,17 @@ will make the period half as long. Here's the code (``pwm7.pru0.c``) -pwm7.pru0.c Using Both PRUs -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/pwm7.pru0.c + :caption: pwm7.pru0.c Using Both PRUs + :linenos: :download:`pwm7.pru0.c Using Both PRUs <code/pwm7.pru0.c>` Be sure to run ``pwm7_setup.sh`` to get the correct pins configured. -pwm7_setup.sh -~~~~~~~~~~~~~~~ +.. literalinclude:: code/pwm7_setup.sh + :caption: pwm7_setup.sh + :linenos: :download:`pw7_setup.sh <code/pwm7_setup.sh>` @@ -908,6 +905,7 @@ Discussion There weren't many changes to be made. Line 15 we set MAXCH to 2. Lines 44-48 is where the big change is. + .. code-block:: c pru0_dram[2*ch ] = on [ch+PRUNUN*MAXCH]; // Copy to DRAM0 so the ARM can change it @@ -924,30 +922,28 @@ behavior. Running the code you will see the next figure. -pwm7.pru0 Two PRUs running -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/pwm7_two_prus_running.png :align: center :alt: pwm7.pru0 Two PRUs running + pwm7.pru0 Two PRUs running + What's going on there, the first channels look fine, but the PRU 1 channels are blurred. To see what's happening, let's stop the oscilloscope. -pwm7.pru0 Two PRUs stopped -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/pwm7_two_prus_stopped.png :align: center :alt: pwm7 Two PRUs stopped + pwm7.pru0 Two PRUs stopped + The stopped display shows that the four channels are doing what we wanted, except The PRU 0 channels have a period of 370ns while the PRU 1 channels at 330ns. It appears the compiler has optimied the two PRUs slightly differenty. Synchronizing Two PRUs -======================= +*********************** Problem ----------- @@ -962,22 +958,24 @@ Page 225 of the `AM335x Technical Reference Manual <https://www.ti.com/lit/ug/sp has details of how it works. Here's the code for PRU 0, which at the end of the ``while`` loop signals PRU 1 to start(``pwm8.pru0.c``). -pwm8.pru0.c PRU 0 using INTC to send a signal to PRU 1 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/pwm8.pru0.c + :caption: pwm8.pru0.c PRU 0 using INTC to send a signal to PRU 1 + :linenos: :download:`pwm8.pru0.c PRU 0 using INTC to send a signal to PRU 1 <code/pwm8.pru0.c>` PRU 2's code waits for PRU 0 before going. -pwm8.pru1.c PRU 1 waiting for INTC from PRU 0 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/pwm8.pru1.c + :caption: pwm8.pru1.c PRU 1 waiting for INTC from PRU 0 + :linenos: :download:`pwm8.pru1.c PRU 1 waiting for INTC from PRU 0 <code/pwm8.pru1.c>` In ``pwm8.pru0.c`` PRU 1 waits for a signal from PRU 0, so be sure to start PRU 1 first. .. code-block:: bash - + bone$ *make TARGET=pwm8.pru0; make TARGET=pwm8.pru1* Discussion @@ -986,19 +984,15 @@ Discussion The figure below shows the two PRUs are synchronized, though there is some extra overhead in the process so the period is longer. -pwm8.pru0 PRUs sycned -~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/pwm8_prus_sycned.png :align: center :alt: pwm8.pru0 PRUs sycned -This isn't much different from the previous examples. + pwm8.pru0 PRUs sycned -pwm8.pru0.c changes from pwm7.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This isn't much different from the previous examples. -.. table:: +.. table:: pwm8.pru0.c changes from pwm7.pru0.c +-----+-------+---------------------------------------------------------------------------------------+ |PRU |Line |Change | @@ -1022,7 +1016,7 @@ pwm8.pru0.c changes from pwm7.pru0.c This ends the multipart pwm example. Reading an Input at Regular Intervals -====================================== +************************************** Problem ----------- @@ -1037,10 +1031,7 @@ pins. .. _blocks_io_pins: -Input/Output pins -~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: Input/Output pins +---------+----------+-----+----------+---------+ |Direction|Bit number|Black|AI (ICSS2)|Pocket | @@ -1054,15 +1045,17 @@ These values came from :ref:`blocks_mapping_bits`. Configure the pins with ``input_setup.sh``. -input_setup.sh -~~~~~~~~~~~~~~~ +.. literalinclude:: code/input_setup.sh + :caption: input_setup.sh + :linenos: :download:`input_setup.sh <code/input_setup.sh>` The following code reads the input pin and writes its value to the output pin. -input.c -~~~~~~~~~~ +.. literalinclude:: code/input.pru0.c + :caption: code/input.pru0.c + :linenos: :download:`input.pru0.c <code/input.pru0.c>` @@ -1072,7 +1065,7 @@ Discussion Just remember that ``pass:[__]R30`` is for outputs and ``pass:[__]R31`` is for inputs. Analog Wave Generator -======================= +********************** Problem ----------- @@ -1092,13 +1085,13 @@ a large duty cycle for when it is large. This example was inspired by `A PRU Sin Wave Generator <https://github.com/derekmolloy/exploringBB/tree/master/chp13/sineWave>`_ -in chapter 13 of -`Exploring BeagleBone by Derek Molloy<http://exploringbeaglebone.com/>`_. +in chapter 13 of `Exploring BeagleBone by Derek Molloy <http://exploringbeaglebone.com/>`_. Here's the code. -sine.pru0.c -~~~~~~~~~~~~~ +.. literalinclude:: code/sine.pru0.c + :caption: sine.pru0.c + :linenos: :download:`sine.pru0.c <code/sine.pru0.c>` @@ -1124,32 +1117,27 @@ Suppose you want to generate a sawtooth waveform like the one shown in :ref:`blo .. _blocks_sawtooth: -Continuous Sawtooth Waveform -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/sawtoothsmooth.png :align: center :alt: Continuous Sawtooth Waveform + Continuous Sawtooth Waveform + You need to sample the waveform and store one cycle. :ref:`blocks_sawtoothsampled` shows a sampled version of the sawtooth. You need to generate ``MAXT`` samples; here we show 20 samples, which may be enough. In the code ``MAXT`` is set to 100. .. _blocks_sawtoothsampled: -Sampled Sawtooth Waveform -~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/sawtoothsampled.png :align: center :alt: Sampled Sawtooth Waveform -There's a lot going on here; let's take it line by line. + Sampled Sawtooth Waveform -Line-by-line of sine.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There's a lot going on here; let's take it line by line. -.. table:: +.. table:: Line-by-line of sine.pru0.c +-------+---------------------------------------------------------------------------------+ |Line | Explanation | @@ -1194,13 +1182,12 @@ Line-by-line of sine.pru0.c .. _blocks_sawunfiltered: -Unfiltered Sawtooth Waveform -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/sawunfiltered.png :align: center :alt: Unfiltered Sawtooth Waveform + Unfiltered Sawtooth Waveform + It doesn't look like a sawtooth; but if you look at the left side you will see each cycle has a longer and longer on time. The duty cycle is increasing. Once it's almost 100% duty cycle, it switches to a very small duty cycle. @@ -1214,13 +1201,12 @@ A simple low-pass filter, built with one resistor and one capacitor will do it. .. _blocks_filterwiring: -Low-Pass Filter Wiring Diagram -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/filter_bb.png :align: center :alt: Low-Pass Filter Wiring Diagram + Low-Pass Filter Wiring Diagram + .. note:: I used a 10K variable resistor and a 0.022uF capacitor. @@ -1231,13 +1217,12 @@ Low-Pass Filter Wiring Diagram .. _blocks_sawscope: -Reconstructed Sawtooth Waveform -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/sawscope.png :align: center :alt: Reconstructed Sawtooth Waveform + Reconstructed Sawtooth Waveform + Now that looks more like a sawtooth wave. The top plot is the time-domain plot of the output of the low-pass filter. The bottom plot is the FFT of the top plot, therefore it's the frequency domain. We are getting a sawtooth with a @@ -1252,13 +1237,12 @@ resistor. You'll see something like :ref:`blocks_lowercutoff`. .. _blocks_lowercutoff: -Reconstructed Sawtooth Waveform with Lower Cutoff Frequency -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/sawlowercutoff.png :align: center :alt: Reconstructed Sawtooth Waveform with Lower Cutoff Frequency + Reconstructed Sawtooth Waveform with Lower Cutoff Frequency + The high freqencies have been reduced, but the corner of the waveform has been rounded. You can also adjust the cutoff to a higher frequency and you'll get a sharper corner, but you'll also get more high frequencies. See @@ -1266,13 +1250,12 @@ get a sharper corner, but you'll also get more high frequencies. See .. _blocks_highercutoff: -Reconstructed Sawtooth Waveform with Higher Cutoff Frequency -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/sawhighercutoff.png :align: center :alt: Reconstructed Sawtooth Waveform with Higher Cutoff Frequency + Reconstructed Sawtooth Waveform with Higher Cutoff Frequency + Adjust to taste, though the real solution is to build a higher order filter. Search for _second order **filter** and you'll find some nice circuits. @@ -1285,24 +1268,22 @@ You can also get a triangle waveform by setting the ``#define``. .. _blocks_triangle: -Reconstructed Triangle Waveform -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/triangle.png :align: center :alt: Reconstructed Triangle Waveform + Reconstructed Triangle Waveform + And also the sine wave as shown in :ref:`blocks_sine`. .. _blocks_sine: -Reconstructed Sinusoid Waveform -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/sine.png :align: center :alt: Reconstructed Sinusoid Waveform + Reconstructed Sinusoid Waveform + Notice on the bottom plot the harmonics are much more suppressed. Generating the sine waveform uses **floats**. This requires much more code. @@ -1311,8 +1292,9 @@ You can look in `/tmp/cloud9-examples/sine.pru0.map` to see how much memory is b .. _blocks_sine_map: -/tmp/cloud9-examples/sine.pru0.map for Sine Wave -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/sine.map + :caption: /tmp/cloud9-examples/sine.pru0.map for Sine Wave + :linenos: :download:`lines=1..22 <code/sine.map>` @@ -1330,7 +1312,7 @@ to the PRU. .. _blocks_ws2812: WS2812 (NeoPixel) driver -========================== +*************************** Problem ----------- @@ -1353,40 +1335,38 @@ Wire the input to ``P9_29`` and power to 3.3V and ground to ground as shown in .. _blocks_neo_wiring: -.NeoPixel Wiring .. figure:: figures/neo_bb.png :align: center :alt: NeoPixel Wiring + NeoPixel Wiring + Test your wiring with the simple code in :ref:`blocks_neo1` which to turns all pixels white. .. _blocks_neo1: -neo1.pru0.c - Code to turn all NeoPixels's white -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: bash +.. literalinclude:: code/neo1.pru0.c + :caption: neo1.pru0.c - Code to turn all NeoPixels's white + :linenos: :download:`neo1.pru0.c <code/neo1.pru0.c>` Discussion ----------- -:ref:`blocks_sequence` (taken from `WS2812 Data Sheet <https://cdn-shop.adafruit.com/datasheets/WS2812.pdf>`_) shows the following waveforms are used to send a bit of data. +:ref:`blocks_sequence` (taken from `WS2812 Data Sheet <https://cdn-shop.adafruit.com/datasheets/WS2812.pdf>`_) +shows the following waveforms are used to send a bit of data. .. _blocks_sequence: -NeoPixel bit sequence -~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/neo_sequence.png :align: center :alt: NeoPixel bit sequence -Where the times are: + NeoPixel bit sequence -.. table:: +.. table:: Where the times are: +-------+-------------+ |Label | Time in ns | @@ -1411,12 +1391,11 @@ shows the waveform for sending a 0 value. Note the times are spot on. .. _blocks_zero_scope: -NeoPixel zero timing -~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/neo_scope.png :align: center - :alt: + :alt: NeoPixel zero timing + + NeoPixel zero timing Each NeoPixel listens for a RGB value. Once a value has arrived all other values that follow are passed on to the next NeoPixel which does the same thing. @@ -1428,23 +1407,24 @@ grab the next value for itself and start over again. Setting NeoPixels to Different Colors -====================================== +*************************************** Problem ------------ +--------- I want to set the LEDs to different colors. Solution ------------ +--------- -Wire your NeoPixels as shown in :ref:`blocks_neo_wiring` then run the code in -:ref:`blocks_neo2`. +Wire your NeoPixels as shown in :ref:`blocks_neo_wiring` +then run the code in :ref:`blocks_neo2`. .. _blocks_neo2: -neo2.pru0.c - Code to turn on green, red, blue -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/neo2.pru0.c + :caption: neo2.pru0.c - Code to turn on green, red, blue + :linenos: :download:`neo2.pru0.c <code/neo2.pru0.c>` @@ -1458,25 +1438,21 @@ used to control the green, red and blue values. .. _blocks_new_data_seq: -NeoPixel data sequence -~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/neo_data_seq.png :align: center - :alt: + :alt: NeoPixel data sequence + + NeoPixel data sequence .. note:: -The usual order for colors is RGB (red, green, blue), but the NeoPixels use GRB (green, red, blue). + The usual order for colors is RGB (red, green, blue), but the NeoPixels use GRB (green, red, blue). :ref:`blocks_neo2_line` is the line-by-line for ``neo2.pru0.c``. .. _blocks_neo2_line: -Line-by-line for neo2.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: Line-by-line for neo2.pru0.c +-------+---------------------------------------------------------------------------------+ |Line | Explanation | @@ -1501,12 +1477,10 @@ Line-by-line for neo2.pru0.c .. note:: -This will only change the first ``STR_LEN`` LEDs. The LEDs that follow will not -be changed. -==== + This will only change the first ``STR_LEN`` LEDs. The LEDs that follow will not be changed. Controlling Arbitrary LEDs -============================ +*************************** Problem ----------- @@ -1522,30 +1496,30 @@ string to the LEDs. :ref:`blocks_neo3` shows an example animates a red pixel running around a ring of blue background. :ref:`blocks_neo3_video` shows the code in action. -.. _blocks_neo3_video: +.. _blocks_neo3: -neo3.pru0.c - Simple animation +.. literalinclude:: code/neo3.pru0.c + :caption: neo3.pru0.c - Code to animate a red pixel running around a ring of blue + :linenos: -:download:`ring_around.mp4 <figures/ring_around.mp4>` +:download:`neo3.pru0.c <code/neo3.pru0.c>` -.. _blocks_neo3: +.. _blocks_neo3_video: -neo3.pru0.c - Code to animate a red pixel running around a ring of blue -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Neo3 Video +----------- -:download:`neo3.pru0.c <code/neo3.pru0.c>` +:download:`neo3.pru0.c - Simple animation <figures/ring_around.mp4>` Discussion ----------- -Here's the highlights. - -.. table:: +.. table:: Here's the highlights. +-----+---------------------------------+ |Line |Explanation | - +=====|=================================+ + +=====+=================================+ |32,33|Initiallize the array of colors. | +-----+---------------------------------+ |38-41|Update the array. | @@ -1558,7 +1532,7 @@ Here's the highlights. +-----+---------------------------------+ Controlling NeoPixels Through a Kernel Driver -====================================== +************************************************* Problem ----------- @@ -1576,8 +1550,9 @@ an example. .. _blocks_neo4: -neo4.pru0.c - Code to talk to the PRU via rpmsg_pru -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/neo4.pru0.c + :caption: neo4.pru0.c - Code to talk to the PRU via rpmsg_pru + :linenos: :download:`neo4.pru0.c <code/neo4.pru0.c>` @@ -1614,32 +1589,41 @@ There's a lot here. I'll just hit some of the highlights in :ref:`blocks_neo4_l .. _blocks_neo4_lines: -Line-by-line for neo4.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: - -|Line |Explanation - -|30 |The `CHAN_NAME` of `rpmsg-pru` matches that `prmsg_pru` driver that is -is already installed. This connects this PRU to the driver. -|32 |The `CHAN_PORT` tells it to use port 30. That's why we use -`/dev/rpmsg_pru30` -|40 |`payload[]` is the buffer that receives the data from the ARM. -|42-48|Same as the previous NeoPixel examples. -|52 |`color[]` is the state to be sent to the LEDs. -|66-68|`color[]` is initialized. -|70-85|Here are a number of details needed to set up the channel between -the PRU and the ARM. -|88 |Here we wait until the ARM sends us some numbers. -|99 |Receive all the data from the ARM, store it in `payload[]`. -|101-111|The data sent is: index red green blue. Pull off the index. If it's -in the right range, pull off the red, green and blue values. -|113 |The NeoPixels want the data in GRB order. Shift and OR everything -together. -|116-133|If the `index` = -1, send the contents of `color` to the LEDs. This -code is same as before. -|==== +.. table:: Line-by-line for neo4.pru0.c + + +---------+---------------------------------------------------------------------------+ + |Line | Explanation | + +=========+===========================================================================+ + |30 | The `CHAN_NAME` of `rpmsg-pru` matches that `prmsg_pru` driver that is | + | | is already installed. This connects this PRU to the driver. | + +---------+---------------------------------------------------------------------------+ + |32 | The `CHAN_PORT` tells it to use port 30. That's why we use | + | | `/dev/rpmsg_pru30` | + +---------+---------------------------------------------------------------------------+ + |40 | `payload[]` is the buffer that receives the data from the ARM. | + +---------+---------------------------------------------------------------------------+ + |42-48 | Same as the previous NeoPixel examples. | + +---------+---------------------------------------------------------------------------+ + |52 | `color[]` is the state to be sent to the LEDs. | + +---------+---------------------------------------------------------------------------+ + |66-68 | `color[]` is initialized. | + +---------+---------------------------------------------------------------------------+ + |70-85 | Here are a number of details needed to set up the channel between | + | | the PRU and the ARM. | + +---------+---------------------------------------------------------------------------+ + |88 | Here we wait until the ARM sends us some numbers. | + +---------+---------------------------------------------------------------------------+ + |99 | Receive all the data from the ARM, store it in `payload[]`. | + +---------+---------------------------------------------------------------------------+ + |101-111 | The data sent is: index red green blue. Pull off the index. If it's | + | | in the right range, pull off the red, green and blue values. | + +---------+---------------------------------------------------------------------------+ + |113 | The NeoPixels want the data in GRB order. Shift and OR everything | + | | together. | + +---------+---------------------------------------------------------------------------+ + |116-133 | If the `index` = -1, send the contents of `color` to the LEDs. This | + | | code is same as before. | + +---------+---------------------------------------------------------------------------+ You can now use programs running on the ARM to send colors to the PRU. @@ -1647,8 +1631,9 @@ You can now use programs running on the ARM to send colors to the PRU. .. _blocks_neo-rainbow: -neo-rainbow.py - A python program using /dev/rpmsg_pru30 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/neo-rainbow.py + :caption: neo-rainbow.py - A python program using /dev/rpmsg_pru30 + :linenos: :download:`neo-rainbow.py <code/neo-rainbow.py>` @@ -1659,7 +1644,6 @@ the last number, or you numbers will get blurred together. Switching from pru0 to pru1 with rpmsg_pru ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - There are three things you need to change when switching from pru0 to pru1 when using rpmsg_pru. @@ -1675,14 +1659,13 @@ when using rpmsg_pru. These changes switch to the proper channel numbers to use pru1 instead of pru0. RGB LED Matrix - No Integrated Drivers -====================================== - +*************************************** Problem ----------- You have a RGB LED matrix -(:ref:`../01case/case.html#case_rgb_matrix, 1.4. RGB LED Matrix - No Integrated Drivers`) and want to know +(:ref:`case_rgb_matrix`) and want to know at a low level how the PRU works. Solution @@ -1735,8 +1718,9 @@ high-level view of how to drive the display. .. _blocks_rgb_python: -rgb_python.py - Python code for driving RGB LED matrix -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/rgb_python.py + :caption: rgb_python.py - Python code for driving RGB LED matrix + :linenos: :download:`rgb_python.py <code/rgb_python.py>` @@ -1744,8 +1728,9 @@ Be sure to run the :ref:`blocks_rgb_setup` script before running the python code .. _blocks_rgb_setup: -rgb_python_setup.sh -~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/rgb_python_setup.sh + :caption: rgb_python_setup.sh + :linenos: :download:`rgb_python_setup.sh <code/rgb_python_setup.sh>` @@ -1762,26 +1747,27 @@ Your display should look like :ref:`blocks_rgb_python_jpg`. .. _blocks_rgb_python_jpg: -Display running rgb_python.py -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/rgb_python.jpg :align: center :alt: Display running rgb_python.py + Display running rgb_python.py + So why do only two lines appear at a time? That's how the display works. Currently lines 6 and 22 are showing, then a moment later 7 and 23 show, etc. The display can only display two lines at a time, so it cycles through all the lines. Unfortunately, python is too slow to make the display appear all at once. Here's where the PRU comes in. -:ref:``blocks_rgb1`` is the PRU code to drive the RGB LED matrix. Be sure to run -``bone$ source rgb_setup.sh`` first. +:ref:``blocks_rgb1`` is the PRU code to drive the RGB LED matrix. +Be sure to run ``bone$ source rgb_setup.sh`` first. .. _blocks_rgb1: -PRU code for driving the RGB LED matrix -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: code/rgb1.pru0.c + :caption: PRU code for driving the RGB LED matrix + :linenos: :download:`rgb1.pru0.c <code/rgb1.pru0.c>` @@ -1790,33 +1776,31 @@ The results are shown in :ref:`blocks_rgb_pru`. .. _blocks_rgb_pru: -Display running rgb1.c on PRU 0 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/rgb_pru.jpg :align: center :alt: Display running rgb1.pru0.c on PRU 0 + Display running rgb1.c on PRU 0 + The PRU is fast enough to quickly write to the display so that it appears as if all the LEDs are on at once. Discussion ----------- -There are a lot of details needed to make this simple display work. Let's -go over some of them. +There are a lot of details needed to make this simple display work. +Let's go over some of them. First, the connector looks like :ref:`blocks_matrix_j1`. .. _blocks_matrix_j1: -RGB Matrix J1 connector -~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/matrix_j1.jpg :align: center :alt: RGB Matrix J1 connector, 200 + RGB Matrix J1 connector + Notice the labels on the connect match the labels in the code. :ref:`blocks_pocket_scroller_pins` shows how the pins on the display are mapped to the pins on the Pocket Beagle. @@ -1826,10 +1810,7 @@ mapped to the pins on the Pocket Beagle. .. _blocks_pocket_scroller_pins: -PocketScroller pin table -~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: PocketScroller pin table +-----------------+---------------+------------------------+------------------+-------------------+ |J1 Connector Pin |Pocket Headers |gpio port and bit number|Linux gpio number |PRU R30 bit number | @@ -1870,12 +1851,11 @@ https://docs.google.com/spreadsheets/d/1FRGvYOyW1RiNSEVprvstfJAVeapnASgDXHtxeDOj .. _blocks_rgb_waveforms: -Oscilloscope display of CLK, OE, LAT and R1 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/rgb_waveforms.png :align: center - :alt: .Oscilloscope display of CLK, OE, LAT and R1 + :alt: Oscilloscope display of CLK, OE, LAT and R1 + + Oscilloscope display of CLK, OE, LAT and R1 The top waveform is the CLK, the next is OE, followed by LAT and finally R1. The OE (output enable) is active low, so most of the time the display is visible. @@ -1883,9 +1863,7 @@ The sequence is: * Put data on the R1, G1, B1, R2, G2 and B2 lines * Toggle the clock. -* Repeat the first two steps as one row of data is transfered. There are -384 LEDs (2 rows of 32 RGB LEDs times 3 LED per RGB), but we are clocking in -six bits (R1, G1, etc.) at a time, so 384/6=64 values need to be clocked in. +* Repeat the first two steps as one row of data is transfered. There are 384 LEDs (2 rows of 32 RGB LEDs times 3 LED per RGB), but we are clocking in six bits (R1, G1, etc.) at a time, so 384/6=64 values need to be clocked in. * Once all the values are in, disable the display (OE goes high) * Then toggle the latch (LAT) to latch the new data. * Turn the display back on. @@ -1901,13 +1879,12 @@ comparision. .. _blocks_rgb_fpp: -FPP waveforms -~~~~~~~~~~~~~~ - .. figure:: figures/rgb_fpp.png :align: center :alt: FPP waveforms + FPP waveforms + Getting More Colors ~~~~~~~~~~~~~~~~~~~~~ @@ -1927,7 +1904,7 @@ The Adafruit description goes on to say: This is what FPP does, but it's beyond the scope of this project. Compiling and Inserting rpmsg_pru -====================================== +*********************************** Problem ----------- @@ -1970,8 +1947,9 @@ It's now installed and ready to go. Copyright ========== -copyright.c -~~~~~~~~~~~~~ +.. literalinclude:: code/copyright.c + :caption: copyright.c + :linenos: :download:`copyright.c <code/copyright.c>` diff --git a/books/pru-cookbook/06io/io.html b/books/pru-cookbook/06io/io.html deleted file mode 100644 index 5bb5425d..00000000 --- a/books/pru-cookbook/06io/io.html +++ /dev/null @@ -1,1003 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> -<meta charset="UTF-8"> -<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--> -<meta name="viewport" content="width=device-width, initial-scale=1.0"> -<meta name="generator" content="Asciidoctor 1.5.8"> -<title>Accessing More I/O</title> -<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"> -<style> -/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */ -/* Uncomment @import statement below to use as custom stylesheet */ -/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/ -article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block} -audio,canvas,video{display:inline-block} -audio:not([controls]){display:none;height:0} -script{display:none!important} -html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} -a{background:transparent} -a:focus{outline:thin dotted} -a:active,a:hover{outline:0} -h1{font-size:2em;margin:.67em 0} -abbr[title]{border-bottom:1px dotted} -b,strong{font-weight:bold} -dfn{font-style:italic} -hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0} -mark{background:#ff0;color:#000} -code,kbd,pre,samp{font-family:monospace;font-size:1em} -pre{white-space:pre-wrap} -q{quotes:"\201C" "\201D" "\2018" "\2019"} -small{font-size:80%} -sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} -sup{top:-.5em} -sub{bottom:-.25em} -img{border:0} -svg:not(:root){overflow:hidden} -figure{margin:0} -fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} -legend{border:0;padding:0} -button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} -button,input{line-height:normal} -button,select{text-transform:none} -button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer} -button[disabled],html input[disabled]{cursor:default} -input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0} -button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} -textarea{overflow:auto;vertical-align:top} -table{border-collapse:collapse;border-spacing:0} -*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box} -html,body{font-size:100%} -body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased} -a:hover{cursor:pointer} -img,object,embed{max-width:100%;height:auto} -object,embed{height:100%} -img{-ms-interpolation-mode:bicubic} -.left{float:left!important} -.right{float:right!important} -.text-left{text-align:left!important} -.text-right{text-align:right!important} -.text-center{text-align:center!important} -.text-justify{text-align:justify!important} -.hide{display:none} -img,object,svg{display:inline-block;vertical-align:middle} -textarea{height:auto;min-height:50px} -select{width:100%} -.center{margin-left:auto;margin-right:auto} -.stretch{width:100%} -.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} -div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr} -a{color:#2156a5;text-decoration:underline;line-height:inherit} -a:hover,a:focus{color:#1d4b8f} -a img{border:none} -p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} -p aside{font-size:.875em;line-height:1.35;font-style:italic} -h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} -h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0} -h1{font-size:2.125em} -h2{font-size:1.6875em} -h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} -h4,h5{font-size:1.125em} -h6{font-size:1em} -hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0} -em,i{font-style:italic;line-height:inherit} -strong,b{font-weight:bold;line-height:inherit} -small{font-size:60%;line-height:inherit} -code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} -ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} -ul,ol{margin-left:1.5em} -ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em} -ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit} -ul.square{list-style-type:square} -ul.circle{list-style-type:circle} -ul.disc{list-style-type:disc} -ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} -dl dt{margin-bottom:.3125em;font-weight:bold} -dl dd{margin-bottom:1.25em} -abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help} -abbr{text-transform:none} -blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} -blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)} -blockquote cite::before{content:"\2014 \0020"} -blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)} -blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} -@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} -h1{font-size:2.75em} -h2{font-size:2.3125em} -h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} -h4{font-size:1.4375em}} -table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede} -table thead,table tfoot{background:#f7f8f7} -table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left} -table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} -table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7} -table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6} -h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} -h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} -.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table} -.clearfix::after,.float-group::after{clear:both} -*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word} -*:not(pre)>code.nobreak{word-wrap:normal} -*:not(pre)>code.nowrap{white-space:nowrap} -pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed} -em em{font-style:normal} -strong strong{font-weight:400} -.keyseq{color:rgba(51,51,51,.8)} -kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} -.keyseq kbd:first-child{margin-left:0} -.keyseq kbd:last-child{margin-right:0} -.menuseq,.menuref{color:#000} -.menuseq b:not(.caret),.menuref{font-weight:inherit} -.menuseq{word-spacing:-.02em} -.menuseq b.caret{font-size:1.25em;line-height:.8} -.menuseq i.caret{font-weight:bold;text-align:center;width:.45em} -b.button::before,b.button::after{position:relative;top:-1px;font-weight:400} -b.button::before{content:"[";padding:0 3px 0 2px} -b.button::after{content:"]";padding:0 2px 0 3px} -p a>code:hover{color:rgba(0,0,0,.9)} -#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} -#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table} -#header::after,#content::after,#footnotes::after,#footer::after{clear:both} -#content{margin-top:1.25em} -#content::before{content:none} -#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} -#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} -#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} -#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap} -#header .details span:first-child{margin-left:-.125em} -#header .details span.email a{color:rgba(0,0,0,.85)} -#header .details br{display:none} -#header .details br+span::before{content:"\00a0\2013\00a0"} -#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} -#header .details br+span#revremark::before{content:"\00a0|\00a0"} -#header #revnumber{text-transform:capitalize} -#header #revnumber::after{content:"\00a0"} -#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem} -#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em} -#toc>ul{margin-left:.125em} -#toc ul.sectlevel0>li>a{font-style:italic} -#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} -#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} -#toc li{line-height:1.3334;margin-top:.3334em} -#toc a{text-decoration:none} -#toc a:active{text-decoration:underline} -#toctitle{color:#7a2518;font-size:1.2em} -@media screen and (min-width:768px){#toctitle{font-size:1.375em} -body.toc2{padding-left:15em;padding-right:0} -#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} -#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} -#toc.toc2>ul{font-size:.9em;margin-bottom:0} -#toc.toc2 ul ul{margin-left:0;padding-left:1em} -#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} -body.toc2.toc-right{padding-left:0;padding-right:15em} -body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}} -@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} -#toc.toc2{width:20em} -#toc.toc2 #toctitle{font-size:1.375em} -#toc.toc2>ul{font-size:.95em} -#toc.toc2 ul ul{padding-left:1.25em} -body.toc2.toc-right{padding-left:0;padding-right:20em}} -#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} -#content #toc>:first-child{margin-top:0} -#content #toc>:last-child{margin-bottom:0} -#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em} -#footer-text{color:rgba(255,255,255,.8);line-height:1.44} -#content{margin-bottom:.625em} -.sect1{padding-bottom:.625em} -@media screen and (min-width:768px){#content{margin-bottom:1.25em} -.sect1{padding-bottom:1.25em}} -.sect1:last-child{padding-bottom:0} -.sect1+.sect1{border-top:1px solid #e7e7e9} -#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} -#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} -#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} -#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} -#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} -.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} -.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic} -table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} -.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)} -table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit} -.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} -.admonitionblock>table td.icon{text-align:center;width:80px} -.admonitionblock>table td.icon img{max-width:none} -.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} -.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)} -.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} -.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px} -.exampleblock>.content>:first-child{margin-top:0} -.exampleblock>.content>:last-child{margin-bottom:0} -.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} -.sidebarblock>:first-child{margin-top:0} -.sidebarblock>:last-child{margin-bottom:0} -.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center} -.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0} -.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8} -.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1} -.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em} -@media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}} -@media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}} -.literalblock pre.nowrap,.literalblock pre.nowrap pre,.listingblock pre.nowrap,.listingblock pre.nowrap pre{white-space:pre;word-wrap:normal} -.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)} -.listingblock pre.highlightjs{padding:0} -.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px} -.listingblock pre.prettyprint{border-width:0} -.listingblock>.content{position:relative} -.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999} -.listingblock:hover code[data-lang]::before{display:block} -.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999} -.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"} -table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none} -table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45} -table.pyhltable td.code{padding-left:.75em;padding-right:0} -pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #dddddf} -pre.pygments .lineno{display:inline-block;margin-right:.25em} -table.pyhltable .linenodiv{background:none!important;padding-right:0!important} -.quoteblock{margin:0 1em 1.25em 1.5em;display:table} -.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em} -.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} -.quoteblock blockquote{margin:0;padding:0;border:0} -.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)} -.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} -.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right} -.verseblock{margin:0 1em 1.25em} -.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} -.verseblock pre strong{font-weight:400} -.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} -.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} -.quoteblock .attribution br,.verseblock .attribution br{display:none} -.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)} -.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none} -.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0} -.quoteblock.abstract{margin:0 1em 1.25em;display:block} -.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center} -.quoteblock.excerpt,.quoteblock .quoteblock{margin:0 0 1.25em;padding:0 0 .25em 1em;border-left:.25em solid #dddddf} -.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem} -.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0} -table.tableblock{max-width:100%;border-collapse:separate} -p.tableblock:last-child{margin-bottom:0} -td.tableblock>.content{margin-bottom:-1.25em} -table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} -table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0} -table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0} -table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0} -table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px} -table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0} -table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0} -table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0} -table.frame-all{border-width:1px} -table.frame-sides{border-width:0 1px} -table.frame-topbot,table.frame-ends{border-width:1px 0} -table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7} -table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none} -th.halign-left,td.halign-left{text-align:left} -th.halign-right,td.halign-right{text-align:right} -th.halign-center,td.halign-center{text-align:center} -th.valign-top,td.valign-top{vertical-align:top} -th.valign-bottom,td.valign-bottom{vertical-align:bottom} -th.valign-middle,td.valign-middle{vertical-align:middle} -table thead th,table tfoot th{font-weight:bold} -tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7} -tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold} -p.tableblock>code:only-child{background:none;padding:0} -p.tableblock{font-size:1em} -td>div.verse{white-space:pre} -ol{margin-left:1.75em} -ul li ol{margin-left:1.5em} -dl dd{margin-left:1.125em} -dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} -ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} -ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none} -ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em} -ul.unstyled,ol.unstyled{margin-left:0} -ul.checklist{margin-left:.625em} -ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em} -ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em} -ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em} -ul.inline>li{margin-left:1.25em} -.unstyled dl dt{font-weight:400;font-style:normal} -ol.arabic{list-style-type:decimal} -ol.decimal{list-style-type:decimal-leading-zero} -ol.loweralpha{list-style-type:lower-alpha} -ol.upperalpha{list-style-type:upper-alpha} -ol.lowerroman{list-style-type:lower-roman} -ol.upperroman{list-style-type:upper-roman} -ol.lowergreek{list-style-type:lower-greek} -.hdlist>table,.colist>table{border:0;background:none} -.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} -td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em} -td.hdlist1{font-weight:bold;padding-bottom:1.25em} -.literalblock+.colist,.listingblock+.colist{margin-top:-.5em} -.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top} -.colist td:not([class]):first-child img{max-width:none} -.colist td:not([class]):last-child{padding:.25em 0} -.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd} -.imageblock.left{margin:.25em .625em 1.25em 0} -.imageblock.right{margin:.25em 0 1.25em .625em} -.imageblock>.title{margin-bottom:0} -.imageblock.thumb,.imageblock.th{border-width:6px} -.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} -.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} -.image.left{margin-right:.625em} -.image.right{margin-left:.625em} -a.image{text-decoration:none;display:inline-block} -a.image object{pointer-events:none} -sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} -sup.footnote a,sup.footnoteref a{text-decoration:none} -sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} -#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} -#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} -#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} -#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em} -#footnotes .footnote:last-of-type{margin-bottom:0} -#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} -.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0} -.gist .file-data>table td.line-data{width:99%} -div.unbreakable{page-break-inside:avoid} -.big{font-size:larger} -.small{font-size:smaller} -.underline{text-decoration:underline} -.overline{text-decoration:overline} -.line-through{text-decoration:line-through} -.aqua{color:#00bfbf} -.aqua-background{background-color:#00fafa} -.black{color:#000} -.black-background{background-color:#000} -.blue{color:#0000bf} -.blue-background{background-color:#0000fa} -.fuchsia{color:#bf00bf} -.fuchsia-background{background-color:#fa00fa} -.gray{color:#606060} -.gray-background{background-color:#7d7d7d} -.green{color:#006000} -.green-background{background-color:#007d00} -.lime{color:#00bf00} -.lime-background{background-color:#00fa00} -.maroon{color:#600000} -.maroon-background{background-color:#7d0000} -.navy{color:#000060} -.navy-background{background-color:#00007d} -.olive{color:#606000} -.olive-background{background-color:#7d7d00} -.purple{color:#600060} -.purple-background{background-color:#7d007d} -.red{color:#bf0000} -.red-background{background-color:#fa0000} -.silver{color:#909090} -.silver-background{background-color:#bcbcbc} -.teal{color:#006060} -.teal-background{background-color:#007d7d} -.white{color:#bfbfbf} -.white-background{background-color:#fafafa} -.yellow{color:#bfbf00} -.yellow-background{background-color:#fafa00} -span.icon>.fa{cursor:default} -a span.icon>.fa{cursor:inherit} -.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} -.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c} -.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} -.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900} -.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400} -.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000} -.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} -.conum[data-value] *{color:#fff!important} -.conum[data-value]+b{display:none} -.conum[data-value]::after{content:attr(data-value)} -pre .conum[data-value]{position:relative;top:-.125em} -b.conum *{color:inherit!important} -.conum:not([data-value]):empty{display:none} -dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility} -h1,h2,p,td.content,span.alt{letter-spacing:-.01em} -p strong,td.content strong,div.footnote strong{letter-spacing:-.005em} -p,blockquote,dt,td.content,span.alt{font-size:1.0625rem} -p{margin-bottom:1.25rem} -.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} -.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc} -.print-only{display:none!important} -@page{margin:1.25cm .75cm} -@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important} -html{font-size:80%} -a{color:inherit!important;text-decoration:underline!important} -a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} -a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} -abbr[title]::after{content:" (" attr(title) ")"} -pre,blockquote,tr,img,object,svg{page-break-inside:avoid} -thead{display:table-header-group} -svg{max-width:100%} -p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} -h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} -#toc,.sidebarblock,.exampleblock>.content{background:none!important} -#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important} -body.book #header{text-align:center} -body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em} -body.book #header .details{border:0!important;display:block;padding:0!important} -body.book #header .details span:first-child{margin-left:0!important} -body.book #header .details br{display:block} -body.book #header .details br+span::before{content:none!important} -body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} -body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} -.listingblock code[data-lang]::before{display:block} -#footer{padding:0 .9375em} -.hide-on-print{display:none!important} -.print-only{display:block!important} -.hide-for-print{display:none!important} -.show-for-print{display:inherit!important}} -@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem} -.sect1{padding:0!important} -.sect1+.sect1{border:0} -#footer{background:none} -#footer-text{color:rgba(0,0,0,.6);font-size:.9em}} -@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}} -</style> -<style> -/* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */ -/*pre.CodeRay {background-color:#f7f7f8;}*/ -.CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em} -.CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)} -.CodeRay .line-numbers strong{color:rgba(0,0,0,.4)} -table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none} -table.CodeRay td{vertical-align: top;line-height:1.45} -table.CodeRay td.line-numbers{text-align:right} -table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)} -table.CodeRay td.code{padding:0 0 0 .5em} -table.CodeRay td.code>pre{padding:0} -.CodeRay .debug{color:#fff !important;background:#000080 !important} -.CodeRay .annotation{color:#007} -.CodeRay .attribute-name{color:#000080} -.CodeRay .attribute-value{color:#700} -.CodeRay .binary{color:#509} -.CodeRay .comment{color:#998;font-style:italic} -.CodeRay .char{color:#04d} -.CodeRay .char .content{color:#04d} -.CodeRay .char .delimiter{color:#039} -.CodeRay .class{color:#458;font-weight:bold} -.CodeRay .complex{color:#a08} -.CodeRay .constant,.CodeRay .predefined-constant{color:#008080} -.CodeRay .color{color:#099} -.CodeRay .class-variable{color:#369} -.CodeRay .decorator{color:#b0b} -.CodeRay .definition{color:#099} -.CodeRay .delimiter{color:#000} -.CodeRay .doc{color:#970} -.CodeRay .doctype{color:#34b} -.CodeRay .doc-string{color:#d42} -.CodeRay .escape{color:#666} -.CodeRay .entity{color:#800} -.CodeRay .error{color:#808} -.CodeRay .exception{color:inherit} -.CodeRay .filename{color:#099} -.CodeRay .function{color:#900;font-weight:bold} -.CodeRay .global-variable{color:#008080} -.CodeRay .hex{color:#058} -.CodeRay .integer,.CodeRay .float{color:#099} -.CodeRay .include{color:#555} -.CodeRay .inline{color:#000} -.CodeRay .inline .inline{background:#ccc} -.CodeRay .inline .inline .inline{background:#bbb} -.CodeRay .inline .inline-delimiter{color:#d14} -.CodeRay .inline-delimiter{color:#d14} -.CodeRay .important{color:#555;font-weight:bold} -.CodeRay .interpreted{color:#b2b} -.CodeRay .instance-variable{color:#008080} -.CodeRay .label{color:#970} -.CodeRay .local-variable{color:#963} -.CodeRay .octal{color:#40e} -.CodeRay .predefined{color:#369} -.CodeRay .preprocessor{color:#579} -.CodeRay .pseudo-class{color:#555} -.CodeRay .directive{font-weight:bold} -.CodeRay .type{font-weight:bold} -.CodeRay .predefined-type{color:inherit} -.CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold} -.CodeRay .key{color:#808} -.CodeRay .key .delimiter{color:#606} -.CodeRay .key .char{color:#80f} -.CodeRay .value{color:#088} -.CodeRay .regexp .delimiter{color:#808} -.CodeRay .regexp .content{color:#808} -.CodeRay .regexp .modifier{color:#808} -.CodeRay .regexp .char{color:#d14} -.CodeRay .regexp .function{color:#404;font-weight:bold} -.CodeRay .string{color:#d20} -.CodeRay .string .string .string{background:#ffd0d0} -.CodeRay .string .content{color:#d14} -.CodeRay .string .char{color:#d14} -.CodeRay .string .delimiter{color:#d14} -.CodeRay .shell{color:#d14} -.CodeRay .shell .delimiter{color:#d14} -.CodeRay .symbol{color:#990073} -.CodeRay .symbol .content{color:#a60} -.CodeRay .symbol .delimiter{color:#630} -.CodeRay .tag{color:#008080} -.CodeRay .tag-special{color:#d70} -.CodeRay .variable{color:#036} -.CodeRay .insert{background:#afa} -.CodeRay .delete{background:#faa} -.CodeRay .change{color:#aaf;background:#007} -.CodeRay .head{color:#f8f;background:#505} -.CodeRay .insert .insert{color:#080} -.CodeRay .delete .delete{color:#800} -.CodeRay .change .change{color:#66f} -.CodeRay .head .head{color:#f4f} -</style> -</head> -<body class="article"> -<div id="header"> -<div id="toc" class="toc"> -<div id="toctitle">Table of Contents</div> -<ul class="sectlevel1"> -<li><a href="#_accessing_more_io">1. Accessing More I/O</a> -<ul class="sectlevel2"> -<li><a href="#_editing_bootuenv_txt_to_access_the_p8_header_on_the_black">1.1. Editing /boot/uEnv.txt to Access the P8 Header on the Black</a></li> -<li><a href="#_accessing_gpio">1.2. Accessing gpio</a></li> -<li><a href="#io_uio">1.3. Configuring for UIO Instead of RemoteProc</a></li> -<li><a href="#_converting_pasm_assembly_code_to_clpru">1.4. Converting pasm Assembly Code to clpru</a></li> -</ul> -</li> -</ul> -</div> -</div> -<div id="content"> -<div class="paragraph"> -<p><a href="../index.html">Outline</a></p> -</div> -<div class="sect1"> -<h2 id="_accessing_more_io"><a class="link" href="#_accessing_more_io">1. Accessing More I/O</a></h2> -<div class="sectionbody"> -<div class="paragraph"> -<p>So far the examples have shown how to access the GPIO pins on the BeagleBone Black’s -<code>P9</code> header and through the <code>__R30</code> register. Below shows how more GPIO pins -can be accessed.</p> -</div> -<div class="paragraph"> -<p>The following are resources used in this chapter.</p> -</div> -<div class="ulist"> -<div class="title">Resources</div> -<ul> -<li> -<p><a href="https://github.com/derekmolloy/exploringBB/blob/master/chp06/docs/BeagleboneBlackP8HeaderTable.pdf">P8 Header Table</a></p> -</li> -<li> -<p><a href="https://github.com/derekmolloy/exploringBB/blob/master/chp06/docs/BeagleboneBlackP9HeaderTable.pdf">P9 Header Table</a></p> -</li> -<li> -<p><a href="http://www.ti.com/lit/pdf/spruhz6l">AM572x Technical Reference Manual</a> (AI)</p> -</li> -<li> -<p><a href="http://www.ti.com/lit/pdf/spruh73">AM335x Technical Reference Manual</a> (All others)</p> -</li> -<li> -<p><a href="http://www.ti.com/lit/ug/spruhv6a/spruhv6a.pdf">PRU Assembly Language Tools</a></p> -</li> -</ul> -</div> -<div class="sect2"> -<h3 id="_editing_bootuenv_txt_to_access_the_p8_header_on_the_black"><a class="link" href="#_editing_bootuenv_txt_to_access_the_p8_header_on_the_black">1.1. Editing /boot/uEnv.txt to Access the P8 Header on the Black</a></h3> -<div class="sect3"> -<h4 id="_problem"><a class="link" href="#_problem">Problem</a></h4> -<div class="paragraph"> -<p>When I try to configure some pins on the <code>P8</code> header of the Black I get an error.</p> -</div> -<div class="listingblock"> -<div class="title">config-pin</div> -<div class="content"> -<pre class="CodeRay highlight"><code data-lang="bash">bone$ <strong>config-pin P8_28 pruout</strong> -ERROR: open() for /sys/devices/platform/ocp/ocp:P8_28_pinmux/state failed, No such file or directory</code></pre> -</div> -</div> -</div> -<div class="sect3"> -<h4 id="_solution"><a class="link" href="#_solution">Solution</a></h4> -<div class="paragraph"> -<p>On the images for the BeagleBone Black, the HDMI display driver is enabled by -default and uses many of the <code>P8</code> pins. If you are not using -HDMI video (or the HDI audio, or even the eMMC) you can disable it by editing -<code>/boot/uEnv.txt</code></p> -</div> -<div class="paragraph"> -<p>Open <code>/boot/uEnv.txt</code> and scroll down aways until you see:</p> -</div> -<div class="listingblock"> -<div class="title">/boot/uEnv.txt</div> -<div class="content"> -<pre class="CodeRay highlight"><code data-lang="bash">###Disable auto loading of virtual capes (emmc/video/wireless/adc) -#disable_uboot_overlay_emmc=1 -disable_uboot_overlay_video=1 -#disable_uboot_overlay_audio=1</code></pre> -</div> -</div> -<div class="paragraph"> -<p>Uncomment the lines that correspond to the devices you want to disable and -free up their pins.</p> -</div> -<div class="admonitionblock tip"> -<table> -<tr> -<td class="icon"> -<div class="title">Tip</div> -</td> -<td class="content"> -<div class="paragraph"> -<p><a href="https://github.com/derekmolloy/exploringBB/blob/master/chp06/docs/BeagleboneBlackP8HeaderTable.pdf">P8 Header Table</a> -shows what pins are allocated for what.</p> -</div> -</td> -</tr> -</table> -</div> -<div class="paragraph"> -<p>Save the file and reboot. You now have access to the <code>P8</code> pins.</p> -</div> -</div> -</div> -<div class="sect2"> -<h3 id="_accessing_gpio"><a class="link" href="#_accessing_gpio">1.2. Accessing gpio</a></h3> -<div class="sect3"> -<h4 id="_problem_2"><a class="link" href="#_problem_2">Problem</a></h4> -<div class="paragraph"> -<p>I’ve used up all the GPIO in <code>__R30</code>, where can I get more?</p> -</div> -</div> -<div class="sect3"> -<h4 id="_solution_2"><a class="link" href="#_solution_2">Solution</a></h4> -<div class="paragraph"> -<p>So far we have focused on using PRU 0. -<a href="../05blocks/blocks.html#blocks_mapping_bits">Mapping bit positions to pin names -PRU</a> shows -that PRU 0 can access ten GPIO pins on the BeagleBone Black. If you use -PRU 1 you can get to an additional 14 pins (if they aren’t in use for other things.)</p> -</div> -<div class="paragraph"> -<p>What if you need even more GPIO pins? You can access <em>any</em> GPIO pin by going -through the <strong>O</strong>pen-<strong>C</strong>ore <strong>P</strong>rotocol (OCP) port.</p> -</div> -<div class="paragraph"> -<div class="title">PRU Integration</div> -<p><span class="image"><img src="figures/pruIntegration.png" alt="PRU Integration"></span></p> -</div> -<div class="paragraph"> -<p>The figure above shows we’ve been using the <em>Enhanced GPIO</em> interface when using -<code>__R30</code>, but it also shows you can use the OCP. You get access to many more -GPIO pins, but it’s a slower access.</p> -</div> -<div class="listingblock"> -<div class="title">gpio.pru0.c</div> -<div class="content"> -<pre class="CodeRay highlight"><code data-lang="c"><table class="CodeRay"><tr> - <td class="line-numbers"><pre>1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -</pre></td> - <td class="code"><pre><span class="comment">// This code accesses GPIO without using R30 and R31</span> -<span class="preprocessor">#include</span> <span class="include"><stdint.h></span> -<span class="preprocessor">#include</span> <span class="include"><pru_cfg.h></span> -<span class="preprocessor">#include</span> <span class="include">"resource_table_empty.h"</span> -<span class="preprocessor">#include</span> <span class="include">"prugpio.h"</span> - -<span class="preprocessor">#define</span> P9_11 (<span class="hex">0x1</span><<<span class="integer">30</span>) <span class="comment">// Bit position tied to P9_11 on Black</span> -<span class="preprocessor">#define</span> P2_05 (<span class="hex">0x1</span><<<span class="integer">30</span>) <span class="comment">// Bit position tied to P2_05 on Pocket</span> - -<span class="directive">volatile</span> <span class="directive">register</span> uint32_t __R30; -<span class="directive">volatile</span> <span class="directive">register</span> uint32_t __R31; - -<span class="directive">void</span> main(<span class="directive">void</span>) -{ - uint32_t *gpio0 = (uint32_t *)GPIO0; - - <span class="keyword">while</span>(<span class="integer">1</span>) { - gpio0[GPIO_SETDATAOUT] = P9_11; - __delay_cycles(<span class="integer">100000000</span>); - gpio0[GPIO_CLEARDATAOUT] = P9_11; - __delay_cycles(<span class="integer">100000000</span>); - } -}</pre></td> -</tr></table></code></pre> -</div> -</div> -<div class="paragraph"> -<p>This code will toggle <code>P9_11</code> on and off. Here’s the setup file.</p> -</div> -<div class="listingblock"> -<div class="title">setup.sh</div> -<div class="content"> -<pre class="CodeRay highlight"><code data-lang="bash"><table class="CodeRay"><tr> - <td class="line-numbers"><pre>1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -</pre></td> - <td class="code"><pre>#!/bin/bash - -export TARGET=gpio.pru0 -echo TARGET=$TARGET - -# Configure the PRU pins based on which Beagle is running -machine=$(awk '{print $NF}' /proc/device-tree/model) -echo -n $machine -if [ $machine = "Black" ]; then - echo " Found" - pins="P9_11" -elif [ $machine = "Blue" ]; then - echo " Found" - pins="" -elif [ $machine = "PocketBeagle" ]; then - echo " Found" - pins="P2_05" -else - echo " Not Found" - pins="" -fi - -for pin in $pins -do - echo $pin - config-pin $pin gpio - config-pin -q $pin -done</pre></td> -</tr></table></code></pre> -</div> -</div> -<div class="paragraph"> -<p>Notice in the code <code>config-pin</code> set <code>P9_11</code> to <code>gpio</code>, not <code>pruout</code>. This is because -are are using the OCP interface to the pin, not the usual PRU interface.</p> -</div> -<div class="paragraph"> -<p>Set your exports and make.</p> -</div> -<div class="listingblock"> -<div class="content"> -<pre class="CodeRay highlight"><code data-lang="bash">bone$ <strong>source setup.sh</strong> -TARGET=gpio.pru0 -... -bone$ <strong>make</strong> -/var/lib/cloud9/common/Makefile:29: MODEL=TI_AM335x_BeagleBone_Black,TARGET=gpio.pru0 -- Stopping PRU 0 -- copying firmware file /tmp/cloud9-examples/gpio.pru0.out to /lib/firmware/am335x-pru0-fw -write_init_pins.sh -- Starting PRU 0 -MODEL = TI_AM335x_BeagleBone_Black -PROC = pru -PRUN = 0 -PRU_DIR = /sys/class/remoteproc/remoteproc1</code></pre> -</div> -</div> -</div> -<div class="sect3"> -<h4 id="_discussion"><a class="link" href="#_discussion">Discussion</a></h4> -<div class="paragraph"> -<p>When you run the code you see <code>P9_11</code> toggling on and off. Let’s go through -the code line-by-line to see what’s happening.</p> -</div> -<table class="tableblock frame-all grid-all stretch"> -<caption class="title">Table 1. gpio.pru0.c line-by-line</caption> -<colgroup> -<col style="width: 10%;"> -<col style="width: 90%;"> -</colgroup> -<thead> -<tr> -<th class="tableblock halign-left valign-top">Line</th> -<th class="tableblock halign-left valign-top">Explanation</th> -</tr> -</thead> -<tbody> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">2-5</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock">Standard includes</p></td> -</tr> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock">The AM335x has four 32-bit GPIO ports. Lines 55-58 of <code>prugpio.h</code> define the addresses -for each of the ports. You can find these in Table 2-2 page 180 of the -<a href="https://www.ti.com/lit/ug/spruh73p/spruh73p.pdf">AM335x Technical Reference Manual</a>. -Look up <code>P9_11</code> in the <a href="https://github.com/derekmolloy/exploringBB/blob/master/chp06/docs/BeagleboneBlackP9HeaderTable.pdf">P9 Header Table</a>. -Under the <em>Mode7</em> column you see <code>gpio0[30]</code>. This means <code>P9_11</code> is bit 30 -on GPIO port 0. Therefore we will use <code>GPIO0</code> in this code.</p> -<p class="tableblock">You can also run -<code>gpioinfo</code> and look for P9_11.</p></td> -</tr> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock">Line 103 of <code>prugpio.h</code> defines the address offset from <code>GIO0</code> that will -allow us to <em>clear</em> -any (or all) bits in GPIO port 0. Other architectures require you to read a port, -then change some bit, then write it out again, three steps. Here we can do the same by writing to one location, just one step.</p></td> -</tr> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock">Line 104 of <code>prugpio.h</code> is like above, but for <em>setting</em> bits.</p></td> -</tr> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">5</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock">Using this offset of line 105 of <code>prugpio.h</code> lets us just read the bits -without changing them.</p></td> -</tr> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">7,8</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock">This shifts <code>0x1</code> to the 30<sup>th</sup> bit position, which is the one corresponding -to <code>P9_11</code>.</p></td> -</tr> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">15</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock">Here we initialize <code>gpio0</code> to point to the start of GPIO port 0’s control -registers.</p></td> -</tr> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">18</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock"><code>gpio0[GPIO_SETDATAOUT]</code> refers to the <code>SETDATAOUT</code> register of port 0. -Writing to this register turns on the bits where 1’s are written, -but leaves alone the bits where 0’s are.</p></td> -</tr> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">19</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock">Wait 100,000,000 cycles, which is 0.5 seconds.</p></td> -</tr> -<tr> -<td class="tableblock halign-left valign-top"><p class="tableblock">20</p></td> -<td class="tableblock halign-left valign-top"><p class="tableblock">This is line 18, but the output bit is set to 0 where 1’s are written.</p></td> -</tr> -</tbody> -</table> -<div class="sect4"> -<h5 id="_how_fast_can_it_go"><a class="link" href="#_how_fast_can_it_go">How fast can it go?</a></h5> -<div class="paragraph"> -<p>This approach to GPIO goes through the slower OCP interface. If you set <code>__delay_cycles(0)</code> you can see how fast it is.</p> -</div> -<div class="paragraph"> -<div class="title">gpio.pru0.c with __delay_cycles(0)</div> -<p><span class="image"><img src="figures/gpio0delay.png" alt="gpio.pru0.c with __delay_cycles(0)"></span></p> -</div> -<div class="paragraph"> -<p>The period is 80ns which is 12.MHz. That’s about one forth the speed of the -<code>__R30</code> method, but still not bad.</p> -</div> -<div class="paragraph"> -<p>If you are using an oscilloscope, look closely and you’ll see the following.</p> -</div> -<div class="paragraph"> -<div class="title">PWM with jitter</div> -<p><span class="image"><img src="figures/jitter.png" alt="PWM with jitter"></span></p> -</div> -<div class="paragraph"> -<p>The PRU is still as solid as before in it’s timing, but now it’s going through -the OCP interface. This interface is shared with other parts of the system, -therefore the sometimes the PRU must wait for the other parts to finish. -When this happens the pulse width is a bit longer than usual thus adding -jitter to the output.</p> -</div> -<div class="paragraph"> -<p>For many applications a few nanoseconds of jitter is unimportant and this -GPIO interface can be used. If your application needs better timing, -use the <code>__R30</code> interface.</p> -</div> -</div> -</div> -</div> -<div class="sect2"> -<h3 id="io_uio"><a class="link" href="#io_uio">1.3. Configuring for UIO Instead of RemoteProc</a></h3> -<div class="sect3"> -<h4 id="_problem_3"><a class="link" href="#_problem_3">Problem</a></h4> -<div class="paragraph"> -<p>You have some legacy PRU code that uses UIO instead of remoteproc and -you want to switch to UIO.</p> -</div> -</div> -<div class="sect3"> -<h4 id="_solution_3"><a class="link" href="#_solution_3">Solution</a></h4> -<div class="paragraph"> -<p>Edit <code>/boot/uEnt.txt</code> and search for <code>uio</code>. I find</p> -</div> -<div class="listingblock"> -<div class="content"> -<pre>###pru_uio (4.4.x-ti, 4.9.x-ti, 4.14.x-ti & mainline/bone kernel) -uboot_overlay_pru=/lib/firmware/AM335X-PRU-UIO-00A0.dtbo</pre> -</div> -</div> -<div class="paragraph"> -<p>Uncomment the <code>uboot</code> line. Look for other lines with -<code>uboot_overlay_pru=</code> and be sure they are commented out.</p> -</div> -<div class="paragraph"> -<p>Reboot your Bone.</p> -</div> -<div class="listingblock"> -<div class="content"> -<pre>bone$ <strong>sudo reboot</strong></pre> -</div> -</div> -<div class="paragraph"> -<p>Check that UIO is running.</p> -</div> -<div class="listingblock"> -<div class="content"> -<pre>bone$ <strong>lsmod | grep uio</strong> -uio_pruss 16384 0 -uio_pdrv_genirq 16384 0 -uio 20480 2 uio_pruss,uio_pdrv_genirq</pre> -</div> -</div> -<div class="paragraph"> -<p>You are now ready to run the legacy PRU code.</p> -</div> -</div> -</div> -<div class="sect2"> -<h3 id="_converting_pasm_assembly_code_to_clpru"><a class="link" href="#_converting_pasm_assembly_code_to_clpru">1.4. Converting pasm Assembly Code to clpru</a></h3> -<div class="sect3"> -<h4 id="_problem_4"><a class="link" href="#_problem_4">Problem</a></h4> -<div class="paragraph"> -<p>You have some legacy assembly code written in pasm and it won’t assemble -with clpru.</p> -</div> -</div> -<div class="sect3"> -<h4 id="_solution_4"><a class="link" href="#_solution_4">Solution</a></h4> -<div class="paragraph"> -<p>Generally there is a simple mapping from pasm to clpru. -<a href="http://processors.wiki.ti.com/index.php/PRU_Assembly_Instructions#pasm_vs._clpru">pasm vs. clpru</a> -notes what needs to be changed. I have a less complete version on my -<a href="https://elinux.org/EBC_Exercise_30_PRU_porting_pasm_to_clpru">eLinux.org site</a>.</p> -</div> -</div> -<div class="sect3"> -<h4 id="_discussion_2"><a class="link" href="#_discussion_2">Discussion</a></h4> -<div class="paragraph"> -<p>The clpru assembly can be found in <a href="http://www.ti.com/lit/ug/spruhv6a/spruhv6a.pdf">PRU Assembly Language Tools</a>.</p> -</div> -</div> -</div> -</div> -</div> -</div> -<div id="footer"> -<div id="footer-text"> -Last updated 2021-08-04 14:38:24 -0400 -</div> -</div> -</body> -</html> \ No newline at end of file diff --git a/books/pru-cookbook/06io/io.rst b/books/pru-cookbook/06io/io.rst index 3548d5e0..a252c44c 100644 --- a/books/pru-cookbook/06io/io.rst +++ b/books/pru-cookbook/06io/io.rst @@ -3,9 +3,8 @@ Accessing More I/O #################### -So far the examples have shown how to access the GPIO pins on the BeagleBone Black's -``P9`` header and through the ``pass:[__]R30`` register. Below shows how more GPIO pins -can be accessed. +So far the examples have shown how to access the GPIO pins on the BeagleBone Black's ``P9`` header and +through the ``pass:[__]R30`` register. Below shows how more GPIO pins can be accessed. The following are resources used in this chapter. @@ -14,21 +13,18 @@ Resources * `P8 Header Table <https://github.com/derekmolloy/exploringBB/blob/master/chp06/docs/BeagleboneBlackP8HeaderTable.pdf>`_ * `P9 Header Table <https://github.com/derekmolloy/exploringBB/blob/master/chp06/docs/BeagleboneBlackP9HeaderTable.pdf>`_ -* `AM572x Technical Reference Manual<http://www.ti.com/lit/pdf/spruhz6l>`_ (AI) +* `AM572x Technical Reference Manual <http://www.ti.com/lit/pdf/spruhz6l>`_ (AI) * `AM335x Technical Reference Manual <http://www.ti.com/lit/pdf/spruh73>`_ (All others) -* `PRU Assembly Language Tools<http://www.ti.com/lit/ug/spruhv6a/spruhv6a.pdf>`_ +* `PRU Assembly Language Tools <http://www.ti.com/lit/ug/spruhv6a/spruhv6a.pdf>`_ Editing /boot/uEnv.txt to Access the P8 Header on the Black -============================================================ +************************************************************ Problem -------- When I try to configure some pins on the `P8` header of the Black I get an error. -config-pin -~~~~~~~~~~~ - .. code-block:: bash :linenos: @@ -36,7 +32,7 @@ config-pin ERROR: open() for /sys/devices/platform/ocp/ocp:P8_28_pinmux/state failed, No such file or directory Solution --------- +--------- On the images for the BeagleBone Black, the HDMI display driver is enabled by default and uses many of the ``P8`` pins. If you are not using HDMI video (or the HDI audio, @@ -44,10 +40,8 @@ or even the eMMC) you can disable it by editing ``/boot/uEnv.txt`` Open ``/boot/uEnv.txt`` and scroll down aways until you see: -/boot/uEnv.txt -~~~~~~~~~~~~~~~~ - .. code-block:: bash + :caption: /boot/uEnv.txt :linenos: ###Disable auto loading of virtual capes (emmc/video/wireless/adc) @@ -65,7 +59,7 @@ Uncomment the lines that correspond to the devices you want to disable and free Save the file and reboot. You now have access to the ``P8`` pins. Accessing gpio -================ +**************** Problem -------- @@ -73,36 +67,38 @@ Problem I've used up all the GPIO in ``pass:[__]R30``, where can I get more? Solution --------- +--------- So far we have focused on using PRU 0. -:ref:`../05blocks/blocks.html#blocks_mapping_bits,Mapping bit positions to pin names PRU` shows +:ref:`blocks_mapping_bits` shows that PRU 0 can access ten GPIO pins on the BeagleBone Black. If you use PRU 1 you can get to an additional 14 pins (if they aren't in use for other things.) What if you need even more GPIO pins? You can access **any** GPIO pin by going -through the **O**pen-**C**ore **P**rotocol (OCP) port. +through the **O**\ pen-\ **C**\ ore **P**\ rotocol (OCP) port. -PRU Integration -~~~~~~~~~~~~~~~~~ .. figure:: figures/pruIntegration.png :align: center :alt: PRU Integration + PRU Integration + The figure above shows we've been using the _Enhanced **GPIO** interface when using ``pass:[__]R30``, but it also shows you can use the OCP. You get access to many more GPIO pins, but it's a slower access. -gpio.pru0.c -~~~~~~~~~~~~ +.. literalinclude:: code/gpio.pru0.c + :caption: gpio.pru0.c + :linenos: :download:`gpio.pru0.c <code/gpio.pru0.c>` This code will toggle ``P9_11`` on and off. Here's the setup file. -setup.sh -~~~~~~~~~ +.. literalinclude:: code/setup.sh + :caption: setup.sh + :linenos: :download:`setup.sh <code/setup.sh>` @@ -134,10 +130,8 @@ Discussion When you run the code you see ``P9_11`` toggling on and off. Let's go through the code line-by-line to see what's happening. -gpio.pru0.c line-by-line -~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. table:: +.. table:: gpio.pru0.c line-by-line +-------+-----------------------------------------------------------------------------------------------------------------------------------------------+ |Line | Explanation | @@ -172,30 +166,28 @@ gpio.pru0.c line-by-line +-------+-----------------------------------------------------------------------------------------------------------------------------------------------+ How fast can it go? -~~~~~~~~~~~~~~~~~~~~ +-------------------- This approach to GPIO goes through the slower OCP interface. If you set ``pass:[__]delay_cycles(0)`` you can see how fast it is. -gpio.pru0.c with pass:[__]delay_cycles(0) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/gpio0delay.png :align: center :alt: gpio.pru0.c with pass:[__]delay_cycles(0) + gpio.pru0.c with pass:[__]delay_cycles(0) + The period is 80ns which is 12.MHz. That's about one forth the speed of the ``pass:[__]R30`` method, but still not bad. If you are using an oscilloscope, look closely and you'll see the following. -PWM with jitter -~~~~~~~~~~~~~~~~ - .. figure:: figures/jitter.png :align: center :alt: PWM with jitter + PWM with jitter + The PRU is still as solid as before in it's timing, but now it's going through the OCP interface. This interface is shared with other parts of the system, therefore the sometimes the PRU must wait for the other parts to finish. @@ -206,11 +198,10 @@ For many applications a few nanoseconds of jitter is unimportant and this GPIO interface can be used. If your application needs better timing, use the ``pass:[__]R30`` interface. - .. _io_uio: Configuring for UIO Instead of RemoteProc -======================================== +******************************************* Problem -------- @@ -249,7 +240,7 @@ Check that UIO is running. You are now ready to run the legacy PRU code. Converting pasm Assembly Code to clpru -======================================== +*************************************** Problem -------- @@ -257,7 +248,7 @@ Problem You have some legacy assembly code written in pasm and it won't assemble with clpru. Solution --------- +--------- Generally there is a simple mapping from pasm to clpru. `pasm vs. clpru <http://processors.wiki.ti.com/index.php/PRU_Assembly_Instructions#pasm_vs._clpru>`_ @@ -265,7 +256,7 @@ notes what needs to be changed. I have a less complete version on my `eLinux.org site <https://elinux.org/EBC_Exercise_30_PRU_porting_pasm_to_clpru>`_. Discussion --------- +----------- The clpru assembly can be found in `PRU Assembly Language Tools <http://www.ti.com/lit/ug/spruhv6a/spruhv6a.pdf>`_. diff --git a/books/pru-cookbook/07more/more.rst b/books/pru-cookbook/07more/more.rst index ae3abcf8..4bae78b1 100644 --- a/books/pru-cookbook/07more/more.rst +++ b/books/pru-cookbook/07more/more.rst @@ -22,15 +22,15 @@ Resources * `PRU Assembly Instruction User Guide <http://www.ti.com/lit/ug/spruij2/spruij2.pdf>`_ Calling Assembly from C -------------------------- +************************ Problem -~~~~~~~~~ +-------- You have some C code and you want to call an assembly language routine from it. Solution -~~~~~~~~~ +--------- You need to do two things, write the assembler file and modify the ``Makefile`` to include it. For example, let's write our own ``my_delay_cycles`` routine in @@ -42,28 +42,30 @@ constant. Our new ``delay_cycles`` can take a runtime delay value. .. _more_delay-test: -delay-test.pru0.c -~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/delay-test.pru0.c + :caption: delay-test.pru0.c + :linenos: -:download:`code/delay-test.pru0.c <code/delay-test.pru0.c>` +:download:`delay-test.pru0.c <code/delay-test.pru0.c>` :ref:`more_delay` is the assembly code. .. _more_delay: -delay.pru0.asm -~~~~~~~~~~~~~~~ +.. literalinclude:: code/delay.pru0.asm + :caption: delay.pru0.asm + :linenos: :download:`delay.pru0.asm <code/delay.pru0.asm>` The ``Makefile`` has one addition that needs to be made to compile both :ref:`more_delay-test` -and :ref:`more_delay`. -If you look in the local ``Makefile`` you'll see: +and :ref:`more_delay`. If you look in the local ``Makefile`` you'll see: .. _more_makefile: -Makefile -~~~~~~~~~ +.. literalinclude:: code/Makefile + :caption: Makefile + :linenos: :download:`Makefile <code/Makefile>` @@ -102,23 +104,20 @@ The resulting output is shown in :ref:`more_my_delay_cycles`. .. _more_my_delay_cycles: -Output of my_delay_cycles() -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. figure:: figures/my_delay_cycles.png :align: center :alt: Output of my_delay_cycles() + Output of my_delay_cycles() + Notice the on time is about 35ns and the off time is 30ns. Discission -~~~~~~~~~~~~ +----------- There is much to explain here. Let's start with :ref:`more_delay`. -Line-by-line of delay.pru0.asm -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. table:: +.. table:: Line-by-line of delay.pru0.asm +-------+-------------------------------------------------------------------------------------------------------+ |Line | Explanation | @@ -152,22 +151,23 @@ The extra instruction is the branch at the bottom of the ``while`` loop. Returning a Value from Assembly --------------------------------- +******************************** Problem -~~~~~~~~~ +-------- Your assembly code needs to return a value. Solution -~~~~~~~~~ +-------- ``R14`` is how the return value is passed back. :ref:`more_test2` shows the c code. .. _more_test2: -delay-test2.pru0.c -~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/delay-test2.pru0.c + :caption: delay-test2.pru0.c + :linenos: :download:`delay-test2.pru0.c <code/delay-test2.pru0.c>` @@ -175,8 +175,9 @@ delay-test2.pru0.c .. _more_delay2: -delay2.pru0.asm -~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/delay2.pru0.asm + :caption: delay2.pru0.asm + :linenos: :download:`delay2.pru0.asm <code/delay2.pru0.asm>` @@ -187,15 +188,15 @@ In this example, line 6 of :ref:`more_test2` `#defines` TEST and line 12 of Using the Built-In Counter for Timing ---------------------------------------- +*************************************** Problem -~~~~~~~~~ +-------- I want to count how many cycles my routine takes. Solution -~~~~~~~~~ +--------- Each PRU has a ``CYCLE`` register which counts the number of cycles since the PRU was enabled. They also have a ``STALL`` register that counts how @@ -204,23 +205,21 @@ many times the PRU stalled fetching an instruction. .. _more_cycle: -cycle.pru0.c - Code to count cycles. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/cycle.pru0.c + :caption: cycle.pru0.c - Code to count cycles. + :linenos: -:download:`delay2.pru0.asm <code/cycle.pru0.c>` +:download:`cycle.pru0.c <code/cycle.pru0.c>` Discission -~~~~~~~~~~~~ +------------ The code is mostly the same as other examples. ``cycle`` and ``stall`` end up in registers which we can read using prudebug. :ref:`more_cycle_lines` is the Line-by-line. .. _more_cycle_lines: -Line-by-line for cycle.pru0.c -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: Line-by-line for cycle.pru0.c +-------+---------------------------------------------------------------------------------------+ |Line | Explanation | @@ -244,20 +243,26 @@ You can see where ``cycle`` and ``stall`` are stored by looking into :ref:`more_ .. _more_cycle_list0: -/tmp/cloud9-examples/cycle.pru0.lst Lines 113..119 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/cycle.pru0.lst + :caption: /tmp/cloud9-examples/cycle.pru0.lst Lines 113..119 + :lines: 113-119 + :lineno-start: 113 + :linenos: -:download:`cycle.pru0.lst lines=113..119 <code/cycle.pru0.lst>` +:download:`cycle.pru0.lst <code/cycle.pru0.lst>` Here the ``LDI32`` instruction loads the address ``0x22000`` into ``r0``. This is the offset to the ``CTRL`` registers. Later in the file we see :ref:`more_cycle_list1`. .. _more_cycle_list1: -/tmp/cloud9-examples/cycle.pru0.lst Lines 146..152 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. literalinclude:: code/cycle.pru0.lst + :caption: /tmp/cloud9-examples/cycle.pru0.lst Lines 146..152 + :lines: 146-152 + :lineno-start: 146 + :linenos: -:download:`lines=146..152 <code/cycle.pru0.lst>` +:download:`cycle.pru0.lst <code/cycle.pru0.lst>` The first ``LBBO`` takes the contents of ``r0`` and adds the offset 12 to it and copies 4 bytes @@ -298,23 +303,24 @@ If you switch the order of lines 30 and 31 you'll see ``cycle`` is 7 and ``stall time needed to read ``stall`` and ``stall`` no longer includes the time to read ``cycle``. Xout and Xin - Transfering Between PRUs ---------------------------------------- +***************************************** Problem -~~~~~~~~~ +-------- I need to transfer data between PRUs quickly. Solution -~~~~~~~~~ +--------- The ``pass:[__]xout()`` and ``pass:[__]xin()`` intrinsics are able to transfer up to 30 registers between PRU 0 and PRU 1 quickly. :ref:`more_xout` shows how ``xout()`` running on PRU 0 transfers six registers to PRU 1. .. _more_xout: -xout.pru0.c -~~~~~~~~~~~~ +.. literalinclude:: code/xout.pru0.c + :caption: xout.pru0.c + :linenos: :download:`xout.pru0.c <code/xout.pru0.c>` @@ -323,8 +329,9 @@ interupt to PRU 0 and waits for it to send the data. .. _more_xin: -xin.pru1.c -~~~~~~~~~~~ +.. literalinclude:: code/xin.pru1.c + :caption: xin.pru1.c + :linenos: :download:`xin.pru1.c <code/xin.pru1.c>` @@ -373,15 +380,13 @@ Use ``prudebug`` to see registers R5-R10 are transfered from PRU 0 to PRU 1. Discussion -~~~~~~~~~ +----------- :ref:`more_zout_lines` shows the line-by-line for ``xout.pru0.c`` .. _more_zout_lines: -xout.pru0.c Line-by-line -~~~~~~~~~~~~~~~~~~~~~~~~~ -.. table:: +.. table:: xout.pru0.c Line-by-line +-------+---------------------------------------------------------------------------------------------------------+ |Line | Explanation | @@ -415,9 +420,7 @@ xout.pru0.c Line-by-line .. _more_xin_lines: -xin.pru1.c Line-by-line -~~~~~~~~~~~~~~~~~~~~~~~~ -.. table:: +.. table:: xin.pru1.c Line-by-line +-------+-----------------------------------------------------------+ |Line | Explanation | @@ -435,9 +438,10 @@ xin.pru1.c Line-by-line If you really need speed, considering using ``pass:[__]xout()`` and ``pass:[__]xin()`` in assembly. Copyright ----------- +========== -copyright.c -~~~~~~~~~~~~~ +.. literalinclude:: code/copyright.c + :caption: copyright.c + :linenos: :download:`copyright.c <code/copyright.c>` diff --git a/books/pru-cookbook/08ai/ai.rst b/books/pru-cookbook/08ai/ai.rst index db36f383..ca507562 100644 --- a/books/pru-cookbook/08ai/ai.rst +++ b/books/pru-cookbook/08ai/ai.rst @@ -18,7 +18,7 @@ Resources * `BeagleBone AI PRU pins <https://docs.google.com/spreadsheets/d/1dFSBVem86vAUD7MLXvqdS-N0Efi8_g_O1iTqzql8DAo/edit#gid=0>`_ Moving from two to four PRUs -============================= +***************************** Problem -------- @@ -37,21 +37,18 @@ Things to consider when moving to the AI are: Knowing which pins to use impacts the PRU you'll use. Discission --------- +----------- The various System Reference Manuals (SRM's) list which pins go to the PRUs. Here the tables are combined into one to make it easier to see what goes where. .. _aimapping_bits: -Mapping bit positions to pin names -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. table:: +.. table:: Mapping bit positions to pin names +---+---+---------+-----------+-----------+-------------+ |PRU|Bit|Black pin|AI PRU1 pin|AI PRU2 pin|Pocket pin | - |0 |0 |P9_31 | |P8_44 |P1.36 | + |0 |0 |P9_31 | |P8_44 |P1.36 | +---+---+---------+-----------+-----------+-------------+ |0 |1 |P9_29 | |P8_41 |P1.33 | +---+---+---------+-----------+-----------+-------------+ @@ -67,31 +64,31 @@ Mapping bit positions to pin names +---+---+---------+-----------+-----------+-------------+ |0 |7 |P9_25 | |P8_36/P8_6 |P1.29 | +---+---+---------+-----------+-----------+-------------+ - |0 |8 | | |P8_34/P8_23| | + |0 |8 | | |P8_34/P8_23| | +---+---+---------+-----------+-----------+-------------+ - |0 |9 | | |P8_35/P8_22| | + |0 |9 | | |P8_35/P8_22| | +---+---+---------+-----------+-----------+-------------+ - |0 |19 | | |P8_33/P8_3 | | + |0 |19 | | |P8_33/P8_3 | | +---+---+---------+-----------+-----------+-------------+ - |0 |11 | | |P8_31/P8_4 | | + |0 |11 | | |P8_31/P8_4 | | +---+---+---------+-----------+-----------+-------------+ - |0 |12 | | |P8_32 | | + |0 |12 | | |P8_32 | | +---+---+---------+-----------+-----------+-------------+ - |0 |13 | | |P8_45 | | + |0 |13 | | |P8_45 | | +---+---+---------+-----------+-----------+-------------+ |0 |14 |P8_12(out) P8_16(in)||P9_11 |P2.24 | +---+---+---------+-----------+-----------+-------------+ |0 |15 |P8_11(out) P8_15(in)||P8_17/P9_13|P2.33 | +---+---+---------+-----------+-----------+-------------+ - |0 |16 |P9_41(in) P9_26(in)| |P8_27 | | + |0 |16 |P9_41(in) P9_26(in)| |P8_27 | | +---+---+---------+-----------+-----------+-------------+ - |0 |17 | |P9_26 |P8_28 | | + |0 |17 | |P9_26 |P8_28 | | +---+---+---------+-----------+-----------+-------------+ - |0 |18 | | |P8_29 | | + |0 |18 | | |P8_29 | | +---+---+---------+-----------+-----------+-------------+ - |0 |19 | | |P8_30 | | + |0 |19 | | |P8_30 | | +---+---+---------+-----------+-----------+-------------+ - |0 |20 | | |P8_46/P8_8 | | + |0 |20 | | |P8_46/P8_8 | | +---+---+---------+-----------+-----------+-------------+ | | | | | | | +---+---+---------+-----------+-----------+-------------+ @@ -127,15 +124,15 @@ Mapping bit positions to pin names +---+---+---------+-----------+-----------+-------------+ |1 |15 | |*P9_16* |P8_10 |P1.30 | +---+---+---------+-----------+-----------+-------------+ - |1 |16 |P9_26(in)|*P8_15* |P8_7 | | + |1 |16 |P9_26(in)|*P8_15* |P8_7 | | +---+---+---------+-----------+-----------+-------------+ - |1 |17 | |*P8_26* |P8_27 | | + |1 |17 | |*P8_26* |P8_27 | | +---+---+---------+-----------+-----------+-------------+ - |1 |18 | |*P8_16* |P8_45 | | + |1 |18 | |*P8_16* |P8_45 | | +---+---+---------+-----------+-----------+-------------+ - |1 |19 | | |P8_46 | | + |1 |19 | | |P8_46 | | +---+---+---------+-----------+-----------+-------------+ - |1 |19 | | |P8_43 | | + |1 |19 | | |P8_43 | | +---+---+---------+-----------+-----------+-------------+ The pins in *bold* are already configured as pru pins. See :ref:`ai_config` to @@ -145,7 +142,7 @@ configure pins. .. _ai_config: Seeing how pins are configured -=============================== +******************************* Problem -------- @@ -231,7 +228,7 @@ Five are input pins and four are out. .. _ai_device_tree: Configuring pins on the AI via device trees -============================================ +******************************************** Problem -------- @@ -274,6 +271,7 @@ We see that when ``P9_31a`` is set to ``MODE13`` it will be a PRU **out** pin. Next, find which kernel you are running. .. code-block:: bash + bone$ uname -a Linux ai 4.14.108-ti-r131 #1buster SMP PREEMPT Tue Mar 24 19:18:36 UTC 2020 armv7l GNU/Linux @@ -335,7 +333,7 @@ There it is. `P9_31` is now a PRU output pin on PRU1_0, bit 3. .. _ai_using_pru_pins: Using the PRU pins -==================== +********************* Problem -------- @@ -350,7 +348,7 @@ that it appears at ``pr2_pru1_gpo10``, which means pru2_1 accesses it using bit 10 of register ``R30``. Discission --------- +----------- It's easy to modify the pwm example from :ref:`blocks_pwm` to use this pin. First copy the example you want to modify to ``pwm1.pru2_1.c``. The ``pru2_1`` in @@ -359,8 +357,9 @@ the adapted code. .. _ai_pwm1: -pwm1.pru2_1.c -~~~~~~~~~~~~~~ +.. literalinclude:: code/pwm1.pru2_1.c + :caption: pwm1.pru2_1.c + :linenos: :download:`pwm1.pru2_1.c <code/pwm1.pru2_1.c>` -- GitLab