├── C lib ├── .gitignore ├── ATTRIB ├── LICENSE ├── README.md ├── examples │ ├── adc │ │ ├── AM3359_PRU.cmd │ │ ├── bin.cmd │ │ ├── build.sh │ │ ├── host_main.c │ │ └── pru_main.c │ ├── cycle_counter │ │ ├── AM3359_PRU.cmd │ │ ├── bin.cmd │ │ ├── build.sh │ │ ├── host_main.c │ │ └── pru_main.c │ ├── gpio │ │ ├── AM3359_PRU.cmd │ │ ├── bin.cmd │ │ ├── build.sh │ │ ├── config-pins.sh │ │ ├── host_main.c │ │ └── pru_main.c │ ├── iep_timer │ │ ├── AM3359_PRU.cmd │ │ ├── bin.cmd │ │ ├── build.sh │ │ ├── host_main.c │ │ └── pru_main.c │ ├── measure_time_sync │ │ ├── AM3359_PRU.cmd │ │ ├── README.md │ │ ├── bin.cmd │ │ ├── build.sh │ │ ├── config-pins.sh │ │ ├── host_main.c │ │ ├── host_qot.c │ │ ├── host_qot.h │ │ ├── host_report_main.c │ │ ├── pru_main.c │ │ ├── shared_conf.h │ │ ├── stats.py │ │ ├── sync-32-sec_sample-250-ms.csv │ │ ├── sync-8-sec_sample-250-ms.csv │ │ └── sync-once_sample-250-ms.csv │ ├── pru_clock │ │ ├── AM3359_PRU.cmd │ │ ├── README.md │ │ ├── bin.cmd │ │ ├── build.sh │ │ ├── config-pins.sh │ │ ├── host_main.c │ │ ├── host_qot.c │ │ ├── host_qot.h │ │ ├── pru_main.c │ │ └── shared_conf.h │ ├── pwm │ │ ├── AM3359_PRU.cmd │ │ ├── README.md │ │ ├── bin.cmd │ │ ├── build.sh │ │ ├── config-pins.sh │ │ ├── host_main.c │ │ └── pru_main.c │ ├── read_time_latency │ │ ├── AM3359_PRU.cmd │ │ ├── README.md │ │ ├── bin.cmd │ │ ├── build.sh │ │ ├── host_main.c │ │ └── pru_main.c │ └── time_sync │ │ ├── AM3359_PRU.cmd │ │ ├── README.md │ │ ├── bin.cmd │ │ ├── build.sh │ │ ├── config-pins.sh │ │ ├── host_main.c │ │ ├── host_qot.c │ │ ├── host_qot.h │ │ ├── pru_main.c │ │ ├── shared_conf.h │ │ └── time_sync_setup.jpg ├── include │ ├── nesl_pru_adc.h │ ├── nesl_pru_gpio.h │ ├── nesl_pru_iep.h │ ├── nesl_pru_intc.h │ ├── nesl_pru_rbuffer.h │ ├── nesl_pru_regs.h │ ├── nesl_pru_ticks.h │ ├── nesl_pru_time.h │ └── nesl_pru_wait.h ├── overlay │ ├── NESL-PRU-00A0.dtbo │ ├── NESL-PRU-PINS-00A0.dtbo │ ├── NESL-PRU-QOT-00A0.dtbo │ ├── NESL-PRU-QOT.dts │ ├── NESL-PRU.dts │ ├── NESL-PRU0-PINS.dts │ ├── NESL-PRU1-PINS-00A0.dtbo │ ├── NESL-PRU1-PINS.dts │ ├── README.md │ ├── install.sh │ ├── list_overlays.sh │ ├── load.sh │ └── unload.sh └── scripts │ ├── bbb-usb-net-gateway.sh │ ├── host-usb-net-forwarding.sh │ └── update-time.sh ├── Cyclops IDE ├── .gitignore ├── README.md ├── images │ ├── ide_screenshot.png │ └── pru.png └── term-proj │ ├── device-tree │ ├── PRU-ACTIVATE-00A0.dtbo │ └── PRU-ACTIVATE-00A0.dts │ ├── driver │ ├── 99-pinpirate.rules │ ├── Makefile │ └── pin-pirate.c │ ├── ide │ ├── bottle.py │ ├── pru_process.py │ ├── start.py │ ├── static │ │ ├── ace │ │ │ ├── ace.js │ │ │ ├── mode-assembly_pru.js │ │ │ ├── mode-cyclops.js │ │ │ ├── theme-dawn.js │ │ │ └── theme-solarized_light.js │ │ ├── compiler.js │ │ ├── editor.css │ │ ├── editor.js │ │ ├── jquery.js │ │ └── peg.js │ └── views │ │ ├── base.tpl │ │ ├── editor.tpl │ │ └── grammar.tpl │ ├── pru-loader │ └── pru_loader.c │ ├── scripts │ ├── activate-pruss.sh │ ├── beaglebone-net-forwarding.sh │ ├── beaglebone-net-gateway.sh │ ├── compile-pru.sh │ ├── install-BBB-kernel-headers.sh │ ├── list-capemgr-slots.sh │ ├── list-pinmux.sh │ ├── start-ide.sh │ └── update-time.sh │ └── web │ ├── PRU-ACTIVATE.tpl │ ├── base.tpl │ ├── bottle.py │ ├── pinmux-pin.tpl │ ├── pinmux.tpl │ ├── pins.py │ ├── start.py │ └── start.sh ├── FullImage ├── .gitattributes ├── README.md └── images │ ├── BBB-IMAGE-QOT-23MAR2017-6PM.img.xz │ ├── BBB-IMAGE-QOT-28MAR2017-size.txt │ ├── BBB-IMAGE-QOT-28MAR2017.img.xz │ ├── BBB-IMAGE-QOT-STACK-FATIMA.img.xz │ ├── README.md │ ├── debian-7.5-kernel-3.8.13-bone50-16gb-nesl.img.xz │ └── nesl-qot-4.1.12-bone-rt-r16-4gb.img.xz └── README.md /C lib/.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | *.su 34 | 35 | gen/ 36 | -------------------------------------------------------------------------------- /C lib/ATTRIB: -------------------------------------------------------------------------------- 1 | ATTRIBUTIONS/CREDITS 2 | 3 | This project uses open source code. The source code and 4 | corresponding license information is listed below. 5 | 6 | Beaglebone PRU IO Library 7 | AUTHOR: Rafael Vega 8 | URL: https://github.com/outer-space-sounds/beaglebone-pruio 9 | LICENSE: GPLv3 10 | 11 | "Exploring BeagleBone: Tools and Techniques for Building with Embedded Linux" 12 | ISBN: 9781118935125 13 | AUTHOR: Derek Molloy 14 | URL: https://github.com/derekmolloy/exploringBB 15 | LICENSE: GPLv3 16 | 17 | Quality of Time Stack for Linux 18 | URL: https://bitbucket.org/rose-line/qot-stack 19 | LICENSE: BSD 2-Clause 20 | 21 | Linux Kernel 22 | URL: https://www.kernel.org 23 | LICENSE: GPLv2 24 | -------------------------------------------------------------------------------- /C lib/README.md: -------------------------------------------------------------------------------- 1 | # UCLA NESL PRU Library 2 | 3 | There are two approaches to interfacing with the PRU subsystem (PRUSS). 4 | Older kernels (pre-4.1.x) generally use the user-space IO (UIO) driver and newer ones use [`remote_proc`](https://www.kernel.org/doc/Documentation/remoteproc.txt) and [`RPMsg`](https://www.kernel.org/doc/Documentation/rpmsg.txt). 5 | The UIO driver simply maps regions of PRUSS memory and registers directly into user-space with a minimal kernel part for handling interrupts. 6 | On the other hand, the `remote_proc` framework provides a high level interface for controlling (power on, load firmware, power off) heterogeneous remote processor systems as well as the ability to map ELF formatted binaries into PRU memory. 7 | `RPMsg` provides a communication channel between the PRU and the main processor using `virtio` based messaging. 8 | User-space programs are expected to use syscalls on device nodes (e.g. `/dev/rpmsg31`) to access the PRU (direct access may still be possible using `/dev/mem`, but I have not tested this). 9 | 10 | Despite these advantages, we chose to use the UIO driver because it is better documented and there exists more code examples from the community. 11 | We also prefer the low latency properties of accessing PRU memory mapped directly into user-space over the more throughput optimized approach of `RPMsg`. 12 | Finally, the UIO driver is more portable and works on both old and new Linux kernels. Even the corresponding PRU driver on the FreeBSD operating system takes a similar approach. 13 | 14 | ## Quick Start 15 | 16 | The easiest way to get started is to boot with our [image](https://github.com/yifanz/ucla-nesl-pru-sys-images#how-to-flash-to-sd-card) which contains this repository along with all of the necessary dependencies. This helps avoid the 'works on my machine' syndrome and should save you hours of dependency management problems. If you choose not to use our image, here is roughly what you would need to install on your own system. 17 | 18 | * A kernel which has the `uio_pruss` module. Do `lsmod | grep pru` to see if `uio_pruss` is running. 19 | * The AM335x PRU PACKAGE ([source](https://github.com/beagleboard/am335x_pru_package)). Check under `/usr/local/include` and `/usr/local/lib` to see if your distribution already has `prussdrv.h` and `libprussdrv.so` installed. 20 | * TI's PRU code generation tools ([binaries](http://software-dl.ti.com/codegen/non-esd/downloads/beta.ht)). Check `/usr/share/ti/cgt-pru` to see if your distribution already has this installed. 21 | 22 | Assuming that you are using our image, you can terminal into the device using `root` as the username without any password. Here is an example of how to run the `gpio` example: 23 | 24 | ``` 25 | cd ucla-nesl-pru-lib/examples/gpio 26 | ./build.sh 27 | ./config-pins.sh 28 | cd gen/ 29 | ./host 30 | ``` 31 | 32 | As a convention, all examples have a `pru_main.c` and `host_main.c` which correspond to the parts that runs on the PRU and Linux, respectively. Take a look at `build.sh` if you want to change this. 33 | Every project under the [`examples`](https://github.com/yifanz/ucla-nesl-pru-lib/tree/master/examples) directory can be used as a template. Simply copy them elsewhere to create your own project. 34 | -------------------------------------------------------------------------------- /C lib/examples/adc/AM3359_PRU.cmd: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* AM3359_PRU.cmd */ 3 | /* Description: This file is a sample linker command file that can be */ 4 | /* used for linking programs built with the PRU C compiler and running the */ 5 | /* resulting .out file on an AM3359 PRU0. Use it as a guideline. You will */ 6 | /* want to change the memory layout to match your specific target system. */ 7 | /* You may want to change the allocation scheme according to the size of */ 8 | /* your program. */ 9 | /******************************************************************************/ 10 | 11 | -cr 12 | -stack 0x100 13 | -heap 0x100 14 | 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */ 19 | PAGE 1: 20 | PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */ 21 | } 22 | 23 | SECTIONS 24 | { 25 | /* Thanks to Jakub for the next line! */ 26 | .text:_c_int00* > 0x0, PAGE 0 27 | .stack > PRUDMEM, PAGE 1 28 | .bss > PRUDMEM, PAGE 1 29 | .cio > PRUDMEM, PAGE 1 30 | .const > PRUDMEM, PAGE 1 31 | .data > PRUDMEM, PAGE 1 32 | .switch > PRUDMEM, PAGE 1 33 | .sysmem > PRUDMEM, PAGE 1 34 | .cinit > PRUDMEM, PAGE 1 35 | } 36 | -------------------------------------------------------------------------------- /C lib/examples/adc/bin.cmd: -------------------------------------------------------------------------------- 1 | -b 2 | -image 3 | 4 | ROMS { 5 | PAGE 0: 6 | text: o = 0x0, l = 0x1000, files={text.bin} 7 | PAGE 1: 8 | data: o = 0x0, l = 0x1000, files={data.bin} 9 | } -------------------------------------------------------------------------------- /C lib/examples/adc/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | #Copyright (c) Regents of the University of California, 2017. All rights reserved. 5 | #See LICENSE and ATTRIB in the repository root. 6 | # 7 | # 8 | # 9 | #Based on code from Derek Molloy for the book "Exploring BeagleBone: 10 | #Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 11 | #2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 12 | #directory for copyright and GNU GPLv3 license information. 13 | # 14 | 15 | PRU_NUM=0; # which PRU 0 or 1 16 | PRU_SDK=/root/pru_2.0.0B2 17 | PRU_SRC="pru_main.c" 18 | HOST_SRC="host_main.c" 19 | PRU_TARGET=pru.out 20 | HOST_TARGET=host 21 | GEN=gen 22 | SCRIPT_DIR=${0%/*} 23 | 24 | cd $SCRIPT_DIR 25 | mkdir -p $GEN 26 | 27 | echo "Compiling and linking the PRU firmware" 28 | $PRU_SDK/bin/clpru --silicon_version=3 --keep_asm --c_src_interlist \ 29 | --asm_directory=$GEN --obj_directory=$GEN --temp_directory=$GEN \ 30 | -DPRU_NUM=$PRU_NUM \ 31 | $PRU_SRC \ 32 | -i$PRU_SDK/include \ 33 | -i$PRU_SDK/lib \ 34 | -i../../include \ 35 | -z AM3359_PRU.cmd \ 36 | -o $GEN/$PRU_TARGET \ 37 | -m $GEN/$PRU_TARGET.map 38 | 39 | if [ $? -ne 0 ]; then 40 | echo "Compile and link FAILED" 41 | exit 1 42 | fi 43 | 44 | pushd . 45 | cd $GEN 46 | 47 | # The output of the compiler/linker is an ELF executable. 48 | # We cannot directly load the ELF file into the PRU because unlike Linux, 49 | # the PRU does not have a ELF loader. 50 | # In theory, we could parse the ELF file in our host application, 51 | # but that is too much work. 52 | # Instead, we break out the text and data segments and so that we can 53 | # manually map them into PRU memory. 54 | echo "Generating text and data segments (text.bin and data.bin)" 55 | $PRU_SDK/bin/hexpru ../bin.cmd $PRU_TARGET 56 | 57 | if [ $? -ne 0 ]; then 58 | echo "Generating text and data segments FAILED" 59 | exit 1 60 | fi 61 | 62 | popd 63 | 64 | echo "Compiling and linking the host application" 65 | gcc -I../../include -DPRU_NUM=$PRU_NUM $HOST_SRC -o $GEN/$HOST_TARGET -lpthread -lprussdrv 66 | 67 | if [ $? -ne 0 ]; then 68 | echo "Compiling and linking the host application FAILED" 69 | exit 1 70 | fi 71 | 72 | echo "Build SUCCESSFUL." 73 | echo "To run you must change to the gen directory:" 74 | echo "cd gen/" 75 | echo "./host" 76 | -------------------------------------------------------------------------------- /C lib/examples/adc/host_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 9 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | int main (void) 21 | { 22 | int n, ret; 23 | uint32_t *shared_mem; 24 | 25 | if(getuid()!=0){ 26 | printf("You must run this program as root. Exiting.\n"); 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | /* Initialize structure used by prussdrv_pruintc_intc */ 31 | /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 32 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 33 | 34 | /* Allocate and initialize memory */ 35 | prussdrv_init (); 36 | ret = prussdrv_open (PRU_EVTOUT_0); 37 | if(ret){ 38 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 39 | exit(EXIT_FAILURE); 40 | } 41 | /* Map PRU's INTC */ 42 | prussdrv_pruintc_init(&pruss_intc_initdata); 43 | 44 | // Map PRU's shared memory into user-space 45 | if (prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, (void **) &shared_mem)) { 46 | printf("map shared memory failed\n"); 47 | exit(EXIT_FAILURE); 48 | } 49 | 50 | memset(shared_mem, 0, 0x2000); 51 | 52 | /* Load the memory data file */ 53 | prussdrv_load_datafile(PRU_NUM, "./data.bin"); 54 | 55 | /* Load and execute binary on PRU */ 56 | prussdrv_exec_program (PRU_NUM, "./text.bin"); 57 | 58 | /* Wait for event completion from PRU */ 59 | n = prussdrv_pru_wait_event (PRU_EVTOUT_0); // This assumes the PRU generates an interrupt 60 | //prussdrv_pru_clear_event(PRU_EVTOUT0, PRU0_ARM_INTERRUPT); 61 | // connected to event out 0 immediately before halting 62 | printf("PRU program completed, event number %d.\n", n); 63 | int i; 64 | for (i = 0; i < 7; i++) { 65 | printf("Channel %lu: %f Volts\n", 66 | shared_mem[i*2], 67 | (shared_mem[i*2+1] / 4096.0f) * 1.8f); // 12 bit ADC 68 | } 69 | 70 | /* Disable PRU and close memory mappings */ 71 | prussdrv_pru_disable(PRU_NUM); 72 | prussdrv_exit (); 73 | return(EXIT_SUCCESS); 74 | } 75 | -------------------------------------------------------------------------------- /C lib/examples/adc/pru_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 9 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | /* 14 | * Based on code from the Beaglebone PRU IO project. 15 | * https://github.com/outer-space-sounds/beaglebone-pruio 16 | * Please see the file ATTRIB in the repository root 17 | * directory for copyright and GNU GPLv3 license information. 18 | */ 19 | 20 | #include "nesl_pru_regs.h" 21 | #include "nesl_pru_wait.h" 22 | #include "nesl_pru_intc.h" 23 | #include "nesl_pru_adc.h" 24 | #include 25 | 26 | int main() 27 | { 28 | init_ocp(); 29 | 30 | init_adc(); 31 | adc_start_sampling(); 32 | wait_for_adc(); 33 | 34 | uint32_t *shared_mem = (void*) (unsigned long) 0x10000; 35 | unsigned int data, i, step_id, value; 36 | unsigned int count = read_adc_count(); 37 | 38 | for(i=0; i> 16; 41 | value = (data & 0xfff); 42 | shared_mem[i*2] = step_id; 43 | shared_mem[i*2+1] = value; 44 | } 45 | 46 | // Exiting the application - send the interrupt 47 | TRIG_INTC(3); // Trigger interrupt PRUEVENT_0 48 | __halt(); // halt the PRU 49 | } 50 | -------------------------------------------------------------------------------- /C lib/examples/cycle_counter/AM3359_PRU.cmd: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* AM3359_PRU.cmd */ 3 | /* Description: This file is a sample linker command file that can be */ 4 | /* used for linking programs built with the PRU C compiler and running the */ 5 | /* resulting .out file on an AM3359 PRU0. Use it as a guideline. You will */ 6 | /* want to change the memory layout to match your specific target system. */ 7 | /* You may want to change the allocation scheme according to the size of */ 8 | /* your program. */ 9 | /******************************************************************************/ 10 | 11 | -cr 12 | -stack 0x100 13 | -heap 0x100 14 | 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */ 19 | PAGE 1: 20 | PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */ 21 | } 22 | 23 | SECTIONS 24 | { 25 | /* Thanks to Jakub for the next line! */ 26 | .text:_c_int00* > 0x0, PAGE 0 27 | .stack > PRUDMEM, PAGE 1 28 | .bss > PRUDMEM, PAGE 1 29 | .cio > PRUDMEM, PAGE 1 30 | .const > PRUDMEM, PAGE 1 31 | .data > PRUDMEM, PAGE 1 32 | .switch > PRUDMEM, PAGE 1 33 | .sysmem > PRUDMEM, PAGE 1 34 | .cinit > PRUDMEM, PAGE 1 35 | } 36 | -------------------------------------------------------------------------------- /C lib/examples/cycle_counter/bin.cmd: -------------------------------------------------------------------------------- 1 | -b 2 | -image 3 | 4 | ROMS { 5 | PAGE 0: 6 | text: o = 0x0, l = 0x1000, files={text.bin} 7 | PAGE 1: 8 | data: o = 0x0, l = 0x1000, files={data.bin} 9 | } -------------------------------------------------------------------------------- /C lib/examples/cycle_counter/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | #Copyright (c) Regents of the University of California, 2017. All rights reserved. 5 | #See LICENSE and ATTRIB in the repository root. 6 | # 7 | # 8 | # 9 | #Based on code from Derek Molloy for the book "Exploring BeagleBone: 10 | #Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 11 | #2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 12 | #directory for copyright and GNU GPLv3 license information. 13 | # 14 | 15 | PRU_NUM=1; # which PRU 0 or 1 16 | PRU_SRC="pru_main.c" 17 | HOST_SRC="host_main.c" 18 | PRU_TARGET=pru.out 19 | HOST_TARGET=host 20 | GEN=gen 21 | SCRIPT_DIR=${0%/*} 22 | 23 | cd $SCRIPT_DIR 24 | mkdir -p $GEN 25 | 26 | echo "Compiling and linking the PRU firmware" 27 | clpru --silicon_version=3 --keep_asm --c_src_interlist \ 28 | --asm_directory=$GEN --obj_directory=$GEN --temp_directory=$GEN \ 29 | -DPRU_NUM=$PRU_NUM \ 30 | $PRU_SRC \ 31 | -i../../include \ 32 | -z AM3359_PRU.cmd \ 33 | -o $GEN/$PRU_TARGET \ 34 | -m $GEN/$PRU_TARGET.map 35 | 36 | if [ $? -ne 0 ]; then 37 | echo "Compile and link FAILED" 38 | exit 1 39 | fi 40 | 41 | pushd . 42 | cd $GEN 43 | 44 | # The output of the compiler/linker is an ELF executable. 45 | # We cannot directly load the ELF file into the PRU because unlike Linux, 46 | # the PRU does not have a ELF loader. 47 | # In theory, we could parse the ELF file in our host application, 48 | # but that is too much work. 49 | # Instead, we break out the text and data segments and so that we can 50 | # manually map them into PRU memory. 51 | echo "Generating text and data segments (text.bin and data.bin)" 52 | hexpru ../bin.cmd $PRU_TARGET 53 | 54 | if [ $? -ne 0 ]; then 55 | echo "Generating text and data segments FAILED" 56 | exit 1 57 | fi 58 | 59 | popd 60 | 61 | echo "Compiling and linking the host application" 62 | gcc -I../../include -DPRU_NUM=$PRU_NUM $HOST_SRC -o $GEN/$HOST_TARGET -lpthread -lprussdrv 63 | 64 | if [ $? -ne 0 ]; then 65 | echo "Compiling and linking the host application FAILED" 66 | exit 1 67 | fi 68 | 69 | echo "Build SUCCESSFUL." 70 | echo "To run you must change to the gen directory:" 71 | echo "cd gen/" 72 | echo "./host" 73 | -------------------------------------------------------------------------------- /C lib/examples/cycle_counter/host_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 9 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | int main (void) 21 | { 22 | int n, ret; 23 | uint8_t *shared_mem; 24 | 25 | if(getuid()!=0){ 26 | printf("You must run this program as root. Exiting.\n"); 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | /* Initialize structure used by prussdrv_pruintc_intc */ 31 | /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 32 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 33 | 34 | /* Allocate and initialize memory */ 35 | prussdrv_init (); 36 | ret = prussdrv_open (PRU_EVTOUT_0); 37 | if(ret){ 38 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 39 | exit(EXIT_FAILURE); 40 | } 41 | /* Map PRU's INTC */ 42 | prussdrv_pruintc_init(&pruss_intc_initdata); 43 | 44 | // Map PRU's shared memory into user-space 45 | if (prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, (void **) &shared_mem)) { 46 | printf("map shared memory failed\n"); 47 | exit(EXIT_FAILURE); 48 | } 49 | 50 | memset(shared_mem, 0, 0x2000); 51 | 52 | /* Load the memory data file */ 53 | prussdrv_load_datafile(PRU_NUM, "./data.bin"); 54 | 55 | /* Load and execute binary on PRU */ 56 | prussdrv_exec_program (PRU_NUM, "./text.bin"); 57 | 58 | /* Wait for event completion from PRU */ 59 | n = prussdrv_pru_wait_event (PRU_EVTOUT_0); // This assumes the PRU generates an interrupt 60 | // connected to event out 0 immediately before halting 61 | printf("PRU program completed, event number %d.\n", n); 62 | printf("cycles %lu\n", *((uint32_t*) shared_mem)); 63 | printf("cycles %lu\n", *((uint32_t*) (shared_mem+4))); 64 | printf("cycles %lu\n", *((uint32_t*) (shared_mem+8))); 65 | 66 | /* Disable PRU and close memory mappings */ 67 | prussdrv_pru_disable(PRU_NUM); 68 | prussdrv_exit (); 69 | return(EXIT_SUCCESS); 70 | } 71 | -------------------------------------------------------------------------------- /C lib/examples/cycle_counter/pru_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 9 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | #include "nesl_pru_intc.h" 14 | #include "nesl_pru_ticks.h" 15 | #include "nesl_pru_wait.h" 16 | #include 17 | 18 | int main() 19 | { 20 | uint32_t *shared_mem = (void*) (unsigned long) 0x10000; 21 | uint32_t *mem1 = shared_mem; 22 | uint32_t *mem2 = shared_mem+1; 23 | uint32_t *mem3 = shared_mem+2; 24 | 25 | ENABLE_TICKS(); 26 | 27 | TICKS = 0; 28 | WAIT_CYCLES(200); // 1 us 29 | *mem1 = TICKS; 30 | 31 | TICKS = 0; 32 | WAIT_US(1); // 1 us 33 | *mem2 = TICKS; 34 | 35 | TICKS = 0; 36 | // Wait 1 us using inline assembly 37 | __asm__ __volatile__ 38 | ( 39 | " LDI32 r0, 99\n" 40 | "WAIT_LABEL: SUB r0, r0, 1\n" 41 | " QBNE WAIT_LABEL, r0, 0\n" 42 | ); 43 | *mem3 = TICKS; 44 | 45 | // Exiting the application - send the interrupt 46 | TRIG_INTC(3); // Trigger interrupt PRUEVENT_0 47 | __halt(); // halt the PRU 48 | } 49 | -------------------------------------------------------------------------------- /C lib/examples/gpio/AM3359_PRU.cmd: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* AM3359_PRU.cmd */ 3 | /* Description: This file is a sample linker command file that can be */ 4 | /* used for linking programs built with the PRU C compiler and running the */ 5 | /* resulting .out file on an AM3359 PRU0. Use it as a guideline. You will */ 6 | /* want to change the memory layout to match your specific target system. */ 7 | /* You may want to change the allocation scheme according to the size of */ 8 | /* your program. */ 9 | /******************************************************************************/ 10 | 11 | -cr 12 | -stack 0x100 13 | -heap 0x100 14 | 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */ 19 | PAGE 1: 20 | PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */ 21 | } 22 | 23 | SECTIONS 24 | { 25 | /* Thanks to Jakub for the next line! */ 26 | .text:_c_int00* > 0x0, PAGE 0 27 | .stack > PRUDMEM, PAGE 1 28 | .bss > PRUDMEM, PAGE 1 29 | .cio > PRUDMEM, PAGE 1 30 | .const > PRUDMEM, PAGE 1 31 | .data > PRUDMEM, PAGE 1 32 | .switch > PRUDMEM, PAGE 1 33 | .sysmem > PRUDMEM, PAGE 1 34 | .cinit > PRUDMEM, PAGE 1 35 | } 36 | -------------------------------------------------------------------------------- /C lib/examples/gpio/bin.cmd: -------------------------------------------------------------------------------- 1 | -b 2 | -image 3 | 4 | ROMS { 5 | PAGE 0: 6 | text: o = 0x0, l = 0x1000, files={text.bin} 7 | PAGE 1: 8 | data: o = 0x0, l = 0x1000, files={data.bin} 9 | } -------------------------------------------------------------------------------- /C lib/examples/gpio/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | #Copyright (c) Regents of the University of California, 2017. All rights reserved. 5 | #See LICENSE and ATTRIB in the repository root. 6 | # 7 | # 8 | # 9 | #Based on code from Derek Molloy for the book "Exploring BeagleBone: 10 | #Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 11 | #2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 12 | #directory for copyright and GNU GPLv3 license information. 13 | # 14 | 15 | PRU_NUM=1; # which PRU 0 or 1 16 | PRU_SRC="pru_main.c" 17 | HOST_SRC="host_main.c" 18 | PRU_TARGET=pru.out 19 | HOST_TARGET=host 20 | GEN=gen 21 | SCRIPT_DIR=${0%/*} 22 | 23 | cd $SCRIPT_DIR 24 | mkdir -p $GEN 25 | 26 | echo "Compiling and linking the PRU firmware" 27 | clpru --silicon_version=3 --keep_asm --c_src_interlist \ 28 | --asm_directory=$GEN --obj_directory=$GEN --temp_directory=$GEN \ 29 | -DPRU_NUM=$PRU_NUM \ 30 | $PRU_SRC \ 31 | -i../../include \ 32 | -z AM3359_PRU.cmd \ 33 | -o $GEN/$PRU_TARGET \ 34 | -m $GEN/$PRU_TARGET.map 35 | 36 | if [ $? -ne 0 ]; then 37 | echo "Compile and link FAILED" 38 | exit 1 39 | fi 40 | 41 | pushd . 42 | cd $GEN 43 | 44 | # The output of the compiler/linker is an ELF executable. 45 | # We cannot directly load the ELF file into the PRU because unlike Linux, 46 | # the PRU does not have a ELF loader. 47 | # In theory, we could parse the ELF file in our host application, 48 | # but that is too much work. 49 | # Instead, we break out the text and data segments and so that we can 50 | # manually map them into PRU memory. 51 | echo "Generating text and data segments (text.bin and data.bin)" 52 | hexpru ../bin.cmd $PRU_TARGET 53 | 54 | if [ $? -ne 0 ]; then 55 | echo "Generating text and data segments FAILED" 56 | exit 1 57 | fi 58 | 59 | popd 60 | 61 | echo "Compiling and linking the host application" 62 | gcc -I../../include -DPRU_NUM=$PRU_NUM $HOST_SRC -o $GEN/$HOST_TARGET -lpthread -lprussdrv 63 | 64 | if [ $? -ne 0 ]; then 65 | echo "Compiling and linking the host application FAILED" 66 | exit 1 67 | fi 68 | 69 | echo "Build SUCCESSFUL." 70 | echo "To run you must change to the gen directory:" 71 | echo "cd gen/" 72 | echo "./host" 73 | -------------------------------------------------------------------------------- /C lib/examples/gpio/config-pins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Configuring pins" 4 | 5 | #config-pin P9_27 pruout 6 | #config-pin -q P9_27 7 | #config-pin P9_28 pruin 8 | #config-pin -q P9_28 9 | 10 | config-pin P8_46 pruout 11 | config-pin -q P8_46 12 | config-pin P8_45 pruin 13 | config-pin -q P8_45 14 | -------------------------------------------------------------------------------- /C lib/examples/gpio/host_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 9 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int main (void) 20 | { 21 | int n, ret; 22 | 23 | if(getuid()!=0){ 24 | printf("You must run this program as root. Exiting.\n"); 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | /* Initialize structure used by prussdrv_pruintc_intc */ 29 | /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 30 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 31 | 32 | /* Allocate and initialize memory */ 33 | prussdrv_init (); 34 | ret = prussdrv_open (PRU_EVTOUT_0); 35 | if(ret){ 36 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 37 | exit(EXIT_FAILURE); 38 | } 39 | /* Map PRU's INTC */ 40 | prussdrv_pruintc_init(&pruss_intc_initdata); 41 | 42 | /* Load the memory data file */ 43 | prussdrv_load_datafile(PRU_NUM, "./data.bin"); 44 | 45 | /* Load and execute binary on PRU */ 46 | prussdrv_exec_program (PRU_NUM, "./text.bin"); 47 | 48 | /* Wait for event completion from PRU */ 49 | n = prussdrv_pru_wait_event (PRU_EVTOUT_0); // This assumes the PRU generates an interrupt 50 | // connected to event out 0 immediately before halting 51 | printf("PRU program completed, event number %d.\n", n); 52 | 53 | /* Disable PRU and close memory mappings */ 54 | prussdrv_pru_disable(PRU_NUM); 55 | prussdrv_exit (); 56 | return(EXIT_SUCCESS); 57 | } 58 | -------------------------------------------------------------------------------- /C lib/examples/gpio/pru_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 9 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | #include "nesl_pru_intc.h" 14 | #include "nesl_pru_gpio.h" 15 | #include "nesl_pru_wait.h" 16 | 17 | int main() 18 | { 19 | #if PRU_NUM == 0 20 | // Set pin to high 21 | assert_pin(P9_27); 22 | 23 | // Blink pin P9_27 every half of a second 24 | // Stop when P9_28 is set high 25 | while(!read_pin(P9_28)){ 26 | toggle_pin(P9_27); 27 | WAIT_MS(500); 28 | } 29 | 30 | // Set pin to low before we exit 31 | deassert_pin(P9_27); 32 | #else 33 | // Set pin to high 34 | assert_pin(P8_46); 35 | 36 | // Blink pin P9_27 every half of a second 37 | // Stop when P9_28 is set high 38 | while(!read_pin(P8_45)){ 39 | toggle_pin(P8_46); 40 | WAIT_MS(500); 41 | } 42 | 43 | // Set pin to low before we exit 44 | deassert_pin(P8_46); 45 | #endif 46 | 47 | // Exiting the application - send the interrupt 48 | TRIG_INTC(3); // PRUEVENT_0 on PRU0_R31_VEC_VALID 49 | __halt(); // halt the PRU 50 | } 51 | -------------------------------------------------------------------------------- /C lib/examples/iep_timer/AM3359_PRU.cmd: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* AM3359_PRU.cmd */ 3 | /* Description: This file is a sample linker command file that can be */ 4 | /* used for linking programs built with the PRU C compiler and running the */ 5 | /* resulting .out file on an AM3359 PRU0. Use it as a guideline. You will */ 6 | /* want to change the memory layout to match your specific target system. */ 7 | /* You may want to change the allocation scheme according to the size of */ 8 | /* your program. */ 9 | /******************************************************************************/ 10 | 11 | -cr 12 | -stack 0x100 13 | -heap 0x100 14 | 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */ 19 | PAGE 1: 20 | PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */ 21 | } 22 | 23 | SECTIONS 24 | { 25 | /* Thanks to Jakub for the next line! */ 26 | .text:_c_int00* > 0x0, PAGE 0 27 | .stack > PRUDMEM, PAGE 1 28 | .bss > PRUDMEM, PAGE 1 29 | .cio > PRUDMEM, PAGE 1 30 | .const > PRUDMEM, PAGE 1 31 | .data > PRUDMEM, PAGE 1 32 | .switch > PRUDMEM, PAGE 1 33 | .sysmem > PRUDMEM, PAGE 1 34 | .cinit > PRUDMEM, PAGE 1 35 | } 36 | -------------------------------------------------------------------------------- /C lib/examples/iep_timer/bin.cmd: -------------------------------------------------------------------------------- 1 | -b 2 | -image 3 | 4 | ROMS { 5 | PAGE 0: 6 | text: o = 0x0, l = 0x1000, files={text.bin} 7 | PAGE 1: 8 | data: o = 0x0, l = 0x1000, files={data.bin} 9 | } -------------------------------------------------------------------------------- /C lib/examples/iep_timer/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | #Copyright (c) Regents of the University of California, 2017. All rights reserved. 5 | #See LICENSE and ATTRIB in the repository root. 6 | # 7 | # 8 | # 9 | #Based on code from Derek Molloy for the book "Exploring BeagleBone: 10 | #Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 11 | #2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 12 | #directory for copyright and GNU GPLv3 license information. 13 | # 14 | 15 | PRU_NUM=0; # which PRU 0 or 1 16 | PRU_SDK=/root/pru_2.0.0B2 17 | PRU_SRC="pru_main.c" 18 | HOST_SRC="host_main.c" 19 | PRU_TARGET=pru.out 20 | HOST_TARGET=host 21 | GEN=gen 22 | SCRIPT_DIR=${0%/*} 23 | 24 | cd $SCRIPT_DIR 25 | mkdir -p $GEN 26 | 27 | echo "Compiling and linking the PRU firmware" 28 | $PRU_SDK/bin/clpru --silicon_version=3 --keep_asm --c_src_interlist \ 29 | --asm_directory=$GEN --obj_directory=$GEN --temp_directory=$GEN \ 30 | -DPRU_NUM=$PRU_NUM \ 31 | $PRU_SRC \ 32 | -i$PRU_SDK/include \ 33 | -i$PRU_SDK/lib \ 34 | -i../../include \ 35 | -z AM3359_PRU.cmd \ 36 | -o $GEN/$PRU_TARGET \ 37 | -m $GEN/$PRU_TARGET.map 38 | 39 | if [ $? -ne 0 ]; then 40 | echo "Compile and link FAILED" 41 | exit 1 42 | fi 43 | 44 | pushd . 45 | cd $GEN 46 | 47 | # The output of the compiler/linker is an ELF executable. 48 | # We cannot directly load the ELF file into the PRU because unlike Linux, 49 | # the PRU does not have a ELF loader. 50 | # In theory, we could parse the ELF file in our host application, 51 | # but that is too much work. 52 | # Instead, we break out the text and data segments and so that we can 53 | # manually map them into PRU memory. 54 | echo "Generating text and data segments (text.bin and data.bin)" 55 | $PRU_SDK/bin/hexpru ../bin.cmd $PRU_TARGET 56 | 57 | if [ $? -ne 0 ]; then 58 | echo "Generating text and data segments FAILED" 59 | exit 1 60 | fi 61 | 62 | popd 63 | 64 | echo "Compiling and linking the host application" 65 | gcc -I../../include -DPRU_NUM=$PRU_NUM $HOST_SRC -o $GEN/$HOST_TARGET -lpthread -lprussdrv 66 | 67 | if [ $? -ne 0 ]; then 68 | echo "Compiling and linking the host application FAILED" 69 | exit 1 70 | fi 71 | 72 | echo "Build SUCCESSFUL." 73 | echo "To run you must change to the gen directory:" 74 | echo "cd gen/" 75 | echo "./host" 76 | -------------------------------------------------------------------------------- /C lib/examples/iep_timer/host_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 9 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "nesl_pru_rbuffer.h" 21 | 22 | volatile int stop = 0; 23 | volatile uint8_t *shared_mem; 24 | 25 | void *threadFunction(void *value){ 26 | do { 27 | prussdrv_pru_wait_event(PRU_EVTOUT_0); 28 | prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); 29 | struct rbuffer *rbuf = (struct rbuffer *) shared_mem; 30 | short status = 0; 31 | uint32_t data; 32 | data = rbuf_read_uint32(rbuf, &status); 33 | if (!status) { 34 | uint64_t ms = data; 35 | ms *= 5; 36 | ms /= 1000000; 37 | printf("IEP count: %lu (%lu ms)\n", data, ms); 38 | } 39 | } while (!stop); 40 | } 41 | 42 | int main (void) 43 | { 44 | int n, ret; 45 | 46 | if(getuid()!=0){ 47 | printf("You must run this program as root. Exiting.\n"); 48 | exit(EXIT_FAILURE); 49 | } 50 | 51 | pthread_t thread; 52 | 53 | /* Initialize structure used by prussdrv_pruintc_intc */ 54 | /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 55 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 56 | 57 | /* Allocate and initialize memory */ 58 | prussdrv_init (); 59 | ret = prussdrv_open (PRU_EVTOUT_0); 60 | if(ret){ 61 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 62 | exit(EXIT_FAILURE); 63 | } 64 | ret = prussdrv_open (PRU_EVTOUT_1); 65 | if(ret){ 66 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 67 | exit(EXIT_FAILURE); 68 | } 69 | 70 | /* Map PRU's INTC */ 71 | prussdrv_pruintc_init(&pruss_intc_initdata); 72 | 73 | // Map PRU's shared memory into user-space 74 | if (prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, (void **) &shared_mem)) { 75 | printf("map shared memory failed\n"); 76 | exit(EXIT_FAILURE); 77 | } 78 | 79 | memset((void*) shared_mem, 0, 0x2000); 80 | 81 | /* Load the memory data file */ 82 | prussdrv_load_datafile(PRU_NUM, "./data.bin"); 83 | 84 | /* Load and execute binary on PRU */ 85 | prussdrv_exec_program (PRU_NUM, "./text.bin"); 86 | 87 | /* Wait for event completion from PRU */ 88 | if (pthread_create(&thread, NULL, &threadFunction, NULL)){ 89 | printf("Failed to create thread!\n"); 90 | exit(EXIT_FAILURE); 91 | } 92 | 93 | prussdrv_pru_wait_event(PRU_EVTOUT_1); 94 | stop = 1; 95 | 96 | /* Disable PRU and close memory mappings */ 97 | prussdrv_pru_disable(PRU_NUM); 98 | prussdrv_exit (); 99 | return(EXIT_SUCCESS); 100 | } 101 | -------------------------------------------------------------------------------- /C lib/examples/iep_timer/pru_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root * directory for copyright and GNU GPLv3 license information. 9 | */ 10 | 11 | #include "nesl_pru_intc.h" 12 | #include "nesl_pru_iep.h" 13 | #include "nesl_pru_wait.h" 14 | #include "nesl_pru_rbuffer.h" 15 | #include 16 | 17 | int main() 18 | { 19 | struct rbuffer *rbuf = (struct rbuffer *) (uint32_t) 0x10000; 20 | init_rbuffer(rbuf); 21 | 22 | DISABLE_IEP_TMR(); 23 | ENABLE_IEP_TMR(); 24 | 25 | int i = 30; 26 | IEP_CNT = 0; 27 | 28 | while(i--) { 29 | rbuf_write_uint32(rbuf, IEP_CNT); 30 | TRIG_INTC(3); // Trigger interrupt PRUEVENT_0 31 | WAIT_MS(1000); 32 | } 33 | 34 | DISABLE_IEP_TMR(); 35 | 36 | // Exiting the application - send the interrupt 37 | TRIG_INTC(4); // Trigger interrupt PRUEVENT_1 38 | __halt(); // halt the PRU 39 | } 40 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/AM3359_PRU.cmd: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* AM3359_PRU.cmd */ 3 | /* Description: This file is a sample linker command file that can be */ 4 | /* used for linking programs built with the PRU C compiler and running the */ 5 | /* resulting .out file on an AM3359 PRU0. Use it as a guideline. You will */ 6 | /* want to change the memory layout to match your specific target system. */ 7 | /* You may want to change the allocation scheme according to the size of */ 8 | /* your program. */ 9 | /******************************************************************************/ 10 | 11 | -cr 12 | -stack 0x100 13 | -heap 0x100 14 | 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */ 19 | PAGE 1: 20 | PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */ 21 | } 22 | 23 | SECTIONS 24 | { 25 | /* Thanks to Jakub for the next line! */ 26 | .text:_c_int00* > 0x0, PAGE 0 27 | .stack > PRUDMEM, PAGE 1 28 | .bss > PRUDMEM, PAGE 1 29 | .cio > PRUDMEM, PAGE 1 30 | .const > PRUDMEM, PAGE 1 31 | .data > PRUDMEM, PAGE 1 32 | .switch > PRUDMEM, PAGE 1 33 | .sysmem > PRUDMEM, PAGE 1 34 | .cinit > PRUDMEM, PAGE 1 35 | } 36 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/README.md: -------------------------------------------------------------------------------- 1 | ### QoT and PRU Time Synchronization Accuracy 2 | 3 | #### Pins 4 | * __P8_46__: PRU output for time sync. 5 | * __P8_45__: PRU input for reporting timestamp. 6 | * __P8_9__: QoT input capture for time sync. 7 | * __P8_10__: QoT input capture for reporting timestamp. 8 | 9 | __P8_46__ is connected to __P8_9__ and this connection is used for time synchronization between the PRU and main processor. 10 | Asserting __P8_45__ causes the PRU to report its current timestamp. Similarily asserting __P8_10__, reports the current timestamp from the main processor. 11 | __P8_45__ and __P8_10__ are connected to a PWM output from an external microcontroller which will periodically assert both pins simultaneously to produce timestamps for comparing the synchronization accuracy. 12 | 13 | The PRU initiates time synchronization by asserting __P8_46__ and records its own timestamp at that instant (__T1__). 14 | Since __P8_46__ is connected to __P8_9__, this will produce an input capture timestamp (__T2__) on the main processor. 15 | __T2__ is delivered to the PRU by a user-space program and the PRU will subtract __T1__ and __T2__ to calculate the offset and adjust its own clock. 16 | 17 | #### Results 18 | 19 | Test run lasts approximately 33 minutes. 20 | For each run, time synchronization between the PRU and the main procesor occurs every 8 or 32 seconds or just once at the beginning. 21 | Once the PRU and main processor are synchronized, we assert __P8_45__ and __P8_10__ 22 | every 250 milliseconds and record the timestamps from the PRU and main processor. 23 | We use the difference between the reported timestamps as a measure for the accuracy of synchronization. 24 | 25 | The csv files contain the timestamps from each run. The __left column is the QoT timestamp__, the __middle column is the PRU timestamp__ the __right column is the time difference__. 26 | All values are in nanoseconds. 27 | 28 | * [sync-8-sec_sample-250-ms.csv](https://github.com/yifanz/ucla-nesl-pru-lib/blob/master/examples/measure_time_sync/sync-8-sec_sample-250-ms.csv) (sync every 8 sec, test every 250 ms) 29 | * [sync-32-sec_sample-250-ms.csv](https://github.com/yifanz/ucla-nesl-pru-lib/blob/master/examples/measure_time_sync/sync-32-sec_sample-250-ms.csv) (sync every 32 sec, test every 250 ms) 30 | * [sync-once_sample-250-ms.csv](https://github.com/yifanz/ucla-nesl-pru-lib/blob/master/examples/measure_time_sync/sync-once_sample-250-ms.csv) (sync only once at beginning then test every 250 ms) 31 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/bin.cmd: -------------------------------------------------------------------------------- 1 | -b 2 | -image 3 | 4 | ROMS { 5 | PAGE 0: 6 | text: o = 0x0, l = 0x1000, files={text.bin} 7 | PAGE 1: 8 | data: o = 0x0, l = 0x1000, files={data.bin} 9 | } -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | #Copyright (c) Regents of the University of California, 2017. All rights reserved. 5 | #See LICENSE and ATTRIB in the repository root. 6 | # 7 | # 8 | # 9 | #Based on code from Derek Molloy for the book "Exploring BeagleBone: 10 | #Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 11 | #2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 12 | #directory for copyright and GNU GPLv3 license information. 13 | # 14 | 15 | PRU_NUM=1; # which PRU 0 or 1 16 | #PRU_SDK=/root/pru_2.0.0B2 17 | PRU_SRC="pru_main.c" 18 | HOST_SRC="host_main.c host_qot.c" 19 | PRU_TARGET=pru.out 20 | HOST_TARGET=host 21 | GEN=gen 22 | SCRIPT_DIR=${0%/*} 23 | 24 | cd $SCRIPT_DIR 25 | mkdir -p $GEN 26 | 27 | echo "Compiling and linking the PRU firmware" 28 | clpru --silicon_version=3 --keep_asm --c_src_interlist \ 29 | --asm_directory=$GEN --obj_directory=$GEN --temp_directory=$GEN \ 30 | -DPRU_NUM=$PRU_NUM \ 31 | $PRU_SRC \ 32 | -i../../include \ 33 | -z AM3359_PRU.cmd \ 34 | -o $GEN/$PRU_TARGET \ 35 | -m $GEN/$PRU_TARGET.map 36 | #-i$PRU_SDK/include 37 | #-i$PRU_SDK/lib 38 | 39 | if [ $? -ne 0 ]; then 40 | echo "Compile and link FAILED" 41 | exit 1 42 | fi 43 | 44 | pushd . 45 | cd $GEN 46 | 47 | # The output of the compiler/linker is an ELF executable. 48 | # We cannot directly load the ELF file into the PRU because unlike Linux, 49 | # the PRU does not have a ELF loader. 50 | # In theory, we could parse the ELF file in our host application, 51 | # but that is too much work. 52 | # Instead, we break out the text and data segments and so that we can 53 | # manually map them into PRU memory. 54 | echo "Generating text and data segments (text.bin and data.bin)" 55 | hexpru ../bin.cmd $PRU_TARGET 56 | 57 | if [ $? -ne 0 ]; then 58 | echo "Generating text and data segments FAILED" 59 | exit 1 60 | fi 61 | 62 | popd 63 | 64 | echo "Compiling and linking the host application" 65 | gcc -I../../include -DPRU_NUM=$PRU_NUM $HOST_SRC -o $GEN/$HOST_TARGET -lpthread -lprussdrv 66 | gcc -I../../include host_report_main.c host_qot.c -o $GEN/report -lpthread 67 | 68 | if [ $? -ne 0 ]; then 69 | echo "Compiling and linking the host application FAILED" 70 | exit 1 71 | fi 72 | 73 | echo "Build SUCCESSFUL." 74 | echo "To run you must change to the gen directory:" 75 | echo "cd gen/" 76 | echo "./host" 77 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/config-pins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Configuring pins" 4 | #config-pin P9_27 pruout 5 | #config-pin -q P9_27 6 | 7 | config-pin P8_45 pruin 8 | config-pin -q P8_45 9 | config-pin P8_46 pruout 10 | config-pin -q P8_46 11 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/host_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | 11 | /* 12 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 13 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 14 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 15 | * directory for copyright and GNU GPLv3 license information. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "shared_conf.h" 37 | #include "nesl_pru_rbuffer.h" 38 | #include "host_qot.h" 39 | 40 | #define DEBUG 41 | 42 | volatile int stop = 0; 43 | volatile uint8_t *shared_mem; 44 | 45 | struct rbuffer *send_to_pru_rbuffer; 46 | struct rbuffer *receive_from_pru_rbuffer; 47 | 48 | volatile int ts_ready = 0; 49 | volatile uint64_t last_pru_ts = 0; 50 | volatile uint64_t last_host_ts = 0; 51 | 52 | // Handles interrupts from the PRU 53 | void *receive_pru_thread(void *value) 54 | { 55 | while(!stop) { 56 | short status = 0; 57 | int64_t data; 58 | 59 | // This call will block until PRU interrupts the host 60 | prussdrv_pru_wait_event(PRU_EVTOUT_0); 61 | prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); 62 | 63 | while(!status) { 64 | data = rbuf_read_uint64(receive_from_pru_rbuffer, &status); 65 | if (!status) { 66 | last_pru_ts = data; 67 | ts_ready |= 0x1; 68 | if (ts_ready == 0x3) { 69 | ts_ready = 0; 70 | #ifdef DEBUG 71 | printf("%lld, %lld, %lld\n", 72 | last_host_ts, last_pru_ts, 73 | last_pru_ts - last_host_ts); 74 | #else 75 | printf("%lld, %lld\n", 76 | last_host_ts, last_pru_ts); 77 | #endif 78 | } 79 | } 80 | } 81 | } 82 | } 83 | 84 | // Handles sending QoT timestamp to the PRU 85 | void *send_pru_thread(void *value) 86 | { 87 | int err = 0; 88 | uint64_t nano_ts; 89 | int i = 1; 90 | 91 | while (!stop) { 92 | // This call will block until a QoT input capture event is triggered 93 | int channel; 94 | nano_ts = qot_read_event_ts(&err, &channel); 95 | if (channel == 0) { 96 | //printf("SYNC: %llu ns, channel %d\n", 97 | // nano_ts, channel); 98 | rbuf_write_uint64(send_to_pru_rbuffer, nano_ts); 99 | } else if (channel == 1) { 100 | // Skip the falling edge timestamp 101 | if (i++ % 2) { 102 | last_host_ts = nano_ts; 103 | ts_ready |= 0x2; 104 | if (ts_ready == 0x3) { 105 | ts_ready = 0; 106 | #ifdef DEBUG 107 | printf("%lld, %lld, %lld\n", 108 | last_host_ts, last_pru_ts, 109 | last_pru_ts - last_host_ts); 110 | #else 111 | printf("%lld, %lld\n", 112 | last_host_ts, last_pru_ts); 113 | #endif 114 | } 115 | } 116 | } 117 | } 118 | } 119 | 120 | int main (void) 121 | { 122 | int err; 123 | 124 | if(getuid()!=0){ 125 | printf("You must run this program as root. Exiting.\n"); 126 | exit(EXIT_FAILURE); 127 | } 128 | 129 | pthread_t thread; 130 | pthread_t thread2; 131 | 132 | /* Initialize structure used by prussdrv_pruintc_intc */ 133 | /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 134 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 135 | 136 | /* Initialize PRUSS (PRU Sub-System Driver) */ 137 | prussdrv_init(); 138 | 139 | // PRU_EVTOUT_0 - interrupt generated by PRU to indicate that it has 140 | // sent messages to the host. Pending messages are in the 141 | // receive_from_pru_rbuffer. 142 | err = prussdrv_open (PRU_EVTOUT_0); 143 | if(err){ 144 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 145 | exit(EXIT_FAILURE); 146 | } 147 | 148 | // PRU_EVTOUT_1 - interrupt generated by PRU to indicate that is is 149 | // going to halt. 150 | err = prussdrv_open (PRU_EVTOUT_1); 151 | if(err){ 152 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 153 | exit(EXIT_FAILURE); 154 | } 155 | 156 | /* Map PRU's INTC */ 157 | prussdrv_pruintc_init(&pruss_intc_initdata); 158 | 159 | // Map PRU's shared memory into user-space 160 | if (prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, (void **) &shared_mem)) { 161 | printf("map shared memory failed\n"); 162 | exit(EXIT_FAILURE); 163 | } 164 | 165 | // Clear 12Kb of shared memory 166 | memset((void*) shared_mem, 0, 0x3000); 167 | 168 | // Setup buffers for communication between host and PRU 169 | 170 | // Only the sender initializes the rbuffer. 171 | // PRU will initialize this buffer. Host should NOT initalize this. 172 | receive_from_pru_rbuffer = (struct rbuffer *) (shared_mem + RBUF_ADDR); 173 | 174 | send_to_pru_rbuffer = (struct rbuffer *) (shared_mem + RBUF_ADDR + sizeof(struct rbuffer)); 175 | init_rbuffer(send_to_pru_rbuffer); 176 | 177 | // Setup QoT 178 | if (init_qot("/dev/ptp1")) { 179 | printf("Initialize QoT time sync failed\n"); 180 | exit(EXIT_FAILURE); 181 | } 182 | 183 | /* Load the memory data file */ 184 | prussdrv_load_datafile(PRU_NUM, "./data.bin"); 185 | 186 | /* Load and execute binary on PRU */ 187 | prussdrv_exec_program (PRU_NUM, "./text.bin"); 188 | 189 | /* Thread for handling message from the PRU */ 190 | if (pthread_create(&thread, NULL, &receive_pru_thread, NULL)){ 191 | printf("Failed to create thread!\n"); 192 | exit(EXIT_FAILURE); 193 | } 194 | 195 | /* Thread for sending messages to the PRU */ 196 | if (pthread_create(&thread2, NULL, &send_pru_thread, NULL)){ 197 | printf("Failed to create thread!\n"); 198 | exit(EXIT_FAILURE); 199 | } 200 | 201 | /* Wait for event completion from PRU */ 202 | // This call will block until PRU interrupts the host. 203 | prussdrv_pru_wait_event(PRU_EVTOUT_1); 204 | stop = 1; 205 | 206 | // Teardown QoT 207 | if (deinit_qot()) { 208 | printf("Deinitialize QoT time sync failed\n"); 209 | } 210 | 211 | /* Disable PRU and close memory mappings */ 212 | prussdrv_pru_disable(PRU_NUM); 213 | prussdrv_exit (); 214 | return(EXIT_SUCCESS); 215 | } 216 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/host_qot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "host_qot.h" 28 | 29 | #define PTP_PIN_SETFUNC _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc) 30 | 31 | //struct ptp_pin_desc { 32 | // /* 33 | // * Hardware specific human readable pin name. This field is 34 | // * set by the kernel during the PTP_PIN_GETFUNC ioctl and is 35 | // * ignored for the PTP_PIN_SETFUNC ioctl. 36 | // */ 37 | // char name[64]; 38 | // /* 39 | // * Pin index in the range of zero to ptp_clock_caps.n_pins - 1. 40 | // */ 41 | // unsigned int index; 42 | // /* 43 | // * Which of the PTP_PF_xxx functions to use on this pin. 44 | // */ 45 | // unsigned int func; 46 | // /* 47 | // * The specific channel to use for this function. 48 | // * This corresponds to the 'index' field of the 49 | // * PTP_EXTTS_REQUEST and PTP_PEROUT_REQUEST ioctls. 50 | // */ 51 | // unsigned int chan; 52 | // /* 53 | // * Reserved for future use. 54 | // */ 55 | // unsigned int rsv[5]; 56 | //}; 57 | 58 | char *device_m; /* PTP device */ 59 | int index_m; /* Channel index, '1' corresponds to 'TIMER6' */ 60 | int fd_m; /* device file descriptor */ 61 | struct ptp_pin_desc desc; /* Pin configuration */ 62 | struct ptp_extts_event event; /* PTP event */ 63 | 64 | /** 65 | * Initialize the QoT system for capturing input event timestamps. 66 | * 67 | * Params: 68 | * dev - PTP device file 69 | * channel - Channel index, '1' corresponds to 'TIMER6' 70 | */ 71 | int 72 | init_qot(char* dev) 73 | { 74 | struct ptp_extts_request extts_request; /* External timestamp req */ 75 | 76 | device_m = dev; /* PTP device */ 77 | 78 | /* Open the character device */ 79 | fd_m = open(device_m, O_RDWR); 80 | if (fd_m < 0) { 81 | fprintf(stderr, "opening device %s: %s\n", 82 | device_m, strerror(errno)); 83 | return -1; 84 | } 85 | //printf("Device opened %d\n", fd_m); 86 | 87 | memset(&desc, 0, sizeof(desc)); 88 | desc.index = 0; 89 | desc.func = 1; // '1' corresponds to external timestamp 90 | desc.chan = 0; 91 | if (ioctl(fd_m, PTP_PIN_SETFUNC, &desc)) { 92 | printf("Set pin func failed for %d\n", fd_m); 93 | return -1; 94 | } 95 | //printf("Set pin func successful for %d\n", fd_m); 96 | 97 | memset(&desc, 0, sizeof(desc)); 98 | desc.index = 1; 99 | desc.func = 1; // '1' corresponds to external timestamp 100 | desc.chan = 1; 101 | if (ioctl(fd_m, PTP_PIN_SETFUNC, &desc)) { 102 | printf("Set pin func failed for %d\n", fd_m); 103 | return -1; 104 | } 105 | //printf("Set pin func successful for %d\n", fd_m); 106 | 107 | // Setup to request timestamps from the pin 108 | memset(&extts_request, 0, sizeof(extts_request)); 109 | extts_request.index = 0; 110 | extts_request.flags = PTP_ENABLE_FEATURE; 111 | if (ioctl(fd_m, PTP_EXTTS_REQUEST, &extts_request)) { 112 | printf("Requesting timestamps failed for %d\n", fd_m); 113 | return -1; 114 | } 115 | //printf("Requesting timestamps success for %d\n", fd_m); 116 | 117 | memset(&extts_request, 0, sizeof(extts_request)); 118 | extts_request.index = 1; 119 | extts_request.flags = PTP_ENABLE_FEATURE; 120 | if (ioctl(fd_m, PTP_EXTTS_REQUEST, &extts_request)) { 121 | printf("Requesting timestamps failed for %d\n", fd_m); 122 | return -1; 123 | } 124 | //printf("Requesting timestamps success for %d\n", fd_m); 125 | 126 | 127 | return 0; 128 | } 129 | 130 | int 131 | deinit_qot() 132 | { 133 | int ret = 0; 134 | 135 | /* Disable the pin */ 136 | memset(&desc, 0, sizeof(desc)); 137 | desc.index = 0; 138 | desc.func = 0; // '0' corresponds to no function 139 | desc.chan = 0; 140 | if (ioctl(fd_m, PTP_PIN_SETFUNC, &desc)) { 141 | printf("Disable pin func failed for %d\n", fd_m); 142 | ret = -1; 143 | } 144 | 145 | /* Disable the pin */ 146 | memset(&desc, 0, sizeof(desc)); 147 | desc.index = 1; 148 | desc.func = 0; // '0' corresponds to no function 149 | desc.chan = 1; 150 | if (ioctl(fd_m, PTP_PIN_SETFUNC, &desc)) { 151 | printf("Disable pin func failed for %d\n", fd_m); 152 | ret = -1; 153 | } 154 | /* Close the character device */ 155 | close(fd_m); 156 | 157 | return ret; 158 | } 159 | 160 | /** 161 | * Reads QoT timestamp of event. 162 | * This call will block until an event is triggered! 163 | * 164 | * Params: 165 | * err - pointer to error, -1 on error 166 | * Return: 167 | * Time of event in nanoseconds 168 | */ 169 | uint64_t 170 | qot_read_event_ts(int* err, int* channel) 171 | { 172 | /* Read events coming in */ 173 | 174 | // Debugging 175 | //printf("Trying to read events %d\n", running++); 176 | 177 | // This call to read is blocking 178 | int cnt = read(fd_m, &event, sizeof(event)); 179 | if (cnt != sizeof(event)) { 180 | printf("Cannot read QoT event"); 181 | if (err != NULL) *err = -1; 182 | return 0; 183 | } 184 | uint64_t nano_ts = event.t.sec * 1000000000; 185 | nano_ts += event.t.nsec; 186 | *channel = event.index; 187 | 188 | // Debugging 189 | // printf("Sync Time - %lld.%09u - %llu ns\n", 190 | // event.t.sec, event.t.nsec, nano_ts); 191 | 192 | //printf("QoT event time: %llu ns, channel %d\n", 193 | // nano_ts, *channel); 194 | 195 | return nano_ts; 196 | } 197 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/host_qot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | 11 | #ifndef HOST_QOT_H 12 | #define HOST_QOT_H 13 | 14 | #include 15 | 16 | int init_qot(char* dev); 17 | int deinit_qot(); 18 | uint64_t qot_read_event_ts(int* err, int* channel); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/host_report_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | 11 | /* 12 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 13 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 14 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 15 | * directory for copyright and GNU GPLv3 license information. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "shared_conf.h" 37 | #include "nesl_pru_rbuffer.h" 38 | #include "host_qot.h" 39 | 40 | void *report_thread(void *value) 41 | { 42 | int err = 0; 43 | uint64_t nano_ts; 44 | int i = 1; 45 | 46 | while (1) { 47 | int channel; 48 | nano_ts = qot_read_event_ts(&err, &channel); 49 | if (channel == 0) { 50 | printf("%lld, chan %d\n", nano_ts, channel); 51 | } else if (channel == 1) { 52 | printf("%lld, chan %d\n", nano_ts, channel); 53 | } 54 | } 55 | } 56 | 57 | /* 58 | * Tried asserting P8.9 and P8.10 simultaneously. 59 | * QoT timestamps from both input captures are very accurate. 60 | * Only a few hundred nanoseconds apart. 61 | * 62 | * 1425252214579059335, chan 1 63 | * 1425252214579058961, chan 0 64 | * 1425252214579159376, chan 1 65 | * 1425252214579159002, chan 0 66 | * 1425252214829071585, chan 1 67 | * 1425252214829071211, chan 0 68 | * 1425252214829171585, chan 1 69 | * 1425252214829171211, chan 0 70 | * 1425252215079083793, chan 1 71 | * 1425252215079083419, chan 0 72 | * 1425252215079183835, chan 1 73 | * 1425252215079183461, chan 0 74 | * 1425252215329096043, chan 1 75 | * 1425252215329095669, chan 0 76 | * 1425252215329196085, chan 1 77 | * 1425252215329195711, chan 0 78 | * 1425252215579108293, chan 1 79 | * 1425252215579107919, chan 0 80 | * 1425252215579208335, chan 1 81 | * 1425252215579207961, chan 0 82 | * 83 | */ 84 | int main (void) 85 | { 86 | int err; 87 | 88 | if(getuid()!=0){ 89 | printf("You must run this program as root. Exiting.\n"); 90 | exit(EXIT_FAILURE); 91 | } 92 | 93 | pthread_t thread; 94 | 95 | // Setup QoT 96 | if (init_qot("/dev/ptp1")) { 97 | printf("Initialize QoT time sync failed\n"); 98 | exit(EXIT_FAILURE); 99 | } 100 | 101 | /* Thread for sending messages to the PRU */ 102 | if (pthread_create(&thread, NULL, &report_thread, NULL)){ 103 | printf("Failed to create thread!\n"); 104 | exit(EXIT_FAILURE); 105 | } 106 | 107 | while(1) {} 108 | 109 | // Teardown QoT 110 | if (deinit_qot()) { 111 | printf("Deinitialize QoT time sync failed\n"); 112 | } 113 | 114 | return(EXIT_SUCCESS); 115 | } 116 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/pru_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root * directory for copyright and GNU GPLv3 license information. 9 | */ 10 | 11 | #include "nesl_pru_intc.h" 12 | #include "nesl_pru_iep.h" 13 | #include "nesl_pru_wait.h" 14 | #include "nesl_pru_rbuffer.h" 15 | #include "nesl_pru_ticks.h" 16 | #include "nesl_pru_gpio.h" 17 | #include 18 | #include 19 | 20 | #include "shared_conf.h" 21 | 22 | #define SHARED_MEM_BASE 0x10000 23 | #define SYNC_PERIOD_NS 8000000000 24 | 25 | void 26 | terminate() 27 | { 28 | TRIG_INTC(4); // Trigger interrupt PRUEVENT_1 29 | __halt(); // halt the PRU 30 | } 31 | 32 | int num_samples = 8000; 33 | int input_high = 0; 34 | 35 | void check_input_pin(struct iep_time *time, struct rbuffer *send_buf) 36 | { 37 | if (!input_high) { 38 | if (read_pin(P8_45)) { 39 | input_high = 1; 40 | // Send current pru time back to host for printing 41 | rbuf_write_uint64(send_buf, iep_get_time(time)); 42 | // Interrupt the host: there is a message in the rbuffer 43 | TRIG_INTC(3); // Trigger interrupt PRUEVENT_0 44 | num_samples--; 45 | } 46 | } else { 47 | if (!read_pin(P8_45)) { 48 | input_high = 0; 49 | } 50 | } 51 | } 52 | 53 | int main() 54 | { 55 | // Wait enough time for host to startup 56 | WAIT_MS(1000); 57 | 58 | // Send PRU time back to host for printing 59 | struct rbuffer *send_buf = 60 | (struct rbuffer *) (uint32_t) (SHARED_MEM_BASE + RBUF_ADDR); 61 | init_rbuffer(send_buf); 62 | 63 | // Required for getting host timestamp 64 | struct rbuffer *rec_buf = 65 | (struct rbuffer *) (uint32_t) (SHARED_MEM_BASE + RBUF_ADDR 66 | + sizeof(struct rbuffer)); 67 | 68 | // IEP is our clock source 69 | struct iep_time time; 70 | init_iep_time(&time); 71 | 72 | short status = -1; 73 | int first = 1; 74 | uint64_t last_ts = 0; 75 | uint64_t ts = 0; 76 | uint64_t host_ts = 0; 77 | 78 | while(num_samples > 0) { 79 | ts = iep_get_time(&time); 80 | // Do synchronization every SYNC_PERIOD_NS 81 | if (((ts - last_ts) > SYNC_PERIOD_NS) || first) { 82 | first = 0; 83 | 84 | #if PRU_NUM == 0 85 | // Send a pulse on P9_27 86 | assert_pin(P9_27); 87 | deassert_pin(P9_27); 88 | #else 89 | // Send a pulse on P8_46 90 | assert_pin(P8_46); 91 | deassert_pin(P8_46); 92 | #endif 93 | // time of sync event 94 | ts = iep_get_time(&time); 95 | 96 | // Get the time when the host received the pulse 97 | do { 98 | host_ts = rbuf_read_uint64(rec_buf, &status); 99 | check_input_pin(&time, send_buf); 100 | } while(status); 101 | 102 | // Calculate the offset between host and pru 103 | iep_adj_time(&time, ts, host_ts); 104 | 105 | last_ts = iep_get_time(&time); 106 | // Debugging. If you want to print the ts and delta. 107 | //rbuf_write_uint64(send_buf, ts); 108 | //rbuf_write_uint64(send_buf, delta); 109 | } 110 | 111 | check_input_pin(&time, send_buf); 112 | 113 | //WAIT_MS(1000); 114 | } 115 | 116 | DISABLE_IEP_TMR(); 117 | 118 | // Exiting the application 119 | terminate(); 120 | } 121 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/shared_conf.h: -------------------------------------------------------------------------------- 1 | #ifndef SHARED_CONF_H 2 | #define SHARED_CONF_H 3 | 4 | #define RBUF_ADDR 0 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /C lib/examples/measure_time_sync/stats.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy 3 | 4 | filename = sys.argv[1] 5 | f = open(filename, "r") 6 | 7 | diff = [] 8 | 9 | for line in f: 10 | t = line.split(",") 11 | qot_ts = int(t[0]) 12 | pru_ts = int(t[1]) 13 | diff.append(pru_ts - qot_ts) 14 | 15 | print("mean: %s" % numpy.mean(diff)) 16 | print("stdev: %s" % numpy.std(diff)) 17 | print("median: %s" % numpy.median(diff)) 18 | -------------------------------------------------------------------------------- /C lib/examples/pru_clock/AM3359_PRU.cmd: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* AM3359_PRU.cmd */ 3 | /* Description: This file is a sample linker command file that can be */ 4 | /* used for linking programs built with the PRU C compiler and running the */ 5 | /* resulting .out file on an AM3359 PRU0. Use it as a guideline. You will */ 6 | /* want to change the memory layout to match your specific target system. */ 7 | /* You may want to change the allocation scheme according to the size of */ 8 | /* your program. */ 9 | /******************************************************************************/ 10 | 11 | -cr 12 | -stack 0x100 13 | -heap 0x100 14 | 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */ 19 | PAGE 1: 20 | PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */ 21 | } 22 | 23 | SECTIONS 24 | { 25 | /* Thanks to Jakub for the next line! */ 26 | .text:_c_int00* > 0x0, PAGE 0 27 | .stack > PRUDMEM, PAGE 1 28 | .bss > PRUDMEM, PAGE 1 29 | .cio > PRUDMEM, PAGE 1 30 | .const > PRUDMEM, PAGE 1 31 | .data > PRUDMEM, PAGE 1 32 | .switch > PRUDMEM, PAGE 1 33 | .sysmem > PRUDMEM, PAGE 1 34 | .cinit > PRUDMEM, PAGE 1 35 | } 36 | -------------------------------------------------------------------------------- /C lib/examples/pru_clock/README.md: -------------------------------------------------------------------------------- 1 | ### PRU Clock 2 | 3 | #### Pins 4 | * __P8_46__: PRU output for time sync. 5 | * __P8_9__: QoT input capture for time sync. 6 | 7 | __P8_46__ should be connected to __P8_9__ and this connection is used for time synchronization between the PRU and main processor. 8 | 9 | ``` 10 | # Login as the root user 11 | ssh root@ 12 | 13 | cd ~ 14 | 15 | # load the QoT device tree and kernel modules 16 | ./load_QOT_DT_modules 17 | 18 | # Activate the PRUSS and PINS for PRU1 19 | cd ucla-nesl-pru-lib/overlay 20 | ./install.sh NESL-PRU 21 | ./install.sh NESL-PRU1-PINS 22 | 23 | # Build the pru_clock example 24 | cd ../examples/pru_clock 25 | ./config-pins.sh 26 | ./build.sh 27 | 28 | # Run the pru_clock 29 | cd gen 30 | ./host 31 | 32 | # Now you can run whatever you want on PRU0. 33 | # The PRU1 timestamp is continuously updated 34 | # in the PRU shared memory region. 35 | # By default this will be at 0x11400. 36 | ``` 37 | 38 | You may redefine where in memory the timestamp is located by editing [shared_conf.h](https://github.com/yifanz/ucla-nesl-pru-lib/blob/master/examples/pru_clock/shared_conf.h). 39 | -------------------------------------------------------------------------------- /C lib/examples/pru_clock/bin.cmd: -------------------------------------------------------------------------------- 1 | -b 2 | -image 3 | 4 | ROMS { 5 | PAGE 0: 6 | text: o = 0x0, l = 0x1000, files={text.bin} 7 | PAGE 1: 8 | data: o = 0x0, l = 0x1000, files={data.bin} 9 | } -------------------------------------------------------------------------------- /C lib/examples/pru_clock/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | #Copyright (c) Regents of the University of California, 2017. All rights reserved. 5 | #See LICENSE and ATTRIB in the repository root. 6 | # 7 | # 8 | # 9 | #Based on code from Derek Molloy for the book "Exploring BeagleBone: 10 | #Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 11 | #2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 12 | #directory for copyright and GNU GPLv3 license information. 13 | # 14 | 15 | PRU_NUM=1; # which PRU 0 or 1 16 | PRU_SDK=/usr/share/ti/cgt-pru 17 | PRU_SRC="pru_main.c" 18 | HOST_SRC="host_main.c host_qot.c" 19 | PRU_TARGET=pru.out 20 | HOST_TARGET=host 21 | GEN=gen 22 | SCRIPT_DIR=${0%/*} 23 | 24 | cd $SCRIPT_DIR 25 | mkdir -p $GEN 26 | 27 | echo "Compiling and linking the PRU firmware" 28 | clpru --silicon_version=3 --keep_asm --c_src_interlist \ 29 | --asm_directory=$GEN --obj_directory=$GEN --temp_directory=$GEN \ 30 | -DPRU_NUM=$PRU_NUM \ 31 | $PRU_SRC \ 32 | -i$PRU_SDK/include \ 33 | -i$PRU_SDK/lib \ 34 | -i../../include \ 35 | -z AM3359_PRU.cmd \ 36 | -o $GEN/$PRU_TARGET \ 37 | -m $GEN/$PRU_TARGET.map 38 | 39 | if [ $? -ne 0 ]; then 40 | echo "Compile and link FAILED" 41 | exit 1 42 | fi 43 | 44 | pushd . 45 | cd $GEN 46 | 47 | # The output of the compiler/linker is an ELF executable. 48 | # We cannot directly load the ELF file into the PRU because unlike Linux, 49 | # the PRU does not have a ELF loader. 50 | # In theory, we could parse the ELF file in our host application, 51 | # but that is too much work. 52 | # Instead, we break out the text and data segments and so that we can 53 | # manually map them into PRU memory. 54 | echo "Generating text and data segments (text.bin and data.bin)" 55 | hexpru ../bin.cmd $PRU_TARGET 56 | 57 | if [ $? -ne 0 ]; then 58 | echo "Generating text and data segments FAILED" 59 | exit 1 60 | fi 61 | 62 | popd 63 | 64 | echo "Compiling and linking the host application" 65 | gcc -I../../include -DPRU_NUM=$PRU_NUM $HOST_SRC -o $GEN/$HOST_TARGET -lpthread -lprussdrv 66 | 67 | if [ $? -ne 0 ]; then 68 | echo "Compiling and linking the host application FAILED" 69 | exit 1 70 | fi 71 | 72 | echo "Build SUCCESSFUL." 73 | echo "To run you must change to the gen directory:" 74 | echo "cd gen/" 75 | echo "./host" 76 | -------------------------------------------------------------------------------- /C lib/examples/pru_clock/config-pins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Configuring pins" 4 | 5 | config-pin P8_46 pruout 6 | config-pin -q P8_46 7 | -------------------------------------------------------------------------------- /C lib/examples/pru_clock/host_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | 11 | /* 12 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 13 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 14 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 15 | * directory for copyright and GNU GPLv3 license information. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "shared_conf.h" 37 | #include "nesl_pru_rbuffer.h" 38 | #include "host_qot.h" 39 | 40 | volatile int stop = 0; 41 | volatile uint8_t *shared_mem; 42 | 43 | struct rbuffer *send_to_pru_rbuffer; 44 | 45 | void *poll_time_thread(void *value) 46 | { 47 | while(!stop) { 48 | uint64_t data; 49 | 50 | sleep(1); 51 | 52 | // Poll shared memory location for PRU timestamp 53 | data = *((uint64_t*) (shared_mem + TS_ADDR)); 54 | printf("PRU: %lld ns\n", data); 55 | } 56 | } 57 | 58 | // Handles sending QoT timestamp to the PRU 59 | void *send_pru_thread(void *value) 60 | { 61 | int err = 0; 62 | uint64_t nano_ts; 63 | 64 | while (!stop) { 65 | // This call will block until a QoT input capture event is triggered 66 | nano_ts = qot_read_event_ts(&err); 67 | rbuf_write_uint64(send_to_pru_rbuffer, nano_ts); 68 | } 69 | } 70 | 71 | int main (void) 72 | { 73 | int err; 74 | 75 | if(getuid()!=0){ 76 | printf("You must run this program as root. Exiting.\n"); 77 | exit(EXIT_FAILURE); 78 | } 79 | 80 | pthread_t thread; 81 | pthread_t thread2; 82 | 83 | /* Initialize structure used by prussdrv_pruintc_intc */ 84 | /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 85 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 86 | 87 | /* Initialize PRUSS (PRU Sub-System Driver) */ 88 | prussdrv_init(); 89 | 90 | err = prussdrv_open (PRU_EVTOUT_0); 91 | if(err){ 92 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 93 | exit(EXIT_FAILURE); 94 | } 95 | 96 | // PRU_EVTOUT_1 - interrupt generated by PRU to indicate that is is 97 | // going to halt. 98 | err = prussdrv_open (PRU_EVTOUT_1); 99 | if(err){ 100 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 101 | exit(EXIT_FAILURE); 102 | } 103 | 104 | /* Map PRU's INTC */ 105 | prussdrv_pruintc_init(&pruss_intc_initdata); 106 | 107 | // Map PRU's shared memory into user-space 108 | if (prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, (void **) &shared_mem)) { 109 | printf("map shared memory failed\n"); 110 | exit(EXIT_FAILURE); 111 | } 112 | 113 | // Clear 12Kb of shared memory 114 | memset((void*) shared_mem, 0, 0x3000); 115 | 116 | // Setup buffers for communication between host and PRU 117 | 118 | // Only the sender initializes the rbuffer. 119 | send_to_pru_rbuffer = (struct rbuffer *) (shared_mem + RBUF_ADDR + sizeof(struct rbuffer)); 120 | init_rbuffer(send_to_pru_rbuffer); 121 | 122 | // Setup QoT 123 | if (init_qot("/dev/ptp1", 0)) { 124 | printf("Initialize QoT time sync failed\n"); 125 | exit(EXIT_FAILURE); 126 | } 127 | 128 | /* Load the memory data file */ 129 | prussdrv_load_datafile(PRU_NUM, "./data.bin"); 130 | 131 | /* Load and execute binary on PRU */ 132 | prussdrv_exec_program (PRU_NUM, "./text.bin"); 133 | 134 | /* Thread for handling message from the PRU */ 135 | if (pthread_create(&thread, NULL, &poll_time_thread, NULL)){ 136 | printf("Failed to create thread!\n"); 137 | exit(EXIT_FAILURE); 138 | } 139 | 140 | /* Thread for sending messages to the PRU */ 141 | if (pthread_create(&thread2, NULL, &send_pru_thread, NULL)){ 142 | printf("Failed to create thread!\n"); 143 | exit(EXIT_FAILURE); 144 | } 145 | 146 | /* Wait for event completion from PRU */ 147 | // This call will block until PRU interrupts the host. 148 | prussdrv_pru_wait_event(PRU_EVTOUT_1); 149 | stop = 1; 150 | 151 | // Teardown QoT 152 | if (deinit_qot()) { 153 | printf("Deinitialize QoT time sync failed\n"); 154 | } 155 | 156 | /* Disable PRU and close memory mappings */ 157 | prussdrv_pru_disable(PRU_NUM); 158 | prussdrv_exit (); 159 | return(EXIT_SUCCESS); 160 | } 161 | -------------------------------------------------------------------------------- /C lib/examples/pru_clock/host_qot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "host_qot.h" 28 | 29 | #define PTP_PIN_SETFUNC _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc) 30 | 31 | //struct ptp_pin_desc { 32 | // /* 33 | // * Hardware specific human readable pin name. This field is 34 | // * set by the kernel during the PTP_PIN_GETFUNC ioctl and is 35 | // * ignored for the PTP_PIN_SETFUNC ioctl. 36 | // */ 37 | // char name[64]; 38 | // /* 39 | // * Pin index in the range of zero to ptp_clock_caps.n_pins - 1. 40 | // */ 41 | // unsigned int index; 42 | // /* 43 | // * Which of the PTP_PF_xxx functions to use on this pin. 44 | // */ 45 | // unsigned int func; 46 | // /* 47 | // * The specific channel to use for this function. 48 | // * This corresponds to the 'index' field of the 49 | // * PTP_EXTTS_REQUEST and PTP_PEROUT_REQUEST ioctls. 50 | // */ 51 | // unsigned int chan; 52 | // /* 53 | // * Reserved for future use. 54 | // */ 55 | // unsigned int rsv[5]; 56 | //}; 57 | 58 | char *device_m; /* PTP device */ 59 | int index_m; /* Channel index, '1' corresponds to 'TIMER6' */ 60 | int fd_m; /* device file descriptor */ 61 | struct ptp_pin_desc desc; /* Pin configuration */ 62 | struct ptp_extts_event event; /* PTP event */ 63 | 64 | /** 65 | * Initialize the QoT system for capturing input event timestamps. 66 | * 67 | * Params: 68 | * dev - PTP device file 69 | * channel - Channel index, '1' corresponds to 'TIMER6' 70 | */ 71 | int 72 | init_qot(char* dev, int channel) 73 | { 74 | struct ptp_extts_request extts_request; /* External timestamp req */ 75 | 76 | device_m = dev; /* PTP device */ 77 | index_m = channel; /* Channel index */ 78 | 79 | /* Open the character device */ 80 | fd_m = open(device_m, O_RDWR); 81 | if (fd_m < 0) { 82 | fprintf(stderr, "opening device %s: %s\n", 83 | device_m, strerror(errno)); 84 | return -1; 85 | } 86 | printf("Device opened %d\n", fd_m); 87 | 88 | memset(&desc, 0, sizeof(desc)); 89 | desc.index = index_m; 90 | desc.func = 1; // '1' corresponds to external timestamp 91 | desc.chan = index_m; 92 | if (ioctl(fd_m, PTP_PIN_SETFUNC, &desc)) { 93 | printf("Set pin func failed for %d\n", fd_m); 94 | return -1; 95 | } 96 | printf("Set pin func successful for %d\n", fd_m); 97 | 98 | // Setup to request timestamps from the pin 99 | memset(&extts_request, 0, sizeof(extts_request)); 100 | extts_request.index = index_m; 101 | extts_request.flags = PTP_ENABLE_FEATURE; 102 | if (ioctl(fd_m, PTP_EXTTS_REQUEST, &extts_request)) { 103 | printf("Requesting timestamps failed for %d\n", fd_m); 104 | return -1; 105 | } 106 | printf("Requesting timestamps success for %d\n", fd_m); 107 | 108 | return 0; 109 | } 110 | 111 | int 112 | deinit_qot() 113 | { 114 | int ret = 0; 115 | 116 | /* Disable the pin */ 117 | memset(&desc, 0, sizeof(desc)); 118 | desc.index = index_m; 119 | desc.func = 0; // '0' corresponds to no function 120 | desc.chan = index_m; 121 | if (ioctl(fd_m, PTP_PIN_SETFUNC, &desc)) { 122 | printf("Disable pin func failed for %d\n", fd_m); 123 | ret = -1; 124 | } 125 | 126 | /* Close the character device */ 127 | close(fd_m); 128 | 129 | return ret; 130 | } 131 | 132 | /** 133 | * Reads QoT timestamp of event. 134 | * This call will block until an event is triggered! 135 | * 136 | * Params: 137 | * err - pointer to error, -1 on error 138 | * Return: 139 | * Time of event in nanoseconds 140 | */ 141 | uint64_t 142 | qot_read_event_ts(int* err) 143 | { 144 | /* Read events coming in */ 145 | 146 | // Debugging 147 | //printf("Trying to read events %d\n", running++); 148 | 149 | // This call to read is blocking 150 | int cnt = read(fd_m, &event, sizeof(event)); 151 | if (cnt != sizeof(event)) { 152 | printf("Cannot read QoT event"); 153 | if (err != NULL) *err = -1; 154 | return 0; 155 | } 156 | uint64_t nano_ts = event.t.sec * 1000000000; 157 | nano_ts += event.t.nsec; 158 | 159 | // Debugging 160 | // printf("Sync Time - %lld.%09u - %llu ns\n", 161 | // event.t.sec, event.t.nsec, nano_ts); 162 | 163 | //printf("QoT event time: %llu ns\n", nano_ts); 164 | 165 | return nano_ts; 166 | } 167 | -------------------------------------------------------------------------------- /C lib/examples/pru_clock/host_qot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | 11 | #ifndef HOST_QOT_H 12 | #define HOST_QOT_H 13 | 14 | #include 15 | 16 | int init_qot(char* dev, int channel); 17 | int deinit_qot(); 18 | uint64_t qot_read_event_ts(int* err); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /C lib/examples/pru_clock/pru_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root * directory for copyright and GNU GPLv3 license information. 9 | */ 10 | 11 | #include "nesl_pru_intc.h" 12 | #include "nesl_pru_iep.h" 13 | #include "nesl_pru_wait.h" 14 | #include "nesl_pru_rbuffer.h" 15 | #include "nesl_pru_time.h" 16 | #include "nesl_pru_ticks.h" 17 | #include "nesl_pru_gpio.h" 18 | #include 19 | #include 20 | 21 | #include "shared_conf.h" 22 | 23 | #define SYNC_PERIOD_NS 5000000000 24 | 25 | void 26 | terminate() 27 | { 28 | TRIG_INTC(4); // Trigger interrupt PRUEVENT_1 29 | __halt(); // halt the PRU 30 | } 31 | 32 | cycle_t 33 | read_cc(const struct cyclecounter *cc) 34 | { 35 | return IEP_CNT; 36 | } 37 | 38 | /* 39 | * Custom function that lets you slew the IEP counter. 40 | * This is just for demo purposes. You should define your own algorithm. 41 | */ 42 | int 43 | slew_cc(s64 delta) 44 | { 45 | uint8_t comp_cycles = 0; 46 | uint8_t comp_inc = 0; 47 | uint64_t abs_delta = llabs(delta); 48 | 49 | if (abs_delta < 100) { 50 | if (delta < 0) { 51 | // PRU clock was too fast 52 | comp_cycles = abs_delta / 5; 53 | comp_inc = 0; 54 | } else { 55 | // PRU clock was too slow 56 | comp_cycles = 1; 57 | comp_inc = abs_delta / 5; 58 | } 59 | 60 | SET_IEP_COMP_INC(comp_inc); 61 | IEP_COMPEN = comp_cycles; 62 | 63 | return 1; 64 | } else { 65 | return 0; 66 | } 67 | } 68 | 69 | /* 70 | * This program runs on PRU1 and periodically performs time synchronization between the host and PRU. 71 | * It will continuously write the current 64 bit timestamp value (nanoseconds) to a shared memory location (SHARED_MEM_BASE + TS_ADDR). 72 | */ 73 | int main() 74 | { 75 | uint64_t *ts_mem = (void*) (unsigned long) (SHARED_MEM_BASE + TS_ADDR); 76 | 77 | // Wait enough time for host to startup 78 | WAIT_MS(100); 79 | 80 | // Required for getting host timestamp 81 | struct rbuffer *rec_buf = 82 | (struct rbuffer *) (uint32_t) (SHARED_MEM_BASE + RBUF_ADDR 83 | + sizeof(struct rbuffer)); 84 | 85 | // IEP is our clock source 86 | DISABLE_IEP_TMR(); 87 | ENABLE_IEP_TMR(); 88 | IEP_CNT = 0; 89 | 90 | struct pru_time time; 91 | 92 | // Initialize pru_time with IEP as the source 93 | // slew_cc is optional 94 | //init_pru_time(&time, 5, 0, 32, read_cc, slew_cc); 95 | init_pru_time(&time, 5, 0, 32, read_cc, NULL); 96 | 97 | short status = -1; 98 | uint64_t data = 0; 99 | 100 | u64 last_ts = 0; 101 | int first = 1; 102 | while(1) { 103 | u64 ts = read_pru_time(&time); 104 | if (((ts - last_ts) > SYNC_PERIOD_NS) || first) { 105 | first = 0; 106 | last_ts = ts; 107 | 108 | // Time synchronization started 109 | u64 ts_pru = read_pru_time(&time); 110 | 111 | assert_pin(P8_46); 112 | deassert_pin(P8_46); 113 | 114 | // Get the time when the host received the pulse 115 | uint64_t ts_host = 0; 116 | do { 117 | data = rbuf_read_uint64(rec_buf, &status); 118 | *ts_mem = read_pru_time(&time); 119 | } while(status); 120 | ts_host = data; 121 | 122 | // Calculate the offset between host and pru 123 | s64 delta = adj_pru_time(&time, ts_pru, ts_host); 124 | } 125 | 126 | // Write timestamp to shared memory location 127 | *ts_mem = read_pru_time(&time); 128 | } 129 | 130 | /* this program never terminates 131 | DISABLE_IEP_TMR(); 132 | 133 | // Exiting the application 134 | terminate(); 135 | */ 136 | } 137 | -------------------------------------------------------------------------------- /C lib/examples/pru_clock/shared_conf.h: -------------------------------------------------------------------------------- 1 | #ifndef SHARED_CONF_H 2 | #define SHARED_CONF_H 3 | 4 | #define SHARED_MEM_BASE 0x10000 5 | 6 | // Location of ring buffer needed for getting 7 | // host timestamp to PRU. 8 | // SHARED_MEM_BASE + RBUG_ADDR 9 | #define RBUF_ADDR 0 10 | 11 | // Location of 64 bit PRU timestamp. 12 | // SHARED_MEM_BASE + TS_ADDR 13 | #define TS_ADDR 0x1400 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /C lib/examples/pwm/AM3359_PRU.cmd: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* AM3359_PRU.cmd */ 3 | /* Description: This file is a sample linker command file that can be */ 4 | /* used for linking programs built with the PRU C compiler and running the */ 5 | /* resulting .out file on an AM3359 PRU0. Use it as a guideline. You will */ 6 | /* want to change the memory layout to match your specific target system. */ 7 | /* You may want to change the allocation scheme according to the size of */ 8 | /* your program. */ 9 | /******************************************************************************/ 10 | 11 | -cr 12 | -stack 0x100 13 | -heap 0x100 14 | 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */ 19 | PAGE 1: 20 | PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */ 21 | } 22 | 23 | SECTIONS 24 | { 25 | /* Thanks to Jakub for the next line! */ 26 | .text:_c_int00* > 0x0, PAGE 0 27 | .stack > PRUDMEM, PAGE 1 28 | .bss > PRUDMEM, PAGE 1 29 | .cio > PRUDMEM, PAGE 1 30 | .const > PRUDMEM, PAGE 1 31 | .data > PRUDMEM, PAGE 1 32 | .switch > PRUDMEM, PAGE 1 33 | .sysmem > PRUDMEM, PAGE 1 34 | .cinit > PRUDMEM, PAGE 1 35 | } 36 | -------------------------------------------------------------------------------- /C lib/examples/pwm/README.md: -------------------------------------------------------------------------------- 1 | ### Code Comparison 2 | 3 | __C__ Language Example ([pru_main.c](https://github.com/yifanz/ucla-nesl-pru-lib/blob/master/examples/pwm/pru_main.c)) 4 | ``` 5 | #include "nesl_pru_intc.h" 6 | #include "nesl_pru_gpio.h" 7 | #include "nesl_pru_wait.h" 8 | 9 | void pwm(enum pru_pin pin, 10 | unsigned int period_us, unsigned int pulse_width_us) 11 | { 12 | // Keep sending PWM signal until P8_45 is asserted. 13 | while(read_pin(P8_45) == 0) { 14 | assert_pin(pin); 15 | WAIT_US(pulse_width_us); 16 | deassert_pin(pin); 17 | WAIT_US(period_us - pulse_width_us); 18 | } 19 | } 20 | 21 | int main() 22 | { 23 | // Ouput PWM signal with period of 1 second and 24 | // pulse width of 0.5 seconds. 25 | pwm(P8_46, 1000000, 500000); 26 | 27 | // Terminate program 28 | TRIG_INTC(3); 29 | __halt(); 30 | } 31 | ``` 32 | 33 | __Cyclops__ high-level language PWM example (https://github.com/yifanz/CSM213A). 34 | The `tick` is implemented using the cycle counter. Setting `tick = 0` resets the cycle counter. 35 | This language is in a prototype phase. We currently don't support function declarations in the grammar. 36 | ``` 37 | // PWM with 1 second period and pulse width of 0.5 seconds. 38 | while(P8_45 == 0) { 39 | // Each tick is 5 nanoseconds. 40 | tick = 0; 41 | 42 | // Output High 43 | P8_46 = 1; 44 | 45 | // Wait for 0.5 seconds (2 * 10^8 cycles) 46 | while (tick < 0xBEBC200) {} 47 | 48 | tick = 0; 49 | 50 | // Output Low 51 | P8_46 = 0; 52 | 53 | // Wait for 0.5 seconds (2 * 10^8 cycles) 54 | while (tick < 0xBEBC200) {} 55 | } 56 | ``` 57 | 58 | __PASM__ example (adapted from Derek Molloy's "[Exploring Beaglebone](http://exploringbeaglebone.com)" Chapter 13) 59 | ``` 60 | .origin 0 61 | .entrypoint START 62 | 63 | #define PRU0_R31_VEC_VALID 32 64 | #define EVENTOUT0 3 65 | 66 | // PWM with 1 second period and pulse width of 0.5 seconds. 67 | 68 | START: 69 | MOV r0, 0xBEBC200 // count for 0.5 seconds (2 * 10^8 cycles) 70 | 71 | MAINLOOP: 72 | 73 | SET r30.t1 // set the output pin P8_46 high 74 | 75 | MOV r1, r0 // wait for 0.5 seconds 76 | HOLD_HIGH: 77 | SUB r1, r1, 1 78 | QBNE HOLD_HIGH, r1, 0 79 | 80 | CLR r30.t1 // set the output pin P8_46 low 81 | 82 | MOV r1, r0 // wait for 0.5 seconds 83 | HOLD_LOW: 84 | SUB r1, r1, 1 85 | QBNE HOLD_LOW, r1, 0 86 | 87 | QBBS END, r31.t0 // quit if input pin P8_45 is asserted 88 | QBA MAINLOOP 89 | 90 | END: 91 | MOV R31.b0, PRU0_R31_VEC_VALID | EVENTOUT0 // Terminate program 92 | HALT 93 | ``` 94 | -------------------------------------------------------------------------------- /C lib/examples/pwm/bin.cmd: -------------------------------------------------------------------------------- 1 | -b 2 | -image 3 | 4 | ROMS { 5 | PAGE 0: 6 | text: o = 0x0, l = 0x1000, files={text.bin} 7 | PAGE 1: 8 | data: o = 0x0, l = 0x1000, files={data.bin} 9 | } -------------------------------------------------------------------------------- /C lib/examples/pwm/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | #Copyright (c) Regents of the University of California, 2017. All rights reserved. 5 | #See LICENSE and ATTRIB in the repository root. 6 | # 7 | # 8 | # 9 | #Based on code from Derek Molloy for the book "Exploring BeagleBone: 10 | #Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 11 | #2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 12 | #directory for copyright and GNU GPLv3 license information. 13 | # 14 | 15 | PRU_NUM=1; # which PRU 0 or 1 16 | PRU_SRC="pru_main.c" 17 | HOST_SRC="host_main.c" 18 | PRU_TARGET=pru.out 19 | HOST_TARGET=host 20 | GEN=gen 21 | SCRIPT_DIR=${0%/*} 22 | 23 | cd $SCRIPT_DIR 24 | mkdir -p $GEN 25 | 26 | echo "Compiling and linking the PRU firmware" 27 | clpru --silicon_version=3 --keep_asm --c_src_interlist \ 28 | --asm_directory=$GEN --obj_directory=$GEN --temp_directory=$GEN \ 29 | -DPRU_NUM=$PRU_NUM \ 30 | $PRU_SRC \ 31 | -i../../include \ 32 | -z AM3359_PRU.cmd \ 33 | -o $GEN/$PRU_TARGET \ 34 | -m $GEN/$PRU_TARGET.map 35 | 36 | if [ $? -ne 0 ]; then 37 | echo "Compile and link FAILED" 38 | exit 1 39 | fi 40 | 41 | pushd . 42 | cd $GEN 43 | 44 | # The output of the compiler/linker is an ELF executable. 45 | # We cannot directly load the ELF file into the PRU because unlike Linux, 46 | # the PRU does not have a ELF loader. 47 | # In theory, we could parse the ELF file in our host application, 48 | # but that is too much work. 49 | # Instead, we break out the text and data segments and so that we can 50 | # manually map them into PRU memory. 51 | echo "Generating text and data segments (text.bin and data.bin)" 52 | hexpru ../bin.cmd $PRU_TARGET 53 | 54 | if [ $? -ne 0 ]; then 55 | echo "Generating text and data segments FAILED" 56 | exit 1 57 | fi 58 | 59 | popd 60 | 61 | echo "Compiling and linking the host application" 62 | gcc -I../../include -DPRU_NUM=$PRU_NUM $HOST_SRC -o $GEN/$HOST_TARGET -lpthread -lprussdrv 63 | 64 | if [ $? -ne 0 ]; then 65 | echo "Compiling and linking the host application FAILED" 66 | exit 1 67 | fi 68 | 69 | echo "Build SUCCESSFUL." 70 | echo "To run you must change to the gen directory:" 71 | echo "cd gen/" 72 | echo "./host" 73 | -------------------------------------------------------------------------------- /C lib/examples/pwm/config-pins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Configuring pins" 4 | 5 | #config-pin P9_27 pruout 6 | #config-pin -q P9_27 7 | #config-pin P9_28 pruin 8 | #config-pin -q P9_28 9 | 10 | config-pin P8_46 pruout 11 | config-pin -q P8_46 12 | config-pin P8_45 pruin 13 | config-pin -q P8_45 14 | -------------------------------------------------------------------------------- /C lib/examples/pwm/host_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 9 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int main (void) 20 | { 21 | int n, ret; 22 | 23 | if(getuid()!=0){ 24 | printf("You must run this program as root. Exiting.\n"); 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | /* Initialize structure used by prussdrv_pruintc_intc */ 29 | /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 30 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 31 | 32 | /* Allocate and initialize memory */ 33 | prussdrv_init (); 34 | ret = prussdrv_open (PRU_EVTOUT_0); 35 | if(ret){ 36 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 37 | exit(EXIT_FAILURE); 38 | } 39 | /* Map PRU's INTC */ 40 | prussdrv_pruintc_init(&pruss_intc_initdata); 41 | 42 | /* Load the memory data file */ 43 | prussdrv_load_datafile(PRU_NUM, "./data.bin"); 44 | 45 | /* Load and execute binary on PRU */ 46 | prussdrv_exec_program (PRU_NUM, "./text.bin"); 47 | 48 | /* Wait for event completion from PRU */ 49 | n = prussdrv_pru_wait_event (PRU_EVTOUT_0); // This assumes the PRU generates an interrupt 50 | // connected to event out 0 immediately before halting 51 | printf("PRU program completed, event number %d.\n", n); 52 | 53 | /* Disable PRU and close memory mappings */ 54 | prussdrv_pru_disable(PRU_NUM); 55 | prussdrv_exit (); 56 | return(EXIT_SUCCESS); 57 | } 58 | -------------------------------------------------------------------------------- /C lib/examples/pwm/pru_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 9 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | #include "nesl_pru_intc.h" 14 | #include "nesl_pru_gpio.h" 15 | #include "nesl_pru_wait.h" 16 | 17 | void pwm(enum pru_pin pin, 18 | unsigned int period_us, unsigned int pulse_width_us) 19 | { 20 | // Keep sending PWM signal until P8_45 is asserted. 21 | while(read_pin(P8_45) == 0) { 22 | assert_pin(pin); 23 | WAIT_US(pulse_width_us); 24 | deassert_pin(pin); 25 | WAIT_US(period_us - pulse_width_us); 26 | } 27 | } 28 | 29 | int main() 30 | { 31 | // Ouput PWM signal with period of 1 second and 32 | // pulse width of 0.5 seconds. 33 | pwm(P8_46, 1000000, 500000); 34 | 35 | // Exiting the application. 36 | TRIG_INTC(3); 37 | __halt(); // halt the PRU. 38 | } 39 | -------------------------------------------------------------------------------- /C lib/examples/read_time_latency/AM3359_PRU.cmd: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* AM3359_PRU.cmd */ 3 | /* Description: This file is a sample linker command file that can be */ 4 | /* used for linking programs built with the PRU C compiler and running the */ 5 | /* resulting .out file on an AM3359 PRU0. Use it as a guideline. You will */ 6 | /* want to change the memory layout to match your specific target system. */ 7 | /* You may want to change the allocation scheme according to the size of */ 8 | /* your program. */ 9 | /******************************************************************************/ 10 | 11 | -cr 12 | -stack 0x100 13 | -heap 0x100 14 | 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */ 19 | PAGE 1: 20 | PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */ 21 | } 22 | 23 | SECTIONS 24 | { 25 | /* Thanks to Jakub for the next line! */ 26 | .text:_c_int00* > 0x0, PAGE 0 27 | .stack > PRUDMEM, PAGE 1 28 | .bss > PRUDMEM, PAGE 1 29 | .cio > PRUDMEM, PAGE 1 30 | .const > PRUDMEM, PAGE 1 31 | .data > PRUDMEM, PAGE 1 32 | .switch > PRUDMEM, PAGE 1 33 | .sysmem > PRUDMEM, PAGE 1 34 | .cinit > PRUDMEM, PAGE 1 35 | } 36 | -------------------------------------------------------------------------------- /C lib/examples/read_time_latency/README.md: -------------------------------------------------------------------------------- 1 | ### Measure latency for reading/calculating PRU timestamp 2 | 3 | Measure the latency for `iep_get_time()`, `iep_adj_time()` and reading the IEP counter. 4 | 5 | PRU is 200 MHz so 1 cycle is 5 ns. 6 | There is no cache or pipeline in the PRU architecture so every instruction (as long as it does not access main processor resources) executes deterministically. 7 | In this test, it appears that all functions are completely deterministic and they take the same number of cycles to execute everytime. 8 | 9 | * `iep_get_time()` = 124 cycles = 620 ns 10 | * `iep_adj_time()` = 58 cycles = 290 ns 11 | * Reading IEP counter (32-bit) = 23 cycles = 115 ns 12 | 13 | `iep_get_time()` is used to get the current 64-bit PRU timestamp. It includes reading the IEP counter and handles roll over checking. 14 | 15 | `iep_adj_time()` is a simpler function used to adjust the current PRU timestamp based on it's offset with respect to an external timestamp. 16 | It does not read the IEP counter. 17 | -------------------------------------------------------------------------------- /C lib/examples/read_time_latency/bin.cmd: -------------------------------------------------------------------------------- 1 | -b 2 | -image 3 | 4 | ROMS { 5 | PAGE 0: 6 | text: o = 0x0, l = 0x1000, files={text.bin} 7 | PAGE 1: 8 | data: o = 0x0, l = 0x1000, files={data.bin} 9 | } -------------------------------------------------------------------------------- /C lib/examples/read_time_latency/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | #Copyright (c) Regents of the University of California, 2017. All rights reserved. 5 | #See LICENSE and ATTRIB in the repository root. 6 | # 7 | # 8 | # 9 | #Based on code from Derek Molloy for the book "Exploring BeagleBone: 10 | #Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 11 | #2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 12 | #directory for copyright and GNU GPLv3 license information. 13 | # 14 | 15 | PRU_NUM=1; # which PRU 0 or 1 16 | #PRU_SDK=/root/pru_2.0.0B2 17 | PRU_SRC="pru_main.c" 18 | HOST_SRC="host_main.c" 19 | PRU_TARGET=pru.out 20 | HOST_TARGET=host 21 | GEN=gen 22 | SCRIPT_DIR=${0%/*} 23 | 24 | cd $SCRIPT_DIR 25 | mkdir -p $GEN 26 | 27 | echo "Compiling and linking the PRU firmware" 28 | clpru --silicon_version=3 --keep_asm --c_src_interlist \ 29 | --asm_directory=$GEN --obj_directory=$GEN --temp_directory=$GEN \ 30 | -DPRU_NUM=$PRU_NUM \ 31 | $PRU_SRC \ 32 | -i../../include \ 33 | -z AM3359_PRU.cmd \ 34 | -o $GEN/$PRU_TARGET \ 35 | -m $GEN/$PRU_TARGET.map 36 | #-i$PRU_SDK/include 37 | #-i$PRU_SDK/lib 38 | 39 | if [ $? -ne 0 ]; then 40 | echo "Compile and link FAILED" 41 | exit 1 42 | fi 43 | 44 | pushd . 45 | cd $GEN 46 | 47 | # The output of the compiler/linker is an ELF executable. 48 | # We cannot directly load the ELF file into the PRU because unlike Linux, 49 | # the PRU does not have a ELF loader. 50 | # In theory, we could parse the ELF file in our host application, 51 | # but that is too much work. 52 | # Instead, we break out the text and data segments and so that we can 53 | # manually map them into PRU memory. 54 | echo "Generating text and data segments (text.bin and data.bin)" 55 | hexpru ../bin.cmd $PRU_TARGET 56 | 57 | if [ $? -ne 0 ]; then 58 | echo "Generating text and data segments FAILED" 59 | exit 1 60 | fi 61 | 62 | popd 63 | 64 | echo "Compiling and linking the host application" 65 | gcc -I../../include -DPRU_NUM=$PRU_NUM $HOST_SRC -o $GEN/$HOST_TARGET -lpthread -lprussdrv 66 | 67 | if [ $? -ne 0 ]; then 68 | echo "Compiling and linking the host application FAILED" 69 | exit 1 70 | fi 71 | 72 | echo "Build SUCCESSFUL." 73 | echo "To run you must change to the gen directory:" 74 | echo "cd gen/" 75 | echo "./host" 76 | -------------------------------------------------------------------------------- /C lib/examples/read_time_latency/host_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | 11 | /* 12 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 13 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 14 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 15 | * directory for copyright and GNU GPLv3 license information. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | volatile uint8_t *shared_mem; 37 | 38 | int main (void) 39 | { 40 | int err; 41 | 42 | if(getuid()!=0){ 43 | printf("You must run this program as root. Exiting.\n"); 44 | exit(EXIT_FAILURE); 45 | } 46 | 47 | /* Initialize structure used by prussdrv_pruintc_intc */ 48 | /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 49 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 50 | 51 | /* Initialize PRUSS (PRU Sub-System Driver) */ 52 | prussdrv_init(); 53 | 54 | // PRU_EVTOUT_0 - interrupt generated by PRU to indicate that it has 55 | // sent messages to the host. Pending messages are in the 56 | // receive_from_pru_rbuffer. 57 | err = prussdrv_open (PRU_EVTOUT_0); 58 | if(err){ 59 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 60 | exit(EXIT_FAILURE); 61 | } 62 | 63 | // PRU_EVTOUT_1 - interrupt generated by PRU to indicate that is is 64 | // going to halt. 65 | err = prussdrv_open (PRU_EVTOUT_1); 66 | if(err){ 67 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 68 | exit(EXIT_FAILURE); 69 | } 70 | 71 | /* Map PRU's INTC */ 72 | prussdrv_pruintc_init(&pruss_intc_initdata); 73 | 74 | // Map PRU's shared memory into user-space 75 | if (prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, (void **) &shared_mem)) { 76 | printf("map shared memory failed\n"); 77 | exit(EXIT_FAILURE); 78 | } 79 | 80 | // Clear 12Kb of shared memory 81 | memset((void*) shared_mem, 0, 0x3000); 82 | 83 | /* Load the memory data file */ 84 | prussdrv_load_datafile(PRU_NUM, "./data.bin"); 85 | 86 | /* Load and execute binary on PRU */ 87 | prussdrv_exec_program (PRU_NUM, "./text.bin"); 88 | 89 | /* Wait for event completion from PRU */ 90 | // This call will block until PRU interrupts the host. 91 | prussdrv_pru_wait_event(PRU_EVTOUT_1); 92 | 93 | uint32_t *p = (uint32_t *) shared_mem; 94 | int i = 1000; 95 | while (i--) { 96 | printf("%lu\n", *p); 97 | p++; 98 | } 99 | 100 | /* Disable PRU and close memory mappings */ 101 | prussdrv_pru_disable(PRU_NUM); 102 | prussdrv_exit (); 103 | return(EXIT_SUCCESS); 104 | } 105 | -------------------------------------------------------------------------------- /C lib/examples/read_time_latency/pru_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root * directory for copyright and GNU GPLv3 license information. 9 | */ 10 | 11 | #include "nesl_pru_intc.h" 12 | #include "nesl_pru_iep.h" 13 | #include "nesl_pru_wait.h" 14 | #include "nesl_pru_rbuffer.h" 15 | #include "nesl_pru_ticks.h" 16 | #include "nesl_pru_gpio.h" 17 | #include 18 | #include 19 | 20 | void 21 | terminate() 22 | { 23 | TRIG_INTC(4); // Trigger interrupt PRUEVENT_1 24 | __halt(); // halt the PRU 25 | } 26 | 27 | /* 28 | * Measure the latency for read_pru_time() and adj_pru_time(). 29 | * 30 | * PRU is 200 MHz -> 1 cycle is 5 ns 31 | * 32 | * ie_get_time = 124 cycles = 620 ns 33 | * adj_pru_time = 58 cycles = 290 ns 34 | * read IEP counter = 23 cycles = 115 ns 35 | */ 36 | int main() 37 | { 38 | uint32_t *shared_mem = (void*) (unsigned long) 0x10000; 39 | 40 | ENABLE_TICKS(); 41 | 42 | // IEP is our clock source 43 | DISABLE_IEP_TMR(); 44 | ENABLE_IEP_TMR(); 45 | IEP_CNT = 0; 46 | 47 | uint64_t ts = 0; 48 | uint64_t host_ts = 0; 49 | 50 | struct iep_time time; 51 | init_iep_time(&time); 52 | 53 | unsigned int i = 1000; 54 | while(i--) { 55 | TICKS = 0; 56 | uint64_t ts_pru = iep_get_time(&time); 57 | //iep_adj_time(&time, ts, host_ts); 58 | //uint32_t iep_cnt = IEP_CNT; 59 | *shared_mem = TICKS; 60 | shared_mem++; 61 | } 62 | 63 | DISABLE_IEP_TMR(); 64 | 65 | // Exiting the application 66 | terminate(); 67 | } 68 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/AM3359_PRU.cmd: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* AM3359_PRU.cmd */ 3 | /* Description: This file is a sample linker command file that can be */ 4 | /* used for linking programs built with the PRU C compiler and running the */ 5 | /* resulting .out file on an AM3359 PRU0. Use it as a guideline. You will */ 6 | /* want to change the memory layout to match your specific target system. */ 7 | /* You may want to change the allocation scheme according to the size of */ 8 | /* your program. */ 9 | /******************************************************************************/ 10 | 11 | -cr 12 | -stack 0x100 13 | -heap 0x100 14 | 15 | MEMORY 16 | { 17 | PAGE 0: 18 | PRUIMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU0 Instruction RAM */ 19 | PAGE 1: 20 | PRUDMEM: o = 0x00000000 l = 0x00001000 /* 8kB PRU Data RAM 0 */ 21 | } 22 | 23 | SECTIONS 24 | { 25 | /* Thanks to Jakub for the next line! */ 26 | .text:_c_int00* > 0x0, PAGE 0 27 | .stack > PRUDMEM, PAGE 1 28 | .bss > PRUDMEM, PAGE 1 29 | .cio > PRUDMEM, PAGE 1 30 | .const > PRUDMEM, PAGE 1 31 | .data > PRUDMEM, PAGE 1 32 | .switch > PRUDMEM, PAGE 1 33 | .sysmem > PRUDMEM, PAGE 1 34 | .cinit > PRUDMEM, PAGE 1 35 | } 36 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/README.md: -------------------------------------------------------------------------------- 1 | Make sure you have loaded the necessary DT [overlays](https://github.com/yifanz/ucla-nesl-pru-lib/tree/master/overlay). 2 | Run `./config-pins`. 3 | Then connect P9\_27 to P8\_10 on the beaglebone (see image below). 4 | 5 | ![alt text](https://github.com/yifanz/ucla-nesl-pru-lib/blob/master/examples/time_sync/time_sync_setup.jpg) 6 | 7 | Here is roughly what happens during synchronization: 8 | 9 | 1. The PRU will send a pulse on P9\_27 and record the its own time (T1). 10 | 2. This will trigger the input capture configured on P8\_10 to record the time the pulse was received (T2). 11 | 3. The user-space program reads T2 from "/dev/ptp\*" and sends it to the PRU. 12 | 4. The PRU calculates its offset simply by subtracting T2 minus T1. 13 | 14 | Here is some example output. The PRU will send its timestamp to the host every second. Synchronization occurs every 5 seconds. 15 | 16 | ``` 17 | root@beaglebone:~/ucla-nesl-pru-lib/examples/time_sync# ./build.sh 18 | Compiling and linking the PRU firmware 19 | 20 | ~/ucla-nesl-pru-lib/examples/time_sync ~/ucla-nesl-pru-lib/examples/time_sync 21 | Generating text and data segments (text.bin and data.bin) 22 | Translating to Binary format... 23 | "pru.out" .text:_c_int00* ==> .text:_c_int00* 24 | "pru.out" .text ==> .text 25 | "pru.out" .data ==> .data 26 | ~/ucla-nesl-pru-lib/examples/time_sync 27 | Compiling and linking the host application 28 | Build SUCCESSFUL. 29 | To run you must change to the gen directory: 30 | cd gen/ 31 | ./host 32 | root@beaglebone:~/ucla-nesl-pru-lib/examples/time_sync# cd gen 33 | root@beaglebone:~/ucla-nesl-pru-lib/examples/time_sync/gen# ./host 34 | Device opened 5 35 | Set pin func successful for 5 36 | Requesting timestamps success for 5 37 | PRU: 1531 ns 38 | PRU: 1000015906 ns 39 | PRU: 2000031611 ns 40 | PRU: 3000047276 ns 41 | QoT event time: 1487137387350957509 ns 42 | PRU: 1487137387352118384 ns 43 | PRU: 1487137388352133609 ns 44 | PRU: 1487137389352149304 ns 45 | PRU: 1487137390352164959 ns 46 | PRU: 1487137391352180654 ns 47 | QoT event time: 1487137392352196385 ns 48 | PRU: 1487137392352442105 ns 49 | PRU: 1487137393352457280 ns 50 | PRU: 1487137394352473005 ns 51 | PRU: 1487137395352488670 ns 52 | PRU: 1487137396352504375 ns 53 | QoT event time: 1487137397352519969 ns 54 | PRU: 1487137397352756659 ns 55 | PRU: 1487137398352771729 ns 56 | PRU: 1487137399352787369 ns 57 | PRU: 1487137400352802989 ns 58 | PRU: 1487137401352818609 ns 59 | QoT event time: 1487137402352834220 ns 60 | PRU: 1487137402353068290 ns 61 | PRU: 1487137403353083400 ns 62 | PRU: 1487137404353099060 ns 63 | PRU: 1487137405353114665 ns 64 | PRU: 1487137406353130250 ns 65 | QoT event time: 1487137407353145845 ns 66 | PRU: 1487137407353385765 ns 67 | PRU: 1487137408353400685 ns 68 | PRU: 1487137409353416155 ns 69 | PRU: 1487137410353431625 ns 70 | PRU: 1487137411353447095 ns 71 | QoT event time: 1487137412353462554 ns 72 | PRU: 1487137412353715799 ns 73 | ``` 74 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/bin.cmd: -------------------------------------------------------------------------------- 1 | -b 2 | -image 3 | 4 | ROMS { 5 | PAGE 0: 6 | text: o = 0x0, l = 0x1000, files={text.bin} 7 | PAGE 1: 8 | data: o = 0x0, l = 0x1000, files={data.bin} 9 | } -------------------------------------------------------------------------------- /C lib/examples/time_sync/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | #Copyright (c) Regents of the University of California, 2017. All rights reserved. 5 | #See LICENSE and ATTRIB in the repository root. 6 | # 7 | # 8 | # 9 | #Based on code from Derek Molloy for the book "Exploring BeagleBone: 10 | #Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 11 | #2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 12 | #directory for copyright and GNU GPLv3 license information. 13 | # 14 | 15 | PRU_NUM=1; # which PRU 0 or 1 16 | #PRU_SDK=/root/pru_2.0.0B2 17 | PRU_SRC="pru_main.c" 18 | HOST_SRC="host_main.c host_qot.c" 19 | PRU_TARGET=pru.out 20 | HOST_TARGET=host 21 | GEN=gen 22 | SCRIPT_DIR=${0%/*} 23 | 24 | cd $SCRIPT_DIR 25 | mkdir -p $GEN 26 | 27 | echo "Compiling and linking the PRU firmware" 28 | clpru --silicon_version=3 --keep_asm --c_src_interlist \ 29 | --asm_directory=$GEN --obj_directory=$GEN --temp_directory=$GEN \ 30 | -DPRU_NUM=$PRU_NUM \ 31 | $PRU_SRC \ 32 | -i../../include \ 33 | -z AM3359_PRU.cmd \ 34 | -o $GEN/$PRU_TARGET \ 35 | -m $GEN/$PRU_TARGET.map 36 | #-i$PRU_SDK/include 37 | #-i$PRU_SDK/lib 38 | 39 | if [ $? -ne 0 ]; then 40 | echo "Compile and link FAILED" 41 | exit 1 42 | fi 43 | 44 | pushd . 45 | cd $GEN 46 | 47 | # The output of the compiler/linker is an ELF executable. 48 | # We cannot directly load the ELF file into the PRU because unlike Linux, 49 | # the PRU does not have a ELF loader. 50 | # In theory, we could parse the ELF file in our host application, 51 | # but that is too much work. 52 | # Instead, we break out the text and data segments and so that we can 53 | # manually map them into PRU memory. 54 | echo "Generating text and data segments (text.bin and data.bin)" 55 | hexpru ../bin.cmd $PRU_TARGET 56 | 57 | if [ $? -ne 0 ]; then 58 | echo "Generating text and data segments FAILED" 59 | exit 1 60 | fi 61 | 62 | popd 63 | 64 | echo "Compiling and linking the host application" 65 | gcc -I../../include -DPRU_NUM=$PRU_NUM $HOST_SRC -o $GEN/$HOST_TARGET -lpthread -lprussdrv 66 | 67 | if [ $? -ne 0 ]; then 68 | echo "Compiling and linking the host application FAILED" 69 | exit 1 70 | fi 71 | 72 | echo "Build SUCCESSFUL." 73 | echo "To run you must change to the gen directory:" 74 | echo "cd gen/" 75 | echo "./host" 76 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/config-pins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Configuring pins" 4 | #config-pin P9_27 pruout 5 | #config-pin -q P9_27 6 | 7 | config-pin P8_46 pruout 8 | config-pin -q P8_46 9 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/host_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | 11 | /* 12 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 13 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, 14 | * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root 15 | * directory for copyright and GNU GPLv3 license information. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "shared_conf.h" 37 | #include "nesl_pru_rbuffer.h" 38 | #include "host_qot.h" 39 | 40 | volatile int stop = 0; 41 | volatile uint8_t *shared_mem; 42 | 43 | struct rbuffer *send_to_pru_rbuffer; 44 | struct rbuffer *receive_from_pru_rbuffer; 45 | 46 | // Handles interrupts from the PRU 47 | void *receive_pru_thread(void *value) 48 | { 49 | while(!stop) { 50 | short status = 0; 51 | int64_t data; 52 | 53 | // This call will block until PRU interrupts the host 54 | prussdrv_pru_wait_event(PRU_EVTOUT_0); 55 | prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT); 56 | 57 | while(!status) { 58 | data = rbuf_read_uint64(receive_from_pru_rbuffer, &status); 59 | if (!status) { 60 | printf("PRU: %lld ns\n", data); 61 | } 62 | } 63 | } 64 | } 65 | 66 | // Handles sending QoT timestamp to the PRU 67 | void *send_pru_thread(void *value) 68 | { 69 | int err = 0; 70 | uint64_t nano_ts; 71 | 72 | while (!stop) { 73 | // This call will block until a QoT input capture event is triggered 74 | nano_ts = qot_read_event_ts(&err); 75 | rbuf_write_uint64(send_to_pru_rbuffer, nano_ts); 76 | } 77 | } 78 | 79 | int main (void) 80 | { 81 | int err; 82 | 83 | if(getuid()!=0){ 84 | printf("You must run this program as root. Exiting.\n"); 85 | exit(EXIT_FAILURE); 86 | } 87 | 88 | pthread_t thread; 89 | pthread_t thread2; 90 | 91 | /* Initialize structure used by prussdrv_pruintc_intc */ 92 | /* PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h */ 93 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 94 | 95 | /* Initialize PRUSS (PRU Sub-System Driver) */ 96 | prussdrv_init(); 97 | 98 | // PRU_EVTOUT_0 - interrupt generated by PRU to indicate that it has 99 | // sent messages to the host. Pending messages are in the 100 | // receive_from_pru_rbuffer. 101 | err = prussdrv_open (PRU_EVTOUT_0); 102 | if(err){ 103 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 104 | exit(EXIT_FAILURE); 105 | } 106 | 107 | // PRU_EVTOUT_1 - interrupt generated by PRU to indicate that is is 108 | // going to halt. 109 | err = prussdrv_open (PRU_EVTOUT_1); 110 | if(err){ 111 | printf("Failed to open the PRU-ICSS, have you loaded the overlay?"); 112 | exit(EXIT_FAILURE); 113 | } 114 | 115 | /* Map PRU's INTC */ 116 | prussdrv_pruintc_init(&pruss_intc_initdata); 117 | 118 | // Map PRU's shared memory into user-space 119 | if (prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, (void **) &shared_mem)) { 120 | printf("map shared memory failed\n"); 121 | exit(EXIT_FAILURE); 122 | } 123 | 124 | // Clear 12Kb of shared memory 125 | memset((void*) shared_mem, 0, 0x3000); 126 | 127 | // Setup buffers for communication between host and PRU 128 | 129 | // Only the sender initializes the rbuffer. 130 | // PRU will initialize this buffer. Host should NOT initalize this. 131 | receive_from_pru_rbuffer = (struct rbuffer *) (shared_mem + RBUF_ADDR); 132 | 133 | send_to_pru_rbuffer = (struct rbuffer *) (shared_mem + RBUF_ADDR + sizeof(struct rbuffer)); 134 | init_rbuffer(send_to_pru_rbuffer); 135 | 136 | // Setup QoT 137 | if (init_qot("/dev/ptp1", 0)) { 138 | printf("Initialize QoT time sync failed\n"); 139 | exit(EXIT_FAILURE); 140 | } 141 | 142 | /* Load the memory data file */ 143 | prussdrv_load_datafile(PRU_NUM, "./data.bin"); 144 | 145 | /* Load and execute binary on PRU */ 146 | prussdrv_exec_program (PRU_NUM, "./text.bin"); 147 | 148 | /* Thread for handling message from the PRU */ 149 | if (pthread_create(&thread, NULL, &receive_pru_thread, NULL)){ 150 | printf("Failed to create thread!\n"); 151 | exit(EXIT_FAILURE); 152 | } 153 | 154 | /* Thread for sending messages to the PRU */ 155 | if (pthread_create(&thread2, NULL, &send_pru_thread, NULL)){ 156 | printf("Failed to create thread!\n"); 157 | exit(EXIT_FAILURE); 158 | } 159 | 160 | /* Wait for event completion from PRU */ 161 | // This call will block until PRU interrupts the host. 162 | prussdrv_pru_wait_event(PRU_EVTOUT_1); 163 | stop = 1; 164 | 165 | // Teardown QoT 166 | if (deinit_qot()) { 167 | printf("Deinitialize QoT time sync failed\n"); 168 | } 169 | 170 | /* Disable PRU and close memory mappings */ 171 | prussdrv_pru_disable(PRU_NUM); 172 | prussdrv_exit (); 173 | return(EXIT_SUCCESS); 174 | } 175 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/host_qot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "host_qot.h" 28 | 29 | #define PTP_PIN_SETFUNC _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc) 30 | 31 | //struct ptp_pin_desc { 32 | // /* 33 | // * Hardware specific human readable pin name. This field is 34 | // * set by the kernel during the PTP_PIN_GETFUNC ioctl and is 35 | // * ignored for the PTP_PIN_SETFUNC ioctl. 36 | // */ 37 | // char name[64]; 38 | // /* 39 | // * Pin index in the range of zero to ptp_clock_caps.n_pins - 1. 40 | // */ 41 | // unsigned int index; 42 | // /* 43 | // * Which of the PTP_PF_xxx functions to use on this pin. 44 | // */ 45 | // unsigned int func; 46 | // /* 47 | // * The specific channel to use for this function. 48 | // * This corresponds to the 'index' field of the 49 | // * PTP_EXTTS_REQUEST and PTP_PEROUT_REQUEST ioctls. 50 | // */ 51 | // unsigned int chan; 52 | // /* 53 | // * Reserved for future use. 54 | // */ 55 | // unsigned int rsv[5]; 56 | //}; 57 | 58 | char *device_m; /* PTP device */ 59 | int index_m; /* Channel index, '1' corresponds to 'TIMER6' */ 60 | int fd_m; /* device file descriptor */ 61 | struct ptp_pin_desc desc; /* Pin configuration */ 62 | struct ptp_extts_event event; /* PTP event */ 63 | 64 | /** 65 | * Initialize the QoT system for capturing input event timestamps. 66 | * 67 | * Params: 68 | * dev - PTP device file 69 | * channel - Channel index, '1' corresponds to 'TIMER6' 70 | */ 71 | int 72 | init_qot(char* dev, int channel) 73 | { 74 | struct ptp_extts_request extts_request; /* External timestamp req */ 75 | 76 | device_m = dev; /* PTP device */ 77 | index_m = channel; /* Channel index */ 78 | 79 | /* Open the character device */ 80 | fd_m = open(device_m, O_RDWR); 81 | if (fd_m < 0) { 82 | fprintf(stderr, "opening device %s: %s\n", 83 | device_m, strerror(errno)); 84 | return -1; 85 | } 86 | printf("Device opened %d\n", fd_m); 87 | 88 | memset(&desc, 0, sizeof(desc)); 89 | desc.index = index_m; 90 | desc.func = 1; // '1' corresponds to external timestamp 91 | desc.chan = index_m; 92 | if (ioctl(fd_m, PTP_PIN_SETFUNC, &desc)) { 93 | printf("Set pin func failed for %d\n", fd_m); 94 | return -1; 95 | } 96 | printf("Set pin func successful for %d\n", fd_m); 97 | 98 | // Setup to request timestamps from the pin 99 | memset(&extts_request, 0, sizeof(extts_request)); 100 | extts_request.index = index_m; 101 | extts_request.flags = PTP_ENABLE_FEATURE; 102 | if (ioctl(fd_m, PTP_EXTTS_REQUEST, &extts_request)) { 103 | printf("Requesting timestamps failed for %d\n", fd_m); 104 | return -1; 105 | } 106 | printf("Requesting timestamps success for %d\n", fd_m); 107 | 108 | return 0; 109 | } 110 | 111 | int 112 | deinit_qot() 113 | { 114 | int ret = 0; 115 | 116 | /* Disable the pin */ 117 | memset(&desc, 0, sizeof(desc)); 118 | desc.index = index_m; 119 | desc.func = 0; // '0' corresponds to no function 120 | desc.chan = index_m; 121 | if (ioctl(fd_m, PTP_PIN_SETFUNC, &desc)) { 122 | printf("Disable pin func failed for %d\n", fd_m); 123 | ret = -1; 124 | } 125 | 126 | /* Close the character device */ 127 | close(fd_m); 128 | 129 | return ret; 130 | } 131 | 132 | /** 133 | * Reads QoT timestamp of event. 134 | * This call will block until an event is triggered! 135 | * 136 | * Params: 137 | * err - pointer to error, -1 on error 138 | * Return: 139 | * Time of event in nanoseconds 140 | */ 141 | uint64_t 142 | qot_read_event_ts(int* err) 143 | { 144 | /* Read events coming in */ 145 | 146 | // Debugging 147 | //printf("Trying to read events %d\n", running++); 148 | 149 | // This call to read is blocking 150 | int cnt = read(fd_m, &event, sizeof(event)); 151 | if (cnt != sizeof(event)) { 152 | printf("Cannot read QoT event"); 153 | if (err != NULL) *err = -1; 154 | return 0; 155 | } 156 | uint64_t nano_ts = event.t.sec * 1000000000; 157 | nano_ts += event.t.nsec; 158 | 159 | // Debugging 160 | // printf("Sync Time - %lld.%09u - %llu ns\n", 161 | // event.t.sec, event.t.nsec, nano_ts); 162 | 163 | printf("QoT event time: %llu ns\n", nano_ts); 164 | 165 | return nano_ts; 166 | } 167 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/host_qot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on helloworld_capture.c, a simple C example showing how to register 8 | * to listen for capture events by Fatima Anwar and Andrew Symington. 9 | */ 10 | 11 | #ifndef HOST_QOT_H 12 | #define HOST_QOT_H 13 | 14 | #include 15 | 16 | int init_qot(char* dev, int channel); 17 | int deinit_qot(); 18 | uint64_t qot_read_event_ts(int* err); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/pru_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from Derek Molloy for the book "Exploring BeagleBone: 8 | * Tools and Techniques for Building with Embedded Linux" by John Wiley & Sons, * 2014 ISBN 9781118935125. Please see the file ATTRIB in the repository root * directory for copyright and GNU GPLv3 license information. 9 | */ 10 | 11 | #include "nesl_pru_intc.h" 12 | #include "nesl_pru_iep.h" 13 | #include "nesl_pru_wait.h" 14 | #include "nesl_pru_rbuffer.h" 15 | #include "nesl_pru_time.h" 16 | #include "nesl_pru_ticks.h" 17 | #include "nesl_pru_gpio.h" 18 | #include 19 | #include 20 | 21 | #include "shared_conf.h" 22 | 23 | #define SHARED_MEM_BASE 0x10000 24 | 25 | void 26 | terminate() 27 | { 28 | TRIG_INTC(4); // Trigger interrupt PRUEVENT_1 29 | __halt(); // halt the PRU 30 | } 31 | 32 | cycle_t 33 | read_cc(const struct cyclecounter *cc) 34 | { 35 | return IEP_CNT; 36 | } 37 | 38 | /* 39 | * Custom function that lets you slew the IEP counter. 40 | * This is just for demo purposes. You should define your own algorithm. 41 | */ 42 | int 43 | slew_cc(s64 delta) 44 | { 45 | uint8_t comp_cycles = 0; 46 | uint8_t comp_inc = 0; 47 | uint64_t abs_delta = llabs(delta); 48 | 49 | if (abs_delta < 100) { 50 | if (delta < 0) { 51 | // PRU clock was too fast 52 | comp_cycles = abs_delta / 5; 53 | comp_inc = 0; 54 | } else { 55 | // PRU clock was too slow 56 | comp_cycles = 1; 57 | comp_inc = abs_delta / 5; 58 | } 59 | 60 | SET_IEP_COMP_INC(comp_inc); 61 | IEP_COMPEN = comp_cycles; 62 | 63 | return 1; 64 | } else { 65 | return 0; 66 | } 67 | } 68 | 69 | /* 70 | * This program demonstrates time synchronization between the host and PRU. 71 | * 72 | * The PRU will send it's own time to the host every ~1 second and the host 73 | * will print that time out on the terminal. 74 | * Every ~5 seconds, we will do a time synchronization. 75 | * This will continue for ~30 seconds and then we terminate. 76 | */ 77 | int main() 78 | { 79 | // Wait enough time for host to startup 80 | WAIT_MS(1000); 81 | 82 | // Send PRU time back to host for printing 83 | struct rbuffer *send_buf = 84 | (struct rbuffer *) (uint32_t) (SHARED_MEM_BASE + RBUF_ADDR); 85 | init_rbuffer(send_buf); 86 | 87 | // Required for getting host timestamp 88 | struct rbuffer *rec_buf = 89 | (struct rbuffer *) (uint32_t) (SHARED_MEM_BASE + RBUF_ADDR 90 | + sizeof(struct rbuffer)); 91 | 92 | // IEP is our clock source 93 | DISABLE_IEP_TMR(); 94 | ENABLE_IEP_TMR(); 95 | IEP_CNT = 0; 96 | 97 | struct pru_time time; 98 | 99 | // Initialize pru_time with IEP as the source 100 | // slew_cc is optional 101 | //init_pru_time(&time, 5, 0, 32, read_cc, slew_cc); 102 | init_pru_time(&time, 5, 0, 32, read_cc, NULL); 103 | 104 | short status = -1; 105 | uint64_t data = 0; 106 | 107 | // Run for ~30 seconds total. 108 | int i = 30; 109 | while(i--) { 110 | // Do synchronization every ~5 seconds 111 | if (i % 5 == 0) { 112 | // Time synchronization started 113 | u64 ts_pru = read_pru_time(&time); 114 | 115 | #if PRU_NUM == 0 116 | // Send a pulse on P9_27 117 | assert_pin(P9_27); 118 | WAIT_US(10); 119 | deassert_pin(P9_27); 120 | #else 121 | // Send a pulse on P9_27 122 | assert_pin(P8_46); 123 | WAIT_US(10); 124 | deassert_pin(P8_46); 125 | #endif 126 | 127 | // Get the time when the host received the pulse 128 | uint64_t ts_host = 0; 129 | do { 130 | data = rbuf_read_uint64(rec_buf, &status); 131 | } while(status); 132 | ts_host = data; 133 | 134 | // Calculate the offset between host and pru 135 | s64 delta = adj_pru_time(&time, ts_pru, ts_host); 136 | 137 | // Debugging. If you want to print the ts_pru and delta. 138 | //rbuf_write_uint64(send_buf, ts_pru); 139 | //rbuf_write_uint64(send_buf, delta); 140 | } 141 | 142 | // Send current pru time back to host for printing 143 | rbuf_write_uint64(send_buf, read_pru_time(&time)); 144 | // Interrupt the host: there is a message in the rbuffer 145 | TRIG_INTC(3); // Trigger interrupt PRUEVENT_0 146 | 147 | // Pause for a second. Don't want to flood the host with messages. 148 | WAIT_MS(1000); 149 | } 150 | 151 | DISABLE_IEP_TMR(); 152 | 153 | // Exiting the application 154 | terminate(); 155 | } 156 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/shared_conf.h: -------------------------------------------------------------------------------- 1 | #ifndef SHARED_CONF_H 2 | #define SHARED_CONF_H 3 | 4 | #define RBUF_ADDR 0 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /C lib/examples/time_sync/time_sync_setup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesl/Cyclops-PRU/6e4ab486669d4aa06404f24d9bed9f0376b6f786/C lib/examples/time_sync/time_sync_setup.jpg -------------------------------------------------------------------------------- /C lib/include/nesl_pru_gpio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | #ifndef NESL_PRU_GPIO_H 6 | #define NESL_PRU_GPIO_H 7 | 8 | #include "nesl_pru_regs.h" 9 | 10 | enum pru_pin 11 | { 12 | #if PRU_NUM == 0 13 | // PRU0 14 | P8_11 = 1 << 15, // output only 15 | P8_12 = 1 << 14, // output only 16 | P8_15 = 1 << 15, // input only 17 | P8_16 = 1 << 14, // input only 18 | P9_24 = 1 << 16, // input only 19 | P9_25 = 1 << 7, 20 | P9_27 = 1 << 5, 21 | P9_28 = 1 << 3, 22 | P9_29 = 1 << 1, 23 | P9_30 = 1 << 2, 24 | P9_31 = 1 << 0, 25 | P9_41A = 1 << 16, // input only 26 | P9_41B = 1 << 6, 27 | P9_42B = 1 << 4, 28 | #else 29 | // PRU1 30 | P8_20 = 1 << 13, 31 | P8_21 = 1 << 12, 32 | P8_27 = 1 << 8, 33 | P8_28 = 1 << 10, 34 | P8_29 = 1 << 9, 35 | P8_39 = 1 << 6, 36 | P8_40 = 1 << 7, 37 | P8_41 = 1 << 4, 38 | P8_42 = 1 << 5, 39 | P8_43 = 1 << 2, 40 | P8_44 = 1 << 3, 41 | P8_45 = 1 << 0, 42 | P8_46 = 1 << 1, 43 | P9_26 = 1 << 16, // input only 44 | #endif 45 | }; 46 | 47 | inline unsigned int read_pin(enum pru_pin pin) 48 | { 49 | return __R31 & pin; 50 | } 51 | 52 | inline void toggle_pin(enum pru_pin pin) 53 | { 54 | __R30 ^= pin; 55 | } 56 | 57 | inline void assert_pin(enum pru_pin pin) 58 | { 59 | __R30 |= pin; 60 | } 61 | 62 | inline void deassert_pin(enum pru_pin pin) 63 | { 64 | __R30 &= ~pin; 65 | } 66 | #endif 67 | -------------------------------------------------------------------------------- /C lib/include/nesl_pru_iep.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | #ifndef NESL_PRU_IEP_H 6 | #define NESL_PRU_IEP_H 7 | 8 | #include 9 | 10 | static uint32_t *IEP_REG = (uint32_t*) 0x2E000; 11 | static uint32_t *IEP_TMR_CNT = (uint32_t*) 0x2E00C; 12 | static uint32_t *IEP_TMR_COMPEN = (uint32_t*) 0x2E008; 13 | 14 | #define ENABLE_IEP_TMR() (*IEP_REG |= 0x011) 15 | #define DISABLE_IEP_TMR() (*IEP_REG &= 0) 16 | #define IEP_CNT (*IEP_TMR_CNT) 17 | #define IEP_COMPEN (*IEP_TMR_COMPEN) 18 | #define SET_IEP_COMP_INC(val) (*IEP_REG |= (val << 8)) 19 | #define IEP_CNT_TO_NS(count) ((count) * 5); 20 | 21 | struct iep_time { 22 | uint64_t ts_ns; 23 | uint32_t last_iep_cnt; 24 | int64_t offset; 25 | }; 26 | 27 | inline void init_iep_time(struct iep_time *time) 28 | { 29 | DISABLE_IEP_TMR(); 30 | ENABLE_IEP_TMR(); 31 | IEP_CNT = 0; 32 | 33 | time->last_iep_cnt = 0; 34 | time->ts_ns = 0; 35 | time->offset = 0; 36 | } 37 | 38 | inline uint64_t iep_get_time(struct iep_time *time) 39 | { 40 | uint32_t iep_cnt = IEP_CNT; 41 | uint32_t last_iep_cnt = time->last_iep_cnt; 42 | uint64_t ts_ns = time->ts_ns; 43 | 44 | if (iep_cnt < last_iep_cnt) { 45 | // roll over happened 46 | ts_ns += 47 | IEP_CNT_TO_NS((UINT32_MAX - last_iep_cnt) 48 | + iep_cnt); 49 | } else { 50 | ts_ns += IEP_CNT_TO_NS(iep_cnt - last_iep_cnt); 51 | } 52 | 53 | time->last_iep_cnt = iep_cnt; 54 | time->ts_ns = ts_ns; 55 | 56 | return ts_ns + time->offset; 57 | } 58 | 59 | inline void iep_adj_time(struct iep_time *time, 60 | uint64_t ts_ns, uint64_t external_ts_ns) 61 | { 62 | time->offset += external_ts_ns - ts_ns; 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /C lib/include/nesl_pru_intc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | #ifndef NESL_PRU_INTC_H 6 | #define NESL_PRU_INTC_H 7 | 8 | #include 9 | #include "nesl_pru_regs.h" 10 | 11 | #define TRIG_INTC(int_num) (__R31 = (1<<5) | int_num) 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /C lib/include/nesl_pru_rbuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | #ifndef NESL_PRU_RBUFFER_H 6 | #define NESL_PRU_RBUFFER_H 7 | 8 | #include 9 | #include 10 | 11 | #define RBUF_SIZE 256 12 | #define RBUF_IDX(i) ((i) % RBUF_SIZE) 13 | 14 | /* 15 | * Generic ring buffer implementation 16 | * Create two if you want bi-directional communication 17 | */ 18 | struct rbuffer 19 | { 20 | uint16_t c; 21 | uint16_t p; 22 | uint32_t buffer[RBUF_SIZE]; 23 | }; 24 | 25 | void 26 | init_rbuffer(struct rbuffer *rbuf) 27 | { 28 | memset(rbuf, 0, sizeof(struct rbuffer)); 29 | rbuf->c = 0; 30 | rbuf->p = 1; 31 | } 32 | 33 | short 34 | rbuf_write_uint32(struct rbuffer *rbuf, uint32_t data) 35 | { 36 | uint16_t p = rbuf->p; 37 | if (p != rbuf->c) { 38 | rbuf->buffer[p] = data; 39 | rbuf->p = RBUF_IDX(p+1); 40 | return 0; 41 | } 42 | // else buffer is full 43 | return -1; 44 | } 45 | 46 | short 47 | rbuf_write_uint64(struct rbuffer *rbuf, uint64_t data) 48 | { 49 | uint32_t lower = (uint32_t) data; 50 | uint32_t upper = data >> 32; 51 | uint16_t p = rbuf->p; 52 | if (p != rbuf->c && RBUF_IDX(p+1) != rbuf->c) { 53 | rbuf->buffer[p] = lower; 54 | rbuf->buffer[RBUF_IDX(p+1)] = upper; 55 | rbuf->p = RBUF_IDX(p+2); 56 | return 0; 57 | } 58 | // else buffer is full 59 | return -1; 60 | } 61 | 62 | uint32_t 63 | rbuf_read_uint32(struct rbuffer *rbuf, short *status) 64 | { 65 | uint16_t c = RBUF_IDX(rbuf->c+1); 66 | if (c != rbuf->p) { 67 | uint32_t data = rbuf->buffer[c]; 68 | rbuf->c = c; 69 | if (status != NULL) *status = 0; 70 | return data; 71 | } 72 | // no new data 73 | if (status != NULL) *status = -1; 74 | return 0; 75 | } 76 | 77 | uint64_t 78 | rbuf_read_uint64(struct rbuffer *rbuf, short *status) 79 | { 80 | uint64_t data = 0; 81 | uint16_t c = RBUF_IDX(rbuf->c+1); 82 | if (c != rbuf->p && RBUF_IDX(c+1) != rbuf->p) { 83 | uint32_t lower = rbuf->buffer[c]; 84 | uint32_t upper = rbuf->buffer[RBUF_IDX(c+1)]; 85 | data = upper; 86 | data = data << 32; 87 | data |= lower; 88 | rbuf->c = RBUF_IDX(c+1); 89 | if (status != NULL) *status = 0; 90 | return data; 91 | } 92 | // no new data 93 | if (status != NULL) *status = -1; 94 | return 0; 95 | } 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /C lib/include/nesl_pru_regs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on code from the Beaglebone PRU IO project. 8 | * https://github.com/outer-space-sounds/beaglebone-pruio 9 | * Please see the file ATTRIB in the repository root 10 | * directory for copyright and GNU GPLv3 license information. 11 | */ 12 | 13 | #ifndef NESL_PRU_REGS_H 14 | #define NESL_PRU_REGS_H 15 | 16 | #include 17 | 18 | volatile register unsigned int __R31, __R30; 19 | 20 | #if PRU_NUM == 0 21 | static uint32_t *CTRL_REG = (uint32_t*) 0x22000; 22 | #else 23 | static uint32_t *CTRL_REG = (uint32_t*) 0x24000; 24 | #endif 25 | 26 | #define HWREG(addr) (*((volatile uint32_t *)(addr))) 27 | 28 | // PRU Module Registers 29 | #define PRU_ICSS_CFG 0x26000 30 | #define PRU_ICSS_CFG_SYSCFG 0x04 31 | 32 | // Enable OCP so we can access the whole memory map for the 33 | // device from the PRU. Clear bit 4 of SYSCFG register 34 | void init_ocp() 35 | { 36 | HWREG(PRU_ICSS_CFG + PRU_ICSS_CFG_SYSCFG) &= ~(1 << 4); 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /C lib/include/nesl_pru_ticks.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | #ifndef NESL_PRU_TICKS_H 6 | #define NESL_PRU_TICKS_H 7 | 8 | #include 9 | #include "nesl_pru_regs.h" 10 | 11 | #if PRU_NUM == 0 12 | static uint32_t *CYCLE_CNT_REG = (uint32_t*) 0x2200C; 13 | #else 14 | static uint32_t *CYCLE_CNT_REG = (uint32_t*) 0x2400C; 15 | #endif 16 | 17 | #define ENABLE_TICKS() *CTRL_REG |= 1 << 3; *CYCLE_CNT_REG = 0 18 | #define TICKS (*CYCLE_CNT_REG) 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /C lib/include/nesl_pru_time.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on timecounter and clocksource from the Linux kernel v4.1 8 | * See ATTRIB for GPLv2 licensing information. 9 | */ 10 | 11 | #ifndef NESL_PRU_TIME_H 12 | #define NESL_PRU_TIME_H 13 | 14 | #include 15 | 16 | #define CLOCKSOURCE_MASK(bits) (cycle_t)((bits) < 64 ? ((1ULL<<(bits))-1) : (cycle_t) -1) 17 | 18 | typedef int64_t s64; 19 | typedef uint64_t u64; 20 | typedef uint32_t u32; 21 | typedef u64 cycle_t; 22 | 23 | struct cyclecounter 24 | { 25 | cycle_t (*read)(const struct cyclecounter *cc); 26 | cycle_t mask; 27 | u32 mult; 28 | u32 shift; 29 | }; 30 | 31 | struct timecounter 32 | { 33 | const struct cyclecounter *cc; 34 | cycle_t cycle_last; 35 | u64 nsec; 36 | u64 mask; 37 | u64 frac; 38 | }; 39 | 40 | struct pru_time 41 | { 42 | struct timecounter tc; 43 | struct cyclecounter cc; 44 | int (*slew_cc)(s64 delta); 45 | }; 46 | 47 | void 48 | timecounter_init(struct timecounter *tc, 49 | const struct cyclecounter *cc, 50 | u64 start_tstamp) 51 | { 52 | tc->cc = cc; 53 | tc->cycle_last = cc->read(cc); 54 | tc->nsec = start_tstamp; 55 | tc->mask = (1ULL << cc->shift) - 1; 56 | tc->frac = 0; 57 | } 58 | 59 | static inline void 60 | timecounter_adjtime(struct timecounter *tc, s64 delta) 61 | { 62 | tc->nsec += delta; 63 | } 64 | 65 | static inline u64 66 | cyclecounter_cyc2ns(const struct cyclecounter *cc, 67 | cycle_t cycles, u64 mask, u64 *frac) 68 | { 69 | u64 ns = (u64) cycles; 70 | 71 | ns = (ns * cc->mult) + *frac; 72 | *frac = ns & mask; 73 | return ns >> cc->shift; 74 | } 75 | 76 | static u64 77 | timecounter_read_delta(struct timecounter *tc) 78 | { 79 | cycle_t cycle_now, cycle_delta; 80 | u64 ns_offset; 81 | 82 | /* read cycle counter: */ 83 | cycle_now = tc->cc->read(tc->cc); 84 | 85 | /* calculate the delta since the last timecounter_read_delta(): */ 86 | cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask; 87 | 88 | /* convert to nanoseconds: */ 89 | ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta, 90 | tc->mask, &tc->frac); 91 | 92 | /* update time stamp of timecounter_read_delta() call: */ 93 | tc->cycle_last = cycle_now; 94 | 95 | return ns_offset; 96 | } 97 | 98 | u64 99 | timecounter_read(struct timecounter *tc) 100 | { 101 | u64 nsec; 102 | 103 | /* increment time by nanoseconds since last call */ 104 | nsec = timecounter_read_delta(tc); 105 | nsec += tc->nsec; 106 | tc->nsec = nsec; 107 | 108 | return nsec; 109 | } 110 | 111 | /** 112 | * Initialize pru_time with a clock source (e.g. IEP). 113 | * This tracks absolute time in nanoseconds. 114 | * 115 | * Params: 116 | * pru_time - pointer to uninitialized pru_time struct 117 | * mult, shift - for calculating nanoseconds per clock cycle 118 | * bits - bits in clock counter source 119 | * read_cc - function for reading the clock counter 120 | * slew_cc - Optional function for adjusting clock counter 121 | * Return 0 on success 122 | */ 123 | int 124 | init_pru_time(struct pru_time *pru_time, 125 | u32 mult, u32 shift, u32 bits, 126 | cycle_t (*read_cc)(const struct cyclecounter *cc), 127 | int (*slew_cc)(s64 delta) 128 | ) 129 | { 130 | memset(pru_time, 0, sizeof(struct pru_time)); 131 | 132 | pru_time->cc.read = read_cc; 133 | pru_time->cc.mask = CLOCKSOURCE_MASK(bits); 134 | pru_time->cc.mult = mult; 135 | pru_time->cc.shift = shift; 136 | 137 | pru_time->slew_cc = slew_cc; 138 | 139 | timecounter_init(&pru_time->tc, &pru_time->cc, IEP_CNT); 140 | 141 | return 0; 142 | } 143 | 144 | /** 145 | * Read the current pru_time and handle clock counter rollover. 146 | * You should call this periodically to maintain proper time. 147 | * 148 | * Return absolute time in nanoseconds 149 | */ 150 | u64 151 | read_pru_time(struct pru_time *pru_time) 152 | { 153 | return timecounter_read(&pru_time->tc); 154 | } 155 | 156 | /** 157 | * Adjust PRU time to align with host timestamp. 158 | * 159 | * Params: 160 | * ts_pru - nanosecond timestamp of pru 161 | * ts_host - nanosecond timestamp of host 162 | * Returns the signed offset in nanoseconds between pru and host 163 | */ 164 | s64 165 | adj_pru_time(struct pru_time *pru_time, u64 ts_pru, u64 ts_host) 166 | { 167 | s64 delta = 0; 168 | if (ts_host > ts_pru) { 169 | delta = ts_host - ts_pru; 170 | } else if (ts_host < ts_pru) { 171 | delta = ts_pru - ts_host; 172 | delta = -delta; 173 | } 174 | 175 | // slew_cc allows users to define a custom callback to slew the 176 | // source clock counter according to their own algorithm. 177 | // This can be useful in preventing time from going backward. 178 | // If slew_cc is not set or returns 0 then just jump the clock. 179 | if (pru_time->slew_cc == NULL 180 | || (pru_time->slew_cc != NULL && !pru_time->slew_cc(delta))) { 181 | timecounter_adjtime(&pru_time->tc, delta); 182 | } 183 | 184 | return delta; 185 | } 186 | 187 | #endif 188 | -------------------------------------------------------------------------------- /C lib/include/nesl_pru_wait.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | #ifndef NESL_PRU_WAIT_H 6 | #define NESL_PRU_WAIT_H 7 | 8 | #define WAIT_MS(ms) \ 9 | { \ 10 | if (ms == 1) { \ 11 | __delay_cycles(199999); \ 12 | } else if (ms > 0) { \ 13 | unsigned int _ms = ms-1; \ 14 | while(_ms--) { \ 15 | __delay_cycles(199993); \ 16 | } \ 17 | __delay_cycles(199993); \ 18 | } \ 19 | } 20 | 21 | #define WAIT_US(us) \ 22 | { \ 23 | if (us == 1) { \ 24 | __delay_cycles(199); \ 25 | } else if (us > 0) { \ 26 | unsigned int _us = us-1; \ 27 | while(_us--) { \ 28 | __delay_cycles(193); \ 29 | } \ 30 | __delay_cycles(193); \ 31 | } \ 32 | } 33 | #define WAIT_CYCLES(cycles) __delay_cycles(cycles); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /C lib/overlay/NESL-PRU-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesl/Cyclops-PRU/6e4ab486669d4aa06404f24d9bed9f0376b6f786/C lib/overlay/NESL-PRU-00A0.dtbo -------------------------------------------------------------------------------- /C lib/overlay/NESL-PRU-PINS-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesl/Cyclops-PRU/6e4ab486669d4aa06404f24d9bed9f0376b6f786/C lib/overlay/NESL-PRU-PINS-00A0.dtbo -------------------------------------------------------------------------------- /C lib/overlay/NESL-PRU-QOT-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesl/Cyclops-PRU/6e4ab486669d4aa06404f24d9bed9f0376b6f786/C lib/overlay/NESL-PRU-QOT-00A0.dtbo -------------------------------------------------------------------------------- /C lib/overlay/NESL-PRU-QOT.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | /* what boards are we compatible with */ 6 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 7 | 8 | /* identification */ 9 | part-number = "NESL-PRU-QOT"; 10 | 11 | /* special version ignores EEPROM */ 12 | version = "00A0"; 13 | 14 | /* Resources used */ 15 | exclusive-use = 16 | "P8.9", /* TIMER5 */ 17 | "P8.10", /* TIMER6 */ 18 | "P8.8"; /* TIMER7 */ 19 | 20 | /* Pin multiplexing */ 21 | fragment@0 { 22 | target = <&am33xx_pinmux>; 23 | __overlay__ { 24 | qot_am335x_pins: qot_am335x_pins { 25 | pinctrl-single,pins = < 26 | 0x9C 0x02 /* P8.9 0x22 = INP PD, 0x02 = OUT PD */ 27 | 0x98 0x22 /* P8.10 0x22 = INP PD, 0x02 = OUT PD */ 28 | 0x94 0x02 /* P8.8 0x22 = INP PD, 0x02 = OUT PD */ 29 | >; 30 | }; 31 | }; 32 | }; 33 | 34 | /* Setup the am335x timer subsystem as a PHC */ 35 | fragment@1 { 36 | target-path="/"; 37 | __overlay__ { 38 | qot_am335x { 39 | compatible = "qot_am335x"; 40 | status = "okay"; 41 | pinctrl-names = "default"; 42 | pinctrl-0 = <&qot_am335x_pins>; 43 | core = <&timer3 0>; /* 0 = SYS, 1 = RTC, 2 = TCLKIN */ 44 | sched = <&timer4 0>; 45 | pin3 { 46 | label = "TIMER7"; 47 | timer = <&timer7>; 48 | gpios = <&gpio2 3 0>; 49 | }; 50 | pin2 { 51 | label = "TIMER6"; 52 | timer = <&timer6>; 53 | gpios = <&gpio2 4 0>; 54 | }; 55 | pin1 { 56 | label = "TIMER5"; 57 | timer = <&timer5>; 58 | gpios = <&gpio2 5 0>; 59 | }; 60 | pin0 { 61 | label = "NOT_USED"; 62 | }; 63 | }; 64 | }; 65 | }; 66 | }; 67 | -------------------------------------------------------------------------------- /C lib/overlay/NESL-PRU.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on Device Tree Overlay for enabling the pins that are used in 8 | * Chapter 13 of the book "Exploring BeagleBone: Tools and 9 | * Techniques for Building with Embedded Linux" by Derek Molloy, 2014 10 | * ISBN 9781118935125. Please see the file ATTRIB in the repository root 11 | * directory for copyright and GNU GPLv3 license information. 12 | */ 13 | /dts-v1/; 14 | /plugin/; 15 | 16 | / { 17 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 18 | 19 | part-number = "NESL-PRU"; 20 | version = "00A0"; 21 | 22 | fragment@1 { // Enable the PRUSS 23 | target = <&pruss>; 24 | __overlay__ { 25 | status = "okay"; 26 | }; 27 | }; 28 | }; 29 | -------------------------------------------------------------------------------- /C lib/overlay/NESL-PRU0-PINS.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on the cape-universala overlay from Robert C. Nelson. 8 | * https://github.com/RobertCNelson/bb.org-overlays 9 | */ 10 | /dts-v1/; 11 | /plugin/; 12 | 13 | / { 14 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 15 | 16 | part-number = "NESL-PRU-PINS"; 17 | version = "00A0"; 18 | 19 | exclusive-use = 20 | "P9.27", "P9.28", "pru0", "pru1", "pruss"; 21 | 22 | fragment@0 { 23 | target = <&am33xx_pinmux>; 24 | __overlay__ { 25 | /* P9_27 (ZCZ ball C13) */ 26 | P9_27_default_pin: pinmux_P9_27_default_pin { 27 | pinctrl-single,pins = <0x1a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */ 28 | P9_27_gpio_pin: pinmux_P9_27_gpio_pin { 29 | pinctrl-single,pins = <0x1a4 0x2F>; }; /* Mode 7, RxActive */ 30 | P9_27_gpio_pu_pin: pinmux_P9_27_gpio_pu_pin { 31 | pinctrl-single,pins = <0x1a4 0x37>; }; /* Mode 7, Pull-Up, RxActive */ 32 | P9_27_gpio_pd_pin: pinmux_P9_27_gpio_pd_pin { 33 | pinctrl-single,pins = <0x1a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */ 34 | P9_27_qep_pin: pinmux_P9_27_qep_pin { 35 | pinctrl-single,pins = <0x1a4 0x21>; }; /* Mode 1, Pull-Down, RxActive */ 36 | P9_27_pruout_pin: pinmux_P9_27_pruout_pin { 37 | pinctrl-single,pins = <0x1a4 0x25>; }; /* Mode 5, Pull-Down, RxActive */ 38 | P9_27_pruin_pin: pinmux_P9_27_pruin_pin { 39 | pinctrl-single,pins = <0x1a4 0x26>; }; /* Mode 6, Pull-Down, RxActive */ 40 | 41 | /* P9_28 (ZCZ ball C12) Audio */ 42 | P9_28_default_pin: pinmux_P9_28_default_pin { 43 | pinctrl-single,pins = <0x19c 0x27>; }; /* Mode 7, Pull-Down, RxActive */ 44 | P9_28_gpio_pin: pinmux_P9_28_gpio_pin { 45 | pinctrl-single,pins = <0x19c 0x2F>; }; /* Mode 7, RxActive */ 46 | P9_28_gpio_pu_pin: pinmux_P9_28_gpio_pu_pin { 47 | pinctrl-single,pins = <0x19c 0x37>; }; /* Mode 7, Pull-Up, RxActive */ 48 | P9_28_gpio_pd_pin: pinmux_P9_28_gpio_pd_pin { 49 | pinctrl-single,pins = <0x19c 0x27>; }; /* Mode 7, Pull-Down, RxActive */ 50 | P9_28_pwm_pin: pinmux_P9_28_pwm_pin { 51 | pinctrl-single,pins = <0x19c 0x21>; }; /* Mode 1, Pull-Down, RxActive */ 52 | P9_28_spi_pin: pinmux_P9_28_spi_pin { 53 | pinctrl-single,pins = <0x19c 0x23>; }; /* Mode 3, Pull-Down, RxActive */ 54 | P9_28_pwm2_pin: pinmux_P9_28_pwm2_pin { 55 | pinctrl-single,pins = <0x19c 0x24>; }; /* Mode 4, Pull-Down, RxActive */ 56 | P9_28_pruout_pin: pinmux_P9_28_pruout_pin { 57 | pinctrl-single,pins = <0x19c 0x25>; }; /* Mode 5, Pull-Down, RxActive */ 58 | P9_28_pruin_pin: pinmux_P9_28_pruin_pin { 59 | pinctrl-single,pins = <0x19c 0x26>; }; /* Mode 6, Pull-Down, RxActive */ 60 | }; 61 | }; 62 | 63 | fragment@1 { 64 | target = <&ocp>; 65 | __overlay__ { 66 | P9_27_pinmux { 67 | compatible = "bone-pinmux-helper"; 68 | status = "okay"; 69 | pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "qep", "pruout", "pruin"; 70 | pinctrl-0 = <&P9_27_default_pin>; 71 | pinctrl-1 = <&P9_27_gpio_pin>; 72 | pinctrl-2 = <&P9_27_gpio_pu_pin>; 73 | pinctrl-3 = <&P9_27_gpio_pd_pin>; 74 | pinctrl-4 = <&P9_27_qep_pin>; 75 | pinctrl-5 = <&P9_27_pruout_pin>; 76 | pinctrl-6 = <&P9_27_pruin_pin>; 77 | }; 78 | 79 | P9_28_pinmux { 80 | compatible = "bone-pinmux-helper"; 81 | status = "okay"; 82 | pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pwm2", "pruout", "pruin"; 83 | pinctrl-0 = <&P9_28_default_pin>; 84 | pinctrl-1 = <&P9_28_gpio_pin>; 85 | pinctrl-2 = <&P9_28_gpio_pu_pin>; 86 | pinctrl-3 = <&P9_28_gpio_pd_pin>; 87 | pinctrl-4 = <&P9_28_pwm_pin>; 88 | pinctrl-5 = <&P9_28_spi_pin>; 89 | pinctrl-6 = <&P9_28_pwm2_pin>; 90 | pinctrl-7 = <&P9_28_pruout_pin>; 91 | pinctrl-8 = <&P9_28_pruin_pin>; 92 | }; 93 | }; 94 | }; 95 | }; 96 | -------------------------------------------------------------------------------- /C lib/overlay/NESL-PRU1-PINS-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesl/Cyclops-PRU/6e4ab486669d4aa06404f24d9bed9f0376b6f786/C lib/overlay/NESL-PRU1-PINS-00A0.dtbo -------------------------------------------------------------------------------- /C lib/overlay/NESL-PRU1-PINS.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Regents of the University of California, 2017. All rights reserved. 3 | * See LICENSE and ATTRIB in the repository root. 4 | */ 5 | 6 | /* 7 | * Based on the cape-universala overlay from Robert C. Nelson. 8 | * https://github.com/RobertCNelson/bb.org-overlays 9 | */ 10 | /dts-v1/; 11 | /plugin/; 12 | 13 | / { 14 | compatible = "ti,beaglebone", "ti,beaglebone-black"; 15 | 16 | part-number = "NESL-PRU-PINS"; 17 | version = "00A0"; 18 | 19 | exclusive-use = 20 | "P9.27", "P9.28", "pru0", "pru1", "pruss"; 21 | 22 | fragment@0 { 23 | target = <&am33xx_pinmux>; 24 | __overlay__ { 25 | /* P8_45 (ZCZ ball R1 ) hdmi */ 26 | P8_45_default_pin: pinmux_P8_45_default_pin { 27 | pinctrl-single,pins = <0x0A0 0x27>; }; /* Mode 7, Pull-Down, RxActive */ 28 | P8_45_gpio_pin: pinmux_P8_45_gpio_pin { 29 | pinctrl-single,pins = <0x0A0 0x2F>; }; /* Mode 7, RxActive */ 30 | P8_45_gpio_pu_pin: pinmux_P8_45_gpio_pu_pin { 31 | pinctrl-single,pins = <0x0A0 0x37>; }; /* Mode 7, Pull-Up, RxActive */ 32 | P8_45_gpio_pd_pin: pinmux_P8_45_gpio_pd_pin { 33 | pinctrl-single,pins = <0x0A0 0x27>; }; /* Mode 7, Pull-Down, RxActive */ 34 | P8_45_pruout_pin: pinmux_P8_45_pruout_pin { 35 | pinctrl-single,pins = <0x0A0 0x05>; }; /* Mode 5, Pull-Down*/ 36 | P8_45_pruin_pin: pinmux_P8_45_pruin_pin { 37 | pinctrl-single,pins = <0x0A0 0x26>; }; /* Mode 6, Pull-Down, RxActive */ 38 | P8_45_pwm_pin: pinmux_P8_45_pwm_pin { 39 | pinctrl-single,pins = <0x0A0 0x03>; }; /* Mode 3, Pull-Down*/ 40 | 41 | /* P8_46 (ZCZ ball R2 ) hdmi */ 42 | P8_46_default_pin: pinmux_P8_46_default_pin { 43 | pinctrl-single,pins = <0x0A4 0x27>; }; /* Mode 7, Pull-Down, RxActive */ 44 | P8_46_gpio_pin: pinmux_P8_46_gpio_pin { 45 | pinctrl-single,pins = <0x0A4 0x2F>; }; /* Mode 7, RxActive */ 46 | P8_46_gpio_pu_pin: pinmux_P8_46_gpio_pu_pin { 47 | pinctrl-single,pins = <0x0A4 0x37>; }; /* Mode 7, Pull-Up, RxActive */ 48 | P8_46_gpio_pd_pin: pinmux_P8_46_gpio_pd_pin { 49 | pinctrl-single,pins = <0x0A4 0x27>; }; /* Mode 7, Pull-Down, RxActive */ 50 | P8_46_pruout_pin: pinmux_P8_46_pruout_pin { 51 | pinctrl-single,pins = <0x0A4 0x05>; }; /* Mode 5, Pull-Down*/ 52 | P8_46_pruin_pin: pinmux_P8_46_pruin_pin { 53 | pinctrl-single,pins = <0x0A4 0x26>; }; /* Mode 6, Pull-Down, RxActive */ 54 | P8_46_pwm_pin: pinmux_P8_46_pwm_pin { 55 | pinctrl-single,pins = <0x0A4 0x03>; }; /* Mode 3, Pull-Down*/ 56 | }; 57 | }; 58 | 59 | fragment@1 { 60 | target = <&ocp>; 61 | __overlay__ { 62 | P8_45_pinmux { /* hdmi */ 63 | compatible = "bone-pinmux-helper"; 64 | status = "okay"; 65 | pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm"; 66 | pinctrl-0 = <&P8_45_default_pin>; 67 | pinctrl-1 = <&P8_45_gpio_pin>; 68 | pinctrl-2 = <&P8_45_gpio_pu_pin>; 69 | pinctrl-3 = <&P8_45_gpio_pd_pin>; 70 | pinctrl-4 = <&P8_45_pruout_pin>; 71 | pinctrl-5 = <&P8_45_pruin_pin>; 72 | pinctrl-6 = <&P8_45_pwm_pin>; 73 | }; 74 | 75 | P8_46_pinmux { /* hdmi */ 76 | compatible = "bone-pinmux-helper"; 77 | status = "okay"; 78 | pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm"; 79 | pinctrl-0 = <&P8_46_default_pin>; 80 | pinctrl-1 = <&P8_46_gpio_pin>; 81 | pinctrl-2 = <&P8_46_gpio_pu_pin>; 82 | pinctrl-3 = <&P8_46_gpio_pd_pin>; 83 | pinctrl-4 = <&P8_46_pruout_pin>; 84 | pinctrl-5 = <&P8_46_pruin_pin>; 85 | pinctrl-6 = <&P8_46_pwm_pin>; 86 | }; 87 | }; 88 | }; 89 | }; 90 | -------------------------------------------------------------------------------- /C lib/overlay/README.md: -------------------------------------------------------------------------------- 1 | Install Overlays: 2 | ----------------- 3 | 4 | ``` 5 | # Activates the PRUSS 6 | ./install.sh NESL-PRU 7 | 8 | # Assigns pins to the pinmux helper 9 | # Use config-pins to assign pins to the PRU (see examples/gpio) 10 | ./install.sh NESL-PRU-PINS 11 | 12 | # Only needed if you are using the QoT stack and want to do accurate time sync 13 | ./install.sh NESL-PRU-QOT 14 | 15 | # If you ran install.sh in the past, you can do this: 16 | ./load.sh NESL-PRU 17 | ./load.sh NESL-PRU-PINS 18 | ./load.sh NESL-PRU-QOT 19 | ``` 20 | 21 | From my experience, repeatedly loading and unloading overlays may cause system instability. Often, the configuration does not get applied when you reload an overlay. In that case, try rebooting. 22 | 23 | Also, avoid P8_33 P8_35 P9_27 P9_29 P9_30 P9_31 as these are used for control system applications. 24 | -------------------------------------------------------------------------------- /C lib/overlay/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NAME=${1:-NESL-PRU} 4 | DTBO=$NAME-00A0.dtbo 5 | DTS=$NAME.dts 6 | 7 | CAPE_MGR="/sys/devices/platform/bone_capemgr/slots" 8 | CAPE_MGR_OLD="/sys/devices/bone_capemgr.9/slots" 9 | 10 | if [ ! -e $CAPE_MGR ]; then 11 | CAPE_MGR=$CAPE_MGR_OLD 12 | fi 13 | 14 | cd ${0%/*} 15 | 16 | echo "Compiling the overlay from .dts to .dtbo" 17 | 18 | dtc -O dtb -o $DTBO -b 0 -@ $DTS 19 | 20 | if [ $? -eq 0 ]; then 21 | echo "Installing into /lib/firmware" 22 | cp $DTBO /lib/firmware 23 | fi 24 | 25 | if [ $? -eq 0 ]; then 26 | echo "Activating PRU overlay" 27 | echo $NAME > $CAPE_MGR 28 | sleep 1 29 | cat $CAPE_MGR 30 | fi 31 | -------------------------------------------------------------------------------- /C lib/overlay/list_overlays.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CAPE_MGR="/sys/devices/platform/bone_capemgr/slots" 4 | CAPE_MGR_OLD="/sys/devices/bone_capemgr.9/slots" 5 | 6 | if [ ! -e $CAPE_MGR ]; then 7 | CAPE_MGR=$CAPE_MGR_OLD 8 | fi 9 | 10 | cat $CAPE_MGR 11 | -------------------------------------------------------------------------------- /C lib/overlay/load.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CAPE_MGR="/sys/devices/platform/bone_capemgr/slots" 4 | CAPE_MGR_OLD="/sys/devices/bone_capemgr.9/slots" 5 | 6 | if [ ! -e $CAPE_MGR ]; then 7 | CAPE_MGR=$CAPE_MGR_OLD 8 | fi 9 | 10 | NAME=${1:-NESL-PRU} 11 | 12 | echo "$NAME" > $CAPE_MGR 13 | 14 | sleep 1 15 | 16 | cat $CAPE_MGR 17 | -------------------------------------------------------------------------------- /C lib/overlay/unload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CAPE_MGR="/sys/devices/platform/bone_capemgr/slots" 4 | CAPE_MGR_OLD="/sys/devices/bone_capemgr.9/slots" 5 | 6 | if [ ! -e $CAPE_MGR ]; then 7 | CAPE_MGR=$CAPE_MGR_OLD 8 | fi 9 | 10 | NAME=${1:-NESL-PRU} 11 | 12 | OVERLAYS=$(cat $CAPE_MGR | grep "$NAME") 13 | if [ ! -z "$OVERLAYS" ]; then 14 | echo "$OVERLAYS" 15 | read -p "Confirm, unload these overlays? [y/n]: " user_in 16 | if [ "$user_in" == "y" ]; then 17 | cat $CAPE_MGR | grep "$NAME" | cut -d':' -f1 | xargs -I{} sh -c "echo -{} > $CAPE_MGR" 18 | 19 | sleep 1 20 | 21 | cat $CAPE_MGR 22 | fi 23 | fi 24 | -------------------------------------------------------------------------------- /C lib/scripts/bbb-usb-net-gateway.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Run on BBB to set the default gateway. 5 | # You may also need to update your /etc/resolv.conf to point to a valid nameserver: 6 | # nameserver 8.8.8.8 7 | # 8 | 9 | BBB_HOST_IFACE="usb0" 10 | 11 | route add default gw $(arp -n | grep $BBB_HOST_IFACE | cut -d' ' -f1) 12 | -------------------------------------------------------------------------------- /C lib/scripts/host-usb-net-forwarding.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # If you are using ethernet over USB. 5 | # Then run this on the host to allow the BBB to access the internet. 6 | # 7 | 8 | # Network interface between host <--> internet 9 | HOST_NET_IFACE="ens33" 10 | #HOST_NET_IFACE="eth0" 11 | # Network interface between host <--> BBB 12 | HOST_BBB_IFACE="enx8030dc55737f" 13 | #HOST_BBB_IFACE="eth2" 14 | 15 | sudo iptables --table nat --append POSTROUTING --out-interface $HOST_NET_IFACE -j MASQUERADE 16 | sudo iptables --append FORWARD --in-interface $HOST_BBB_IFACE -j ACCEPT 17 | sudo sh -c 'echo 1 > /proc/sys/net/ipv4/ip_forward' 18 | -------------------------------------------------------------------------------- /C lib/scripts/update-time.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if ! which ntpdate; then 4 | sudo apt-get update 5 | sudo apt-get -y install ntpdate 6 | fi 7 | 8 | sudo ntpdate -b time.nist.gov 9 | -------------------------------------------------------------------------------- /Cyclops IDE/.gitignore: -------------------------------------------------------------------------------- 1 | ######### 2 | # C/C++ 3 | ######### 4 | 5 | # Compiled Object files 6 | *.slo 7 | *.lo 8 | *.o 9 | *.obj 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Compiled Dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | 20 | # Fortran module files 21 | *.mod 22 | *.smod 23 | 24 | # Compiled Static libraries 25 | *.lai 26 | *.la 27 | *.a 28 | *.lib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | 35 | ########## 36 | # Python 37 | ########## 38 | 39 | # Byte-compiled / optimized / DLL files 40 | __pycache__/ 41 | *.py[cod] 42 | *$py.class 43 | 44 | # C extensions 45 | *.so 46 | 47 | # Distribution / packaging 48 | .Python 49 | env/ 50 | build/ 51 | develop-eggs/ 52 | dist/ 53 | downloads/ 54 | eggs/ 55 | .eggs/ 56 | lib/ 57 | lib64/ 58 | parts/ 59 | sdist/ 60 | var/ 61 | *.egg-info/ 62 | .installed.cfg 63 | *.egg 64 | 65 | # PyInstaller 66 | # Usually these files are written by a python script from a template 67 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 68 | *.manifest 69 | *.spec 70 | 71 | # Installer logs 72 | pip-log.txt 73 | pip-delete-this-directory.txt 74 | 75 | # Unit test / coverage reports 76 | htmlcov/ 77 | .tox/ 78 | .coverage 79 | .coverage.* 80 | .cache 81 | nosetests.xml 82 | coverage.xml 83 | *,cover 84 | .hypothesis/ 85 | 86 | # Translations 87 | *.mo 88 | *.pot 89 | 90 | # Django stuff: 91 | *.log 92 | local_settings.py 93 | 94 | # Flask stuff: 95 | instance/ 96 | .webassets-cache 97 | 98 | # Scrapy stuff: 99 | .scrapy 100 | 101 | # Sphinx documentation 102 | docs/_build/ 103 | 104 | # PyBuilder 105 | target/ 106 | 107 | # IPython Notebook 108 | .ipynb_checkpoints 109 | 110 | # pyenv 111 | .python-version 112 | 113 | # celery beat schedule file 114 | celerybeat-schedule 115 | 116 | # dotenv 117 | .env 118 | 119 | # virtualenv 120 | .venv/ 121 | venv/ 122 | ENV/ 123 | 124 | # Spyder project settings 125 | .spyderproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | ######### 131 | # VIM 132 | ######### 133 | 134 | # swap 135 | [._]*.s[a-w][a-z] 136 | [._]s[a-w][a-z] 137 | # session 138 | Session.vim 139 | # temporary 140 | .netrwhist 141 | *~ 142 | # auto-generated tag files 143 | tags 144 | 145 | ######### 146 | # Project 147 | ######### 148 | 149 | _tmp/ 150 | 151 | ######### 152 | # Kernel Modules 153 | ######### 154 | # 155 | # NOTE! Don't add files that are generated in specific 156 | # subdirectories here. Add them in the ".gitignore" file 157 | # in that subdirectory instead. 158 | # 159 | # NOTE! Please use 'git ls-files -i --exclude-standard' 160 | # command after changing this file, to see if there are 161 | # any tracked files which get ignored after the change. 162 | # 163 | # Normal rules 164 | # 165 | .* 166 | *.o 167 | *.o.* 168 | *.a 169 | *.s 170 | *.ko 171 | *.so 172 | *.so.dbg 173 | *.mod.c 174 | *.i 175 | *.lst 176 | *.symtypes 177 | *.order 178 | modules.builtin 179 | *.elf 180 | *.bin 181 | *.gz 182 | *.bz2 183 | *.lzma 184 | *.xz 185 | *.lzo 186 | *.patch 187 | *.gcno 188 | 189 | # 190 | # Top-level generic files 191 | # 192 | /tags 193 | /TAGS 194 | /linux 195 | /vmlinux 196 | /vmlinuz 197 | /System.map 198 | /Module.markers 199 | Module.symvers 200 | 201 | # 202 | # Debian directory (make deb-pkg) 203 | # 204 | /debian/ 205 | 206 | # 207 | # git files that we don't want to ignore even it they are dot-files 208 | # 209 | !.gitignore 210 | !.mailmap 211 | 212 | # 213 | # Generated include files 214 | # 215 | include/config 216 | include/linux/version.h 217 | include/generated 218 | arch/*/include/generated 219 | 220 | # stgit generated dirs 221 | patches-* 222 | 223 | # quilt's files 224 | patches 225 | series 226 | 227 | # cscope files 228 | cscope.* 229 | ncscope.* 230 | 231 | # gnu global files 232 | GPATH 233 | GRTAGS 234 | GSYMS 235 | GTAGS 236 | 237 | *.orig 238 | *~ 239 | \#*# 240 | 241 | # 242 | # Leavings from module signing 243 | # 244 | extra_certificates 245 | signing_key.priv 246 | signing_key.x509 247 | x509.genkey 248 | -------------------------------------------------------------------------------- /Cyclops IDE/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesl/Cyclops-PRU/6e4ab486669d4aa06404f24d9bed9f0376b6f786/Cyclops IDE/README.md -------------------------------------------------------------------------------- /Cyclops IDE/images/ide_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesl/Cyclops-PRU/6e4ab486669d4aa06404f24d9bed9f0376b6f786/Cyclops IDE/images/ide_screenshot.png -------------------------------------------------------------------------------- /Cyclops IDE/images/pru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesl/Cyclops-PRU/6e4ab486669d4aa06404f24d9bed9f0376b6f786/Cyclops IDE/images/pru.png -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/device-tree/PRU-ACTIVATE-00A0.dtbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesl/Cyclops-PRU/6e4ab486669d4aa06404f24d9bed9f0376b6f786/Cyclops IDE/term-proj/device-tree/PRU-ACTIVATE-00A0.dtbo -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/device-tree/PRU-ACTIVATE-00A0.dts: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | // dtc -O dtb -I dts -o PRU-ACTIVATE-00A0.dtbo -b 0 -@ PRU-ACTIVATE-00A0.dts 5 | / { 6 | compatible = "ti,beaglebone", "ti,beaglebone-green", "ti,beaglebone-black"; 7 | part-number = "PRU-ACTIVATE"; 8 | version = "00A0"; 9 | fragment@0 { 10 | target = <&pruss>; 11 | __overlay__ { 12 | status = "okay"; 13 | }; 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/driver/99-pinpirate.rules: -------------------------------------------------------------------------------- 1 | # Rules file for the pin-pirate device driver to allow non-root access. 2 | # 3 | # You can find the KERNEL and SUBSYSTEM params by running udevadm 4 | # udevadm info -a -p /sys/class/pinmux/pinpirate 5 | # 6 | # Copy this file to: 7 | # /etc/udev/rules.d 8 | KERNEL=="pinpirate", SUBSYSTEM=="pinmux", MODE="0666" 9 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/driver/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # kbuild Makefile based on example code from 3 | # http://derekmolloy.ie/writing-a-linux-kernel-module-part-1-introduction/ 4 | # Linux Device Drivers 3rd Edition by Jonathan Corbet, Alessandro Rubini, 5 | # and Greg Kroah-Hartman. 6 | # 7 | 8 | # If KERNELRELEASE is defined, we've been invoked from the 9 | # kernel build system and can use its language. 10 | ifneq ($(KERNELRELEASE),) 11 | obj-m := pin-pirate.o 12 | # Otherwise we were called directly from the command 13 | # line; invoke the kernel build system. 14 | else 15 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 16 | PWD := $(shell pwd) 17 | 18 | default: 19 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 20 | 21 | .PHONY: clean 22 | clean: 23 | $(MAKE) -C $(KERNELDIR) M=$(PWD) clean 24 | 25 | .PHONY: load 26 | load: default 27 | sudo insmod pin-pirate.ko 28 | lsmod 29 | 30 | .PHONY: unload 31 | unload: 32 | sudo rmmod pin-pirate.ko 33 | endif 34 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/ide/pru_process.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | import time 4 | 5 | def pru_process(pru_num, buf_out, shared): 6 | def check_stop(pru_num): 7 | if shared.get('req' + str(pru_num)) == 'stop': 8 | shared['req' + str(pru_num)] = None 9 | return True 10 | else: 11 | return False 12 | def stop_process(process): 13 | try: 14 | if process and process.poll() is None: 15 | process.terminate() 16 | sleep(0.15) 17 | if process.poll() is None: 18 | process.kill() 19 | except OSError as e: 20 | print(e) 21 | 22 | while True: 23 | time.sleep(0.1) 24 | check_stop(pru_num) 25 | src_key = 'src' + str(pru_num) 26 | src = shared.get(src_key) 27 | if src: 28 | shared[src_key] = None 29 | print("PRU " + str(pru_num) + " compile this: {0}".format(src)) 30 | cur_path = os.path.dirname(os.path.realpath(__file__)) 31 | tmp_dir = cur_path + "/_tmp/" 32 | try: 33 | os.mkdir(tmp_dir) 34 | print("mkdir " + tmp_dir) 35 | except OSError as e: 36 | print(e) 37 | try: 38 | src_file = open(tmp_dir + "pru_" + str(pru_num) + ".p", "w") 39 | src_file.write(src) 40 | src_file.close() 41 | except IOError as e: 42 | print(e) 43 | 44 | if shared.get('req' + str(pru_num)) == 'assemble': 45 | process = subprocess.Popen([cur_path + "/../scripts/compile-pru.sh", str(pru_num)], \ 46 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 47 | elif shared.get('req' + str(pru_num)) == 'run': 48 | process = subprocess.Popen([cur_path + "/../scripts/compile-pru.sh", str(pru_num), 'run'], \ 49 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 50 | 51 | while True: 52 | if check_stop(pru_num): 53 | break 54 | output = process.stdout.readline() 55 | if output == '' and process.poll() is not None: 56 | break 57 | else: 58 | if output: 59 | print str(pru_num) + '@ ' + output.rstrip() 60 | buf_out.put_nowait(output.rstrip()) 61 | stop_process(process) 62 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/ide/start.py: -------------------------------------------------------------------------------- 1 | from bottle import route, get, put, view, post, run, template, request, redirect, static_file 2 | import re 3 | import os 4 | from multiprocessing import Process, Manager, Queue 5 | from pru_process import pru_process 6 | 7 | @get('/pru') 8 | @get('/pru/') 9 | @view('editor') 10 | def route_editor(pru_num=0): 11 | return dict(pru_num=pru_num) 12 | 13 | @route('/static/') 14 | def server_static(filepath): 15 | return static_file(filepath, root='static') 16 | 17 | @get('/pru//out') 18 | def route_output(pru_num): 19 | if int(pru_num) == 0: 20 | buf_out = pru_0_out 21 | else: 22 | buf_out = pru_1_out 23 | output = "" 24 | for i in range(10): 25 | try: 26 | output += buf_out.get_nowait() + "\n" 27 | except: 28 | break 29 | return output 30 | 31 | @post('/pru//assemble') 32 | def route_assemble(pru_num): 33 | src = request.forms.getunicode('src') 34 | shared['req' + str(pru_num)] = 'assemble' 35 | shared['src' + str(pru_num)] = src 36 | 37 | @post('/pru//run') 38 | def route_run(pru_num): 39 | src = request.forms.getunicode('src') 40 | shared['req' + str(pru_num)] = 'run' 41 | shared['src' + str(pru_num)] = src 42 | 43 | @put('/pru//stop') 44 | def route_stop(pru_num): 45 | shared['req' + str(pru_num)] = 'stop' 46 | shared['src' + str(pru_num)] = None 47 | 48 | manager = Manager() 49 | shared = manager.dict() 50 | pru_0_out = manager.Queue() 51 | pru_1_out = manager.Queue() 52 | pru_0_out.put_nowait("PRU0 Enabled\n") 53 | pru_1_out.put_nowait("PRU1 Enabled\n") 54 | process_0 = Process(target=pru_process, args=(0, pru_0_out, shared)) 55 | process_0.start() 56 | process_1 = Process(target=pru_process, args=(1, pru_1_out, shared)) 57 | process_1.start() 58 | 59 | run(host='192.168.7.2', port=8081, quiet=True) 60 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/ide/static/ace/theme-dawn.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/theme/dawn",["require","exports","module","ace/lib/dom"], function(require, exports, module) { 2 | 3 | exports.isDark = false; 4 | exports.cssClass = "ace-dawn"; 5 | exports.cssText = ".ace-dawn .ace_gutter {\ 6 | background: #ebebeb;\ 7 | color: #333\ 8 | }\ 9 | .ace-dawn .ace_print-margin {\ 10 | width: 1px;\ 11 | background: #e8e8e8\ 12 | }\ 13 | .ace-dawn {\ 14 | background-color: #F9F9F9;\ 15 | color: #080808\ 16 | }\ 17 | .ace-dawn .ace_cursor {\ 18 | color: #000000\ 19 | }\ 20 | .ace-dawn .ace_marker-layer .ace_selection {\ 21 | background: rgba(39, 95, 255, 0.30)\ 22 | }\ 23 | .ace-dawn.ace_multiselect .ace_selection.ace_start {\ 24 | box-shadow: 0 0 3px 0px #F9F9F9;\ 25 | }\ 26 | .ace-dawn .ace_marker-layer .ace_step {\ 27 | background: rgb(255, 255, 0)\ 28 | }\ 29 | .ace-dawn .ace_marker-layer .ace_bracket {\ 30 | margin: -1px 0 0 -1px;\ 31 | border: 1px solid rgba(75, 75, 126, 0.50)\ 32 | }\ 33 | .ace-dawn .ace_marker-layer .ace_active-line {\ 34 | background: rgba(36, 99, 180, 0.12)\ 35 | }\ 36 | .ace-dawn .ace_gutter-active-line {\ 37 | background-color : #dcdcdc\ 38 | }\ 39 | .ace-dawn .ace_marker-layer .ace_selected-word {\ 40 | border: 1px solid rgba(39, 95, 255, 0.30)\ 41 | }\ 42 | .ace-dawn .ace_invisible {\ 43 | color: rgba(75, 75, 126, 0.50)\ 44 | }\ 45 | .ace-dawn .ace_keyword,\ 46 | .ace-dawn .ace_meta {\ 47 | color: #794938\ 48 | }\ 49 | .ace-dawn .ace_constant,\ 50 | .ace-dawn .ace_constant.ace_character,\ 51 | .ace-dawn .ace_constant.ace_character.ace_escape,\ 52 | .ace-dawn .ace_constant.ace_other {\ 53 | color: #811F24\ 54 | }\ 55 | .ace-dawn .ace_invalid.ace_illegal {\ 56 | text-decoration: underline;\ 57 | font-style: italic;\ 58 | color: #F8F8F8;\ 59 | background-color: #B52A1D\ 60 | }\ 61 | .ace-dawn .ace_invalid.ace_deprecated {\ 62 | text-decoration: underline;\ 63 | font-style: italic;\ 64 | color: #B52A1D\ 65 | }\ 66 | .ace-dawn .ace_support {\ 67 | color: #691C97\ 68 | }\ 69 | .ace-dawn .ace_support.ace_constant {\ 70 | color: #B4371F\ 71 | }\ 72 | .ace-dawn .ace_fold {\ 73 | background-color: #794938;\ 74 | border-color: #080808\ 75 | }\ 76 | .ace-dawn .ace_list,\ 77 | .ace-dawn .ace_markup.ace_list,\ 78 | .ace-dawn .ace_support.ace_function {\ 79 | color: #693A17\ 80 | }\ 81 | .ace-dawn .ace_storage {\ 82 | font-style: italic;\ 83 | color: #A71D5D\ 84 | }\ 85 | .ace-dawn .ace_string {\ 86 | color: #0B6125\ 87 | }\ 88 | .ace-dawn .ace_string.ace_regexp {\ 89 | color: #CF5628\ 90 | }\ 91 | .ace-dawn .ace_comment {\ 92 | font-style: italic;\ 93 | color: #5A525F\ 94 | }\ 95 | .ace-dawn .ace_heading,\ 96 | .ace-dawn .ace_markup.ace_heading {\ 97 | color: #19356D\ 98 | }\ 99 | .ace-dawn .ace_variable {\ 100 | color: #234A97\ 101 | }\ 102 | .ace-dawn .ace_indent-guide {\ 103 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYLh/5+x/AAizA4hxNNsZAAAAAElFTkSuQmCC) right repeat-y\ 104 | }"; 105 | 106 | var dom = require("../lib/dom"); 107 | dom.importCssString(exports.cssText, exports.cssClass); 108 | }); 109 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/ide/static/ace/theme-solarized_light.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/theme/solarized_light",["require","exports","module","ace/lib/dom"], function(require, exports, module) { 2 | 3 | exports.isDark = false; 4 | exports.cssClass = "ace-solarized-light"; 5 | exports.cssText = ".ace-solarized-light .ace_gutter {\ 6 | background: #fbf1d3;\ 7 | color: #333\ 8 | }\ 9 | .ace-solarized-light .ace_print-margin {\ 10 | width: 1px;\ 11 | background: #e8e8e8\ 12 | }\ 13 | .ace-solarized-light {\ 14 | background-color: #FDF6E3;\ 15 | color: #586E75\ 16 | }\ 17 | .ace-solarized-light .ace_cursor {\ 18 | color: #000000\ 19 | }\ 20 | .ace-solarized-light .ace_marker-layer .ace_selection {\ 21 | background: rgba(7, 54, 67, 0.09)\ 22 | }\ 23 | .ace-solarized-light.ace_multiselect .ace_selection.ace_start {\ 24 | box-shadow: 0 0 3px 0px #FDF6E3;\ 25 | }\ 26 | .ace-solarized-light .ace_marker-layer .ace_step {\ 27 | background: rgb(255, 255, 0)\ 28 | }\ 29 | .ace-solarized-light .ace_marker-layer .ace_bracket {\ 30 | margin: -1px 0 0 -1px;\ 31 | border: 1px solid rgba(147, 161, 161, 0.50)\ 32 | }\ 33 | .ace-solarized-light .ace_marker-layer .ace_active-line {\ 34 | background: #EEE8D5\ 35 | }\ 36 | .ace-solarized-light .ace_gutter-active-line {\ 37 | background-color : #EDE5C1\ 38 | }\ 39 | .ace-solarized-light .ace_marker-layer .ace_selected-word {\ 40 | border: 1px solid #073642\ 41 | }\ 42 | .ace-solarized-light .ace_invisible {\ 43 | color: rgba(147, 161, 161, 0.50)\ 44 | }\ 45 | .ace-solarized-light .ace_keyword,\ 46 | .ace-solarized-light .ace_meta,\ 47 | .ace-solarized-light .ace_support.ace_class,\ 48 | .ace-solarized-light .ace_support.ace_type {\ 49 | color: #859900\ 50 | }\ 51 | .ace-solarized-light .ace_constant.ace_character,\ 52 | .ace-solarized-light .ace_constant.ace_other {\ 53 | color: #CB4B16\ 54 | }\ 55 | .ace-solarized-light .ace_constant.ace_language {\ 56 | color: #B58900\ 57 | }\ 58 | .ace-solarized-light .ace_constant.ace_numeric {\ 59 | color: #D33682\ 60 | }\ 61 | .ace-solarized-light .ace_fold {\ 62 | background-color: #268BD2;\ 63 | border-color: #586E75\ 64 | }\ 65 | .ace-solarized-light .ace_entity.ace_name.ace_function,\ 66 | .ace-solarized-light .ace_entity.ace_name.ace_tag,\ 67 | .ace-solarized-light .ace_support.ace_function,\ 68 | .ace-solarized-light .ace_variable,\ 69 | .ace-solarized-light .ace_variable.ace_language {\ 70 | color: #268BD2\ 71 | }\ 72 | .ace-solarized-light .ace_storage {\ 73 | color: #073642\ 74 | }\ 75 | .ace-solarized-light .ace_string {\ 76 | color: #2AA198\ 77 | }\ 78 | .ace-solarized-light .ace_string.ace_regexp {\ 79 | color: #D30102\ 80 | }\ 81 | .ace-solarized-light .ace_comment,\ 82 | .ace-solarized-light .ace_entity.ace_other.ace_attribute-name {\ 83 | color: #93A1A1\ 84 | }\ 85 | .ace-solarized-light .ace_indent-guide {\ 86 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHjy8NJ/AAjgA5fzQUmBAAAAAElFTkSuQmCC) right repeat-y\ 87 | }"; 88 | 89 | var dom = require("../lib/dom"); 90 | dom.importCssString(exports.cssText, exports.cssClass); 91 | }); 92 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/ide/static/compiler.js: -------------------------------------------------------------------------------- 1 | var code_boilerplate_begin = 2 | ".origin 0\n" + 3 | ".entrypoint TOP\n" + 4 | "\n" + 5 | "TOP:\n" + 6 | "\n" + 7 | "// use r0 as a constant zero register\n" + 8 | "mov r0, 0\n" + 9 | "\n" + 10 | "// Control register base address\n" + 11 | "mov r2, 0x22000\n" + 12 | "// Read in control register\n" + 13 | "lbbo r3, r2, 0, 1\n" + 14 | "// Turn on bit 3 to enable counters\n" + 15 | "set r3.t3\n" + 16 | "// Write to control register\n" + 17 | "sbbo r3, r2, 0, 1\n" + 18 | "// reset cycle counter\n" + 19 | "sbbo r0, r2, 0xC, 4\n" + 20 | "// stack pointer in r1\n" + 21 | "ldi r1, 1024\n\n"; 22 | 23 | var code_boilerplate_end = 24 | "END:\n" + 25 | "// Interrupt the host process\n" + 26 | "ldi r2, 2\n" + 27 | "sbbo r2, r0, r0, 4\n" + 28 | "halt\n\n"; 29 | 30 | var code_print = 31 | "PRINT:\n" + 32 | "sub r1, r1, 4\n" + 33 | "// num args in r2\n" + 34 | "lbbo r2, r1, 0, 4\n" + 35 | "// write offset\n" + 36 | "ldi r4, 0\n" + 37 | "// print status code = 1\n" + 38 | "ldi r3, 1\n" + 39 | "sbbo r3, r4, 0, 4\n" + 40 | "add r4, r4, 4\n" + 41 | "sbbo r2, r4, 0, 4\n" + 42 | "add r4, r4, 4\n" + 43 | "PRINT_LOOP:\n" + 44 | "sub r1, r1, 4\n" + 45 | "lbbo r3, r1, 0, 4\n" + 46 | "sbbo r3, r4, 0, 4\n" + 47 | "add r4, r4, 4\n" + 48 | "sub r2, r2, 1\n" + 49 | "qbne PRINT_LOOP, r2, 0\n" + 50 | "PRINT_WAIT:\n" + 51 | "lbbo r2, r0, 0, 4\n" + 52 | "qbne PRINT_WAIT, r2, 0\n" + 53 | "ret\n"; 54 | 55 | /* Example call to print 56 | 57 | ldi r5, 321 58 | sbbo r5, r1, 0, 4 59 | add r1, r1, 4 60 | ldi r5, 1 61 | sbbo r5, r1, 0, 4 62 | add r1, r1, 4 63 | call PRINT 64 | 65 | */ 66 | 67 | var parser; 68 | 69 | function compiler_init() { 70 | parser = peg.generate($("#grammar").text()); 71 | } 72 | 73 | function compile(src) { 74 | var asm_src = ""; 75 | 76 | parser.parse(src); 77 | 78 | var pin_configs = ""; 79 | for (var key in window.pin_settings) { 80 | if (!window.pin_settings.hasOwnProperty(key)) continue; 81 | 82 | var pin_conf = window.pin_settings[key]; 83 | pin_configs += "//" + pin_conf.conf + "\n" 84 | } 85 | 86 | asm_src += pin_configs 87 | asm_src += code_boilerplate_begin; 88 | 89 | asm_src += "// START\n\n"; 90 | asm_src += window.asm_out_buf; 91 | asm_src += "\n// END\n\n"; 92 | 93 | asm_src += code_boilerplate_end; 94 | asm_src += code_print; 95 | 96 | window.asm_out_buf = ""; 97 | return asm_src; 98 | } 99 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/ide/static/editor.css: -------------------------------------------------------------------------------- 1 | body { 2 | position: absolute; 3 | width: 100%; 4 | height: 100%; 5 | margin: 0; 6 | padding: 0; 7 | font-family: Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro, monospace; 8 | } 9 | 10 | .body-container { 11 | margin: 0; 12 | padding: 0; 13 | position: absolute; 14 | top: 30px; 15 | right: 0; 16 | bottom: 0; 17 | left: 0; 18 | width: 100%; 19 | } 20 | 21 | .menu-bar { 22 | background-color: #6C99B6; 23 | position: absolute; 24 | height: 30px; 25 | width: 100%; 26 | top: 0; 27 | left: 0; 28 | } 29 | 30 | .button { 31 | background-color: #376698; 32 | border: none; 33 | color: white; 34 | text-align: center; 35 | text-decoration: none; 36 | display: inline-block; 37 | font-size: 12px; 38 | margin: 4px 2px; 39 | cursor: pointer; 40 | width: 88px; 41 | height: 22px; 42 | } 43 | 44 | .button:hover { 45 | background-color: #4371a2; 46 | } 47 | 48 | .button:focus { 49 | outline: none; 50 | } 51 | 52 | .editor-container { 53 | margin: 0; 54 | padding: 0; 55 | height: 50%; 56 | width: 400px; 57 | } 58 | 59 | .asm-editor-container { 60 | //border-top: 1px solid #dedede; 61 | } 62 | 63 | .editor { 64 | position: absolute; 65 | margin: 0; 66 | padding: 0; 67 | top: 0; 68 | left: 0; 69 | bottom: 0; 70 | right: 0; 71 | height: 100%; 72 | width: 100%; 73 | } 74 | 75 | #console-container { 76 | overflow: hidden; 77 | margin: 0; 78 | padding: 0; 79 | position: absolute; 80 | top: 0; 81 | left: 400px; 82 | right: 0; 83 | bottom: 0; 84 | } 85 | 86 | #console { 87 | height: 100%; 88 | overflow: scroll; 89 | margin: 0; 90 | padding: 0 0 0 11px; 91 | background-color: white; 92 | font-size: 11px; 93 | } 94 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/ide/static/editor.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | var editor = ace.edit("editor"); 3 | editor.$blockScrolling = Infinity; 4 | editor.setTheme("ace/theme/solarized_light"); 5 | editor.session.setMode("ace/mode/cyclops"); 6 | 7 | var asm_editor = ace.edit("asm-editor"); 8 | asm_editor.$blockScrolling = Infinity; 9 | asm_editor.setTheme("ace/theme/dawn"); 10 | asm_editor.session.setMode("ace/mode/assembly_pru"); 11 | 12 | compiler_init(); 13 | 14 | $('#compile').click(function() { 15 | var terminal = $("#console"); 16 | terminal.append("Compiling...\n"); 17 | try { 18 | var asm_src = compile(editor.getValue()); 19 | asm_editor.setValue(asm_src, -1); 20 | terminal.append("Compile Done\n"); 21 | } catch (e) { 22 | terminal.append("Compile Error: " + e.message + "\n"); 23 | } 24 | $('#tail').click(); 25 | }); 26 | 27 | $('#run').click(function() { 28 | var pru_num = $('#run').attr('pru-num'); 29 | var src = asm_editor.getValue(); 30 | $.post("pru/" + pru_num + "/run", { "src": src }, function(data) { 31 | console.log("run"); 32 | var terminal = $("#console"); 33 | terminal.append("Running...\n"); 34 | $('#tail').click(); 35 | }); 36 | }); 37 | 38 | $('#stop').click(function() { 39 | var pru_num = $('#stop').attr('pru-num'); 40 | $.ajax({ 41 | url: "pru/" + pru_num + "/stop", 42 | type: "PUT" 43 | }); 44 | }); 45 | 46 | $('#clear').click(function() { 47 | $('#console').text(""); 48 | }); 49 | 50 | $('#tail').click(function() { 51 | var terminal = $("#console"); 52 | var height = terminal[0].scrollHeight; 53 | terminal.scrollTop(height); 54 | }); 55 | 56 | function update_terminal() { 57 | var pru_num = $('#run').attr('pru-num'); 58 | $.get("pru/" + pru_num + "/out", function(data) { 59 | if (data) { 60 | var terminal = $("#console"); 61 | terminal.append(data); 62 | var height = terminal[0].scrollHeight; 63 | terminal.scrollTop(height); 64 | console.log(data); 65 | } 66 | window.setTimeout(update_terminal, 100); 67 | }).fail(function() { window.setTimeout(update_terminal, 5000); }); 68 | } 69 | 70 | window.setTimeout(update_terminal, 100); 71 | }); 72 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/ide/views/base.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{title or 'PRU'}} 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 24 |
25 | {{!base}} 26 |
27 | % include('grammar.tpl') 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/ide/views/editor.tpl: -------------------------------------------------------------------------------- 1 | % rebase('base.tpl', title='PRU Editor', pru_num=pru_num) 2 | 3 |
4 |
5 |
6 | 7 |
8 |
9 |
10 | 11 |
12 |

