Hello,
I am having some trouble operating the PRU on the AM3358, specifically on the BeagleBone Black. I ran the example "PRU_memAccess_DDR_PRUsharedRAM" from https://github.com/beagleboard/am335x_pru_package with no problems. Then, in the course of developing my own code which ran on the PRU, the PRU began to hang when trying to write to DDR memory. Note that the OCP master port IS enabled.
Then, I found that sometimes, AFTER rebooting, the PRU would still hang when running other code known not to hang!
Attached is my code. I've commented out some of the parts that are supposed to write to DDR memory for testing. Please let me know how I can read and write to DDR memory in the PRU without having it hang!
Thanks,
William Kalfus
ddrmemtest.c:
#include <stdio.h>
#include "prussdrv.h"
#include <pruss_intc_mapping.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdlib.h>
#define PRU_CODE_FILE "additiontest.bin"
int main() {
int mem_fd = open("/dev/mem", O_RDWR);
if(mem_fd < 0) {
printf("Failed to open /dev/mem");
return -1;
}
void* ddr_mem = mmap(0, 0xFFFFFFF, PROT_WRITE|PROT_READ, MAP_SHARED, mem_fd, 0x80000000);
if(ddr_mem == NULL) {
printf("Failed to map device");
close(mem_fd);
return -1;
}
void* DDR = ddr_mem;
// Take in the value to store
printf("Enter the value to store: ");
scanf("%d", (unsigned int*)DDR);
// Initialize the PRU
printf("Initializing PRU...\n");
prussdrv_init();
int ret = prussdrv_open(PRU_EVTOUT_0);
if(ret) {
printf("opening PRU failed\n");
return ret;
}
// Configure the PRU Interrupts
tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
prussdrv_pruintc_init(&pruss_intc_initdata);
// Write the addresses of addend1 and addend2 into PRU data memory
printf("Loading data into PRU memory...\n");
void* pru0_datamem;
prussdrv_map_prumem(PRUSS0_PRU0_DATARAM, &pru0_datamem);
unsigned int* pru0_datamem_int = (unsigned int*)pru0_datamem;
printf("Address %d\n", (unsigned int)DDR);
pru0_datamem_int[0] = (unsigned int)DDR;
// Now load the PRU code and run it
printf("Loading PRU code and executing...\n");
prussdrv_exec_program(0 /* PRU0 */, PRU_CODE_FILE);
// Wait for the PRU to finish executing the code
printf("Waiting for PRU to halt...\n");
prussdrv_pru_wait_event(PRU_EVTOUT_0);
printf("PRU halted.\n");
prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
void* sharedMem;
prussdrv_map_prumem(PRUSS0_SHARED_DATARAM, &sharedMem);
unsigned int* sharedMem_int = (unsigned int*) sharedMem;
// The PRU will store the value at 0x0001_2000, which is 0x2000 bytes
// into the shared memory, so it's index 0x2000/4 = 0x800
unsigned int res = sharedMem_int[0x800];
// Read the result
printf("Result: %d\n", res);
// Close the PRU
prussdrv_pru_disable(0);
prussdrv_exit();
munmap(ddr_mem, 0x0FFFFFFF);
close(mem_fd);
return 0;
}
ddrmemtest.p:
// PRU Addition Test
// The address of addend 1 is stored in Data Ram address 0, addend 2 is in 1,
// and the result in 3
.origin 0
.entrypoint ADDITION
#define CONST_PRUCFG C4
#define CTPPR_0 0x22028
#define CTPPR_1 0x2202C
ADDITION:
// Enable OCP master port
LBCO R0, CONST_PRUCFG, 4, 4
CLR R0, R0, 4
SBCO R0, CONST_PRUCFG, 4, 4
// Set C28 to 0x0001_2000
MOV R0, 0x00000120
MOV R1, CTPPR_0
SBBO R0, R1, 0, 4
MOV R0, 0x00100000
MOV R1, CTPPR_1
SBBO R0, R1, 0, 4
LDI R0, 0x7
//SBCO R0, C31,0, 4
// Read the value address into R0
//LBCO R0, C24, 0, 4
// Now load the value itself into R1
//LBBO R1, R0, 0, 4
// Store the result in shared memory
SBCO R1, C28, 0, 4
// Finished, notify the host and halt
// Remember: R31 is special - writing to it generates interrupts
// To decode the value written:
// The host is waiting for PRU_EVTOUT0
// In pruss_intc_mapping.h (line 101), PRU_EVTOUT0 is mapped to CHANNEL2
// In the same file (line 100), CHANNEL2 is mapped to PRU0_ARM_INTERRUPT
// In the same file (line 52), we can see that this is number 19
// Checking the PRU reference guide (Section 7), we can see that int 19
// corresponds to pr1_pru_mst_intr[3]_intr_req
// According to Section 4.4.1.2.2 of the TRM, to fire the interrupt, bit
// 5 of R31 must be 1 and bits 3:0 must be the value 3 (because of the
// value in brackets of the interrupt)
// Thus, we write to R31 (1 << 5) + 3 = 35
MOV R31.b0, 35
HALT