zynq freertos 添加中断任务

注意点

注意点1:

freertos中与裸机不同,freertos已初始化中断控制器 XScuGic  xInterruptController,不用再对中断进行初始化,直接将中断关联和设置触发使能就好;

注意点2:

freertos的中断初始化在vTaskStartScheduler之后进行,因此中断关联设置触发等操作不要直接添加到main函数中,要添加到任务中进行;

注意点3:

中断触发后报错以下内容

Assert failed in file port.c, line 625
Assert failed in file port.c, line 494

原因为中断的优先级设置不对,参考以下中断优先级设置

    //设置中断优先级:0x00代表最高优先级;0x1代表电平触发; 0x3代表上升沿触发,0x2下降沿;
    XScuGic_SetPriorityTriggerType(&xInterruptController, UART_INT_IRQ_ID, 0x91, 0x1);
    XScuGic_SetPriorityTriggerType(&xInterruptController, SW1_INT_ID, 0x90, 0x2);

正确工程与代码(基于ZU15eg MPSOC)

首先在BD中设置TTC,UART使能,EMIO连接至Pl的LED,PL中断引出至按键

main.c

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "timers.h"
/* Xilinx includes. */
#include "xil_printf.h"
#include "xparameters.h"
#include "xgpiops.h"

#include "uart_pl_intr.h"

#define TIMER_ID				1
#define DELAY_10_SECONDS		10000UL
#define DELAY_1_SECOND			1000UL
#define TIMER_CHECK_THRESHOLD	9

#define EMIO_78					78		//pl_led
#define GPIO_DEVICE_ID 			XPAR_XGPIOPS_0_DEVICE_ID

//#define EMIO_KEY 54  			//PL_LED0 连接到EMIO0
/*-----------------------------------------------------------*/

/* The Tx and Rx tasks as described at the top of this file. */
static void prvTxTask( void *pvParameters );
static void prvRxTask( void *pvParameters );
static void UartTask( void *pvParameters );
static void vTimerCallback( TimerHandle_t pxTimer );
/*-----------------------------------------------------------*/

/* The queue used by the Tx and Rx tasks, as described at the top of this
file. */
static TaskHandle_t xTxTask;
static TaskHandle_t xRxTask;
static TaskHandle_t xUartTask;
static QueueHandle_t xQueue = NULL;
static TimerHandle_t xTimer = NULL;
char HWstring[15] = "Hello World";
long RxtaskCntr = 0;

XGpioPs Gpio;

TaskHandle_t GetUartTaskHandle(void) {
    return xUartTask;
}

int GPIO_Init(){

	XGpioPs_Config *ConfigPtr;
	ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
	XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
	XGpioPs_SetDirectionPin(&Gpio, EMIO_78, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, EMIO_78, 1);
	return 0;
}



int main( void )
{
	xil_printf("start\r\n");
	/*       INTR Init             */
	int status;
	char str[5];  // 用于字符串转换
	u8 send_buff[1000];     // 发送缓冲区(保持不变)

	// 初始化发送缓冲区(填充'0')
	for(int i=0; i<1000; i++){
		send_buff[i] = '0';
	}

	// 初始化UART和中断
	status = uart_init(&Uart_Ps);



	const TickType_t x10seconds = pdMS_TO_TICKS( DELAY_10_SECONDS );

	xil_printf( "Hello from Freertos example main\r\n" );

	/* Create the two tasks.  The Tx task is given a lower priority than the
	Rx task, so the Rx task will leave the Blocked state and pre-empt the Tx
	task as soon as the Tx task places an item in the queue. */
	xTaskCreate( 	prvTxTask, 					/* The function that implements the task. */
					( const char * ) "Tx", 		/* Text name for the task, provided to assist debugging only. */
					configMINIMAL_STACK_SIZE, 	/* The stack allocated to the task. */
					NULL, 						/* The task parameter is not used, so set to NULL. */
					tskIDLE_PRIORITY,			/* The task runs at the idle priority. */
					&xTxTask );

	xTaskCreate( prvRxTask,
				 ( const char * ) "GB",
				 configMINIMAL_STACK_SIZE,
				 NULL,
				 tskIDLE_PRIORITY + 1,
				 &xRxTask );

	xTaskCreate( UartTask,
				 ( const char * ) "Uart",
				 configMINIMAL_STACK_SIZE,
				 NULL,
				 tskIDLE_PRIORITY + 1,
				 &xUartTask );
	if (xUartTask == NULL) xil_printf("xUartTask create failed!\r\n");

	/* Create the queue used by the tasks.  The Rx task has a higher priority
	than the Tx task, so will preempt the Tx task and remove values from the
	queue as soon as the Tx task writes to the queue - therefore the queue can
	never have more than one item in it. */
	xQueue = xQueueCreate( 	1,						/* There is only one space in the queue. */
							sizeof( HWstring ) );	/* Each space in the queue is large enough to hold a uint32_t. */

	/* Check the queue was created. */
	configASSERT( xQueue );

	/* Create a timer with a timer expiry of 10 seconds. The timer would expire
	 after 10 seconds and the timer call back would get called. In the timer call back
	 checks are done to ensure that the tasks have been running properly till then.
	 The tasks are deleted in the timer call back and a message is printed to convey that
	 the example has run successfully.
	 The timer expiry is set to 10 seconds and the timer set to not auto reload. */
	xTimer = xTimerCreate( (const char *) "Timer",
							x10seconds,
							pdFALSE,
							(void *) TIMER_ID,
							vTimerCallback);
	/* Check the timer was created. */
	configASSERT( xTimer );

	/* start the timer with a block time of 0 ticks. This means as soon
	   as the schedule starts the timer will start running and will expire after
	   10 seconds */
	xTimerStart( xTimer, 0 );

	/* Start the tasks and timer running. */
	vTaskStartScheduler();

	/* If all is well, the scheduler will now be running, and the following line
	will never be reached.  If the following line does execute, then there was
	insufficient FreeRTOS heap memory available for the idle and/or timer tasks
	to be created.  See the memory management section on the FreeRTOS web site
	for more details. */
	for( ;; );
}


