This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TM4C123GH6PM:ISR 只调用一次

Guru**** 2483995 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/725633/tm4c123gh6pm-isr-is-called-only-once

器件型号:TM4C123GH6PM

您好!

我尝试为 TM4123GXl Tiva C 套件编写一些汇编代码。 我在 Keil MDK5中编写了简单的汇编程序。  以下是程序流程和配置:

GPIOF.0作为输入(板载按钮-2)

GPIOF.1 AS OUT (板载红色 LED)

程序的作用:切换按下每个按钮(SW2)时的 LED。

程序如何响应:按下每个按钮时、GPIOF.0会生成一个中断、在 ISR 中、LEAD 位被检查和切换。

问题出在哪里:ISR 只调用一次。 后续按钮按压操作不会触发 ISR。

以下是完整代码:

;
;@说明:打开 Tivs-C TM4C123GXL Launchpad 上的红色 LED
;按下 SW2;


时钟/总线控制寄存器
RCGC2GPIO_REG equ0x400FE108
GPIOHBCTL_REG equ0x400FE06C

;NVIC 寄存器
NVIC_EN0_REG equ 0xE000E100

;GPIO 寄存器
GPIOFDIR_APB_REG equ0x40025400
GPIOFDEN_APB_REG equ0x4002551C
GPIOFDATA_APB_REG equ0x4002500C
GPIOFLOCK_APB_REG equ0x40025520
GPIOFCR_APB_REGequ0x40025524
GPIOPUR_APB_REG equ0x40025510
GPIOFPDR_APB_REG equ0x40025514

GPIOIS_APB_REG equ 0x40025404
GPIOIBE_APB_REG equ 0x40025408
GPIOIEV_APB_REG equ 0x4002540C
GPIOIM_APB_REG equ 0x40025410
GPIOICR_APB_REG equ 0x4002541C


;寄存器值
GPIO_UNLOCK_VALequ0x4C4F434B
GPIOF_NVIC_BIT equ 0x40000000
DELAY_VALUEequ500000

Area|.text|、code、readonly、align=2
拇指
条目
导出主

主函

BL_GPIO_init

BL_config_interrupt

B 。


_CONFIG_INTERRUPT

;启用 PF.0上的边沿检测
LDRR1、=GPIOIS_APB_REG
LDRR0、[R1](R1)
和R0、 R0、 0x3E;清除位0
结构 R0、[R1](R1)

;中断生成由 GPIOIEV reg 控制
LDRR1、=GPIOIBE_APB_REG
LDRR0、[R1](R1)
和R0、 R0、 0x3E;清除位0
结构 R0、[R1](R1)


;下降沿(按下按钮)产生中断
LDRR1、=GPIOIEV_APB_REG
LDRR0、[R1](R1)
和R0、 R0、 0x3E;清除位0
结构 R0、[R1]

;为 PF.0启用中断
LDRR1、=GPIOIM_APB_REG
LDRR0、[R1](R1)
ORR0、 R0、 0x01;设置位0
结构 R0、[R1](R1)

;在 NVIC 侧启用 GPIO-F 中断
;假定内核处于预村庄模式
LDRR1、=NVIC_EN0_REG
LDRR0、=GPIOF_NVIC_BIT
结构 R0、[R1](R1)

BX LR




_GPIO_init
;将 APB 总线用于 GPIOF
LDRR1、=GPIOHBCTL_REG
LDRR0、[R1]
和R0、 R0、 0x1F;清除位5
STRR0、[R1](R1)

;启用 GPIO-F 的时钟
LDR R1、 =RCGC2GPIO_REG
LDRR0、[R1](R1)
ORR0、 R0、 0x20
结构R0、[R1](R1)


;解锁 GPIOCR 寄存器以进行写访问
LDRR1、=GPIOFLOCK_APB_REG
LDRR0、=GPIO_UNLOCK_VAL
结构R0、[R1](R1)

