问题描述
最近在Zynq平台上使用FreeRTOS开发应用,其中使用到了USB,将板子当作USB Slave设备,刚开始,将USB配置相关的代码放在了一个Task里,看起来USB是正常的,在上位机端正常识别到了设备,但后来新添加了另外一个Task,发现这个Task居然不运行,通过xTaskGetTickCount()获取到的Tick,也不增加。
问题原因和解决办法
后来发现,问题的主要原因是中断的配置导致的。USB的配置代码是在网上找的源码,其中做了中断的配置,代码如下:
int UsbSetupIntrSystem(XScuGic *IntcInstancePtr,
XUsbPs *UsbInstancePtr, u16 UsbIntrId)
{
int Status;
XScuGic_Config *IntcConfig;
/*
* Initialize the interrupt controller driver so that it is ready to
* use.*/
IntcConfig = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Xil_ExceptionInit();
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
IntcInstancePtr);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(IntcInstancePtr, UsbIntrId,
(Xil_ExceptionHandler)XUsbPs_IntrHandler,
(void *)UsbInstancePtr);
if (Status != XST_SUCCESS) {
return Status;
}
/*
* Enable the interrupt for the device.
*/
XScuGic_Enable(IntcInstancePtr, UsbIntrId);
/*
* Enable interrupts in the Processor.*/
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
return XST_SUCCESS;
}
而在FreeRTOS的初始化配置中,也配置了中断,代码在portZynq7000.c文件中,如下:
void FreeRTOS_SetupTickInterrupt( void )
{
BaseType_t xStatus;
extern void FreeRTOS_Tick_Handler( void );
XScuTimer_Config *pxTimerConfig;
XScuGic_Config *pxGICConfig;
const uint8_t ucRisingEdge = 3;
/* This function is called with the IRQ interrupt disabled, and the IRQ
interrupt should be left disabled. It is enabled automatically when the
scheduler is started. */
/* Ensure XScuGic_CfgInitialize() has been called. In this demo it has
already been called from prvSetupHardware() in main(). */
pxGICConfig = XScuGic_LookupConfig( XPAR_SCUGIC_SINGLE_DEVICE_ID );
xStatus = XScuGic_CfgInitialize( &xInterruptController, pxGICConfig, pxGICConfig->CpuBaseAddress );
configASSERT( xStatus == XST_SUCCESS );
( void ) xStatus; /* Remove compiler warning if configASSERT() is not defined. */
/* The priority must be the lowest possible. */
XScuGic_SetPriorityTriggerType( &xInterruptController, XPAR_SCUTIMER_INTR, portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT, ucRisingEdge );
/* Install the FreeRTOS tick handler. */
xStatus = XScuGic_Connect( &xInterruptController, XPAR_SCUTIMER_INTR, (Xil_ExceptionHandler) FreeRTOS_Tick_Handler, ( void * ) &xTimer );
configASSERT( xStatus == XST_SUCCESS );
( void ) xStatus; /* Remove compiler warning if configASSERT() is not defined. */
/* Initialise the timer. */
pxTimerConfig = XScuTimer_LookupConfig( XPAR_SCUTIMER_DEVICE_ID );
xStatus = XScuTimer_CfgInitialize( &xTimer, pxTimerConfig, pxTimerConfig->BaseAddr );
configASSERT( xStatus == XST_SUCCESS );
( void ) xStatus; /* Remove compiler warning if configASSERT() is not defined. */
/* Enable Auto reload mode. */
XScuTimer_EnableAutoReload( &xTimer );
/* Ensure there is no prescale. */
XScuTimer_SetPrescaler( &xTimer, 0 );
/* Load the timer counter register. */
XScuTimer_LoadTimer( &xTimer, XSCUTIMER_CLOCK_HZ / configTICK_RATE_HZ );
/* Start the timer counter and then wait for it to timeout a number of
times. */
XScuTimer_Start( &xTimer );
/* Enable the interrupt for the xTimer in the interrupt controller. */
XScuGic_Enable( &xInterruptController, XPAR_SCUTIMER_INTR );
/* Enable the interrupt in the xTimer itself. */
FreeRTOS_ClearTickInterrupt();
XScuTimer_EnableInterrupt( &xTimer );
}
USB的配置在FreeRTOS之后,相当于又重新初始化了一遍中断Gic,所以就出现了USB配置之后,FreeRTOS的Task工作不正常,连正常的Tick都不递增了,所以,解决方法是,将USB配置代码中XScuGic_CfgInitialize和Exception相关的代码都删掉,只保留XScuGic_Connect和XScuGic_Enable就可以了。修改后USB配置中断的代码如下:
int UsbSetupIntrSystem(XScuGic *IntcInstancePtr,
XUsbPs *UsbInstancePtr, u16 UsbIntrId)
{
int Status;
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(IntcInstancePtr, UsbIntrId,
(Xil_ExceptionHandler)XUsbPs_IntrHandler,
(void *)UsbInstancePtr);
if (Status != XST_SUCCESS) {
return Status;
}
/*
* Enable the interrupt for the device.
*/
XScuGic_Enable(IntcInstancePtr, UsbIntrId);
return XST_SUCCESS;
}
评论区