13 | 
14 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/pru-loader/pru_loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, const char *argv[]) { 9 | int pru_num; 10 | 11 | if (argc != 3) { 12 | printf("Usage: %s \n", argv[0]); 13 | fflush(stdout); 14 | return 1; 15 | } 16 | 17 | pru_num = atoi(argv[2]); 18 | 19 | prussdrv_init(); 20 | 21 | if (prussdrv_open(PRU_EVTOUT_0) == -1) { 22 | printf("prussdrv_open() failed\n"); 23 | fflush(stdout); 24 | return 1; 25 | } 26 | 27 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 28 | prussdrv_pruintc_init(&pruss_intc_initdata); 29 | 30 | int which_pru = 0; 31 | 32 | if (pru_num == 0) { 33 | which_pru = 0; 34 | } else if (pru_num == 1) { 35 | which_pru = 1; 36 | } 37 | 38 | void* dataram; 39 | if (prussdrv_map_prumem(which_pru ? PRUSS0_PRU1_DATARAM : PRUSS0_PRU0_DATARAM, &dataram)) { 40 | printf("pru mem map failed\n"); 41 | fflush(stdout); 42 | return 1; 43 | } 44 | memset(dataram, 0, 0x2000); 45 | 46 | printf("Executing program and waiting for termination\n"); 47 | fflush(stdout); 48 | prussdrv_exec_program(which_pru, argv[1]); 49 | 50 | // Wait for interrupt from PRU 51 | //prussdrv_pru_wait_event(PRU_EVTOUT_0); 52 | 53 | while(1) { 54 | uint32_t* p = (uint32_t*) dataram; 55 | 56 | // status code = 1 is print 57 | if (*p == 1) { 58 | uint32_t num_args = *(++p); 59 | for (int i = 0; i < num_args; i++) { 60 | uint32_t arg = *(++p); 61 | if (i == num_args - 1) { 62 | printf(" %u [0x%lx]", arg, arg); 63 | fflush(stdout); 64 | } else { 65 | printf(" %u [0x%lx],", arg, arg); 66 | fflush(stdout); 67 | } 68 | } 69 | printf("\n"); 70 | fflush(stdout); 71 | p = (uint32_t*) dataram; 72 | *p = 0; 73 | } else if (*p == 2) { 74 | // terminate 75 | printf("Terminate\n"); 76 | fflush(stdout); 77 | break; 78 | } 79 | } 80 | 81 | prussdrv_pru_disable(which_pru); 82 | prussdrv_exit(); 83 | 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/scripts/activate-pruss.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CURRENT_DIR="${0%/*}" 4 | 5 | cd $CURRENT_DIR 6 | 7 | DTS_NAME="PRU-ACTIVATE" 8 | FIRMWARE_DIR="/lib/firmware/" 9 | CAPEMGR_SLOTS="/sys/devices/bone_capemgr.9/slots" 10 | 11 | if [ ! -e $CAPEMGR_SLOTS ]; then 12 | CAPEMGR_SLOTS="/sys/devices/platform/bone_capemgr/slots" 13 | if [ ! -e $CAPEMGR_SLOTS ]; then 14 | echo "Bone Cape Manager not found" 15 | fi 16 | fi 17 | 18 | is_active() 19 | { 20 | for f in /sys/class/uio/* 21 | do 22 | if cat "${f}/name" 2>/dev/null | grep --quiet "pruss*"; then 23 | return 0 24 | fi 25 | done 26 | 27 | return 1 28 | } 29 | 30 | if [ "$1" = "unload" ]; then 31 | if is_active; then 32 | if cat $CAPEMGR_SLOTS | grep --quiet $DTS_NAME ; then 33 | SLOT_UNLOAD="sudo sh -c 'echo -$(($(cat $CAPEMGR_SLOTS | grep $DTS_NAME | cut -d':' -f1))) > $CAPEMGR_SLOTS'" 34 | eval $SLOT_UNLOAD 35 | sleep 1 36 | fi 37 | fi 38 | else 39 | if ! is_active; then 40 | 41 | if [ ! -f "${FIRMWARE_DIR}${DTS_NAME}-00A0.dtbo" ]; then 42 | sudo cp ../device-tree/${DTS_NAME}-00A0.dts $FIRMWARE_DIR 43 | sudo dtc -O dtb -I dts -o ${FIRMWARE_DIR}${DTS_NAME}-00A0.dtbo -b 0 -@ ${FIRMWARE_DIR}${DTS_NAME}-00A0.dts 44 | fi 45 | 46 | if ! cat $CAPEMGR_SLOTS | grep --quiet $DTS_NAME ; then 47 | SLOT_LOAD="sudo sh -c 'echo $DTS_NAME > $CAPEMGR_SLOTS'" 48 | eval $SLOT_LOAD 49 | sleep 1 50 | fi 51 | fi 52 | fi 53 | 54 | if is_active; then 55 | echo "PRUSS Active" 56 | else 57 | echo "PRUSS Disabled" 58 | fi 59 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/scripts/beaglebone-net-forwarding.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Run on host to allow the BBB to access the internet 3 | # 4 | 5 | # ens33 is the host interface between host <--> internet 6 | # enx8030dc55737f is thehost interface between BBB <--> host 7 | sudo ifconfig enx8030dc55737f 192.168.7.1 8 | sudo iptables --table nat --append POSTROUTING --out-interface ens33 -j MASQUERADE 9 | sudo iptables --append FORWARD --in-interface enx8030dc55737f -j ACCEPT 10 | sudo sh -c 'echo 1 > /proc/sys/net/ipv4/ip_forward' 11 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/scripts/beaglebone-net-gateway.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Run on BBB to set the gateway 3 | # 4 | 5 | sudo ifconfig usb0 192.168.7.2 6 | sudo route add default gw 192.168.7.1 7 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/scripts/compile-pru.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CURRENT_DIR="${0%/*}" 4 | 5 | cd $CURRENT_DIR 6 | 7 | TMP_DIR="../ide/_tmp/" 8 | 9 | if [ -d "$TMP_DIR" ]; then 10 | cd $TMP_DIR 11 | 12 | cp ../../pru-loader/pru_loader.c . 13 | gcc -std=c99 -o pru_loader pru_loader.c -lprussdrv 14 | 15 | if [ $? -ne 0 ]; then 16 | exit 1 17 | fi 18 | 19 | if [ -e "/dev/pinpirate" ]; then 20 | echo "Adjusting pinmux" 21 | grep "//0x" "pru_$1.p" | sed 's/\/\///' 22 | grep "//0x" "pru_$1.p" | sed 's/\/\///' | xargs -I{} sh -c 'echo {} > /dev/pinpirate' 23 | sleep 0.25 24 | echo "Pinmux done" 25 | fi 26 | 27 | pasm -b "pru_$1.p" 28 | 29 | if [ $? -ne 0 ]; then 30 | exit 1 31 | fi 32 | 33 | if [ "$2" = "run" ]; then 34 | ./pru_loader "pru_$1.bin" "$1" 35 | fi 36 | fi 37 | 38 | 39 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/scripts/install-BBB-kernel-headers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Run this on the BBB to install kernel headers for kernel module development 5 | # 6 | 7 | KERNEL_HEADERS_MAKEFILE="/lib/modules/$(uname -r)/build/Makefile" 8 | 9 | if [ ! -e $KERNEL_HEADERS_MAKEFILE ]; then 10 | sudo apt-get update 11 | sudo apt-get install -y linux-headers-$(uname -r) 12 | else 13 | echo Kernel headers already installed $KERNEL_HEADERS_MAKEFILE 14 | fi 15 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/scripts/list-capemgr-slots.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CAPE_MGR_SLOTS="/sys/devices/bone_capemgr.9/slots" 4 | 5 | if [ ! -e $CAPE_MGR_SLOTS ]; then 6 | CAPE_MGR_SLOTS="/sys/devices/platform/bone_capemgr/slots" 7 | if [ ! -e $CAPE_MGR_SLOTS ]; then 8 | echo "Bone Cape Manager not found" 9 | fi 10 | fi 11 | 12 | cat $CAPE_MGR_SLOTS 13 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/scripts/list-pinmux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Prints current pinmux settings 4 | sudo cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pins 5 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/scripts/start-ide.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CURRENT_DIR="${0%/*}" 4 | 5 | cd $CURRENT_DIR 6 | 7 | sudo ./activate-pruss.sh 8 | sudo ./install-BBB-kernel-headers.sh 9 | if [ ! -e "/etc/udev/rules.d/99-pinpirate.rules" ]; then 10 | sudo cp ../driver/99-pinpirate.rules /etc/udev/rules.d/ 11 | fi 12 | if ! lsmod | grep --quiet pin_pirate; then 13 | echo pin-pirate LKM not loaded 14 | pushd . 15 | cd ../driver 16 | make load 17 | popd 18 | else 19 | echo pin-pirate LKM loaded 20 | fi 21 | 22 | cd ../ide 23 | 24 | python start.py 25 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/scripts/update-time.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ! which ntpdate; then 4 | sudo apt-get update 5 | sudo apt-get -y install ntpdate 6 | fi 7 | 8 | sudo ntpdate -b time.nist.gov 9 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/web/PRU-ACTIVATE.tpl: -------------------------------------------------------------------------------- 1 | /dts-v1/; 2 | /plugin/; 3 | 4 | / { 5 | compatible = "ti,beaglebone", "ti,beaglebone-green", "ti,beaglebone-black"; 6 | part-number = "{{part_num}}"; 7 | version = "{{version}}"; 8 | 9 | %if pins: 10 | exclusive-use = 11 | "{{pins[0]['header']}}.{{pins[0]['pin_num']}}", \\ 12 | %for pin in pins[1:]: 13 | "{{pin['header']}}.{{pin['pin_num']}}", \\ 14 | %end 15 | "pru0", "pru1"; 16 | 17 | fragment@0 { 18 | target = <&am33xx_pinmux>; 19 | __overlay__ { 20 | example_pins: pinmux_pru_pru_pins { 21 | pinctrl-single,pins = < 22 | %for pin in pins: 23 | {{hex(pin['offset'])}} {{hex(pin['bits'])}} 24 | %end 25 | >; 26 | }; 27 | }; 28 | }; 29 | %end 30 | 31 | fragment@1 { 32 | target = <&pruss>; 33 | __overlay__ { 34 | status = "{{status}}"; 35 | %if pins: 36 | pinctrl-names = "default"; 37 | pinctrl-0 = <&example_pins>; 38 | %end 39 | }; 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/web/base.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{title or 'PRU'}} 7 | 8 | 9 | 10 | 11 | 12 | 31 | 32 | 33 | {{!base}} 34 | 35 | 36 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/web/pinmux-pin.tpl: -------------------------------------------------------------------------------- 1 | <% 2 | name = pin['name'] 3 | mode = pin['mode'] 4 | pru_assignable = bool(filter(lambda m: 'pru' in str(m), pin['modes'])) 5 | pru_assigned = bool(mode != None and "pru" in pin['modes'][mode]) 6 | slew = 'checked' if pin['slew'] else '' 7 | input = 'checked' if pin['input'] else '' 8 | pullup = 'checked' if pin['pullup'] else '' 9 | enable_pullupdown = 'checked' if pin['enable_pullupdown'] else '' 10 | disabled = '' if pru_assignable else 'disabled' 11 | row = [('mode', None), ('input', input), ('enable_pullupdown', enable_pullupdown), ('pullup', pullup), ('slew', slew)] 12 | row = list(reversed(row)) if reverse else row 13 | %> 14 | 15 | %for cell in row: 16 | 25 | %if cell[0] == 'mode': 26 | %if mode != None: 27 | %if pru_assignable: 28 | 39 | %else: 40 | {{pin['modes'][mode]}} 41 | %end 42 | %else: 43 | {{name}} 44 | %end 45 | %else: 46 | %if mode != None: 47 | 52 | %end 53 | %end 54 | 55 | %end 56 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/web/pinmux.tpl: -------------------------------------------------------------------------------- 1 | % rebase('base.tpl', title='PRU Pin Configuration') 2 |
3 | 4 | 9 | 10 | 18 | 19 | 20 |
11 | 17 |
21 | 22 | 23 | <%for i in range(1, 46, 2): 24 | l = P8[i] 25 | r = P8[i+1] 26 | %> 27 | 28 | 29 | %include('pinmux-pin.tpl', pin=l, pin_num="P8_" + str(i), reverse=True) 30 | 31 | 32 | %include('pinmux-pin.tpl', pin=r, pin_num="P8_" + str(i+1), reverse=False) 33 | 34 | %end 35 |
P8
{{i}}{{i+1}}
36 |
37 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/web/pins.py: -------------------------------------------------------------------------------- 1 | P8 = {} 2 | P9 = {} 3 | 4 | def _set(name, modes=None, mode=None, offset=None, enable_pullupdown=False,\ 5 | pullup=False, input=False, slew=False): 6 | pin = { 7 | "name": name, 8 | "modes": [None] * 8, 9 | "mode": mode, 10 | "offset": offset, 11 | "enable_pullupdown": enable_pullupdown, 12 | "pullup": pullup, 13 | "input": input, 14 | "slew": slew 15 | } 16 | 17 | if type(modes) is dict: 18 | for key in modes: 19 | pin["modes"][key] = modes[key] 20 | elif type(modes) is list: 21 | pin['modes'] = modes 22 | 23 | return pin 24 | 25 | P8[1] = _set("DGND") 26 | P8[2] = _set("DGND") 27 | P8[3] = _set("GPIO1_6", offset=0x018, modes={0: "gpmc_ad6", 1: "mmc1_dat6", \ 28 | 7: "gpio1[6]"}) 29 | P8[4] = _set("GPIO1_7", offset=0x01c, modes={0: "gpmc_ad7", 1: "mmc1_dat7", \ 30 | 7: "gpio1[7]"}) 31 | P8[5] = _set("GPIO1_2", offset=0x008, modes={0: "gpmc_ad2", 1: "mmc1_dat2", \ 32 | 7: "gpio1[2]"}) 33 | P8[6] = _set("GPIO1_3", offset=0x00c, modes={0: "gpmc_ad3", 1: "mmc1_dat3", \ 34 | 7: "gpio1[3]"}) 35 | P8[7] = _set("TIMER4", offset=0x090, modes={0: "gpmc_advn_ale", 2: "timer4", \ 36 | 7: "gpio2[2]"}) 37 | P8[8] = _set("TIMER7", offset=0x094, modes={0: "gpmc_oen_ren", 2: "timer7", \ 38 | 7: "gpio2[3]"}) 39 | P8[9] = _set("TIMER5", offset=0x09c, modes={0: "gpmc_be0n_cle", 2: "timer5", \ 40 | 7: "gpio2[5]"}) 41 | P8[10] = _set("TIMER6", offset=0x098, modes={0: "gpmc_wen", 2: "timer6", \ 42 | 7: "gpio2[4]"}) 43 | P8[11] = _set("GPIO1_13", offset=0x034, modes=["gpmc_ad13", "lcd_data18", \ 44 | "mmc1_dat5", "mmc2_dat1", "eQEP2B_in", None, \ 45 | "pr1_pru0_pru_r30_15", "gpio1[13]"]) 46 | P8[12] = _set("GPIO1_12", offset=0x030, modes=["gpmc_ad12", "lcd_data19", \ 47 | "mmc1_dat4", "mmc2_dat0", "eQEP2A_in", None, \ 48 | "pr1_pru0_pru_r30_14", "gpio1[12]"]) 49 | P8[13] = _set("EHRPWM2B", offset=0x024, modes=["gpmc_ad9", "lcd_data22", \ 50 | "mmc1_dat1", "mmc2_dat5", "ehrpwm2B", None, None, \ 51 | "gpio0[23]"]) 52 | P8[14] = _set("GPIO0_26", offset=0x028, modes=["gpmc_ad10", "lcd_data21", \ 53 | "mmc1_dat2", "mmc2_dat6", "ehrpwm2_tripzone_in", None, None, \ 54 | "gpio0[26]"]) 55 | P8[15] = _set("GPIO1_15", offset=0x03c, modes=["gpmc_ad15", "lcd_data16", \ 56 | "mmc1_dat7", "mmc2_dat3", "eQEP2_strobe", None, \ 57 | "pr1_pru0_pru_r31_15", "gpio1[15]"]) 58 | P8[16] = _set("GPIO1_14", offset=0x038, modes=["gpmc_ad14", "lcd_data17", \ 59 | "mmc1_dat6", "mmc2_dat2", "eQEP2_index", None, \ 60 | "pr1_pru0_pru_r31_14", "gpio1[14]"]) 61 | P8[17] = _set("GPIO0_27", offset=0x02c, modes=["gpmc_ad11", "lcd_data20", \ 62 | "mmc1_dat3", "mmc2_dat7", "ehrpwm0_synco", None, None, \ 63 | "gpio0[27]"]) 64 | P8[18] = _set("GPIO2_1", offset=0x08c, modes=["gpmc_clk_mux0", \ 65 | "lcd_memory_clk", "gpmc_wait1", "mmc2_clk", None, None, \ 66 | "mcasp0_fsr", "gpio2[1]"]) 67 | P8[19] = _set("EHRPWM2A", offset=0x020, modes=["gpmc_ad8", "lcd_data23", \ 68 | "mmc1_dat0", "mmc2_dat4", "ehrpwm2A", None, None, \ 69 | "gpio0[22]"]) 70 | P8[20] = _set("GPIO1_31", offset=0x084, modes={0: "gpmc_csn2", \ 71 | 1: "gpmc_be1n", 2: "mmc1_cmd", 5: "pr1_pru1_pru_r30_13", \ 72 | 6: "pr1_pru1_pru_r31_13", 7: "gpio1[31]"}) 73 | P8[21] = _set("GPIO1_30", offset=0x080, modes={0: "gpmc_csn1", \ 74 | 1: "gpmc_clk", 2: "mmc1_clk", 5: "pr1_pru1_pru_r30_12", \ 75 | 6: "pr1_pru1_pru_r31_12", 7: "gpio1[30]"}) 76 | P8[22] = _set("GPIO1_5", offset=0x014, modes={0: "gpmc_ad5", \ 77 | 1: "mmc1_dat5", 7: "gpio1[5]"}) 78 | P8[23] = _set("GPIO1_4", offset=0x010, modes={0: "gpmc_ad4", \ 79 | 1: "mmc1_dat4", 7: "gpio1[4]"}) 80 | P8[24] = _set("GPIO1_1", offset=0x004, modes={0: "gpmc_ad1", \ 81 | 1: "mmc1_dat1", 7: "gpio1[1]"}) 82 | P8[25] = _set("GPIO1_0", offset=0x000, modes={0: "gpmc_ad0", \ 83 | 1: "mmc1_dat0", 7: "gpio1[0]"}) 84 | P8[26] = _set("GPIO1_29", offset=0x07c, modes={0: "gpmc_csn0", 7: "gpio1[29]"}) 85 | P8[27] = _set("GPIO2_22", offset=0x0e0, modes={0: "lcd_vsync", \ 86 | 1: "gpmc_a8", 5: "pr1_pru1_pru_r30_8", \ 87 | 6: "pr1_pru1_pru_r31_8", 7: "gpio2[22]"}) 88 | P8[28] = _set("GPIO2_24", offset=0x0e8, modes={0: "lcd_pclk", \ 89 | 1: "gpmc_a10", 5: "pr1_pru1_pru_r30_10", \ 90 | 6: "pr1_pru1_pru_r31_10", 7: "gpio2[24]"}) 91 | P8[29] = _set("GPIO2_23", offset=0x0e4, modes={0: "lcd_hsync", \ 92 | 1: "gpmc_a9", 5: "pr1_pru1_pru_r30_9", \ 93 | 6: "pr1_pru1_pru_r31_9", 7: "gpio2[23]"}) 94 | P8[30] = _set("GPIO2_25", offset=0x0ec, modes={0: "lcd_ac_bias_en", \ 95 | 1: "gpmc_a11", 7: "gpio2[25]"}) 96 | P8[31] = _set("UART5_CTSN", offset=0x0d8, modes=["lcd_data14", "gpmc_a18", \ 97 | "eQEP1_index", "mcasp0_axr1", "uart5_rxd", None, \ 98 | "uart5_ctsn", "gpio0[10]"]) 99 | P8[32] = _set("UART5_RTSN", offset=0x0dc, modes=["lcd_data15", "gpmc_a19", \ 100 | "eQEP1_strobe", "mcasp0_ahclkx", "mcasp0_axr3", None, \ 101 | "uart5_rtsn", "gpio0[11]"]) 102 | P8[33] = _set("UART4_RTSN", offset=0x0d4, modes=["lcd_data13", "gpmc_a17", \ 103 | "eQEP1B_in", "mcasp0_fsr", "mcasp0_axr3", None, "uart4_rtsn", \ 104 | "gpio0[9]"]) 105 | P8[34] = _set("UART3_RTSN", offset=0x0cc, modes=["lcd_data11", "gpmc_a15", \ 106 | "ehrpwm1B", "mcasp0_ahclkr", "mcasp0_axr2", None, \ 107 | "uart3_rtsn", "gpio2[17]"]) 108 | P8[35] = _set("UART4_CTSN", offset=0x0d0, modes=["lcd_data12", "gpmc_a16", \ 109 | "eQEP1A_in", "mcasp0_aclkr", "mcasp0_axr2", None, \ 110 | "uart4_ctsn", "gpio0[8]"]) 111 | P8[36] = _set("UART3_CTSN", offset=0x0c8, modes=["lcd_data10", "gpmc_a14", \ 112 | "ehrpwm1A", "mcasp0_axr0", None, None, "uart3_ctsn", \ 113 | "gpio2[16]"]) 114 | P8[37] = _set("UART5_TXD", offset=0x0c0, modes=["lcd_data8", "gpmc_a12", \ 115 | "ehrpwm1_tripzone_in", "mcasp0_aclkx", "uart5_txd", \ 116 | "None", "uart2_ctsn", "gpio2[14]"]) 117 | P8[38] = _set("UART5_RXD", offset=0x0c4, modes=["lcd_data9", "gpmc_a13", \ 118 | "ehrpwm0_synco", "mcasp0_fsx", "uart5_rxd", None, \ 119 | "uart2_rtsn", "gpio2[15]"]) 120 | P8[39] = _set("GPIO2_12", offset=0x0b8, modes=["lcd_data6", "gpmc_a6", None, \ 121 | "eQEP2_index", None, "pr1_pru1_pru_r30_6", \ 122 | "pr1_pru1_pru_r31_6", "gpio2[12]"]) 123 | P8[40] = _set("GPIO2_13", offset=0x0bc, modes=["lcd_data7", "gpmc_a7", None, \ 124 | "eQEP2_strobe", "pr1_edio_data_out7", "pr1_pru1_pru_r30_7", \ 125 | "pr1_pru1_pru_r31_7", "gpio2[13]"]) 126 | P8[41] = _set("GPIO2_10", offset=0x0b0, modes=["lcd_data4", "gpmc_a4", None, \ 127 | "eQEP2A_in", None, "pr1_pru1_pru_r30_4", "pr1_pru1_pru_r30_4", \ 128 | "gpio2[10]"]) 129 | P8[42] = _set("GPIO2_11", offset=0x0b4, modes=["lcd_data5", "gpmc_a5", None, \ 130 | "eQEP2B_in", None, "pr1_pru1_pru_r30_5", "pr1_pru1_pru_r31_5", \ 131 | "gpio2[11]"]) 132 | P8[43] = _set("GPIO2_8", offset=0x0a8, modes=["lcd_data2", "lcd_data2", None, \ 133 | "ehrpwm2_tripzone_in", None, "pr1_pru1_pru_r30_2", \ 134 | "pr1_pru1_pru_r31_2", "gpio2[8]"]) 135 | P8[44] = _set("GPIO2_9", offset=0x0ac, modes=["lcd_data3", "gpmc_a3", None, \ 136 | "ehrpwm0_synco", None, "pr1_pru1_pru_r30_3", \ 137 | "pr1_pru1_pru_r31_3", "gpio2[9]"]) 138 | P8[45] = _set("GPIO2_6", offset=0x0a0, modes=["lcd_data0", "gpmc_a0", None, \ 139 | "ehrpwm2A", None, "pr1_pru1_pru_r30_0", "pr1_pru1_pru_r31_0", \ 140 | "gpio2[6]"]) 141 | P8[46] = _set("GPIO2_7", offset=0x0a4, modes=["lcd_data1", "gpmc_a1", None, \ 142 | "ehrpwm2B", None, "pr1_pru1_pru_r30_1", "pr1_pru1_pru_r31_1", \ 143 | "gpio2[7]"]) 144 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/web/start.py: -------------------------------------------------------------------------------- 1 | from bottle import route, get, post, run, template, request, redirect 2 | import re 3 | from pins import P8, P9 4 | import os 5 | import subprocess 6 | import time 7 | 8 | BASE_ADDR = 0x44e10800 9 | SLOTS_PATH = '/sys/devices/bone_capemgr.9/slots' 10 | 11 | def search_dict(dictionary, func): 12 | for key in dictionary: 13 | if func(dictionary[key]): 14 | return dictionary[key] 15 | return None 16 | 17 | def read_pin_status(): 18 | f = open("/sys/kernel/debug/pinctrl/44e10800.pinmux/pins", "r") 19 | for line in f: 20 | m = re.search("pin [0-9]+ \(([0-9A-Fa-f]+)\) ([0-9A-Fa-f]+)", line) 21 | if m: 22 | addr = int(m.group(1), base=16) 23 | cfg = int(m.group(2), base=16) 24 | offset = addr - BASE_ADDR 25 | for P in [P8, P9]: 26 | pin = search_dict(P, \ 27 | lambda pin: pin['offset'] == offset) 28 | if pin: 29 | mode = int(cfg & 0b0000111) 30 | pin['mode'] = mode 31 | pin['enable_pullupdown'] = bool(cfg & 0b0001000) 32 | pin['pullup'] = bool(cfg & 0b0010000) 33 | pin['input'] = bool(cfg & 0b0100000) 34 | pin['slew'] = bool(cfg & 0b1000000) 35 | pin['cfg'] = cfg 36 | 37 | f.close() 38 | 39 | def pruss_enabled(): 40 | try: 41 | uio = '/sys/class/uio' 42 | for dir in os.listdir(uio): 43 | f = open(uio + "/" + dir + "/name", "r") 44 | if re.match("pruss.*", f.readline()): 45 | return True 46 | f.close() 47 | except: 48 | pass 49 | 50 | return False 51 | 52 | def unload_slot(name): 53 | ret = False 54 | f = open(SLOTS_PATH, "r") 55 | for line in f: 56 | m = re.search("([0-9]+): .*" + name + "$", line) 57 | if m: 58 | index = int(m.group(1)) 59 | f.close() 60 | f = open(SLOTS_PATH, "a") 61 | f.write("-" + str(index)) 62 | f.flush() 63 | ret = True 64 | break 65 | f.close() 66 | return ret 67 | 68 | def load_slot(name): 69 | f = open(SLOTS_PATH, "a") 70 | f.write(name) 71 | f.flush() 72 | f.close() 73 | 74 | @get('/pru/pinmux') 75 | def route_pinmux(): 76 | read_pin_status() 77 | return template("pinmux", P8=P8, P9=P9, pruss_enabled=pruss_enabled()) 78 | 79 | @post('/pru/pinmux') 80 | def route_pinmux_post(): 81 | read_pin_status() 82 | form = request.forms 83 | dts_name = "PRU-ACTIVATE" 84 | dts_ver = "00A0" 85 | enable_pruss = bool(form.getunicode("enable_pruss")) 86 | status = 'okay' if enable_pruss else 'disabled' 87 | pins = [] 88 | 89 | for P in [P8, P9]: 90 | if P == P8: 91 | prefix="P8_" 92 | else: 93 | prefix = "P9_" 94 | 95 | for i in range(1, 46): 96 | bits = 0; 97 | mode = form.getunicode(prefix + str(i) + "_mode") 98 | enable_pullupdown = form.getunicode(prefix + str(i) + "_enable_pullupdown") 99 | pullup = form.getunicode(prefix + str(i) + "_pullup") 100 | input = form.getunicode(prefix + str(i) + "_input") 101 | slew = form.getunicode(prefix + str(i) + "_slew") 102 | 103 | if mode != None: 104 | bits = bits | int(mode) 105 | if enable_pullupdown: 106 | bits = bits | 0b0001000 107 | if pullup: 108 | bits = bits | 0b0010000 109 | if input: 110 | bits = bits | 0b0100000 111 | if slew: 112 | bits = bits | 0b1000000 113 | 114 | offset = P[i]['offset'] 115 | pru_assignable = bool(filter(lambda m: "pru" in str(m), \ 116 | P[i]['modes'])) 117 | if pru_assignable and offset != None and bits != P[i]['cfg']: 118 | pin = {} 119 | if P == P8: 120 | pin['header'] = "P8" 121 | else: 122 | pin['header'] = "P9" 123 | pin['pin_num'] = i 124 | pin['offset'] = offset 125 | pin['bits'] = bits 126 | pins.append(pin) 127 | 128 | if pins or pruss_enabled() != enable_pruss: 129 | unload_slot(dts_name) 130 | 131 | dts = template(dts_name, part_num=dts_name, version=dts_ver, \ 132 | pins=pins, status=status) 133 | root_firmware_dir = '/lib/firmware/' 134 | dts_filename = dts_name + "-" + dts_ver + ".dts" 135 | full_dts_path = root_firmware_dir + dts_filename 136 | f = open(full_dts_path, "w") 137 | f.write(dts) 138 | print dts 139 | f.flush() 140 | f.close() 141 | 142 | dtbo_filename = dts_name + "-" + dts_ver + ".dtbo" 143 | full_dtbo_path = root_firmware_dir + dtbo_filename 144 | subprocess.call(["dtc", "-O", "dtb", "-I", "dts", "-o", full_dtbo_path, "-b", \ 145 | "0", "-@", full_dts_path]) 146 | 147 | load_slot(dts_name) 148 | 149 | time.sleep(0.25) 150 | 151 | redirect('/pru/pinmux') 152 | 153 | run(host='192.168.7.2', port=8081) 154 | -------------------------------------------------------------------------------- /Cyclops IDE/term-proj/web/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sudo python start.py 4 | -------------------------------------------------------------------------------- /FullImage/.gitattributes: -------------------------------------------------------------------------------- 1 | *.xz filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /FullImage/README.md: -------------------------------------------------------------------------------- 1 | The nesl-qot-4.1.12-bone-rt-r16-4gb image is available at the following link 2 | [link](https://drive.google.com/file/d/1BbqrlW7soqthktslKXc-ADzNKqw2H8XY/view?usp=share_link). 3 | 4 | 5 | # UCLA NESL PRU System Images 6 | 7 | This repository holds the OS images for working on the NESL PRU library. 8 | The images have all the necessary software dependencies installed and configured. 9 | This is aimed to provide a reproducible environment for anyone who wants wants to get involved in the project. 10 | 11 | ## How to Flash to SD Card 12 | 13 | Download [nesl-qot-4.1.12-bone-rt-r16-4gb.img.xz](https://github.com/nesl/Cyclops-PRU/blob/master/FullImage/images/nesl-qot-4.1.12-bone-rt-r16-4gb.img.xz). 14 | 15 | 16 | After decompressing the image with `xz`, copy the image to an SD card with the `dd` command. Find the device node of your SD card. In my case it happens to be `/dev/rdisk2`, but this most likely will **NOT** be the case for you. If you copy to the wrong device node, you may **erase your hard disk**. 17 | 18 | ``` 19 | xz -d nesl-qot-4.1.12-bone-rt-r16-4gb.img.xz 20 | sudo dd bs=1m if=nesl-qot-4.1.12-bone-rt-r16-4gb.img of=/dev/rdisk2 21 | ``` 22 | If you want to create your own image or understand how we built our image, see [here](https://github.com/nesl/Cyclops-PRU/blob/master/FullImage/images/README.md). 23 | -------------------------------------------------------------------------------- /FullImage/images/BBB-IMAGE-QOT-23MAR2017-6PM.img.xz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:90741f2720317fe67c8e418c813b27ecc29bda39a5b0d54348566b6ec13d7061 3 | size 986469232 4 | -------------------------------------------------------------------------------- /FullImage/images/BBB-IMAGE-QOT-28MAR2017-size.txt: -------------------------------------------------------------------------------- 1 | size 7744782336 bytes 2 | -------------------------------------------------------------------------------- /FullImage/images/BBB-IMAGE-QOT-28MAR2017.img.xz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:9b907d0133f36d656bbd327380a2a581a123603b9a524a7339b73e42b793249a 3 | size 983497588 4 | -------------------------------------------------------------------------------- /FullImage/images/BBB-IMAGE-QOT-STACK-FATIMA.img.xz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ee2c58e2e06b7aed31857ff850bb1cf1030c8cf6ab7b7aad7dd2591eb05fdf43 3 | size 630223316 4 | -------------------------------------------------------------------------------- /FullImage/images/README.md: -------------------------------------------------------------------------------- 1 | ### 4.1.12-bone-rt with QoT 2 | I recommend using the [nesl-qot-4.1.12-bone-rt-r16-4gb](https://drive.google.com/file/d/0B-N9bMQfpW6gdUFLUjVvVHR0ZFk/view?usp=sharing) image which has the QoT stack installed. 3 | You will neet the QoT stack in order to run the time synchronization examples. 4 | 5 | ### 3.8.13-bone50 Vanilla 6 | Below, I describe the steps for creating the [debian-7.5-kernel-3.8.13-bone50-16gb-nesl](https://github.com/yifanz/ucla-nesl-pru-sys-images/blob/master/images/debian-7.5-kernel-3.8.13-bone50-16gb-nesl.img.xz) image. 7 | You only need to read this if you want to make your own image. 8 | 9 | I built my image based on the official [`Debian 7.5 (BeagleBone, BeagleBone Black - 2GB SD) 2014-05-14`](https://debian.beagleboard.org/images/bone-debian-7.5-2014-05-14-2gb.img.xz) image which has the `3.8.13-bone50` kernel. 10 | I don't recommend the newer versions for the following reasons: USB ethernet instability, significantly slower boot time and the latest TI kernels force you to use `remote_proc` instead of the better documented and tested `prussdrv` for interfacing with the PRUs. You can copy the image to an SD card with the `dd` command. Find the device node of your SD card. In my case it is `/dev/rdisk2`, but this most likely will NOT be the case for you. If you copy to the wrong device node, you may erase your hard disk. 11 | 12 | ``` 13 | sudo dd bs=1m if=bone-debian-7.5-2014-05-14-2gb.img of=/dev/rdisk2 14 | ``` 15 | 16 | You can terminal into the device as `root` without a password. I'm using USB over ethernet which defaults to `192.168.7.2`. You may need to use a different IP address. 17 | 18 | ``` 19 | ssh root@192.168.7.2 20 | ``` 21 | 22 | First, expand the available storage. Although you only need a 2GB SD card to hold the base image, I'm using a 16 GB SD card. 23 | 24 | ``` 25 | cd /opt/scripts/tools 26 | ./grow_partition.sh 27 | ``` 28 | 29 | I recommend disabling HDMI and eMMC because they occupy too many of the PRU's pins. 30 | In `/boot/uboot/uEnv.txt` uncomment this: 31 | 32 | ``` 33 | ##BeagleBone Black: 34 | ##Disable HDMI/eMMC 35 | cape_disable=capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN,BB-BONE-EMMC-2G 36 | ``` 37 | 38 | Later, when you want to load your own custom overlays on bootup you can uncomment this and add the names of your overlays: 39 | 40 | ``` 41 | ##Example 42 | #cape_disable=capemgr.disable_partno= 43 | cape_enable=capemgr.enable_partno=NESL-PRU,cape-universal 44 | ``` 45 | 46 | Then, `reboot` to apply the changes. You can check if it worked like this: 47 | 48 | ``` 49 | root@beaglebone:/sys/devices/bone_capemgr.9# cat slots 50 | 0: 54:PF--- 51 | 1: 55:PF--- 52 | 2: 56:PF--- 53 | 3: 57:PF--- 54 | 4: ff:P-O-- Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G 55 | 5: ff:P-O-- Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI 56 | 6: ff:P-O-- Bone-Black-HDMIN,00A0,Texas Instrument,BB-BONELT-HDMIN 57 | ``` 58 | 59 | Notice that the `L` is missing from `ff:P-O-L` which means that those overlays are not loaded. 60 | 61 | If you are also using ethernet over USB, then you may need to run [`bbb-usb-net-gateway.sh`](https://github.com/yifanz/ucla-nesl-pru-lib/blob/master/scripts/bbb-usb-net-gateway.sh) on the device and [`host-usb-net-forwarding.sh`](https://github.com/yifanz/ucla-nesl-pru-lib/blob/master/scripts/host-usb-net-forwarding.sh) on the host to be able to access the internet. 62 | Make sure you update the variables in those scripts to match your network interfaces. 63 | If you run into DNS issues, you can try adding `nameserver 8.8.8.8` to `/etc/resolv.conf`. 64 | 65 | Next, install the [PRU code generation tools](http://software-dl.ti.com/codegen/non-esd/downloads/beta.htm) from TI. I'm using `v2.0.0 Beta 2` for `ARM`. Newer versions are available, but this one has better documentation and more code examples. You have to create a TI account and agree to their license. Once you do, you will be allowed to download a 40MB file called `ti_cgt_pru_2.0.0B2_armlinuxa8hf_installer.sh`. Executing it will install the tools in `pru_2.0.0B2/` under the current working directory. 66 | 67 | It is helpful to have `git` setup so you can share code. Here is an example of how to setup your `.gitconfig`. 68 | 69 | ``` 70 | [http] 71 | sslverify = false 72 | [user] 73 | name = Yi-Fan Zhang 74 | email = yifanzhang@engineering.ucla.edu 75 | ``` 76 | 77 | I would `git clone` this project as well as Derek Molloy's [exploringBB project](https://github.com/derekmolloy/exploringBB). Much of the code in this project uses code from exploringBB as a template. You should also install the latest `AM335x PRU Package` which contains `libprussdrv`. 78 | 79 | ``` 80 | git clone https://github.com/beagleboard/am335x_pru_package.git 81 | cd am335x_pru_package 82 | make CROSS_COMPILE="" 83 | make install PREFIX=/usr CROSS_COMPILE="" 84 | ``` 85 | -------------------------------------------------------------------------------- /FullImage/images/debian-7.5-kernel-3.8.13-bone50-16gb-nesl.img.xz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:4ee0c53a1ad1756a1ac55f3775df6aad956dba9f3188ad77f77fe8f45f1d3430 3 | size 1042648500 4 | -------------------------------------------------------------------------------- /FullImage/images/nesl-qot-4.1.12-bone-rt-r16-4gb.img.xz: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:ebe06897ae6df4fe6550bb352e76ac22d9c8f904b07d73308a646b289a11963f 3 | size 1006653000 4 | --------------------------------------------------------------------------------