;为 PF.0-1解锁 GPIOAFSEL、GPIOPUR、GPIOPDR 和 GPIODEN
LDRR1、 =GPIOFCR_APB_REG
LDRR0、[R1](R1)
ORR0、 R0、 0x03
结构R0、[R1](R1)

;将 PF.0设置为输入,PF 方向设置为输出
LDRR1、=GPIOFDIR_APB_REG
MOVR0、0x02
结构R0、[R1](R1)

;上拉 PF.0
LDRR1、 =GPIOFPUR_APB_REG
LDRR0、[R1](R1)
ORR0、 R0、 0x01
结构R0、[R1](R1)


;启用 PF.0-1的数字功能
LDRR1、=GPIOFDEN_APB_REG
MOVR0、0x03
结构R0、[R1](R1)

BX LR

对齐


Area |.text|、code、readonly

GPIOF_Handler PROC
导出 GPIOF_Handler
;假设我们只需要 GPIO-F 的 PF.0中断
;如果打开了多个中断,则需要进行检查
;查看发生了哪个中断事件

;清除中断
LDRR1、=GPIOICR_APB_REG
LDRR0、[R1]
ORRR0、 R0、 0x1;设置位0
STRR0、[R1](R1)

;禁用进一步的 ISR (防止中断重新进入)
LDRR1、=GPIOIM_APB_REG
LDRR0、[R1](R1)
和R0、 R0、 0x3E;设置位0
结构 R0、[R1]


;读取 PF.1的数据寄存器值
LDRR1、=GPIOFDATA_APB_REG
LDRR0、[R1]
和R0、R0、#0x2
CMPR0、#0x2
BNELED_ON

;关闭 LED
和R0、R0、#0x01
STRR0、[R1]
B INT_ENABLE

LED_ON
;打开 LED
ORRR0、R0、#0x02
STRR0、[R1]



INT_ENABLE
;为 PF.0重新启用中断
LDRR1、=GPIOIM_APB_REG
LDRR0、[R1](R1)
ORR0、 R0、 0x01;设置位0
结构 R0、[R1](R1)


ENDP


