我尝试实现低功耗"深度睡眠"按下按钮进入uboot的功能。按下按钮由linux处理,并设置了一个魔术代码,使u-boot知道保持睡眠不重启"
printf ("\nDisable interrupts to restore them later\n");
rupts = disable_interrupts();
printf ("\nEnable interrupts to enable magic wakeup later\n");
enable_interrupts();
printf ("\nSuspending. Press button to restart\n");
while(probe_button()/*gpio probe*/){
#if 1
//FIXME recheck if that one actually needs an unmasked interrupt or any is ok
__asm__ __volatile__(
"mcr p15, 0, %0, c7, c0, 4\n" /* read cp15 */
"mov %0, %0"
: "=r" (tmp)
:
: "memory"
);
#else
udelay (10000);
#endif
}
if (rupts) {
printf ("\nRe-Enabling interrupts\n");
enable_interrupts();
}
不幸的是,无论是否使用热旋转,功耗都不会发生变化(功耗测量与芯片相关)。除此之外,如果我使用Wait-For-Interrupt CP15指令,它永远不会被唤醒。该按钮连接到其中一个GPIO。该平台是基于Marvell Kirkwood ARM9EJ-S的。
我手动启用了一些CONFIG_IRQ_*
,并为arch_init_irq()
以及do_irq()
创建了实施,我认为存在问题。
根据CP15指令文档,它应该足以触发中断(无论是否被屏蔽!)。
除了上面的代码之外,谁能告诉我我做错了什么或需要做什么?
提前多多感谢!
答案 0 :(得分:1)
我不确定这是否是你的aproach没有用于省电但你的内联汇编不正确的唯一原因。根据这个article你需要执行:
MOV R0, #0
MCR p15, 0, r0, c7, c0, 4
但你的内联汇编
__asm__ __volatile__(
"mcr p15, 0, %0, c7, c0, 4\n" /* read cp15 */
"mov %0, %0"
: "=r" (tmp)
:
: "memory"
);
产生
0: ee073f90 mcr 15, 0, r3, cr7, cr0, {4}
4: e1a03003 mov r3, r3
8: e12fff1e bx lr
我不确定你的意图是什么,但mov r3, r3
没有任何效果。因此,您使用随机值进行协处理器调用。您还需要在mcr
调用之前设置r3(mcr的ARM源寄存器)。顺便提一句,将“记忆”放入clobber列表it means
...将导致GCC不在汇编器指令的寄存器中保持缓存的内存值,而不是优化存储器或加载到该内存。
试试这一行,
asm("MOV R0, #0\n MCR p15, 0, r0, c7, c0, 4" : : : "r0");
它产生
c: e3a00000 mov r0, #0 ; 0x0
10: ee070f90 mcr 15, 0, r0, cr7, cr0, {4}
一般来说,为了省电,我建议在ARM的网站上使用article。
奖金部分:
这个协处理器向后兼容性声明的一个小答案提供了WFI:
ARMv7处理器(包括Cortex-A8,Cortex-A9,Cortex-R4和Cortex-M3)都执行WFI指令进入“等待中断”模式。 在这些处理器上,早期处理器上使用的协处理器写入将始终作为NOP执行。因此,可以通过执行MCR和编写可以跨ARMv6K,ARMv6T2和ARMv7的所有配置文件工作的代码。 WFI指令,虽然在ARM11MPCore上,这将导致两次输入“等待中断”模式。要编写进入“等待中断”模式的完全可移植代码,必须在运行时读取CPUID寄存器以确定“等待中断”是否可用以及输入它所需的指令。