diff options
Diffstat (limited to 'src/pru')
| -rw-r--r-- | src/pru/AM335x_PRU.cmd | 86 | ||||
| -rw-r--r-- | src/pru/intc_map.h | 81 | ||||
| -rw-r--r-- | src/pru/pru_pwm.c | 102 | ||||
| -rw-r--r-- | src/pru/pwm_test.c | 80 | ||||
| -rw-r--r-- | src/pru/resource_table_empty.h | 38 |
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_ */ |
