我试图在ESP32上安装一个GPIO中断,尽可能精确地记录每秒一次的脉冲。其他正在运行的进程(在两个处理器上)延迟了我的正常基于C的中断(ESP_INTR_FLAG_LEVEL3),使检测结果变化多达半毫秒。
所以我的下一步是调用汇编中的一个中断,它需要使用ESP32的更高优先级。我所需要的只是获取硬件定时器值并将其存储在一个全局变量中。
我没有装配经验,更不用说ESP32装配了。以下是我能想到的:
.global timer0_isr
.global timer0_value
timer0_isr:
movi a10, 0x3FF5F00C //Timer 0 Update address into a10
s32i a0, a10, 0 //A write instruction copies the timer to the timer registers; doesn't matter what is written
movi a11, timer0_value //timer0_value address into a11
movi a12, 0x3FF5F004 //Timer 0 lower 32 bits address into a12
s32i a12, a11, 0 //Store lower 32 bits to timer0_value
movi a13, 0x3FF5F008 //Timer 0 upper 32 bits address into a13
s32i a13, a11, 4 //Store upper 32 bits to timer0_value + 4
在C语言中,函数和变量声明如下:
extern "C" {
extern uint64_t timer0_value = 0;
void timer0_isr();
}
下面是调用函数时的异常:
我们去查一下地址:3FFD1420〈---这是我在C中提取变量地址的过程。它确实在A11中出现得很恰当
导师冥想错误:核心1死机(非法指令)。未处理异常。
0x400d4fc4处的内存转储:电子商务文件第10号第00001号第9号第21004136条
内核1寄存器转储:
PC:0x400 d4区域卡PS:0x00060英尺30英寸A0:0x800d4 db2 A1:0x3ffb2770
A2:0x3ffd2818和A3:0x3ffd1420 A4:0x3ffd2c2c第5页:0x8814位16位
A6:0x00000000 A7:0x0000001 A8:0x800d3a99 A9:0x0000000
A10:0x3ff5f00c A11:0x3ffd1420 A12:0x3ff5f004第13页:0x3ff5f008
A14:0x0000000a A15:0x0000033c SAR:0x0000003原因:0x0000000
例外地址:0x0000000标签:0x4008bea9贷款:0x4008beb9批号:0xfffffd
回溯:0x400d4fc7:0x3ffb27700x400d4daf:0x3ffb27d0:0x400e44b2:0x3ffb2820
最奇怪的是,我可以注解掉程序集的不同部分并让它运行。我甚至可以将32位复制到timer0_value中,尽管没有更新计时器指令,值不会改变。如果变量写入指令被注解掉,更新计时器指令将运行
以下是ESP32参考:https://www.mouser.com/pdfdocs/ESP32-Tech_Reference.pdf
以下是Xtensa说明参考:https://www.cadence.com/content/dam/cadence-www/global/en_US/documents/tools/ip/tensilica-ip/isa-summary.pdf
另外值得一提的是,我使用的是Arduino IDE 2.0
编辑:Xtensa文档中有movi
描述的"使用12位有符号常量加载寄存器"。32位地址是否有可能损坏内存,如果有,如何为s32i
指令引用32位内存地址?
1条答案
按热度按时间jfgube3f1#
中断处理程序需要存储在“IRAM”-“指令RAM”中,否则无法保证中断处理程序在需要时驻留在可执行内存中,调用它的结果将是不确定和不可预测的。
在C和C++中,您可以使用
IRAM_ATTR
属性来完成此操作:在汇编中,你需要使用
.section
来告诉链接器代码必须存储在IRAM中:Espressif记录了High Level Interrupts中的汇编代码。它们还包括
.align
,我认为它强制代码在32位边界上对齐。我不是100%确信这是必要的,甚至不是它所做的。