Skip to content

Instantly share code, notes, and snippets.

@jadonk
Last active November 9, 2021 00:34
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save jadonk/2ecf864e1b3f250bad82c0eae12b7b64 to your computer and use it in GitHub Desktop.
Save jadonk/2ecf864e1b3f250bad82c0eae12b7b64 to your computer and use it in GitHub Desktop.
PRU programming with Debian Stretch BeagleBoard.org IoT 2017-06-11 image

Instructions

  1. Grab https://rcn-ee.com/rootfs/bb.org/testing/2017-06-11/stretch-iot/bone-debian-stretch-iot-armhf-2017-06-11-4gb.img.xz
  2. Program a microSD card with that image using http://etcher.io
  3. Boot it on a BeagleBone
  4. Get connected to the Internet
  5. Run the following in the shell
cd /var/lib/cloud9
git clone https://gist.github.com/jadonk/2ecf864e1b3f250bad82c0eae12b7b64
cd 2ecf864e1b3f250bad82c0eae12b7b64
make
echo none > /sys/class/leds/beaglebone\:green\:usr0/trigger
sudo config-pin overlay cape-universala
sudo config-pin p9.30 pruout
sudo make run

You'll see USR0 blinking 5 times a second (toggles every 100ms). Modify hello-pru.c as desired and enjoy!

Notes

Version

Debian Stretch BeagleBoard.org BeagleBone IoT Image