结束

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用 USER="Kowalski)]问题是什么:ISR 只调用一次。   随后按下按钮不会触发 ISR。

    我将会"向您喊叫"、因为(缺失) PF0是一个"邪恶的引脚"、需要"特殊处理"。    (然后将此错误归咎于您使用要求苛刻的"asm!")  然而-你认识到了这个需要-并提供了必要的解锁-好的!

    请注意- (此)代码块:

    ;禁用进一步的 ISR (防止中断重新进入)
    LDR R1、=GPIOIM_APB_REG
    LDR R0、[R1]
    R0、R0、#0x3E;设置位0    是否 "不可能"- "和"运算符(与#0x3E 一致) 将"设置"位_0?
    STR R0、[R1]

    您打算使用 此代码块"防止重新进入 ISR!"    (因此-这应该是一个(第一个)值得一看的地方!)

    另请注意-假设您的是 LPAD -这些板开关将反弹-您的代码(理想情况下)将"等待信号稳定"-然后(小心)管理"进一步反弹"、遵循"开关释放!"  

    您是否不可能(意外) 在 ISR 中"保持和/或返回" -因此不能 "触发 (PF0 ISR)(等待)进一步(或更适当)清除?"   (因此、它实际上可以启用和/或响应  新触发器!)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    谢谢@Guru。 我检查了调试器中的代码并验证了:

    ;禁用进一步的 ISR (防止中断重新进入)
    LDR R1、=GPIOIM_APB_REG
    LDR R0、[R1]
    和 R0、R0、#0x3E;设置位0 已验证
    STR R0、[R1]


    我将程序修改为

    1.在 ISR 开始时禁用 PF.0中断
    2.执行 ISR 操作
    3.生成虚拟延迟
    4.最后清除 PF.0中断(标志已经被置位、所以回弹将会刚刚写过)。
    5.在主程序中经过一段延迟后(考虑按钮反弹效应)启用 PF.0中断....

    然而、程序仍然不会触发 ISR。 另一个有趣/奇怪/奇怪的行为是在 ISR 之后、程序回送至 Reset_Handler。

    新 ISR:

    GPIOF_Handler PROC
    导出 GPIOF_Handler
    ;假设我们只需要 GPIO-F 的 PF.0中断
    ;如果打开了多个中断,则需要进行检查
    ;查看发生了哪个中断事件


    ;禁用进一步的 ISR (防止中断重新进入)
    LDRR1、=GPIOIM_APB_REG
    LDRR0、[R1](R1)
    和R0、 R0、 0x3E;设置位0
    结构 R0、[R1](R1)


    ;读取 PF.1的数据寄存器值
    LDRR1、=GPIOFDATA_APB_REG
    LDRR0、[R1]
    和R0、R0、#0x2
    CMPR0、#0x2
    BNELED_ON

    ;关闭 LED
    和R0、R0、#0x01
    STRR0、[R1]

    B 去耦合延迟

    LED_ON
    ;打开 LED
    ORRR0、R0、#0x02
    STRR0、[R1]

    去耦合延迟
    LDR R2、 =DELAY_VALUE
    延迟子R2、R2、#0x1
    CMPR2、#0
    BNE延迟

    ;在结束时清除中断
    LDRR1、=GPIOICR_APB_REG
    LDRR0、[R1](R1)
    ORR0、 R0、 0x1;设置位0
    结构R0、[R1](R1)

    ENDP
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢您-但是、"我很想解释您的代码行:"

    和 R0、R0、#0x3E;设置位0已验证   

    已"第一 个"(相信)-和后来的(验证)-至"设置位_0"。    "Set"( 设置)-您是指创建 A、"logic high or "1"(逻辑高电平还是"1")?   (是否不是"或"运算符-通常哪一个(更多)-实现此类"位设置?")

     我们"更深入(甚至更深入)"之前、您能否详细说明您的想法(在此位设置中)-尤其是您的"验证"?

    您的第一个帖子指出、您"已检查代码-在 Keil 调试器中。"   您 的"错误检查方法" 是否正确且正确?(两者)"合法"和"无意外影响"是正确的?   一些 MCU 寄存器证明"读取敏感"-让它们"在调试器中打开"-是 导致(类似)错误的"已知原因"!   (通常、此类寄存器会在 MCU 手册中被"注意到"(敏感)。)

    当然、对于(近)即时且高效得多的"解决方案"、使用供应商的 API 将(当然)"加快、简化和增强"实现"正确处理中断及其处理"。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Guru:

    感谢您的回复。 以下是我的观点。

    1."在我们"更深入(甚至更深入)之前、您能否详细说明您的想法(在此位设置中)、尤其是您的"验证"?"
    答案:
    LDR R1、=GPIOIM_APB_REG
    a.将 GPIOIM 寄存器的第一个地址加载到 R1中

    LDR R0、[R1]
    b.将 GPIOIM 寄存器值加载到 R0。 假设 R0现在等于0x03 (PF.0、PF.1中断被启用)

    和 R0、R0、#0x3E;设置位0已验证
    c:现在只为了清除 GPIOIM 寄存器的位0、我执行了按位和操作。 即 R0 & 0x3E => 0x03 & 0x3E => 00 0011 & 11 1110 => 0x2

    STR R0、[R1]
    d.最后将值存储到 GPIOIM 中


    2.根据 launchpad 数据表、GPIOIM 寄存器的读操作不敏感。 它的位必须由一个写入操作显式置位清零。

    我将再次检查所有代码、同时专注于您提到的要点、并将返回此处。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您-您提供的详细信息(两者都很有用、非常感谢。

    将'asm 注释'( 即设置 bit_0)放低一个代码行是否证明'更容易理解'(因此有效)?

    (即在列出的行上: STR R0、[R1] 因此  STR R0、[R1]; SET BIT_0)   注意到我们“同意”- “和运算符”只能 “清除位”。

    以下是一些进一步的建议-这些建议试图"更好地遵守/'kiss'-肯定有助于您的努力:

    • 由于引脚'PF0'是'邪恶引脚'-让我们(至少暂时)用(正常) GPIO 替换它
    • 您是否已"处理"PF0"?   在"开关未激活"期间(PF0应证明为"上拉")和"开关激活"期间(PF0应"反弹"-然后在 GND 附近(稳定)。
    • PF0的输入稳定时、几个此类示波器电容器应"告知并通知"所需的必要延迟、以确保实现"端口读取"。   (您尚未说明如何确定您当前的延迟)
    • 为了简化(另一种符合 kiss 标准的方法)、将该"抖动开关"替换为 GPIO 输出-设置为"开漏"-然后驱动为活动状态。  不会遇到反弹-您应该能够注意到"进入 ISR 的确切时刻"。   (特别是当你切换(另一个)位作为第一个 ISR 代码指令时)
    • 由于您的代码(正确)识别并响应 GPIO 中断(一次)-但"再也不会"-这不 会暗示两个潜在问题
      •   ISR 识别和响应过程中、中断设置代码发生了某种改变
      • ISR "不正确"或未"完全清除"-因此 、任何"重新进入 ISR"(即第二次访问)都将被阻止
    • 如果这种方法(仍然)无法满足预期-您对(显然可怕的)"API"的使用 应快速/轻松地解决!   然后、您可以观察(正确的)寄存器设置-并它们与(到目前为止)发生故障的 ASM 所产生的设置进行比较。

    可以注意到、基于 GPIO 的中断的(简单)设置和编程-   通过使用 asm 几乎没有好处(即几乎为零)。   ("执行力"和"代码膨胀"均不在此证明"发挥作用"。)

    市场是否未:

    • '属于 SWIFT
    • 第一批到达的人  
    • 证明最能利用这种"空难"和"最大限度 地提高利润"

    而且(不幸的是) "非战略"使用 "ASM" (确保 ) ASM 倡导者很少(即从不)会成为" 提前到达"(利润最大化)的人之一!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的


    经过数小时的代码挖掘、我找不到任何可能导致问题的原因... 所以我所做的是一个小小的逆向工程。 我使用 CMSIS 寄存器定义编写了相同的代码。 程序运行正常。 因此、我将 C 文件编译为.s (汇编)文件、并对程序内发生的情况进行了反向工程。 猜猜我发现了错误... 哦、MAN 我在 GPIOF_Handler ISR 末尾丢失了一条指令、即

    BX LR

    当然、我们必须从 ISR 返回调用点。 这就是在 ISR 处理完程序后跳转到 Reset_Handler 的原因。 添加此指令后、所有操作都像一个魅力、尽管按钮反弹效果仍然存在、这会导致 LED 多次切换(很明显)。 :-)

    感谢
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    BRAVO -你们中"关闭环路"的好程度-您(可能)注意-我确实建议使用 API (完全用"C"语言编写)-然后仔细检查"生成的 asm 代码"-寻求(任何/全部)程序或注册'DELTA'。   并且- 我的"指定"项(列出)之一是 ASM 代码未能"正确清除 ISR -这是您的问题-是不是吗?   (意味着两个绿色边角应该波形)

    但是-我的(注意)是否还     在"您的(赦免)"低移动(ASM)车辆"(绝不应进入快速通道)处保留"海龟群-匆忙-闪烁其远光灯"

    注意:我们的"海龟联络员"报告了他们(成功)的节目:  

    • 4x4矩阵键盘
    • 5驻 留在图形 OLED 下方的"软键"
    • 和五个- 5x7 (点矩阵)多色 LED

    在(高度)相似的时间范围内!    "峰值到某个值"、它不是吗?    (现实-并非总是证明-善良和愉快...)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢 ... 您确实提出了以下几点... 亲爱的,非常感谢。