雷达智富

首页 > 内容 > 程序笔记 > 正文

程序笔记

Zynq中使用FreeRTOS和USB遇到系统Tick不递增的问题

2024-06-11 49

问题描述

最近在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;
}
更新于:5个月前
赞一波!

文章评论

评论问答