I am using a AM3358 on a Critical Link SOM. Running Linux 3.2.0.
I am using both PRU units. PRU0 is using a gpio input (referred to as FS) as a clock (8 kHz) to sample two other gpios. Here's the code:
#include "digio.hp"
.origin 0
.entrypoint start
start:
// Clear STANDBY_INIT in SYSCFG register
// otherwise PRU can't write outside PRU memory space
lbco r0, CONST_PRUCFG, 4, 4 // SYSCFG register
clr r0, r0, 4 // clear bit 4, STANDBY_INIT
sbco r0, CONST_PRUCFG, 4, 4 // store it
// Setup C28
mov r0, SHARED_RAM // Set C28 to point to shared RAM
mov r1, PRU0_CTRL + CTPPR0 // for PRU0
sbbo r0, r1, 0, 4
// Clear Digital output
mov r4, DIGOUT_GPIO | GPIO_CLEARDATAOUT // r4 points to CLRDATAOUT reg
mov r2, DIGOUT_BIT // set bits to clear
sbbo r2, r4, 0, 4 // write to register
// Detect SS rising edge
mov r4, SS_GPIO | GPIO_RISINGDETECT // r4 points to RISINGDETECT reg
lbbo r2, r4, 0, 4 // read reg
set r2, SS_PIN // set bit
sbbo r2, r4, 0, 4 // write reg
// Detect FS falling edge
mov r4, FS_GPIO | GPIO_FALLINGDETECT // r4 points to FALLINGDETECT reg
lbbo r2, r4, 0, 4 // read reg
set r2, FS_PIN // set bit
sbbo r2, r4, 0, 4 // write reg
// Setup pointers to read i/o
mov regDigIn, DIGIN_GPIO | GPIO_DATAIN // points to Digital Input: DATAIN reg
mov regDigOut, DIGOUT_GPIO | GPIO_DATAOUT // points to Digital Output: DATAOUTreg
mov regSetDigOut, DIGOUT_GPIO | GPIO_SETDATAOUT // points to Digital Output: SETDATAOUT reg
mov regClrDigOut, DIGOUT_GPIO | GPIO_CLEARDATAOUT // points to Digital Output: CLRDATAOUT reg
mov regSsIrqRaw, SS_GPIO | GPIO_IRQSTATUS_RAW_0 // points to Sample Sync: raw irq status
mov regFsIrqRaw, FS_GPIO | GPIO_IRQSTATUS_RAW_0 // points to Frame Sync: raw irq status
mov regSsIrqStatus, SS_GPIO | GPIO_IRQSTATUS_0 // points to Sample Sync: irq status clear
mov regFsIrqStatus, FS_GPIO | GPIO_IRQSTATUS_0 // points to Frame Sync: irq status clear
// Setup pointer to pDigIO in shared RAM
mov ramDigIO, ADDR_SHARED_RAM // ADDR_SHARED_RAM
add ramDigIO, ramDigIO, RAM_DIGIO // ADDR_SHARED_RAM + RAM_DIGIO
// Initialize registers
mov resetCounts, 0
mov irqCounter, 0
mov sampleCount, 0
mov counter, 0
// Disable Debounce, 31 usec
mov r4, SS_GPIO | GPIO_DEBOUNCENABLE // Sample Sync debounce enable reg
mov r3, (~SS_BIT)
and r2, r2, r3
sbbo r2, r4, 0, 4
mov r4, FS_GPIO | GPIO_DEBOUNCENABLE // Frame Sync debounce enable reg
mov r3, (~FS_BIT)
and r2, r2, r3
sbbo r2, r4, 0, 4
mov r4, SS_GPIO | GPIO_DEBOUNCINGTIME // Sample Sync debouncing time reg
mov r2, 0 // 31 usec
sbbo r2, r4, 0, 4
mov r4, FS_GPIO | GPIO_DEBOUNCINGTIME // Frame Sync debouncing time reg
mov r2, 0 // 31 usec
sbbo r2, r4, 0, 4
// clear SS bit in IRQ_STATUS_0, _1
mov r2, SS_BIT // set pin bit
sbbo r2, regSsIrqStatus, 0, 4 // write to clear irq status reg 0
sbbo r2, regSsIrqStatus, 4, 4 // write to clear irq status reg 1
// clear FS bit in IRQ_STATUS_0, _1
mov r2, FS_BIT // set pin bit
sbbo r2, regFsIrqStatus, 0, 4 // write to clear irq status reg 0
sbbo r2, regFsIrqStatus, 4, 4 // write to clear irq status reg 1
READ_LOOP:
// Read SS IRQ_STATUS_RAW_0
lbbo r2, regSsIrqRaw, 0, 4 // read SS irq status reg
qbbc READ_FS, r2, SS_PIN // if SS interrupt
mov resetCounts, 1 // resetCounts = 1
mov r2, 1
sbco r2, C_SHARED_RAM, OFFSET(control.syncReceived), SIZE(control.syncReceived) // control.syncReceived = 1
// clear IRQ_STATUS_CLR_0, _1
mov r2, SS_BIT // set pin bit
sbbo r2, regSsIrqStatus, 0, 4 // write to clear reg 0
sbbo r2, regSsIrqStatus, 4, 4 // write to clear reg 1
READ_FS:
// Read FS IRQ_STATUS_RAW_0
lbbo r2, regFsIrqRaw, 0, 4 // read FS irq status reg
qbbc READ_CONTROL, r2, FS_PIN // if FS interrupt
call SAMPLEIO // sampleIO()
// clear IRQ_STATUS_CLR_0, _1
mov r2, FS_BIT // set pin bit
sbbo r2, regFsIrqStatus, 0, 4 // write to fs irq clear reg 0
sbbo r2, regFsIrqStatus, 4, 4 // write to fs irq clear reg 1
READ_CONTROL:
lbco &control, C_SHARED_RAM, 0, SIZE(control) // Read user space control
mov r2, DIGOUT_BIT // set bit for DigOut
qbeq RC_1, control.setOutput, 0 // if setOutput true, set output
sbbo r2, regSetDigOut, 0, 4 // write to SETDATAOUT reg
RC_1:
qbeq RC_2, control.clrOutput, 0 // if clrOutput true, clear output
sbbo r2, regClrDigOut, 0, 4 // write to CLRDATAOUT reg
RC_2:
mov control.setOutput, 0 // clear setOutput flag
mov control.clrOutput, 0 // clear clrOutput flag
sbco control.setOutput, C_SHARED_RAM, OFFSET(control.setOutput), SIZE(control.setOutput) // store in user space
sbco control.clrOutput, C_SHARED_RAM, OFFSET(control.clrOutput), SIZE(control.clrOutput) // store in user space
// Read stopRunning bit
qbeq READ_LOOP, control.stopRunning, 0 // if not set, jump to READ_LOOP
END:
// Clear detect SS rising edge
mov r4, SS_GPIO | GPIO_RISINGDETECT // r4 points to RISINGDETECT reg
lbbo r2, r4, 0, 4 // read reg
clr r2, SS_PIN // clear bit
sbbo r2, r4, 0, 4 // write reg
// Clear detect FS falling edge
mov r4, FS_GPIO | GPIO_FALLINGDETECT // r4 points to FALLINGDETECT reg
lbbo r2, r4, 0, 4 // read reg
clr r2, FS_PIN // clear bit
sbbo r2, r4, 0, 4 // write reg
// clear SS bit in IRQ_STATUS_0, _1
mov r2, SS_BIT // set pin bit
sbbo r2, regSsIrqStatus, 0, 4 // write to clear irq status reg 0
sbbo r2, regSsIrqStatus, 4, 4 // write to clear irq status reg 1
// clear FS bit in IRQ_STATUS_0, _1
mov r2, FS_BIT // set pin bit
sbbo r2, regFsIrqStatus, 0, 4 // write to clear irq status reg 0
sbbo r2, regFsIrqStatus, 4, 4 // write to clear irq status reg 1
halt
// Subroutine
SAMPLEIO:
qbeq SIO_1, resetCounts, 0 // if resetCounts > 0
mov resetCounts, 0 // set resetCounts to 0
mov irqCounter, 1 // set irq_counter to 1 (see notes 9/12/16)
mov sampleCount, 1 // set sampleCount to 1
mov counter, 1
SIO_1:
add irqCounter, irqCounter, 1 // irq_counter++
qblt SAMPLEIO_END, control.scanRateCounts.b3, irqCounter.b3
qblt SAMPLEIO_END, control.scanRateCounts.b2, irqCounter.b2
qblt SAMPLEIO_END, control.scanRateCounts.b1, irqCounter.b1
qblt SAMPLEIO_END, control.scanRateCounts.b0, irqCounter.b0
// Rollover sampleCount (shared ram buffer)
add sampleCount, sampleCount, 1 // sampleCount++
mov r5, (NUM_PRU_SAMPLES - 1)
and sampleCount, sampleCount, r5 // sampleCount &= NUM_PRU_SAMPLES-1
// Rollover counter
add counter, counter, 1 // counter++
mov r5, (NUM_CM_SAMPLES - 1)
and counter, counter, r5 // counter &= NUM_CM_SAMPLES-1
// Store digital input state
mov r5, 0 // clear r5
lbbo r2, regDigIn, 0, 4 // read digital input
qbbc SIO_2, r2, DIGIN_PIN // check bit
mov r5.b0, MK_DIGIN_STATE // set digio input bit
SIO_2:
// Store digital output state
lbbo r2, regDigOut, 0, 4 // read digital output
qbbc SIO_3, r2, DIGOUT_PIN // check bit
or r5.b0, r5.b0, MK_DIGOUT_STATE // set digio output bit
SIO_3:
// Store digio in array in shared memory
mov r4, sampleCount // sampleCount
add r4, r4, ramDigIO // r4 = c_SHARED_RAM + RAM_DIGIO + sampleCount
sbbo r5.b0, r4, 0, 1 // store digio at sampleCount in output array
sbco counter, C_SHARED_RAM, OFFSET(control.offset), SIZE(control.offset) // control.offset = counter
mov irqCounter, 0 // irq_counter = 0
SAMPLEIO_END:
ret // return
This is loaded using the prussdrv api, after which other gpios that are accessed through user space are initialized. When the application quits, it sets "stopRunning" before disabling the PRU so that the PRU will halt.
The first time running the application after boot is fine, no problems. Quitting and running the application a second time, a kernel error occurs when initializing gpio (the same bank (2) as those used by the PRU but different pins.) The crash occurs on a "gpio_input" call with this error:
Unhandled fault: external abort on non-linefetch (0x1028)
I know this usually means that a clock is not enabled for a peripheral, but that's not the case here. I confirmed that the GPIO clocks are enabled, and I can use devmem2 to read all the GPIO2 registers.
I note that the function gpio_input() uses spinlocks. Could that be a problem?
Thanks in advance,
Mary