summaryrefslogtreecommitdiff
path: root/src/pru
diff options
context:
space:
mode:
Diffstat (limited to 'src/pru')
-rw-r--r--src/pru/AM335x_PRU.cmd86
-rw-r--r--src/pru/intc_map.h81
-rw-r--r--src/pru/pru_pwm.c102
-rw-r--r--src/pru/pwm_test.c80
-rw-r--r--src/pru/resource_table_empty.h38
5 files changed, 387 insertions, 0 deletions
diff --git a/src/pru/AM335x_PRU.cmd b/src/pru/AM335x_PRU.cmd
new file mode 100644
index 0000000..b62f044
--- /dev/null
+++ b/src/pru/AM335x_PRU.cmd
@@ -0,0 +1,86 @@
+/****************************************************************************/
+/* AM335x_PRU.cmd */
+/* Copyright (c) 2015 Texas Instruments Incorporated */
+/* */
+/* Description: This file is a linker command file that can be used for */
+/* linking PRU programs built with the C compiler and */
+/* the resulting .out file on an AM335x device. */
+/****************************************************************************/
+
+-cr /* Link using C conventions */
+
+/* Specify the System Memory Map */
+MEMORY
+{
+ PAGE 0:
+ PRU_IMEM : org = 0x00000000 len = 0x00002000 /* 8kB PRU0 Instruction RAM */
+
+ PAGE 1:
+
+ /* RAM */
+
+ PRU_DMEM_0_1 : org = 0x00000000 len = 0x00002000 CREGISTER=24 /* 8kB PRU Data RAM 0_1 */
+ PRU_DMEM_1_0 : org = 0x00002000 len = 0x00002000 CREGISTER=25 /* 8kB PRU Data RAM 1_0 */
+
+ PAGE 2:
+ PRU_SHAREDMEM : org = 0x00010000 len = 0x00003000 CREGISTER=28 /* 12kB Shared RAM */
+
+ DDR : org = 0x80000000 len = 0x00000100 CREGISTER=31
+ L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30
+
+
+ /* Peripherals */
+
+ PRU_CFG : org = 0x00026000 len = 0x00000044 CREGISTER=4
+ PRU_ECAP : org = 0x00030000 len = 0x00000060 CREGISTER=3
+ PRU_IEP : org = 0x0002E000 len = 0x0000031C CREGISTER=26
+ PRU_INTC : org = 0x00020000 len = 0x00001504 CREGISTER=0
+ PRU_UART : org = 0x00028000 len = 0x00000038 CREGISTER=7
+
+ DCAN0 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14
+ DCAN1 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15
+ DMTIMER2 : org = 0x48040000 len = 0x0000005C CREGISTER=1
+ PWMSS0 : org = 0x48300000 len = 0x000002C4 CREGISTER=18
+ PWMSS1 : org = 0x48302000 len = 0x000002C4 CREGISTER=19
+ PWMSS2 : org = 0x48304000 len = 0x000002C4 CREGISTER=20
+ GEMAC : org = 0x4A100000 len = 0x0000128C CREGISTER=9
+ I2C1 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2
+ I2C2 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17
+ MBX0 : org = 0x480C8000 len = 0x00000140 CREGISTER=22
+ MCASP0_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8
+ MCSPI0 : org = 0x48030000 len = 0x000001A4 CREGISTER=6
+ MCSPI1 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16
+ MMCHS0 : org = 0x48060000 len = 0x00000300 CREGISTER=5
+ SPINLOCK : org = 0x480CA000 len = 0x00000880 CREGISTER=23
+ TPCC : org = 0x49000000 len = 0x00001098 CREGISTER=29
+ UART1 : org = 0x48022000 len = 0x00000088 CREGISTER=11
+ UART2 : org = 0x48024000 len = 0x00000088 CREGISTER=12
+
+ RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10
+ RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13
+ RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21
+ RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27
+
+}
+
+/* Specify the sections allocation into memory */
+SECTIONS {
+ /* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading
+ an ELF file, but useful when loading a binary */
+ .text:_c_int00* > 0x0, PAGE 0
+
+ .text > PRU_IMEM, PAGE 0
+ .stack > PRU_DMEM_0_1, PAGE 1
+ .bss > PRU_DMEM_0_1, PAGE 1
+ .cio > PRU_DMEM_0_1, PAGE 1
+ .data > PRU_DMEM_0_1, PAGE 1
+ .switch > PRU_DMEM_0_1, PAGE 1
+ .sysmem > PRU_DMEM_0_1, PAGE 1
+ .cinit > PRU_DMEM_0_1, PAGE 1
+ .rodata > PRU_DMEM_0_1, PAGE 1
+ .rofardata > PRU_DMEM_0_1, PAGE 1
+ .farbss > PRU_DMEM_0_1, PAGE 1
+ .fardata > PRU_DMEM_0_1, PAGE 1
+
+ .resource_table > PRU_DMEM_0_1, PAGE 1
+}
diff --git a/src/pru/intc_map.h b/src/pru/intc_map.h
new file mode 100644
index 0000000..eebf27b
--- /dev/null
+++ b/src/pru/intc_map.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _INTC_MAP_0_H_
+#define _INTC_MAP_0_H_
+
+/*
+ * ======== PRU INTC Map ========
+ *
+ * Define the INTC mapping for interrupts going to the ICSS / ICSSG:
+ * ICSS Host interrupts 0, 1
+ * ICSSG Host interrupts 0, 1, 10-19
+ *
+ * Note that INTC interrupts going to the ARM Linux host should not be defined
+ * in this file (ICSS/ICSSG Host interrupts 2-9).
+ *
+ * The INTC configuration for interrupts going to the ARM host should be defined
+ * in the device tree node of the client driver, "interrupts" property.
+ * See Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.yaml
+ * entry #interrupt-cells for more.
+ *
+ * For example, on ICSSG:
+ *
+ * &client_driver0 {
+ * interrupt-parent = <&icssg0_intc>;
+ * interrupts = <21 2 2>, <22 3 3>;
+ * interrupt-names = "interrupt_name1", "interrupt_name2";
+ * };
+ *
+ */
+
+#include <stddef.h>
+#include <rsc_types.h>
+
+/*
+ * .pru_irq_map is used by the RemoteProc driver during initialization. However,
+ * the map is NOT used by the PRU firmware. That means DATA_SECTION and RETAIN
+ * are required to prevent the PRU compiler from optimizing out .pru_irq_map.
+ */
+#pragma DATA_SECTION(my_irq_rsc, ".pru_irq_map")
+#pragma RETAIN(my_irq_rsc)
+
+struct pru_irq_rsc my_irq_rsc = {
+ 0, /* type = 0 */
+ 1, /* number of system events being mapped */
+ {
+ {7, 1, 1}, /* {sysevt, channel, host interrupt} */
+ },
+};
+
+#endif /* _INTC_MAP_0_H_ */
diff --git a/src/pru/pru_pwm.c b/src/pru/pru_pwm.c
new file mode 100644
index 0000000..796040b
--- /dev/null
+++ b/src/pru/pru_pwm.c
@@ -0,0 +1,102 @@
+#include <stdint.h>
+#include <pru_cfg.h>
+#include <pru_intc.h>
+#include <pru_iep.h>
+#include "intc_map.h"
+#include "resource_table_empty.h"
+
+#define CYCLES_PER_SECOND 200000000
+#define CYCLES_PER_PERIOD (CYCLES_PER_SECOND / 800)
+#define DEFAULT_DUTY_CYCLE 0
+#define P8_12 (1 << 14)
+#define P8_12_n ~(1 << 14)
+#define PRU0_DRAM 0x00000 // Offset to DRAM
+#define PRU_TIMER_PASSCODE 0x31138423
+#define BURN_TIME 2 // seconds for motor burn
+
+volatile uint32_t *pru0_dram = (uint32_t *) (PRU0_DRAM + 0x200);
+
+
+volatile register uint32_t __R30;
+volatile register uint32_t __R31;
+
+
+void main(void) {
+ uint32_t duty_cycle = DEFAULT_DUTY_CYCLE;
+ uint32_t off_cycles = ((100 - duty_cycle) * CYCLES_PER_PERIOD / 100);
+ uint32_t on_cycles = ((100 - (100 - duty_cycle)) * CYCLES_PER_PERIOD / 100);
+ uint32_t off_count = off_cycles;
+ uint32_t on_count = on_cycles;
+ *pru0_dram = duty_cycle;
+
+ /* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
+ CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
+
+ while (1) {
+ if (pru0_dram[1] == PRU_TIMER_PASSCODE) {
+ /* Disable counter */
+ CT_IEP.TMR_GLB_CFG_bit.CNT_EN = 0;
+
+ /* Reset Count register */
+ CT_IEP.TMR_CNT = 0x0;
+
+ /* Clear overflow status register */
+ CT_IEP.TMR_GLB_STS_bit.CNT_OVF = 0x1;
+
+ /* Set compare value */
+ CT_IEP.TMR_CMP0 = (BURN_TIME * CYCLES_PER_SECOND); // 10 seconds @ 200MHz
+
+ /* Clear compare status */
+ CT_IEP.TMR_CMP_STS_bit.CMP_HIT = 0xFF;
+
+ /* Disable compensation */
+ CT_IEP.TMR_COMPEN_bit.COMPEN_CNT = 0x0;
+
+ /* Enable CMP0 and reset on event */
+ CT_IEP.TMR_CMP_CFG_bit.CMP0_RST_CNT_EN = 0x1;
+ CT_IEP.TMR_CMP_CFG_bit.CMP_EN = 0x1;
+
+ /* Clear the status of all interrupts */
+ CT_INTC.SECR0 = 0xFFFFFFFF;
+ CT_INTC.SECR1 = 0xFFFFFFFF;
+
+ /* Enable counter */
+ CT_IEP.TMR_GLB_CFG = 0x11;
+ break;
+ }
+ }
+
+ /* Poll until R31.31 is set */
+ do {
+ while ((__R31 & 0x80000000) == 0) {
+ }
+ /* Verify that the IEP is the source of the interrupt */
+ } while ((CT_INTC.SECR0 & (1 << 7)) == 0);
+
+ /* Disable counter */
+ CT_IEP.TMR_GLB_CFG_bit.CNT_EN = 0x0;
+
+ /* Disable Compare0 */
+ CT_IEP.TMR_CMP_CFG = 0x0;
+
+ /* Clear Compare status */
+ CT_IEP.TMR_CMP_STS = 0xFF;
+
+ /* Clear the status of the interrupt */
+ CT_INTC.SECR0 = (1 << 7);
+
+ while (1) {
+ if (on_count) {
+ __R30 |= P8_12; // Set the GPIO pin to 1
+ on_count--;
+ __delay_cycles(3);
+ } else if (off_count) {
+ __R30 &= P8_12_n; // Clear the GPIO pin
+ off_count--;
+ } else {
+ duty_cycle = *pru0_dram;
+ off_count = ((100 - duty_cycle) * CYCLES_PER_PERIOD / 100);
+ on_count = ((100 - (100 - duty_cycle)) * CYCLES_PER_PERIOD / 100);
+ }
+ }
+}
diff --git a/src/pru/pwm_test.c b/src/pru/pwm_test.c
new file mode 100644
index 0000000..df8bbf0
--- /dev/null
+++ b/src/pru/pwm_test.c
@@ -0,0 +1,80 @@
+/*
+ *
+ * pwm tester
+ * The on cycle and off cycles are stored in each PRU's Data memory
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#define PRU_ADDR 0x4A300000 // Start of PRU memory Page 184 am335x TRM
+#define PRU_LEN 0x80000 // Length of PRU memory
+#define PRU0_DRAM 0x00000 // Offset to DRAM
+#define PRU1_DRAM 0x02000
+#define PRU_SHAREDMEM 0x10000 // Offset to shared memory
+
+#define CYCLES_PER_SECOND 200000000
+#define CYCLES_PER_PERIOD (CYCLES_PER_SECOND / 800)
+
+uint32_t *pru0DRAM_32int_ptr; // Points to the start of local DRAM
+uint32_t *pru1DRAM_32int_ptr; // Points to the start of local DRAM
+uint32_t *prusharedMem_32int_ptr; // Points to the start of the shared memory
+
+/*******************************************************************************
+* int start_pwm_count(int ch, int countOn, int countOff)
+*
+* Starts a pwm pulse on for countOn and off for countOff to a single channel (ch)
+*******************************************************************************/
+int start_pwm_count(uint32_t duty_cycle) {
+ uint32_t *pruDRAM_32int_ptr = pru0DRAM_32int_ptr;
+ uint32_t old_duty_cycle = pruDRAM_32int_ptr[0];
+ uint32_t old_count_on = (100 - (100 - old_duty_cycle)) * CYCLES_PER_PERIOD / 100;
+ uint32_t old_count_off = (100 - old_duty_cycle) * CYCLES_PER_PERIOD / 100;
+ uint32_t new_count_on = (100 - (100 - duty_cycle)) * CYCLES_PER_PERIOD / 100;
+ uint32_t new_count_off = (100 - duty_cycle) * CYCLES_PER_PERIOD / 100;
+
+ printf("old:\n\tcountOn: %d, countOff: %d, count: %d\nnew:\n\tcountOn: %d, countOff: %d, count: %d\n", old_count_on, old_count_off, old_count_off + old_count_on, new_count_on, new_count_off, new_count_off + new_count_on);
+ // write to PRU shared memory
+ pruDRAM_32int_ptr[0] = duty_cycle; // On time
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ uint32_t *pru; // Points to start of PRU memory.
+ int fd;
+ printf("Servo tester\n");
+
+ fd = open ("/dev/mem", O_RDWR | O_SYNC);
+ if (fd == -1) {
+ printf ("ERROR: could not open /dev/mem.\n\n");
+ return 1;
+ }
+ pru = mmap (0, PRU_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PRU_ADDR);
+ if (pru == MAP_FAILED) {
+ printf ("ERROR: could not map memory.\n\n");
+ return 1;
+ }
+ close(fd);
+ printf ("Using /dev/mem.\n");
+
+ pru0DRAM_32int_ptr = pru + PRU0_DRAM/4 + 0x200/4; // Points to 0x200 of PRU0 memory
+ pru1DRAM_32int_ptr = pru + PRU1_DRAM/4 + 0x200/4; // Points to 0x200 of PRU1 memory
+ prusharedMem_32int_ptr = pru + PRU_SHAREDMEM/4; // Points to start of shared memory
+
+ uint32_t desired_duty_cycle = 0;
+ while (1) {
+ printf("Enter a duty cycle: ");
+ scanf("%d", &desired_duty_cycle);
+ start_pwm_count(desired_duty_cycle);
+ }
+
+ if(munmap(pru, PRU_LEN)) {
+ printf("munmap failed\n");
+ } else {
+ printf("munmap succeeded\n");
+ }
+}
diff --git a/src/pru/resource_table_empty.h b/src/pru/resource_table_empty.h
new file mode 100644
index 0000000..8e7743e
--- /dev/null
+++ b/src/pru/resource_table_empty.h
@@ -0,0 +1,38 @@
+/*
+ * ======== resource_table_empty.h ========
+ *
+ * Define the resource table entries for all PRU cores. This will be
+ * incorporated into corresponding base images, and used by the remoteproc
+ * on the host-side to allocated/reserve resources. Note the remoteproc
+ * driver requires that all PRU firmware be built with a resource table.
+ *
+ * This file contains an empty resource table. It can be used either as:
+ *
+ * 1) A template, or
+ * 2) As-is if a PRU application does not need to configure PRU_INTC
+ * or interact with the rpmsg driver
+ *
+ */
+
+#ifndef _RSC_TABLE_PRU_H_
+#define _RSC_TABLE_PRU_H_
+
+#include <stddef.h>
+#include <rsc_types.h>
+
+struct my_resource_table {
+ struct resource_table base;
+
+ uint32_t offset[1]; /* Should match 'num' in actual definition */
+};
+
+#pragma DATA_SECTION(pru_remoteproc_ResourceTable, ".resource_table")
+#pragma RETAIN(pru_remoteproc_ResourceTable)
+struct my_resource_table pru_remoteproc_ResourceTable = {
+ 1, /* we're the first version that implements this */
+ 0, /* number of entries in the table */
+ 0, 0, /* reserved, must be zero */
+ 0, /* offset[0] */
+};
+
+#endif /* _RSC_TABLE_PRU_H_ */