assembly ESP32程序集中最高优先级中断抓取定时器值

w8rqjzmb  于 2023-01-09  发布在  其他
关注(0)|答案(1)|浏览(170)

我试图在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位内存地址?

jfgube3f

jfgube3f1#

中断处理程序需要存储在“IRAM”-“指令RAM”中,否则无法保证中断处理程序在需要时驻留在可执行内存中,调用它的结果将是不确定和不可预测的。
在C和C++中,您可以使用IRAM_ATTR属性来完成此操作:

void IRAM_ATTR void timer0_isr();

在汇编中,你需要使用.section来告诉链接器代码必须存储在IRAM中:

.section        .iram1,"ax"

.global timer0_isr
.global timer0_value
.align      4

timer0_isr:
    movi a10, 0x3FF5F00C 
    ...

Espressif记录了High Level Interrupts中的汇编代码。它们还包括.align,我认为它强制代码在32位边界上对齐。我不是100%确信这是必要的,甚至不是它所做的。

相关问题