git:/opt/scripts/:[09ae22ec483e5483c6ae7f0ca7bbbabf864b06af]
eeprom:[A335BNLTBP00yywwBP000000]
dogtag:[BeagleBoard.org Debian Image 2017-06-11]
bootloader:[microSD-(push-button)]:[/dev/mmcblk0]:[U-Boot 2017.05-00002-ga302d6e48b]
kernel:[4.4.68-ti-r108]
nodejs:[v6.11.0]
uboot_overlay_options:[enable_uboot_overlays=1]
uboot_overlay_options:[uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-4-TI-00A0.dtbo]
uboot_overlay_options:[enable_uboot_cape_universal=1]
/****************************************************************************/
/* AM335x_PRU.cmd */
/* Copyright (c) 2015 Texas Instruments Incorporated */
/* */
/* Description: This file is a linker command file that can be used for */
/* linking PRU programs built with the C compiler and */
/* the resulting .out file on an AM335x device. */
/****************************************************************************/
-cr /* Link using C conventions */
/* Specify the System Memory Map */
MEMORY
{
PAGE 0:
PRU_IMEM : org = 0x00000000 len = 0x00002000 /* 8kB PRU0 Instruction RAM */
PAGE 1:
/* RAM */
PRU_DMEM_0_1 : org = 0x00000000 len = 0x00002000 CREGISTER=24 /* 8kB PRU Data RAM 0_1 */
PRU_DMEM_1_0 : org = 0x00002000 len = 0x00002000 CREGISTER=25 /* 8kB PRU Data RAM 1_0 */
PAGE 2:
PRU_SHAREDMEM : org = 0x00010000 len = 0x00003000 CREGISTER=28 /* 12kB Shared RAM */
DDR : org = 0x80000000 len = 0x00000100 CREGISTER=31
L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30
/* Peripherals */
PRU_CFG : org = 0x00026000 len = 0x00000044 CREGISTER=4
PRU_ECAP : org = 0x00030000 len = 0x00000060 CREGISTER=3
PRU_IEP : org = 0x0002E000 len = 0x0000031C CREGISTER=26
PRU_INTC : org = 0x00020000 len = 0x00001504 CREGISTER=0
PRU_UART : org = 0x00028000 len = 0x00000038 CREGISTER=7
DCAN0 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14
DCAN1 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15
DMTIMER2 : org = 0x48040000 len = 0x0000005C CREGISTER=1
PWMSS0 : org = 0x48300000 len = 0x000002C4 CREGISTER=18
PWMSS1 : org = 0x48302000 len = 0x000002C4 CREGISTER=19
PWMSS2 : org = 0x48304000 len = 0x000002C4 CREGISTER=20
GEMAC : org = 0x4A100000 len = 0x0000128C CREGISTER=9
I2C1 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2
I2C2 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17
MBX0 : org = 0x480C8000 len = 0x00000140 CREGISTER=22
MCASP0_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8
MCSPI0 : org = 0x48030000 len = 0x000001A4 CREGISTER=6
MCSPI1 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16
MMCHS0 : org = 0x48060000 len = 0x00000300 CREGISTER=5
SPINLOCK : org = 0x480CA000 len = 0x00000880 CREGISTER=23
TPCC : org = 0x49000000 len = 0x00001098 CREGISTER=29
UART1 : org = 0x48022000 len = 0x00000088 CREGISTER=11
UART2 : org = 0x48024000 len = 0x00000088 CREGISTER=12
RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10
RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13
RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21
RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27
}
/* Specify the sections allocation into memory */
SECTIONS {
/* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading
an ELF file, but useful when loading a binary */
.text:_c_int00* > 0x0, PAGE 0
.text > PRU_IMEM, PAGE 0
.stack > PRU_DMEM_0_1, PAGE 1
.bss > PRU_DMEM_0_1, PAGE 1
.cio > PRU_DMEM_0_1, PAGE 1
.data > PRU_DMEM_0_1, PAGE 1
.switch > PRU_DMEM_0_1, PAGE 1
.sysmem > PRU_DMEM_0_1, PAGE 1
.cinit > PRU_DMEM_0_1, PAGE 1
.rodata > PRU_DMEM_0_1, PAGE 1
.rofardata > PRU_DMEM_0_1, PAGE 1
.farbss > PRU_DMEM_0_1, PAGE 1
.fardata > PRU_DMEM_0_1, PAGE 1
.resource_table > PRU_DMEM_0_1, PAGE 1
}
/*
* Source Modified by Zubeen Tolani < ZeekHuge - zeekhuge@gmail.com >
* Based on the examples distributed by TI
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <pru_cfg.h>
#include <pru_ctrl.h>
#include "resource_table_empty.h"
#define INS_PER_US 200 // 5ns per instruction
#define INS_PER_DELAY_LOOP 2 // two instructions per delay loop
#define DELAY_CYCLES_US (INS_PER_US / INS_PER_DELAY_LOOP)
#define GPIO1 0x4804C000
#define GPIO_CLEARDATAOUT 0x190
#define GPIO_SETDATAOUT 0x194
#define USR0 (1<<21)
#define USR1 (1<<22)
#define USR2 (1<<23)
#define USR3 (1<<24)
unsigned int volatile * const GPIO1_CLEAR = (unsigned int *) (GPIO1 + GPIO_CLEARDATAOUT);
unsigned int volatile * const GPIO1_SET = (unsigned int *) (GPIO1 + GPIO_SETDATAOUT);
volatile register unsigned int __R30;
volatile register unsigned int __R31;
#define PRU0_GPIO (1<<2)
#ifndef DECAY_RATE
#define DECAY_RATE 100
#endif
#ifndef DELAY_CYCLES
#define DELAY_CYCLES DELAY_CYCLES_US
#endif
const int decay = DECAY_RATE;
void main(void) {
int i, j;
/* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
for(i = 1000000; i > 0; i = (i * decay) / 100) {
#ifndef LED_DISABLE
*GPIO1_SET = USR0;
#endif
#ifndef GPIO_DISABLE
__R30 |= PRU0_GPIO;
#endif
for(j=0;j<i;j++){ __delay_cycles(DELAY_CYCLES); }
#ifndef LED_DISABLE
*GPIO1_CLEAR = USR0;
#endif
#ifndef GPIO_DISABLE
__R30 ^= PRU0_GPIO;
#endif
for(j=0;j<i;j++){ __delay_cycles(DELAY_CYCLES); }
}
__halt();
}
#
# Copyright (c) 2016 Zubeen Tolani <ZeekHuge - zeekhuge@gmail.com>
# Copyright (c) 2017 Texas Instruments - Jason Kridner <jdk@ti.com>
#
PROJ_NAME=hello-pru
# PRU_CGT environment variable must point to the TI PRU compiler directory.
# PRU_SUPPORT points to pru-software-support-package
# Both are set in setup.sh
PRU_CGT:=/usr/share/ti/cgt-pru
PRU_SUPPORT:=/usr/lib/ti/pru-software-support-package
LINKER_COMMAND_FILE=./AM335x_PRU.cmd
LIBS=--library=$(PRU_SUPPORT)/lib/rpmsg_lib.lib
INCLUDE=--include_path=$(PRU_SUPPORT)/include --include_path=$(PRU_SUPPORT)/include/am335x
STACK_SIZE=0x100
HEAP_SIZE=0x100
CFLAGS=-v3 -O2 --display_error_number --endian=little --hardware_mac=on --obj_directory=$(GEN_DIR) --pp_directory=$(GEN_DIR) -ppd -ppa --asm_listing --c_src_interlist # --absolute_listing
LFLAGS=--reread_libs --warn_sections --stack_size=$(STACK_SIZE) --heap_size=$(HEAP_SIZE) -m $(GEN_DIR)/file.map
GEN_DIR=gen
PRU0_FW =$(GEN_DIR)/$(PROJ_NAME).out
# -----------------------------------------------------
# Variable to edit in the makefile
# add the required firmwares to TARGETS
TARGETS =$(PRU0_FW) $(GEN_DIR)/decay95.out
#------------------------------------------------------
.PHONY: all
all: $(TARGETS)
@echo '- Generated firmwares are : $^'
$(GEN_DIR)/decay95.out: $(GEN_DIR)/decay95.obj
@echo 'LD $^'
@lnkpru -i$(PRU_CGT)/lib -i$(PRU_CGT)/include $(LFLAGS) -o $@ $^ $(LINKER_COMMAND_FILE) --library=libc.a $(LIBS) $^
$(GEN_DIR)/decay95.obj: $(PROJ_NAME).c
@mkdir -p $(GEN_DIR)
@echo 'CC $<'
@clpru --define=DECAY_RATE=95 --include_path=$(PRU_CGT)/include $(INCLUDE) $(CFLAGS) -fe $@ $<
$(PRU0_FW): $(GEN_DIR)/$(PROJ_NAME).obj
@echo 'LD $^'
@lnkpru -i$(PRU_CGT)/lib -i$(PRU_CGT)/include $(LFLAGS) -o $@ $^ $(LINKER_COMMAND_FILE) --library=libc.a $(LIBS) $^
$(GEN_DIR)/$(PROJ_NAME).obj: $(PROJ_NAME).c
@mkdir -p $(GEN_DIR)
@echo 'CC $<'
@clpru --include_path=$(PRU_CGT)/include $(INCLUDE) $(CFLAGS) -fe $@ $<
.PHONY: install run run95
install:
@echo '- copying firmware file $(PRU0_FW) to /lib/firmware/am335x-pru0-fw'
@cp $(PRU0_FW) /lib/firmware/am335x-pru0-fw
run: install
@echo '- rebooting pru core 0'
$(shell echo "4a334000.pru0" > /sys/bus/platform/drivers/pru-rproc/unbind 2> /dev/null)
$(shell echo "4a334000.pru0" > /sys/bus/platform/drivers/pru-rproc/bind)
@echo "- pru core 0 is now loaded with $(PRU0_FW)"
run95:
@echo '- copying firmware file $(GEN_DIR)/decay95.out to /lib/firmware/am335x-pru0-fw'
@cp $(GEN_DIR)/decay95.out /lib/firmware/am335x-pru0-fw
@echo '- rebooting pru core 0'
$(shell echo "4a334000.pru0" > /sys/bus/platform/drivers/pru-rproc/unbind 2> /dev/null)
$(shell echo "4a334000.pru0" > /sys/bus/platform/drivers/pru-rproc/bind)
@echo "- pru core 0 is now loaded with $(GEN_DIR)/decay95.out"
.PHONY: clean
clean:
@echo 'CLEAN .'
@rm -rf $(GEN_DIR) $(PROJ_NAME).asm
/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* ======== resource_table_empty.h ========
*
* Define the resource table entries for all PRU cores. This will be
* incorporated into corresponding base images, and used by the remoteproc
* on the host-side to allocated/reserve resources. Note the remoteproc
* driver requires that all PRU firmware be built with a resource table.
*
* This file contains an empty resource table. It can be used either as:
*
* 1) A template, or
* 2) As-is if a PRU application does not need to configure PRU_INTC
* or interact with the rpmsg driver
*
*/
#ifndef _RSC_TABLE_PRU_H_
#define _RSC_TABLE_PRU_H_
#include <stddef.h>
#include <rsc_types.h>
struct my_resource_table {
struct resource_table base;
uint32_t offset[1]; /* Should match 'num' in actual definition */
};
#pragma DATA_SECTION(pru_remoteproc_ResourceTable, ".resource_table")
#pragma RETAIN(pru_remoteproc_ResourceTable)
struct my_resource_table pru_remoteproc_ResourceTable = {
1, /* we're the first version that implements this */
0, /* number of entries in the table */
0, 0, /* reserved, must be zero */
0, /* offset[0] */
};
#endif /* _RSC_TABLE_PRU_H_ */
@mikeydalby
Copy link