/*-----------------------------------------------------------*/
static void prvTxTask( void *pvParameters )
{
const TickType_t x1second = pdMS_TO_TICKS( DELAY_1_SECOND );

	for( ;; )
	{
		/* Delay for 1 second. */
		vTaskDelay( x1second );

		/* Send the next value on the queue.  The queue should always be
		empty at this point so a block time of 0 is used. */
		xQueueSend( xQueue,			/* The queue being written to. */
					HWstring, /* The address of the data being sent. */
					0UL );			/* The block time. */
	}
}

/*-----------------------------------------------------------*/
static void UartTask( void *pvParameters )
{
	const TickType_t x2second = pdMS_TO_TICKS( DELAY_1_SECOND );
	GPIO_Init();
	all_intr_init(&Uart_Ps);
	for( ;; )
	{
		ulTaskNotifyTake(pdTRUE,portMAX_DELAY);

		XGpioPs_WritePin(&Gpio, EMIO_78, 0x1);
		vTaskDelay( x2second );
		XGpioPs_WritePin(&Gpio, EMIO_78, 0x0);
		vTaskDelay( x2second );
		/* Print the received data. */
		xil_printf( "test  Uart Task\r\n" );
	}
}

/*-----------------------------------------------------------*/
static void prvRxTask( void *pvParameters )
{
char Recdstring[15] = "";

	for( ;; )
	{
		/* Block to wait for data arriving on the queue. */
		xQueueReceive( 	xQueue,				/* The queue being read. */
						Recdstring,	/* Data is read into this address. */
						portMAX_DELAY );	/* Wait without a timeout for data. */

		/* Print the received data. */
		xil_printf( "Rx task received string from Tx task: %s\r\n", Recdstring );
		RxtaskCntr++;
	}
}

/*-----------------------------------------------------------*/
static void vTimerCallback( TimerHandle_t pxTimer )
{
	long lTimerId;
	configASSERT( pxTimer );

	lTimerId = ( long ) pvTimerGetTimerID( pxTimer );

	if (lTimerId != TIMER_ID) {
		xil_printf("FreeRTOS Hello World Example FAILED");
	}

	/* If the RxtaskCntr is updated every time the Rx task is- called. The
	 Rx task is called every time the Tx task sends a message. The Tx task
	 sends a message every 1 second.
	 The timer expires after 10 seconds. We expect the RxtaskCntr to at least
	 have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */
	if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) {
		xil_printf("FreeRTOS Hello World Example PASSED");
	} else {
		xil_printf("FreeRTOS Hello World Example FAILED");
	}

	vTaskDelete( xRxTask );
	vTaskDelete( xTxTask );
}

uart_pl_inrt.c

/*
 * uart_pl_intr.c
 *
 *  Created on: 2025年7月25日
 *      Author: Mingyi
 */

#include "uart_pl_intr.h"

int TotalErrorCount;

volatile int uart_recv_flag = 0;  // UART接收完成标志
volatile int sw1_trigger_flag = 0; // PL中断触发标志

