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.

[参考译文] CC2651R3SIPA:通过 ADC 寄存器写入操作在零延迟 ISR 中澄清 ARM 勘误表838869的适用性

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

https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/1510283/cc2651r3sipa-clarification-on-applicability-of-arm-erratum-838869-in-zero-latency-isr-with-adc-register-write

器件型号:CC2651R3SIPA
主题中讨论的其他部件: PMP

工具/软件:

尊敬的 TI 支持团队:

我们将使用 TI-RTOS 开发 CC2651R3SIPA 固件、一些中断处理程序实现为零延迟 ISR (即绕过 RTOS 内核)。 安装这些处理程序的方法是直接修改 NVIC 矢量表、而不是使用`intRegister ()`来避免中断 OS 管理的中断。

我们知道 ARM 勘误表838869、我们想确认我们的实施是否受到影响。

在我们的一个零延迟 ISR (GPT0A)中、我们在 ISR 结束时对 ADC 寄存器(AUX_ANAIF:ADCTRIG)执行存储操作。 存储发生在调用以下设置函数`pmp_tswTimerStart ()`后,这会设置计时器和其他配置。

以下是设置函数`pmp_tswTimerStart ()`的相关代码:

```c
void pmp_tswTimerStart (PMP_EXEC_t* p_exec)

Power_setDependency (PowerCC26XX_Periph_GPT0);

//停止计时器
TimerDisable (GPT0_BASE、TIMER_A);

//防止转换到待机或空闲状态
Power_setConstraint (PowerCC26XX_SB_disallow);
Power_setConstraint (PowerCC26XX_IDLE_PD_disallow);

//将计时器设置为 PWM 模式
TimerConfigure (GPT0_BASE、TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
TimerLevelControl (GPT0_BASE、TIMER_A、TRUE);//设置为低电平启动

//设置周期
TimerLoadSet (GPT0_BASE、TIMER_A、p_exec->Tswus);
TimerMatchUpdateMode (GPT0_BASE、TIMER_A、TIMER_MATCHUPDATE_NEXTCYCLE);

//清除中断
TimerIntClear (GPT0_BASE、TIMER_CAPA_EVENT);

//手动更新向量表以寄存器 ISR
uint32_t ui32value;
ui32value = HWREG (NVIC_vtable);
HWREG (ui32value +(INT_GPT0A * 4))=(uint32_t) pmp_intTsw;//直接设置矢量表条目

//启用中断
IntPrioritySet (INT_GPT0A、INT_PRI_LEVEL0);
TimerIntEnable (GPT0_BASE、TIMER_CAPA_EVENT);
IntEnable (INT_GPT0A);

//为执行状态设置标志
p_exec->TpdValid = true;
p_exec->enableDrive = true;

//启动计时器
TimerEnable (GPT0_BASE、TIMER_A);
}
以下是零延迟 ISR 的相关代码(pmp_intTsw):


void pmp_intTsw (void)

// ISR 逻辑……

//在 ISR 的最末尾、我们手动触发 ADC
HWREG (AUX_ANAIF_BASE + AUX_ANAIF_O_ADCTRIG)= 0;//手动 ADC 触发
}
我们对以下情况感到关切:

对 NVIC 矢量表进行直接修改的零延迟 ISR:我们使用零延迟 ISR、其中我们直接修改 NVIC 矢量表、不使用 IntRegister ()。 此实现方式是否正确、或者这是否会导致与 ARM 勘误表838869相关的任何问题?

ISR 中的 ADC 寄存器写入:具体而言、在 ISR 结束时对 ADC 寄存器(ADCTRIG)的写入是否符合 ARM 勘误表838869中所述的条件:在这种条件下、具有等待状态的外设寄存器的存储可能会导致错误的中断矢量控制?

请确认:

如果此 ADC 寄存器写入可能会受到勘误表的影响?

使用零延迟 ISR 是否会触发勘误表中提到的问题?

如果需要、我们可以提供更多详细信息或完整实现。

感谢您的支持。

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

    您好!

    ISR 末尾的 HWREG 是一个存储、编译器可以将其编译为具有立即偏移指令的存储。 如果您的其他中断的优先级高于 ADC 中断、则可能会满足 ARM 勘误表838869的条件。

    我建议您在 ISR 末尾添加一条 DSB 指令、以便在 CPU 流水线中完全完成 HWREG 指令。 如何执行此操作的方法在 本应用手册的权变措施中提供、具体取决于您使用的编译器。

    确保 DSB 指令发生在门店和 BX 指令之间。 例外情况
    以 C 语言编写的处理程序、可通过插入适当的内在函数集或来实现
    在中断函数结束之前进行内联汇编、例如:


    ARMCC:
    __schedule_barrier(); __asm{DSB}; __schedule_barrier();


    GCC:
    __asm volatile (“dsb 0xf” ::: “memory”);

    此致、
    Maxence

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

    感谢您的答复。

    我们现在明白、可能会遇到 ARM 勘误表838869。

    我们尝试按照您的建议插入以下解决方法:

    c.
    __schedule_barrier(); __asm{DSB}; __schedule_barrier();

    但是、由于我们使用的是、这导致了构建错误 CCS - TI Arm Clang 编译器 、它不支持__schedule_barrier(){}内联汇编、也不支持内联汇编的语法。

    相反、我们发现下面的行编译没有任何问题:

    c.
    __asm volatile ("DSB");

    我们想确认这条线是否足以减轻我们的情况下的错误。

    再次感谢您的支持。

    此致、

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

    您好、  

     TI Arm Clang 编译器工具用户指南(链接)建议直接使用 asm ()函数。
    对于 __schedule_barrier、用户指南中有关内在__schedule_barrier()函数(链接)的部分没有提及函数。 但是、他们确实提到了 _DISABLE_IRQ ENABLE_IRQ 功能。 从我可以在线阅读的内容(链接)中、您可以使用这些功能来停止和恢复中断。

    生成的代码如下所示:

    bool interrupts_enabled = (__get_PRIMASK() == 0);
    _disable_irq();

    asm("DSB");
    // 3. Restore backed-up-state if (interrupts_enabled) { __enable_irq(); }

    请告诉我它是否可以使用 TI Arm Clang 编译器

    此致、
    Maxence

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

    感谢您的建议。

    我们使用__get_PRIMASK()_disable_irq()、和尝试了代码_enable_irq()、但不幸的是、我们遇到了构建错误。 编译器报告了所有三个函数的"未定义符号"错误、构建无法成功完成。

    我们目前正在使用 CCS - TI Arm Clang 编译器。 如果有任何其他设置步骤或头文件、我们应该包括这些功能、您能告诉我们吗?

    再次感谢您的支持。

    此致、

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

    您好!

    是的、有关编译器的用户指南提到需要添加 arm_acle.h 包含的头文件。

    此致、
    Maxence

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

    您好、Maxence、

    感谢您的支持,感谢您发送编修。

    我们#include <arm_acle.h>按照建议进行添加、如下方式更新中断尾端处理代码:

    c.
    //生成手动触发器
    HWREG (AUX_ANAIF_BASE + AUX_ANAIF_O_ADCTRIG)= 0;

    bool interrupts_enable =(__get_PRIMASK ()=0);

    disable_irq();

    ASM ("DSB");

    if (interrupts_enable){
    _enable_irq();
    }

    但是、我们会看到构建错误、特别是undefined symbol__get_PRIMASK_disable_irq和的""错误__enable_irq
    因此、编译无法完成。

    我们目前正在 CCS 中使用 TI Arm Clang 编译器。 我们是否需要配置启用任何其他内容才能正确使用这些内在函数?

    此致、

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

    您好!

    真的很抱歉前一个答复,用户指南(链接)提到__get_PRIMASK,,_disable_irq_enable_irq是内在函数需要 ti_compatibility.h 而不是 arm_acle.h 标题、抱歉。

    此外,我注意到你应该使用一个下划线_enable_irq(),而不是两个。 解决这些问题应该能解决您的问题。

    此致、
    Maxence

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

    您好、Maxence、

    非常感谢您的跟进

    我们#include <ti_compatibility.h>按照您的建议添加、如下方式更新了中断尾端处理代码:

    c.
    //生成手动触发器
    HWREG (AUX_ANAIF_BASE + AUX_ANAIF_O_ADCTRIG)= 0;

    bool interrupts_enable =(__get_PRIMASK ()=0);

    disable_irq();

    ASM ("DSB");

    if (interrupts_enable){
    _enable_irq();
    }

    但是、我们仍然遇到__get_PRIMASK_disable_irq和的构建错误_enable_irq
    我们尝试同时包括#include <arm_acle.h>#include <ti_compatibility.h>构建错误仍然是一样的。

    我们是否需要启用任何特定的编译器设置定义任何使用这些内在函数?

    此致、
    Hiroki

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

    您好、

     ti_compatibility.h头文件是否正确包含? 我的意思是,你有任何与这些包含在你的编译日志中的错误?

    您能否回复确切的构建错误?

    ti_compatibility.h头文件位于C:\ti\ccs2011\ccs\tools\compiler\ti-cgt-armllvm_4.0.2.LTS\include\c我的位置、包含函数。 只要在工程属性中选择了 TI Clang 编译器、就应该包含该编译器、而无需对包含路径执行任何操作。

    如果您转至项目的属性 General、然后单击编译器版本旁边的"More"(更多)、是否可以向我发送您所看到内容的图像?

    此致、
    Maxence

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

    您好、Maxence、

    感谢您的答复。

    我已经确认ti_compatibility.h文件也存在于我的系统上的同一路径中。

    当前使用的是 CCS Theia这可能会导致任何问题吗?

    我们仍然看到以下构建错误(参阅随附的屏幕截图):

    #10234-D:保留未解析的符号
    链接过程中遇到错误;未构建"re01ds1_5.out"
    tiarmlnk 命令失败、退出代码1 (使用-v 查看调用)

    根据要求附上了工程属性的屏幕截图、包括编译器版本。


    如果还有其他需要我检查的问题、敬请告知。

    此致、

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

    您好、

    解决方法之一是include在 ARM 链接器设置中添加 TI Clang 目录的路径、从而直接包含该文件。

    在工程的设置中、依次导航至 Build > Tools > Arm Linker、点击右上角的画笔图标、并在设置末尾添加以下内容(不要忘记开头使用逗号!) :

    ,-i"C:/ti/ccs2011/ccs/tools/compiler/ti-cgt-armllvm_4.0.2.LTS/include/c" -Wl

    添加后、您可以点击复选框、然后按"Save and Close"

    您能尝试一下、告诉我这是否解决了您的问题吗?

    此致、
    Maxence

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

    感谢您的建议。

    按照说明将以下内容添加到 Arm Linker 设置中、遗憾的是、构建错误仍然存在。
    但是、错误消息更改、因此附加了更新错误的屏幕截图。

    附上了当前 Arm Linker 设置的屏幕截图、以供参考。
    我添加的设置如下:
    ,-i"C:\ti\ccstheia151\ccs\tools\compiler\ti-cgt-armllvm_4.0.0.LTS\include\c"


    此致、

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

    您好、

    我最终测试后发现我错了、您不能把,-i"C:/ti/ccstheia151/ccs/tools/compiler/ti-cgt-armllvm_4.0.0.LTS/include/c" .Wl链接器标志放到末尾。 相反,你应该把它靠近其他-i 标志,例如后-i"C:/ti/ti_cgt_.../lib" -Wl. 此外,由于所有其他路径都使用 /而不是 \,你可以在路径中使用常规斜杠,就像我在我的屏幕截图中所做的那样。

    之后、我能够添加  #include <ti_compatibility.h>和调用所需的函数。

    此致、
    Maxence

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

    您好、Maxence、

    感谢您的答复。

    进行以下更改后、我能够成功编译工程:

    1. 在"Project Properties > General > Products > Product Dependencies"中添加了"TI Arm Clang 3.2.2 LTS 编译器"

    2. 添加#include <ti_compatibility.h>代码中。

    3. _disable_irq_enable_irq将和更改为_disable_IRQ_enable_IRQ(使用大写的"IRQ")

    完成上述更改后、工程构建过程不会出现任何问题。
    随附了屏幕截图其中显示了我所做的修改。

     我的工程属性

      我的代码标头

     我的代码中的 ISR 到此结束。

    您能否确认这些更改是否足以解决勘误表?

    此致、
    Hiroki

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

    您好!

    是的、这些更改足以应对勘误表。

    此致、
    Maxence

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

    非常感谢
    我很高兴听到有勘误的解决方法可用。
    感谢您的及时支持。

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

    尊敬的 TI 支持部门:

    我希望此消息能帮您找到答案。

    我们目前正在 TI-RTOS 环境下使用 ADC 开发一个应用、并且已经在 RTOS 上下文(非 RTOS 中断)之外实现了 ADC 中断处理程序。

    在这种情况下、我们不确定我们的实施是否会受到之前提到的任何勘误的影响、我们希望您能帮助确认这一点。

    以下是我们的 ADC 中断处理程序的当前尾端部分:

    void ADC_COMPLET_ISR (void)

    // ISR 逻辑...

    HWREG (AUX_EVCTL_BASE + AUX_EVCTL_O_EVTOMCUFLAGSCLR)|=
    (AUX_EVCTL_EVTOMCUFLAGSCLR_AUX_ADC_IRQ | AUX_EVCTL_EVTOMCUFLAGSCLR_AUX_ADC_DONE);

    HwiP_clearInterrupt (INT_AUX_ADC_IRQ);
    }

    非常感谢您的支持。

    此致、

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

    您好、

    HwiP_clearInterrupt 函数调用 IntPendClear 函数、该函数又可以以写入结尾、编译器可以将其编译为具有即时偏移指令的存储。 如果您的其他中断的优先级高于 ADC 中断、则可能会满足 ARM 勘误表838869的条件。

    进行前面提到的修复应该足以修复此勘误表。

    如果您有更多问题、我建议您在论坛上创建新主题。

    此致、
    Maxence

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

    您好、 Maxence、

    感谢您的持续帮助。

    在实施建议的解决方法时、我有几个后续问题:

    1. __get_PRIMASK()在示例代码中使用的目的是什么?

    2. 我看到在 DSB 指令周围禁用了中断。 您能解释一下为什么在插入 DSB 时需要禁用中断吗?

    此外、我想问一个与 ADC 中断处理相关的问题:

    • 我知道、在 ISR 结束时清除 ADC 中断标志是有效的(我已经通过之前的查询确认了这一点、因此没有问题)。

    • 但是、要清除 NVIC 中断、我当前使用HwiP_clearInterrupt(INT_AUX_ADC_IRQ);。 由于这是在中断服务例程中、我想尽可能减少开销。

    是否有办法直接清除 NVIC 中断(不使用HwiP_clearInterrupt())、以便尽可能缩短 ISR 内部的处理时间?

    此致、
    Hiroki Saitoh

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

    您好、

    我们禁用中断的原因是因为 CC1312R7器件勘误表 提到在 ARMCC 中修复此问题的方法是在 ISR 结束时添加以下内容:

    __schedule_barrier(); 
    __asm{DSB}; 
    __schedule_barrier(); 

    TI Arm Clang 编译器不存在__schedule_prier 内在函数、因此我们需要做下一个最佳做法、即禁用并重新启用中断。 因此、我们首先禁用中断、执行 DSB 指令、然后使用__get_PRIMASK()函数检查是否首先启用了中断、而不是仅启用中断。

    至于HwiP_clearInterrupt,你可以在 SDK 中看到这个函数的代码。 它只调用 IntClearPend、它只是 C 的几行、我认为开销不是那么重要。

    void IntClearPend(uint32_t intNum)
    {
        // Check the arguments.
        ASSERT(intNum < NUM_INTERRUPTS);
    
        // Determine the interrupt to unpend.
        if (intNum == INT_PENDSV)
        {
            // Unpend the PendSV interrupt.
            SCB->ICSR |= SCB_ICSR_PENDSVCLR_Msk;
        }
        else if (intNum == INT_SYSTICK)
        {
            // Unpend the SysTick interrupt.
            SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk;
        }
        else if ((intNum >= 16) && (intNum <= 47))
        {
            // Unpend the general interrupt.
            NVIC->ICPR[0] = 1 << (intNum - 16);
        }
    }

    据我所知、我认为没有其他方法来清除 NVIC。

    此致、
    Maxence