Timer QEMU ARM versatilepb平台上与SP804双定时器模块的IRQ频率不一致
我用QEMU在ARM平台上编写了一个裸机定时器程序。平台是Timer QEMU ARM versatilepb平台上与SP804双定时器模块的IRQ频率不一致,timer,arm,qemu,Timer,Arm,Qemu,我用QEMU在ARM平台上编写了一个裸机定时器程序。平台是versatilepb。计时器是自动的 SP804提供2个定时器模块。每个模块提供2个定时器。因此总共有4个计时器,即计时器0、1、2、3 计时器0/1共享IRQ 4 定时器2/3共享IRQ 5 我注意到,如果我启动一个单个计时器,或者从不同的计时器模块启动两个计时器,比如0/2或1/3。中断频率非常正常 但是如果我从相同的计时器模块启动两个计时器,比如0/1或2/3。中断频率要高得多 当我从同一个定时器模块启动两个定时器时,我启动的第一
versatilepb
。计时器是自动的
SP804
提供2个定时器模块。每个模块提供2个定时器。因此总共有4个计时器,即计时器0、1、2、3
计时器0/1共享IRQ 4
定时器2/3共享IRQ 5
我注意到,如果我启动一个单个计时器,或者从不同的计时器模块启动两个计时器,比如0/2或1/3。中断频率非常正常
但是如果我从相同的计时器模块启动两个计时器,比如0/1或2/3。中断频率要高得多
当我从同一个定时器模块启动两个定时器时,我启动的第一个定时器的IRQ频率比第二个定时器的IRQ频率高得多,而后者的IRQ频率似乎正常
下面是我的一些IRQ处理程序代码:
void IRQ_handler()
{
u32 vicstatus = VIC_STATUS;
// VIC status BITs: timer0,1=4, timer2,3=5
if (vicstatus & (1<<4))
{// bit4=1:timer0,1, handle timer 0 and 1 one by one
if (*(timer[0].base + TVALUE) == 0) // timer 0
timer_handler(0);
if (*(timer[1].base + TVALUE) == 0) // timer 1
timer_handler(1);
}
if (vicstatus & (1<<5))
{// bit5=1:timer2,3, handle timer 2 and 3 one by one
if (*(timer[2].base + TVALUE) == 0) // timer 2
timer_handler(2);
if (*(timer[3].base + TVALUE) == 0) // timer 3
timer_handler(3);
}
}
void timer_handler(u32 n)
{
TIMER *t = &timer[n];
t->tick++; // Assume 20 ticks per second. Need to calculate it for more accuracy.
if (t->tick == 20)
{
t->tick = 0;
t->ss++;
if (t->ss == 60)
{
t->ss = 0;
t->mm++;
if (t->mm == 60)
{
t->mm = 0;
t->hh++; // no 24 hour roll around
}
}
t->clock[7] = '0' + (t->ss % 10);
t->clock[6] = '0' + (t->ss / 10);
t->clock[4] = '0' + (t->mm % 10);
t->clock[3] = '0' + (t->mm / 10);
t->clock[1] = '0' + (t->hh % 10);
t->clock[0] = '0' + (t->hh / 10);
kprintf("Timer [%d]: %s\n", n, (u8 *)&t->clock[0]);
}
timer_clearInterrupt(n); // clear timer interrupt
}
以下是从同一定时器模块启动定时器2/3的屏幕截图:
IRQ\u处理程序使用
当前值寄存器
来检测哪个计时器导致了中断,它看起来不正确。这里有一个屏蔽中断状态寄存器
,显然就是为了这个,我建议改用它。除了检查IRQ源外,还必须保护通过写入中断清除寄存器
来记录检查结果和清除IRQ,以防止重入,否则单定时器IRQ仍可能被计数多次
我的猜测是,观察到最初的问题是因为计时器IRQ是由其他东西触发的,或者当计时器计数器为零时,为其他IRQ调用IRQ\U处理程序。我认为这些模拟器不应该是周期精确的,它们显然不能使处理器或存储/内存系统周期精确,我知道uart发送器不是周期精确的,我也不希望定时器是周期精确的。你检测哪个定时器是IRQ_处理器中断源的方法在我看来并不可靠。这里有一个屏蔽的中断状态寄存器,显然就是为了这个,我建议用它来代替。此外,代码不完整,因此不清楚如何设置计时器。如果您为这个问题提供了一个自给自足的复制机,那就容易多了。@jcmvbkbc谢谢。稍后我将提供更多详细信息。@jcmvbkbc它现在与
屏蔽中断状态寄存器一起工作。如果你将你的评论作为答案发表,我将荣幸地将其标记为答案。我仍然想知道为什么当前值寄存器
不工作。虽然看起来很自然。。。
void IRQ_handler()
{
u32 vicstatus = VIC_STATUS;
//UART 0
if (vicstatus & UART0_IRQ_VIC_BIT)
{
uart_handler(&uart[0]);
}
//UART 1
if (vicstatus & UART1_IRQ_VIC_BIT)
{
uart_handler(&uart[1]);
}
// VIC status BITs: timer0,1=4, uart0=13, uart1=14
if (vicstatus & TIMER01_IRQ_VIC_BIT)
{// bit4=1:timer0,1, handle timer 0 and 1 one by one
if (*(timer[0].base + TMIS) == 1) // timer 0 <===== HERE changed to use TMIS
timer_handler(0);
if (*(timer[1].base + TMIS) == 1) // timer 1 <===== HERE changed to use TMIS
timer_handler(1);
}
if (vicstatus & TIMER23_IRQ_VIC_BIT)
{// bit5=1:timer2,3, handle timer 2 and 3 one by one
if (*(timer[2].base + TMIS) == 1) // timer 2 <===== HERE changed to use TMIS
timer_handler(2);
if (*(timer[3].base + TMIS) == 1) // timer 3 <===== HERE changed to use TMIS
timer_handler(3);
}
}