比如我开了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");
}
}
}
告辞