I’ve been using the PRUSS on the OMAP-L138 for bit-banged SPI reading data from an external ADC, stuffing it to DDR and then generating an interrupt for the DSP when a block of data is ready. Now I’m trying to get one of them to wait for an event from ECAP1. I am setting up the ECAP1 module in APWM mode to generate an interrupt on CNTR=PRD. I wrote a little test PRU program that looks like what I’ve pasted below.
MAIN:
CALL1 ECAP_SYNC_SETUP
MAIN_LOOP:
// wait for sync (generated by ECAP event)
ECAP_SYNC_WAIT
ECAP_SYNC_ACK
SET r30, r30, 16
// wait for sync (generated by ECAP event)
ECAP_SYNC_WAIT
ECAP_SYNC_ACK
CLR r30, r30, 16
// wait for another sync
QBA MAIN_LOOP
The ECAP1 module is generating a 60Hz wave. The point of the test program is just to generate a 30Hz output wave that is synchronized to the ECAP's output. The problem I’m having is that this code is generating about a 5.5MHz output wave (the frequency purely depends on the number of instructions in my loop, the PRU is never waiting). This happens as soon as I enable the system event and have it mapped to the correct channel and host interrupt (and have the host interrupt enabled). If I turn the ECAP module on/off it makes no difference, so it’s clearly being fed somehow else. I’m not sure from where. I added some XML files for Code Composer for the PRU and PRU interrupt controller registers so I can see what’s going on a little more, but not reliably with the PRU registers since I can’t see them while the PRU is enabled and when I disable it they show up but look like junk. Doing this, though, I can map various events into channel 1/host 1 and regardless I get this 5.5MHz output wave. It could be that my ECAP_SYNC_WAIT calls aren’t doing what I want them to. Any thoughts?
Here’s ECAP_SYNC_WAIT:
.macro ECAP_SYNC_WAIT
SYNC_WAIT:
QBBC SYNC_WAIT, r31, #31
.endm
It’s also possible that ECAP_SYNC_ACK isn’t doing what it should, so here it is (ECCLR is 0x30):
.macro ECAP_SYNC_ACK
INT_ACK ECAP_EVT
// Clear ECAP1 interrupts
MOV32 interrupt_regs.offset, 0x01F07000
MOV interrupt_regs.value.w0, 0xFF
SBBO interrupt_regs.value.w0, interrupt_regs.offset, ECCLR, 2
.endm
It uses the INT_ACK macro, which is here (SICR_OFFSET is 0x24):
.macro INT_ACK
.mparam event
MOV32 interrupt_regs.value, event
SBCO interrupt_regs.value, CONST_PRUSSINTC, SICR_OFFSET, 4
.endm
ECAP_EVT is #defined to be 2 (ECAP1 event from the PRU wiki).
Finally, the ECAP_SYNC_SETUP “function call” is:
ECAP_SYNC_SETUP:
INT_SETUP ECAP_EVT, ECAP_HOST_NUM, ECAP_CHN_NUM
RET1
Where ECAP_EVT is 2, ECAP_HOST_NUM is 1 and ECAP_CHN_NUM is also 1. The INT_SETUP macro is:
.macro INT_SETUP
.mparam event, host, channel
// Disable all host interrupts
LDI interrupt_regs.value.w0, 0
SBCO interrupt_regs.value, CONST_PRUSSINTC, GER_OFFSET, 2
// Map channel "channel" to host interrupt "host"
LDI interrupt_regs.offset.w0, INTC_HOSTMAP_REGS_OFFSET
ADD interrupt_regs.offset.w0, interrupt_regs.offset.w0, channel
LDI interrupt_regs.value.w0, host
SBCO interrupt_regs.value, CONST_PRUSSINTC, interrupt_regs.offset.w0, 1
// Map system event "event" to channel "channel"
LDI interrupt_regs.offset.w0, INTC_CHNMAP_REGS_OFFSET
ADD interrupt_regs.offset, interrupt_regs.offset, event
LDI interrupt_regs.value.b0, channel
SBCO interrupt_regs.value.b0, CONST_PRUSSINTC, interrupt_regs.offset.w0, 1
// Make sure the system event "event" is cleared
MOV32 interrupt_regs.value, event
SBCO interrupt_regs.value, CONST_PRUSSINTC, SICR_OFFSET, 4
// Enable "event" system event
SBCO interrupt_regs.value, CONST_PRUSSINTC, EISR_OFFSET, 4
// Enable host interrupt "host"
MOV32 interrupt_regs.value, host
SBCO interrupt_regs.value, CONST_PRUSSINTC, HIESR_OFFSET, 4
// Global enable all host interrupts
LDI interrupt_regs.value.w0, 1
SBCO interrupt_regs.value, CONST_PRUSSINTC, GER_OFFSET, 2
.endm