Hi,
I wondered if there was a way to make a program running in the PRU available to a Node-Red implementation running on the same BBB??
For example if I had the PRU doing serial communications, could I read/export any data into a Node-Red flow?

Kind regards

Michael

@jadonk
Copy link
Author

jadonk commented Jan 31, 2018

You'd need to add some kind of message passing to the PRU. RPMsg is one possibility. As of now, it is left as an exercise for the reader, but it is a great idea for integration!

@jjtmp
Copy link

jjtmp commented Feb 19, 2018

Hello there,

/sys/bus/platform/drivers/pru-rproc/unbind and /sys/bus/platform/drivers/pru-rproc/bind
don't exist for me (Debian 9.3 IoT).

Instead I had to activate the PRU overlay in uEnv.txt and then echo 'start' > /sys/class/remoteproc/remoteproc1/state
UPDATE (removing mistaken word): You can load a new firmware by (overwriting old one in /lib/firmware and then) first "echo stop" and second "echo start" to .../remoteproc1/state.

BR
jj

@jadonk
Copy link
Author

jadonk commented Mar 3, 2018

The reason it is remoteproc1 is because remoteproc0 is the M3 used for power management.

@jadonk
Copy link
Author

jadonk commented Mar 3, 2018

To remove the index:

echo stop | sudo tee /sys/devices/platform/ocp/4a326000.pruss-soc-bus/4a300000.pruss/4a334000.pru0/remoteproc/remoteproc*/state)
echo start | sudo tee /sys/devices/platform/ocp/4a326000.pruss-soc-bus/4a300000.pruss/4a334000.pru0/remoteproc/remoteproc*/state

@jadonk
Copy link
Author

jadonk commented Mar 3, 2018

@kiddjmadd
Copy link

Was able to get this working on the BB Black with PRU Cape (once I'd edited uBoot.env to include the correct kernel's version PRU cape) but threw the errors "/bin/sh: 1: cannot create /sys/bus/platform/drivers/pru-rproc/unbind: Permission denied" and same error for bind.

Even with the error, running sudo echo "start" > /sys/class/remoteproc/remoteproc1/state allowed the program to proceed.

Another message from make run said "rebooting pru core 0". Does the PRU need to actually reboot between firmware changes, or is it ok to stop, load new firmware and then restart (maybe stop and then start is same as rebooting for the PRU)?

Thanks for the example. Now that I know PRU workflow is within reach for non-EE gurus I'm very much looking forward to working with it more!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment