Other Parts Discussed in Thread: SYSBIOS
Tool/software: TI-RTOS
Hi,
I generate a system event from ICSSG0 PRU0 and routed this via MAIN2MCU_LVL_INTRTR0 to the VIM of R5_0. I registered a ISR on this HWI and it gets executed when I generate the event once with PRU0.
However, the ISR gets executed again and again, even if I cleared the interrupt with OSAL-functions or with the PRUICSS driver. I must miss something but I don't know what..
I've studied the PRUICCS driver example /home/thomas/ti/pdk_am65xx_1_0_3/packages/ti/drv/pruss/test/src
I've worked through the OSAL functions descriptions but it didn't helped.
Here is my code:
1. Initialize board and configure INTC of ICSSG
/*
* ======== main ========
*/
Int main()
{
//Initialize the board and the required peripheral for blinking LED
/* The UART_STDIO initializes the default UART port on the board
* and support stdio like UART_printf which is used by appPrint
*
*
*/
Board_STATUS cfg = BOARD_INIT_UART_STDIO | BOARD_INIT_PINMUX_CONFIG | BOARD_INIT_MODULE_CLOCK;
int status = Board_init(cfg);
if (status != BOARD_SOK) {
appPrint("\n Error: Board_init failed: error %d", status);
}
appPrint("\n Board Init complete");
//Set CTRLMMR_PADCONFIG136 Register, to configure PIN AB25 as PRU0_GPIO0_GPO11
HW_WR_REG32(0x0011C220, 0x00010000);
peripheralInit();
//Try to get interrupt up and running to trigger/kick the PRU
PRUICSS_Config *pruIcssCfg;
int32_t ret;
ret = PRUICSS_socGetInitCfg(&pruIcssCfg);
if(ret != PRUICSS_RETURN_SUCCESS)
{
appPrint("\n PRU Get init config was not sucessfull!");
return 0;
}
PRUICSS_Handle pruHandle = PRUICSS_create(pruIcssCfg, PRUICCSS_INSTANCE_ONE);
//Now lets configure the INTC of PRU: Channel 0 should be Mapped to Host Int 0.
PRUICSS_IntcInitData pruss_intc_config =
{
/*Enabled SYSEVTs. -1 indicates end of list*/
/*I want to enable SYSEVT 16*/
{ARM_PRU0_EVENT, PRU0_ARM_EVENT, 0xFF},
/*SysEvt to Channel map. SYSEVTs - Range:0..63 Channels -Range: 0..9
{-1, -1} indicates end of list*/
/*I want to map SYSEVT 16 to Channel 0*/
{
{ARM_PRU0_EVENT, CHANNEL0, SYS_EVT_POLARITY_HIGH, SYS_EVT_TYPE_PULSE},
{PRU0_ARM_EVENT, CHANNEL2, SYS_EVT_POLARITY_HIGH, SYS_EVT_TYPE_PULSE},
{0xFF, 0xFF, 0xFF, 0xFF}
},
/*Channel to Host map.Channels -Range: 0..9 HOSTs - Range:0..9
{-1, -1} indicates end of list*/
/*I want to map Channel 0 to Host 0 */
{
{CHANNEL0, PRU0}, //This is for ARM_PRU0_EVENT
{CHANNEL2, 2}, //This is for PRU0_ARM_EVENT
{0xFF, 0xFF}
},
/*10-bit mask - Enable Host0-Host9 {Host0/1:PRU0/1, Host2..9 : PRUEVT_OUT0..7)*/
/*I want to enable Interrupts for Host 0 and Host 2*/
(PRU0_HOSTEN_MASK | PRU1_HOSTEN_MASK | PRU_EVTOUT0_HOSTEN_MASK)
};
ret = PRUICSS_pruIntcInit(pruHandle, &pruss_intc_config);
if(ret != PRUICSS_RETURN_SUCCESS)
{
appPrint("\n PRU Interrupt config was not sucessfull!");
return 0;
}
//Generate System Interrupt 0
ret = PRUICSS_pruSendEvent(pruHandle, ARM_PRU0_EVENT);
if(ret != PRUICSS_RETURN_SUCCESS)
{
appPrint("\n System Event 0 was not send successfull to PRU!");
return 0;
}
configureInterruptRouter();
registerISROnPRUEventViaOsal();
//registerISROnPRUEventViaPRUICSSDriver(pruHandle);
BIOS_start();
/*
* normal BIOS programs, would call BIOS_start() to enable interrupts
* and start the scheduler and kick BIOS into gear. But, this program
* is a simple sanity test and calls BIOS_exit() instead.
*/
BIOS_exit(0); /* terminates program and dumps SysMin output */
return(0);
}
2. Configure MAIN2MCU_LVL_INTRTR0
void configureInterruptRouter()
{
CSL_IntrRouterCfg intrRouterMain2MCUCfg;
/* Initialize Main to MCU Interrupt Router config structure */
intrRouterMain2MCUCfg.pIntrRouterRegs = (CSL_intr_router_cfgRegs *)(uintptr_t)(CSL_MAIN2MCU_LVL_INTRTR0_CFG_BASE);
intrRouterMain2MCUCfg.pIntdRegs = (CSL_intr_router_intd_cfgRegs *)(uintptr_t)NULL;
intrRouterMain2MCUCfg.numInputIntrs = 192;
intrRouterMain2MCUCfg.numOutputIntrs = 64;
/* Route PRU int router output to MAIN2MCU int router output, MAIN2MCU int router output int number
* is derived from the MCU GIC interrupt number.*/
/* 32: ICSSG_0_HOST_INT0 PRU_ICSSG0 host interrupt 2, see TRM 9.4.10 MAIN2MCU_LVL_INTRTR0 Interrupt Map */
int pruIntRtrInIntNum = 32;
/* See TRM 9.3.3.2 MAIN2MCU_LVL_INTRTR0 Integration:
* MAIN2MCU_RTR_LVL_MUX_INTR[63:0] is connected to MCU_R5_CORE0_INT_IN[223:160]
* Therefore we have a offset of 160. [0] <-> [160]
* */
int pruIntRtrOutIntNum = CSL_MCU0_INTR_MAIN2MCU_LVL_INTR0_OUTL_2 - 160;
CSL_intrRouterCfgMux(&intrRouterMain2MCUCfg, pruIntRtrInIntNum, pruIntRtrOutIntNum);
}
3a. Register ISR via Osal functions to the interrupt
/*
* This registers an ISR to an event from PRU via Osal functionality.
* It's required, that the component MAIN2MCU_LVL_INTRTR0 is already configured.
*/
void registerISROnPRUEventViaOsal()
{
/*Register on the interrupt from pru*/
HwiP_Handle hwiHandle = NULL;
OsalInterruptRetCode_e retCode;
OsalRegisterIntrParams_t interruptRegParams;
/* Initialize with defaults */
Osal_RegisterInterrupt_initParams(&interruptRegParams);
interruptRegParams.corepacConfig.isrRoutine = (&dummyIrqHandler);
interruptRegParams.corepacConfig.priority = 0x20U;
interruptRegParams.corepacConfig.name=NULL;
interruptRegParams.corepacConfig.corepacEventNum=CSL_MCU0_INTR_MAIN2MCU_LVL_INTR0_OUTL_2;
interruptRegParams.corepacConfig.intVecNum=CSL_MCU0_INTR_MAIN2MCU_LVL_INTR0_OUTL_2; /* Host Interrupt vector */
/* Register interrupts */
retCode = Osal_RegisterInterrupt(&interruptRegParams,&(hwiHandle));
//Enable the interrupt
//Osal_EnableInterrupt(CSL_MCU0_INTR_MAIN2MCU_LVL_INTR0_OUTL_2, CSL_MCU0_INTR_MAIN2MCU_LVL_INTR0_OUTL_2);
if(retCode != osal_OK)
{
appPrint("\n Error: Osal register int failed: error %d", retCode);
}
}
4a. ISR handler which "should" also reset the level interrupt
void dummyIrqHandler(uintptr_t foobar)
{
Osal_ClearInterrupt(CSL_MCU0_INTR_MAIN2MCU_LVL_INTR0_OUTL_2, CSL_MCU0_INTR_MAIN2MCU_LVL_INTR0_OUTL_2);
GPIO_toggle(1);
}
I also tried step 3 and 4 with PRUICSS driver functions (PRUICSS_registerIrqHandler and PRUICSS_pruClearEvent), register works but ISR will be called over and over again too. I can provide that code too if required.
5. Create event on PRU which is routed to R5F
volatile register uint32_t __R31;
void main(void)
{
__R31 = 0x21;
}
Additional Information: Registered ISR via Osal functions. I debugged into the callstack when the ISR gets executed.
Hwi.c Hwi_dispatchIRQC(Hwi_Irp irp)
Log_write5(Hwi_LM_begin, (IArg)hwi, (IArg)hwi->fxn,
(IArg)prevThreadType, (IArg)intNum, hwi->irp);
if (hwi->triggerType == Hwi_TriggerType_PULSE) {
Hwi_vim.GROUP[intNum >> 5].ENABLEDSTATUSCLEAR =
(UInt)(1 << (intNum & 0x1f));
}
if (Hwi_dispatcherAutoNestingSupport) {
Hwi_enable();
/* call the user's isr */
(hwi->fxn)(hwi->arg);
Hwi_disable();
}
else {
/* call the user's isr */
(hwi->fxn)(hwi->arg);
}
if (hwi->triggerType == Hwi_TriggerType_LEVEL) {
Hwi_vim.GROUP[intNum >> 5].ENABLEDSTATUSCLEAR =
(UInt)(1 << (intNum & 0x1f));
}
/* Ack end of interrupt */
Hwi_vim.IRQVECADDRESS = intNum;
Log_write1(Hwi_LD_end, (IArg)hwi);
This function should clear the level interrupt, right? So should I even call the clearInterrupt-function from Osal/PRUICCS?
I hope you can direct me into the right direction.
Best regards,
Thomas