Forums » Software Development »
PRU_gpioToggle example fails sometimes
Added by Andrew Bean over 8 years ago
I'm having multiple issues with the PRU example PRU_gpioToggle. In short, it seems like some read/write operations to memory mapped locations are not always executing properly. The two problem spots are the following:
1) In the example, PRU0 R30 has two bits inverted. The initial value is read through a mmap mechanism, and the final value is read through the same pointer. The example checks whether the initial and final states of R30 are as expected. Sometimes this fails (about 10-20% of the time). I was able to work around this by reading the final state of R30 using a separate pointer with a new mmap() to the same physical location.
2) In the example, the ARM synchronizes with the PRU several times using the following interrupt mechanism:
// .... stuff
prussdrv_pru_wait_event (PRU_EVTOUT_0);
prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT);
// .... more stuff
prussdrv_pru_wait_event (PRU_EVTOUT_0);
prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT);
// .... more stuff
However, the clear_event() call seems not to stall until the interrupt status flag is actually cleared, at least as observed by wait_event(). Hence, wait_event() often is triggered by an event that should have already been cleared.
I have everything set up as follows:
- recompiled the kernel 3.2.0+ ensuring that PRU is enabled in the kernel (not module).
- used MDK_2014-01-13 full root fs (plus newly compiled kernel modules) and recompiled kernel to follow the "Updating devkit to latest MDK" article
Replies (5)
RE: PRU_gpioToggle example fails sometimes - Added by Bob Duke over 8 years ago
Andrew,
Another user was able to successfully run the demos on the MityDSP-L138, but perhaps they didn't test things as strenuously as you did.
<https://support.criticallink.com/redmine/boards/10/topics/4026>
Regarding point 2, do you think this causes the example to fail even after you use the work-around mentioned in point 1?
RE: PRU_gpioToggle example fails sometimes - Added by Andrew Bean over 8 years ago
This seems to be the same as one of the issues that Jonathan Cormier observed in the topic that you linked. E.g., "gpioToggle test passed when i just ran it. Not sure why." whereas he had earlier posted that it failed.
As for trying the workaround from 1 to solve 2, I will need to modify the prussdrv code, but I think it should be doable. This would be on the clear_event() side of things, as that is done simply by writing an appropriate value to one of the device registers. If the issue is on the wait_event() side with the blocking read() on the file descriptor for the interrupt, then I would be at a loss for how to debug that issue. As for why it works (if it works...), I really have no idea. It was just something I randomly tried. I'm somewhat expecting repeated calls to mmap() to be too slow for it to be a practical workaround, though perhaps I'm wrong there.
I'll post anything I find out.
RE: PRU_gpioToggle example fails sometimes - Added by Andrew Bean over 8 years ago
So this is strange. I modified the gpioToggle code to have the following:
static unsigned short LOCAL_examplePassed ( ) { // start new code mem_pruReg30_2 = mmap(0, 0x00000FFF, PROT_WRITE | PROT_READ, MAP_SHARED, mem_fd, 0x01C37000); if (mem_pruReg30_2 == NULL) { printf("Failed to map the device (%s)\n", strerror(errno)); close(mem_fd); return -1; } mem_pruReg30_2 += 0x478; // end new code /* Read final state of reg30 */ reg30_finalState = *(unsigned long*) mem_pruReg30; // start new code reg30_finalState2 = *(unsigned long*) mem_pruReg30_2; printf("reg30 initState = %d\n",reg30_initState); printf("reg30 finalState2 = %d\n",reg30_finalState2); printf("reg30 finalState = %d\n",reg30_finalState); munmap(mem_pruReg30_2, 0x00000FFF); // end new code /* Check bits 30 and 31 in reg30 are inverted */ if ((reg30_initState ^ reg30_finalState) != 0xC0000000) { return FALSE; } return TRUE; }
Note that *(unsigned long*) mem_pruReg30
and *(unsigned long*) mem_pruReg30_2
should be equal at all times, since they point to the same PRU0 memory mapped register. However, upon running the example a number of times, it is observed that this is not always the case. This is what I mention in my first post in issue 1). *(unsigned long*) mem_pruReg30_2
seems to always be the correct value.
I also tried modifying int prussdrv_pru_clear_event(unsigned int eventnum)
to use a new mmap() and munmap() at every call, but this did not fix the clear_event issue.
RE: PRU_gpioToggle example fails sometimes - Added by Andrew Bean over 8 years ago
In static int LOCAL_exampleInit ( unsigned short prunum )
of PRU_gpioToggle.c we need to have
/* open the device */ mem_fd = open("/dev/mem", O_RDWR|O_SYNC);
This fixes the issue with reading the value of PRU0 R30.
I have not yet figured out the issue with the PRU to ARM interrupt.
RE: PRU_gpioToggle example fails sometimes - Added by Andrew Bean over 8 years ago
So, I've been playing around with the example code more to try to get the interrupt wait() and clear() to work.
This is how it is supposed to work:
printf("Waiting for interrupt.\r\n"); prussdrv_pru_wait_event (PRU_EVTOUT_0); printf("Clear the interrupt.\r\n"); prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT); printf("Interrupt cleared.\r\n");
Of course, the issue is that it doesn't work. What does seem to be working is the following:
printf("Waiting for interrupt.\r\n"); prussdrv_pru_wait_event (PRU_EVTOUT_0); printf("Clear the interrupt.\r\n"); // first clear prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT); // need another wait() prussdrv_pru_wait_event (PRU_EVTOUT_0); // need another clear() prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT); printf("Interrupt cleared.\r\n");
In playing around with this, I have needed both the extra
prussdrv_pru_wait_event(PRU_EVTOUT_0)
and the extra prussdrv_pru_clear_event(PRU0_ARM_INTERRUPT)
.
If anyone has any ideas on the cause or how to fix this issue, I'd love to hear them cuz I'm all out of ideas.