Zynq FreeRtos下开启其他中断(定时器Uart)系统崩掉的问题

27 篇文章 7 订阅

FreeRtos下开启其他中断(定时器Uart)系统崩掉的问题

问题来源

比如我开了freertos然后想用uart中断,然后就发现系统正常工作不了,多任务失效,只有一个任务在跑,调度器工作失败

问题原因

主要是全局中断实例只能同时存在一个,因为再初始化中断实例的时候会关闭其他中断,源码如下:

s32  XScuGic_CfgInitialize(XScuGic *InstancePtr,
				XScuGic_Config *ConfigPtr,
				u32 EffectiveAddr)
{
	u32 Int_Id;
	u32 Cpu_Id = CpuId + (u32)1;
	(void) EffectiveAddr;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(ConfigPtr != NULL);
	/*
     * Detect Zynq-7000 base silicon configuration,Dual or Single CPU.
     * If it is single CPU cnfiguration then invoke assert for CPU ID=1
	 */
#ifdef ARMA9
	if (XPAR_CPU_ID == 0x01) {
		Xil_AssertNonvoid((Xil_In32(XPS_EFUSE_BASEADDR
			+ EFUSE_STATUS_OFFSET) & EFUSE_STATUS_CPU_MASK) == 0);
	}
#endif

	if(InstancePtr->IsReady != XIL_COMPONENT_IS_READY) {

		InstancePtr->IsReady = 0U;
		InstancePtr->Config = ConfigPtr;


		for (Int_Id = 0U; Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS;
				Int_Id++) {
			/*
			* Initalize the handler to point to a stub to handle an
			* interrupt which has not been connected to a handler
			* Only initialize it if the handler is 0 which means it
			* was not initialized statically by the tools/user. Set
			* the callback reference to this instance so that
			* unhandled interrupts can be tracked.
			*/
			if ((InstancePtr->Config->HandlerTable[Int_Id].Handler
					== (Xil_InterruptHandler)NULL)) {
				InstancePtr->Config->HandlerTable[Int_Id].Handler
						= (Xil_InterruptHandler)StubHandler;
			}
			InstancePtr->Config->HandlerTable[Int_Id].CallBackRef =
								InstancePtr;
		}
#if defined (versal) && !defined(ARMR5)
	u32 Waker_State;
	xil_printf("Execuing on the a72\n");
	Waker_State = XScuGic_ReDistReadReg(InstancePtr,XSCUGIC_RDIST_WAKER_OFFSET);
	XScuGic_ReDistWriteReg(InstancePtr,XSCUGIC_RDIST_WAKER_OFFSET,
							Waker_State & (~ XSCUGIC_RDIST_WAKER_LOW_POWER_STATE_MASK));
		/* Enable system reg interface through ICC_SRE_EL1 */
		#if EL3
			XScuGic_Enable_SystemReg_CPU_Interface_EL3();
		#endif
			XScuGic_Enable_SystemReg_CPU_Interface_EL1();
		isb();
#endif
		XScuGic_Stop(InstancePtr);//关闭所有中断
		DistributorInit(InstancePtr, Cpu_Id);
#if defined (versal) && !defined(ARMR5)
		XScuGic_set_priority_filter(0xff);
#else
		CPUInitialize(InstancePtr);
#endif

		InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
	}

	return XST_SUCCESS;
}

所以全局只能有一个实例,或者改掉这里,,,
然后freertos初始化的时候会实例一个,就是xInterruptController,所以以后开中断的时候就要用这个了

XScuGic_CfgInitialize( &xInterruptController,
						   pxInterruptControllerConfig,
						   pxInterruptControllerConfig->CpuBaseAddress );

问题解决

开其他中断例子

static int request_irq(int DeviceId, int IRQ_NUM, int INT_TYPE_MASK, struct irq_desc* irq_desc)
{
	XScuGic_Config *IntcConfig;
	int status;

	Xil_ExceptionInit();
	// Interrupt controller initialisation
	IntcConfig = XScuGic_LookupConfig(DeviceId);
	status = XScuGic_Connect(&xInterruptController, IRQ_NUM, (Xil_ExceptionHandler)al5_hardirq_handler, (void *)IRQ_NUM);
	if(status != XST_SUCCESS) {
			xil_printf("register vcu irq failed\r\n");
			return XST_FAILURE;
	}

	IntcTypeSetup(&xInterruptController, IRQ_NUM, INT_TYPE_MASK);

	XScuGic_Enable(&xInterruptController, IRQ_NUM);

	request_bottom_irq(&irq_desc);

	return XST_SUCCESS;
}

这里就是我们的注册函数啦,这里的irq_desc是为了实现下半部中断而写的,然后在rtos中单开一个线程去实现,然后代码在上个文章中也说到了,这里再单独讲一下:

struct irq_desc {
	struct irq_desc* next;
	void (*action)(void *data);
	void *data;
	int isRaised;
};

static SemaphoreHandle_t xIrqSemaphore = NULL;//中断下半部信号量
/*中断链表根*/
static struct irq_desc irq_root = {
		.next = NULL, //下一个irq
		.action = NULL,//任务处理函数
		.data = NULL//私有数据
		.isRaised = 0//当前是否有下半部
};

注册下半部比较简单,往链表上挂就可以

void request_bottom_irq(struct irq_desc* irq_desc_ptr)
{
	struct irq_desc* cur = &irq_root;
	struct irq_desc* next = cur->next;

	while(next){//找到最后一个
		cur = next;
		next = cur->next;
	}
//挂上去
	cur->next = irq_desc_ptr;
	irq_desc_ptr->next = NULL;
}

然后再中断处理函数里面引起下半部,如下

void raise_bottom_irq_from_irq(struct irq_desc* irq_desc_ptr)
{
	static BaseType_t xHigherPriorityTaskWoken;

	irq_desc_ptr->isRaised ++;

	if(xIrqSemaphore) {
		//xil_printf("rasie irq botom, raise sem: %c\r\n", *(char *)(irq_desc_ptr->data));
		xHigherPriorityTaskWoken = 0;
		if(!xSemaphoreGiveFromISR( xIrqSemaphore, &xHigherPriorityTaskWoken )){
		 	err_handler();
		}
	}
}

然后再在任务中处理:

static void do_irq()
{
	struct irq_desc* cur = &irq_root;
	struct irq_desc* next = cur->next;

	//xil_printf("[ irq ] bottom irq in\r\n");
	while(next){
		cur = next;
		next = cur->next;

		if(cur) {
			if(cur->action && cur->isRaised) {
				do {
					cur->isRaised--;
					cur->action(cur->data);
				} while(cur->isRaised);
			}
		}
	}
	//xil_printf("[ irq ] bottom irq exit\r\n");
}

void irq_bottom_thread_entry(void *parameter)
{

	xIrqSemaphore = xSemaphoreCreateBinary();
	if(xIrqSemaphore == NULL) {
		while(1)
			xil_printf("Create SEM ERR!\n");
	}

	while (1)
	{
		if(xSemaphoreTake(xIrqSemaphore, portMAX_DELAY) == pdTRUE)
		{
			//xil_printf("rasie irq do irq\r\n");
			do_irq();
		}else {
			xil_printf("no rasie irq\r\n");
		}
	}
}

END

告辞

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值