This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

PRUSS and peripheral events

Other Parts Discussed in Thread: OMAP-L138

 

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

 

  • I’m now turning on the PRUSS via the PRU_enable call provided in the CSL, but not loading code or enabling either of them.

     

    If I do the following in the debugger with the DSP halted (the ARM is running Linux, however):

    ·         CMR1[23:16] = 1 (intent is to map system event 2, i.e. ECAP1, to channel 1)

    ·         HMR1[15:8] = 1 (intent is to map channel 1 to host interrupt 1)

    ·         STATIDXCLR = 2 (intent is to clear system event 2 status)

    ·         HOSTINTENIDX = 1 (intent is to enable host interrupt 1)

    ·         ENIDXSET = 4 (intent is to enable system event 2)

    ·         GLBLEN = 1 (intent is to globally enable interrupts)

     

    I then immediately get R31.t31 set.  The ECAP modules are not enabled yet.  Maybe I’m messing something up with the indexed vs. non-indexed registers?  There seem to be multiple copies of a couple of them, just with whether or not they take a bit position or actual value to set/clear flags with.  The one that stands out to me is ENIDXSET vs. STATIDXCLR.  I did try 2 and 4 in both of them to no new effect.

  • At this point I've been able to make things work by just polling the ECAP1 registers directly for the interrupt flag bits and then clearing them once they get set.  It's a little bit of a hack, but acceptable for now.  I'd still like to understand why the interrupt into the PRU didn't seem to be working correctly.

  • I've run the attached project on a C6748 DSP.  It uses the timer instead of the ECAP to generate interrupts, and it terminates after a certain number of cycles.  But other than that, I have tried to match your coding conventions as much as possible.

    This project works and makes use of the interrupt controller in pretty much the same way you were trying to.  Based on this test, I can only think that the presence of Linux running is messing things up somehow or the config you are doing on the ECAP is not quite right.

    Regards, Daniel

    PRU_timer0GeneratePinClk.zip