volatile int TotalReceivedCount;
volatile int TotalSentCount;

XUartPs Uart_Ps;           		  	//串口驱动程序实例
// 全局缓冲区
u8 uart_recv_buff[5];  // UART接收缓冲区

// PL中断类型设置:上升沿/高电平
void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType)
{
    int mask;

    intType &= INT_TYPE_MASK;
    mask = XScuGic_DistReadReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4);
    mask &= ~(INT_TYPE_MASK << (intId%16)*2);
    mask |= intType << ((intId%16)*2);
    XScuGic_DistWriteReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4, mask);
}


//UART初始化函数
int uart_init(XUartPs* uart_ps)
{
	int status;
    XUartPs_Config *uart_cfg;

    uart_cfg = XUartPs_LookupConfig(UART_DEVICE_ID);

    if (NULL == uart_cfg)
       return XST_FAILURE;
    status = XUartPs_CfgInitialize(uart_ps, uart_cfg, uart_cfg->BaseAddress);
    if (status != XST_SUCCESS)
       return XST_FAILURE;

    //UART设备自检
     status = XUartPs_SelfTest(uart_ps);
    if (status != XST_SUCCESS)
       return XST_FAILURE;

    //设置工作模式:正常模式
    XUartPs_SetOperMode(uart_ps, XUARTPS_OPER_MODE_NORMAL);
    //设置波特率:115200
    XUartPs_SetBaudRate(uart_ps,115200);
    //设置RX FIFO的中断触发阈值	sdk+1 xcom+2
    XUartPs_SetFifoThreshold(uart_ps, 4+1);

    return XST_SUCCESS;
}

// UART中断处理函数
void uart_intr_handler(void *call_back_ref)
{
    XUartPs *uart_instance_ptr = (XUartPs *) call_back_ref;
    u32 isr_status;

    // 读取中断状态
    isr_status = XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_IMR_OFFSET);
    isr_status &= XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_ISR_OFFSET);


    // 处理接收溢出中断(RXOVR)
    if (isr_status & XUARTPS_IXR_RXOVR) {
        // 读取数据到全局缓冲区
        XUartPs_Recv(uart_instance_ptr, uart_recv_buff, 5);
        // 清除中断标志
        XUartPs_WriteReg(uart_instance_ptr->Config.BaseAddress,
						XUARTPS_ISR_OFFSET,
						XUARTPS_IXR_RXOVR);
        // 设置接收完成标志
        uart_recv_flag = 1;

        TaskHandle_t xUartTask = GetUartTaskHandle();

        BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
        vTaskNotifyGiveFromISR(xUartTask, &pxHigherPriorityTaskWoken);

        portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);

    }


}

//各个中断的回调函数
void SW1_intr_Handler(void *param)
{
//	xil_printf("SW1 interrupt triggered!\r\n");
    // 设置PL中断触发标志
    sw1_trigger_flag = 1;
//    TaskHandle_t xUartTask = GetUartTaskHandle();
//
//    BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
//    vTaskNotifyGiveFromISR(xUartTask, &pxHigherPriorityTaskWoken);
//
//    portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);

}

//中断初始化
int all_intr_init(XUartPs *uart_ps)
{
	int status;
    // 初始化中断控制器和中断异常处理,FreeRTOS中已初始化
//    XScuGic_Config *intc_cfg;
//    intc_cfg = XScuGic_LookupConfig(INTC_DEVICE_ID);
//
//    if (NULL == intc_cfg)
//        return XST_FAILURE;
//    status = XScuGic_CfgInitialize(&xInterruptController,
//    								intc_cfg,
//									intc_cfg->CpuBaseAddress);
//    if (status != XST_SUCCESS)
//        return XST_FAILURE;
//
//    // 设置并打开中断异常处理功能 固定
//    Xil_ExceptionInit();
//    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
//            (Xil_ExceptionHandler)XScuGic_InterruptHandler,
//            (void *)&xInterruptController);
//    Xil_ExceptionEnable();

    // 注册回调函数
    XUartPs_SetHandler(uart_ps, (XUartPs_Handler)Handler, uart_ps);
    // 关联串口中断处理函数
    status = XScuGic_Connect(	&xInterruptController,
    							UART_INT_IRQ_ID,
								(Xil_ExceptionHandler) uart_intr_handler,
								(void *) uart_ps);
    if (status != XST_SUCCESS)
		return XST_FAILURE;

    status = XScuGic_Connect(&xInterruptController,
                             SW1_INT_ID,
                             (Xil_ExceptionHandler)SW1_intr_Handler,
                             (void *)1);
    if(status != XST_SUCCESS) return XST_FAILURE;

    //设置UART中断触发方式
//    XUartPs_SetInterruptMask(uart_ps, XUARTPS_IXR_RXOVR|XUARTPS_IXR_TXEMPTY);
    XUartPs_SetInterruptMask(uart_ps, XUARTPS_IXR_RXOVR);
    //设置PL-PS中断触发方式
    IntcTypeSetup(&xInterruptController, SW1_INT_ID, INT_TYPE_RISING_EDGE);

    //设置中断优先级:0x00代表最高优先级;0x1代表电平触发; 0x3代表上升沿触发;
    XScuGic_SetPriorityTriggerType(&xInterruptController, UART_INT_IRQ_ID, 0x91, 0x1);
    XScuGic_SetPriorityTriggerType(&xInterruptController, SW1_INT_ID, 0x90, 0x2);
    //使能GIC中的串口中断、PL中断
    XScuGic_Enable(&xInterruptController, UART_INT_IRQ_ID);
    XScuGic_Enable(&xInterruptController, SW1_INT_ID);
    return XST_SUCCESS;
}

