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.

AM335x PRU error

Other Parts Discussed in Thread: AM3358

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