void Handler(void *CallBackRef, u32 Event, unsigned int EventData)
{
	/* All of the data has been sent */
	if (Event == XUARTPS_EVENT_SENT_DATA) {
		TotalSentCount = EventData;
	}

	/* All of the data has been received */
	if (Event == XUARTPS_EVENT_RECV_DATA) {
		TotalReceivedCount = EventData;
	}

	/*
	 * Data was received, but not the expected number of bytes, a
	 * timeout just indicates the data stopped for 8 character times
	 */
	if (Event == XUARTPS_EVENT_RECV_TOUT) {
		TotalReceivedCount = EventData;
	}

	/*
	 * Data was received with an error, keep the data but determine
	 * what kind of errors occurred
	 */
	if (Event == XUARTPS_EVENT_RECV_ERROR) {
		TotalReceivedCount = EventData;
		TotalErrorCount++;
	}

	/*
	 * Data was received with an parity or frame or break error, keep the data
	 * but determine what kind of errors occurred. Specific to Zynq Ultrascale+
	 * MP.
	 */
	if (Event == XUARTPS_EVENT_PARE_FRAME_BRKE) {
		TotalReceivedCount = EventData;
		TotalErrorCount++;
	}

	/*
	 * Data was received with an overrun error, keep the data but determine
	 * what kind of errors occurred. Specific to Zynq Ultrascale+ MP.
	 */
	if (Event == XUARTPS_EVENT_RECV_ORERR) {
		TotalReceivedCount = EventData;
		TotalErrorCount++;
	}
}


uart_pl_intr.h

/*
 * uart_pl_intr.h
 *
 *  Created on: 2025年7月25日
 *      Author: Mingyi
 */

#ifndef SRC_UART_PL_INTR_H_
#define SRC_UART_PL_INTR_H_

#include "xparameters.h"
#include "xuartps.h"
#include "xscugic.h"
#include "projdefs.h"
#include "freertos.h"
#include "task.h"

// PS串口中断
#define UART_DEVICE_ID     XPAR_XUARTPS_0_DEVICE_ID     //串口设备ID
#define INTC_DEVICE_ID     XPAR_SCUGIC_SINGLE_DEVICE_ID //中断ID
#define UART_INT_IRQ_ID    XPAR_XUARTPS_0_INTR          //串口中断ID

// PL中断相关定义
#define INT_CFG0_OFFSET 		0x00000C00
#define SW1_INT_ID              121// PL端中断ID
//#define INTC_DEVICE_ID          XPAR_XUARTPS_0_DEVICE_ID
#define INT_TYPE_RISING_EDGE    0x03
#define INT_TYPE_HIGHLEVEL      0x01
#define INT_TYPE_MASK           0x03

extern volatile int uart_recv_flag;  // UART接收完成标志
extern volatile int sw1_trigger_flag; // PL中断触发标志



TaskHandle_t GetUartTaskHandle(void);	// 句柄获取函数

extern XUartPs Uart_Ps;           		  //串口驱动程序实例
extern XScuGic xInterruptController;

extern u8 uart_recv_buff[5];  // UART全局接收缓冲区

void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType);

int uart_init(XUartPs* uart_ps);

void uart_intr_handler(void *call_back_ref);

void Handler(void *CallBackRef, u32 Event, unsigned int EventData);

#endif /* SRC_UART_PL_INTR_H_ */

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