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.

[参考译文] CC1352P:混合单次触发+连续计时器

Guru**** 2393725 points
Other Parts Discussed in Thread: CC1352P, SYSCONFIG

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

https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/1260414/cc1352p-mixing-one-shot-continuous-timers

器件型号:CC1352P
主题中讨论的其他器件: SysConfig

大家好。 我使用的是 CCS 版本:12.3.0.00005、SimpleLink v6.41.0.17

在某种架构中、我将等待数据包、然后使用一次性计时器来等待以微秒为单位的偏移、接着使用几个周期的固定间隔的连续计时器。  

例如、我得到一个数据包、t=1000us、等待偏移2000us、然后每3000us 触发一个连续计时器、运行10个周期。  
我在示波器上使用 GPIO 来验证计时、它看起来与我的无线电线程和 UART 线程同时运行的效果很好。  

其最终目的是将系统事件调度、例如 GPIO 切换或 ADC 读取、精确地安排在我希望发生这些事件的时间、超出一系列串联的无线电命令。  
使用链接的 API 时、似乎需要解耦这些引脚。  

经过一个随机的时间间隔,运行完美的几分钟甚至几个小时,我得到一个硬故障,跳到无效的 PC @ 0x00。  
直到我开始使用连续计时器时才发生这种情况。 我以前使用过很多一次性计时器、现在我正在使用一次性+连续计时的组合、此时我注意到了这种故障模式。

计时器回调是在引导时设置的、这些值永远不会改变。  
我的任务有大量堆栈空间、这是我第二次猜测环境会受到破坏。  

下面是代码-没有针对生产进行优化、只是尝试一些东西。

几个问题  

  • 使用无线电命令链时、是否有更好的方法来计划系统事件?
  • 在这么多个周期后、我是否需要为计时器重新注册回调?
  • 是否有更好的工具来调查硬故障?
    • 我需要使用 ROV 来获取 PC、LR、SP、然后在寄存器视图中覆盖它们以查看硬故障的调用堆栈
    • 不是很能给我一个我要找的吸烟枪



void gpTimerWithCBOneShot(int timer_num, int timeout_us, void(cb)(Timer_Handle myHandle, int_fast16_t status)) {
    Timer_Params params;
    Timer_Params_init(&params);
    params.period        = timeout_us;
    params.periodUnits   = Timer_PERIOD_US;
    params.timerMode     = Timer_ONESHOT_CALLBACK;
    params.timerCallback = cb;

    timer[timer_num] = Timer_open(timer_num, &params);

    if (timer[timer_num] == NULL)
    {
        while (1) {} // should only happen when adding new timers and not closing them
    }
}

void gpTimerWithCBContinuous(int timer_num, int timeout_us, void(cb)(Timer_Handle myHandle, int_fast16_t status)) {
    Timer_Params params;
    Timer_Params_init(&params);
    params.period        = timeout_us;
    params.periodUnits   = Timer_PERIOD_US;
    params.timerMode     = Timer_CONTINUOUS_CALLBACK;
    params.timerCallback = cb;

    timer[timer_num] = Timer_open(timer_num, &params);

    if (timer[timer_num] == NULL)
    {
        while (1) {} // should only happen when adding new timers and not closing them
    }
}

...
    // init timers w/ callbacks but do not start
    gpTimerWithCBOneShot(CONFIG_TIMER_5,1, &offsetCb);
    gpTimerWithCBContinuous(CONFIG_TIMER_7,1, &slotTimerCb);
...
    // radio RX callback, time to start offset timer
    gpStopTimer(CONFIG_TIMER_5);
    gpStartTimer(CONFIG_TIMER_5, offsetInterval);
...
    // offsetCb
    void offsetCb(Timer_Handle myHandle, int_fast16_t status) {
        gpStopTimer(CONFIG_TIMER_5); // turn off offset timer
        gpStopTimer(CONFIG_TIMER_7);
        gpStartTimer(CONFIG_TIMER_7, peroidicInterval);
    }
... 
    // after a number of periodic interrupts, we shut off the peroidic timer
    gpStopTimer(CONFIG_TIMER_7);

 

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

    尊敬的 Mike:

    很抱歉回复被延迟。

    您是否在调试指南中看到了我们有关 CPU 异常的部分?

    https://dev.ti.com/tirex/content/simplelink_cc13xx_cc26xx_sdk_7_10_01_24/docs/proprietary-rf/proprietary-rf-users-guide/proprietary-rf-guide/debugging-index.html#deciphering-cpu-exceptions

    谢谢、

    M·H

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

    谢谢 Marie。  

    我从未在 ROV 中正确显示呼叫堆栈。 请参见下图。  
    我一直在手动将 SP/LR/PC 寄存器复制到调试器中。

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

    尊敬的 Mike:

    您是否刚刚遇到了例外调用堆栈或 ROV 中每个视图的这个问题? 您使用的是 CC1352P LaunchPad 还是自定义电路板?

    您是否     在 SysConfig 中设置了"在运行时启用异常解码"选项?

    谢谢、

    M·H

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

    感谢 Marie!

    这是定制 PCB。  
    我确实有另一个项目的源与 LaunchPad 相同、但我已经有很长时间没有使用它了。  

    异常调用堆栈是唯一无法加载的东西。  
    如果我查看 HWI 下的异常详细信息、我可以看到故障的 SP/LR/PC 寄存器、在这里我可以使用调试器覆盖系统寄存器、并获取调用堆栈。 我可以看到其他任务/信标/邮箱。  

    本例中的问题是 PC 跳至0、因此我无法使用该方法。  

    我启用了"在运行时启用异常解码"、但是我注意到这两种方法的结果都是一样的。  

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

    尊敬的 Mike:

    我明白了。

    当您将 SP/LR/PC 地址复制到 Memory 浏览器中时、您会看到什么呢?

    我以前从未听说过这个问题。 但如果在您的情况下使用一次性计时器、是否有什么东西阻止您使用它们?

    谢谢、

    M·H

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

    Mike:

    如果跳转到0是 对空指针的函数调用的结果、您可能 仍会 在链接寄存器(LR)中找到源地址。 故障处理程序通常不应修改连接寄存器。

    您正在使用多个硬件计时器、并且您在回调中以各种方式启动和停止它们。 您显示的代码不完整。 我们无法猜到可能会出现什么问题。 调试此类问题的一般方法是克隆工程、并在错误仍然发生时尽可能减小工程。  通常情况下、问题是在其他地方。

    由于您在回调中停止某些计时器、因此我想知道这是否是问题所在。 在这种情况下、计时器驱动器会取消注册回调函数、而底层 GPTimer 驱动程序用一个空指针替换该函数。 您可以尝试:

    1. 将 GPTMERCC26XX.c 放入您的项目中
    2. 添加如下所示的虚拟处理程序函数。

    static void nullhandler(GPTimerCC26XX_Handle gptHandle, GPTimerCC26XX_IntMask intMask)
    {
        for (;;);
    }
    
    /*!
     *  @brief  Destruct interrupt for timer handle.
     *          This function must only be called once after opening a timer and
     *          should not be called before calling GPTimerCC26XX_registerInterrupt
     */
    void GPTimerCC26XX_unregisterInterrupt(GPTimerCC26XX_Handle handle)
    {
        GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
        GPTimerCC26XX_Object *object         = handle->object;
    
        uint32_t ui32Base = hwAttrs->baseAddr;
        uint32_t timer    = GPT_LUT[handle->timerPart].map;
    
        /* Disable all timer unit interrupts, use "timer" variable as mask */
        TimerIntDisable(ui32Base, timer);
    
        /* Destroy callback function */
        object->hwiCallbackFxn[handle->timerPart] = nullhandler;
        /* Destruct HWI */
        HwiP_Struct *pHwi                         = &object->hwi[handle->timerPart];
        HwiP_destruct(pHwi);
    }

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

    感谢 Rick!  

    好时机,我现在开始盯着他们。  
    ROV 异常信息显示 PC=0和 LR=2。  
    调试寄存器视图显示的是 customFaultISR 中的 PC、LR 在该视图后面1个字节。  

    通过切换几个备用 GPIO 我学到了一件事、我看到计时器 ISR 在触发、UART ISR 和无线电 ISR 都在同时触发。  
    我看到的另外一件事是、从我的计时器 ISR 发布一个信标可能需要大于1ms 的时间。  
    蓝色迹线是从下面的 uartIsr 切换。 紫色迹线表示无线电 ISR 触发。  
    我预计蓝色脉冲将持续4-5微秒、就像长脉冲右侧的脉冲一样。  



    我正在尝试了解我的系统为什么在 ISR 中花费了如此多的时间。  
    就好像在发布信标时中断了一样。  
    我知道在其他 RTOS 中有一个单独的 API、用于从 ISR 发布信标。  

    下面的蓝色迹线是 UART ISR、而紫色迹线是计时器 ISR。  
    从 UART ISR 发布信标时、我可以看到计时器触发。
    这种情况在大多数周期中都会发生、看起来不会给事情带来困扰。  



    void UartIsrHandler(void)
    {
        uint32_t IntStatusBitField = UARTIntStatus(UART0_BASE, 1);              // Get status of enabled interrupts
        UARTIntClear(UART0_BASE, (IntStatusBitField & 0xF0));                   // Clear flags handled by this handler
    
        if(IntStatusBitField & (UART_INT_RX | UART_INT_RT))                     // RX or RX timeout
        {
            GPIO_write(CONFIG_GPIO_0,1);
            Semaphore_post(uartIsrSem);
            GPIO_write(CONFIG_GPIO_0,0);
        }
        else    // Interrupt due to a non-RX event
        {
    
        }
    }


    在拍摄第二张屏幕截图时、我在 ROV 查看器中获得了更有意义的输出。

    PC = 0  
    LR = 0x20006b63

    查看内存映射  

             20006b63   00000001   scheduleThread.o (.data.schIndex)

    看起来像是将 PC 跳转到.data 段。  
    schIndex 用于我的计划历史记录 RAM 日志。  

           schLog[schIndex++& 0x3f]=事件;  

    在禁用我的 RAM 日志、复制故障后、ROV 显示 PC/LR = 0。
    ROV 显示了在中断3和21之间发生的异常、我需要查找。  



    我从计时器驱动程序更改为 driverlib、出现的故障较少、但仍然存在可靠性问题。  

    这里是我的完整计时器代码。 偏移计时器从无线电回调触发、时隙计时器从偏移计时器回调调用。   
    每次重新启动计时器之前都会调用 DeInit 调用。  
    我们绝不要为任何一个计时器取消注册中断处理程序。  

    /*
     *      GPT1 is the offset timer
     *          * scheduled in  RX callback for slot-rxtime interval
     *      GPT0 is the slot timer
     *          * scheduled in offset timer callback
     *          * fires every slot 
     */
    
    #include "app.h"
    
    #include DeviceFamily_constructPath(driverlib/timer.h)
    
    void Slot_IntHandler(void) {
        Semaphore_post(sem2);
        TimerIntClear(GPT0_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any timer interrupt flags
    }
    
    void Board_Init_Slot_Timer_GPT0A(void)
    {
        PRCMPowerDomainOn(PRCM_DOMAIN_TIMER);                                               // Turn on power to timer domain
        while (PRCMPowerDomainsAllOn(PRCM_DOMAIN_TIMER) != PRCM_DOMAIN_POWER_ON) {}         // Wait for timer power domain to start
    
        PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER0);                                        // Enable timer clock gating in run mode
        PRCMLoadSet();
        while (!PRCMLoadGet()) {}                                                           // Wait for timer clock gate to open
    
        TimerDisable(GPT0_BASE, TIMER_A);                                                   // Ensure timer is disabled
    
        TimerConfigure(GPT0_BASE, TIMER_CFG_PERIODIC);                                      // Configure GPT0 as Full-width (32bit) periodic down-count timer
        TimerStallControl(GPT0_BASE, TIMER_A, true);                                        // Stall timer on debug mode
    
        IntPrioritySet(INT_GPT0A, INT_PRI_LEVEL0);                                          // Set the priority of the GPT0A ISR to 0 (highest priority)
        TimerIntRegister(GPT0_BASE, TIMER_A, Slot_IntHandler);
    }
    
    
    void Board_Restart_Slot_Timer_GPT0A(uint32_t t)
    {
        TimerDisable(GPT0_BASE, TIMER_A);                                                   // Ensure timer is disabled
        TimerIntDisable(GPT0_BASE, TIMER_TIMA_TIMEOUT);
        HWREG(GPT0_BASE + GPT_O_CFG) = 0x00000000;
    
        TimerConfigure(GPT0_BASE, TIMER_CFG_PERIODIC);                                      // Configure GPT0 as Full-width (32bit) periodic down-count timer
                                                                                            // Note: must use down counter, there is an issue on the CC2651 with clearing an periodic up counter !
    
        TimerLoadSet(GPT0_BASE, TIMER_A, t);                                                // Load timeout count value
        TimerIntClear(GPT0_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any timer interrupt flags
        TimerIntEnable(GPT0_BASE, TIMER_TIMA_TIMEOUT);                                      // Configure timer interrupt source mask that will be referred to the ISR
        IntEnable(INT_GPT0A);
    
        TimerEnable(GPT0_BASE, TIMER_A);                                                    // Start timer
    }
    
    
    void Board_DeInit_Slot_Timer_GPT0A(void)
    {
        TimerDisable(GPT0_BASE, TIMER_A);
        IntDisable(INT_GPT0A);
        TimerIntDisable(GPT0_BASE, TIMER_TIMA_TIMEOUT);
        TimerIntClear(GPT0_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any pending interrupt flag.
    }
    
    void Offset_IntHandler(void) {
        Semaphore_post(sem1);
    
        Board_DeInit_Offset_Timer_GPT1A();                                                  // Shut off Offset timer
        Board_DeInit_Slot_Timer_GPT0A();
        Board_Restart_Slot_Timer_GPT0A(PACKET_INTERVAL_US*48);
        TimerIntClear(GPT1_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any timer interrupt flags
    }
    
    void Board_Init_Offset_Timer_GPT1A(void)
    {
        PRCMPowerDomainOn(PRCM_DOMAIN_TIMER);                                               // Turn on power to timer domain
        while (PRCMPowerDomainsAllOn(PRCM_DOMAIN_TIMER) != PRCM_DOMAIN_POWER_ON) {}         // Wait for timer power domain to start
    
        PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER1);                                        // Enable timer clock gating in run mode
        PRCMLoadSet();
        while (!PRCMLoadGet()) {}                                                           // Wait for timer clock gate to open
    
        TimerDisable(GPT1_BASE, TIMER_A);                                                   // Ensure timer is disabled
    
        TimerConfigure(GPT1_BASE, TIMER_CFG_ONE_SHOT);                                      // Configure GPT0 as Full-width (32bit) one shot down-count timer
        TimerStallControl(GPT1_BASE, TIMER_A, true);                                        // Stall timer on debug mode
    
        IntPrioritySet(INT_GPT1A, INT_PRI_LEVEL0);                                          // Set the priority of the GPT0A ISR to 0 (highest priority)
        TimerIntRegister(GPT1_BASE, TIMER_A, Offset_IntHandler);
    }
    
    
    void Board_Restart_Offset_Timer_GPT1A(uint32_t t)
    {
        TimerDisable(GPT1_BASE, TIMER_A);                                                   // Ensure timer is disabled
        TimerIntDisable(GPT1_BASE, TIMER_TIMA_TIMEOUT);
        HWREG(GPT1_BASE + GPT_O_CFG) = 0x00000000;
    
        TimerConfigure(GPT1_BASE, TIMER_CFG_ONE_SHOT);                                      // Configure GPT0 as Full-width (32bit) one shot down-count timer
                                                                                            // Note: must use down counter, there is an issue on the CC2651 with clearing an periodic up counter !
    
        TimerLoadSet(GPT1_BASE, TIMER_A, t);                                                // Load timeout count value
        TimerIntClear(GPT1_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any timer interrupt flags
        TimerIntEnable(GPT1_BASE, TIMER_TIMA_TIMEOUT);                                      // Configure timer interrupt source mask that will be referred to the ISR
        IntEnable(INT_GPT1A);
    
        TimerEnable(GPT1_BASE, TIMER_A);                                                    // Start timer
    }
    
    
    void Board_DeInit_Offset_Timer_GPT1A(void)
    {
        TimerDisable(GPT1_BASE, TIMER_A);
        IntDisable(INT_GPT1A);
        TimerIntDisable(GPT1_BASE, TIMER_TIMA_TIMEOUT);
        TimerIntClear(GPT1_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any pending interrupt flag.
    }


    void radioCb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) {
        ...
    
        Board_DeInit_Slot_Timer_GPT0A();
        Board_DeInit_Offset_Timer_GPT1A();
        Board_Restart_Offset_Timer_GPT1A(48*offsetTimeUs);
        
        ...
    }
    这似乎是一个比赛条件,因为有时它会运行一个小时没有问题,有时它失败了5分钟。  
    回调在引导时注册、并且在运行时不会更改、因此很难跟踪。  
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    更多数据:  

    从计时器 ISR 发布信标始终需要4-5微秒。  
    这似乎特定于 UART 信标  

    UART 任务查找 uartIsrSem、来自 FIFO 的缓冲字节、查找数据包并在找到时将信息发布到邮箱、然后处理 TX 缓冲区。
    将 RX 任务与 TX 任务分开会更好吗? Task_yield ()是否会让我接受完整的 RTOS 时钟周期?  
    我还在我的调度程序上使用 Task_yield (),调度程序使用只需要4-5微秒的计时器 ISR。  

        while(1) {
            // prefer a while below to empty the FIFO in one shot
            // if vs while did not make much of a difference in terms of semaphore post taking 1 ms
            if (Semaphore_pend(uartIsrSem, BIOS_NO_WAIT)) {
                if (UARTCharsAvail(UART0_BASE)) {
                    g_SerialInBuffer[g_SerialInBufferWriteIndex] = UARTCharGetNonBlocking(UART0_BASE);
                    g_SerialInBufferWriteIndex++;
                    g_SerialInBufferWriteIndex &= (uint8_t)(SERIAL_BUFFER_NUM_BYTES - 1);
                }
            }
    
            ... // examine new bytes and look for packets
            // if a packet was found 
            Mailbox_post(uartRxMbox, &uartMsg, BIOS_NO_WAIT);
    
            if (g_SerialOutBufferReadIndex != g_SerialOutBufferWriteIndex) { // if bytes to send
                if (!UARTBusy(UART0_BASE)) {
                    UARTCharPutNonBlocking(UART0_BASE, g_SerialOutBuffer[g_SerialOutBufferReadIndex++]);
                }
            }
            Task_yield();
        }

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

    更多数据:

    这不是支撑 MCU 的信标发布。  
    我将信标取出、并允许 ISR 一次缓冲一个字节(并且整个块、相同的结果)
    看起来这个中断被挤占了、  

    void UartIsrHandler(void)
    {
        uint32_t IntStatusBitField = UARTIntStatus(UART0_BASE, 1);              // Get status of enabled interrupts
    
        if(IntStatusBitField & (UART_INT_RX | UART_INT_RT))                     // RX or RX timeout
        {
            GPIO_write(CONFIG_GPIO_0,1);
            if (UARTCharsAvail(UART0_BASE)) {
                g_SerialInBuffer[g_SerialInBufferWriteIndex] = UARTCharGetNonBlocking(UART0_BASE);
                g_SerialInBufferWriteIndex++;
                g_SerialInBufferWriteIndex &= (uint8_t)(SERIAL_BUFFER_NUM_BYTES - 1);
            }
    
            GPIO_write(CONFIG_GPIO_0,0);
        }
        else    // Interrupt due to a non-RX event
        {
    
        }
        UARTIntClear(UART0_BASE, (IntStatusBitField & 0xF0));                   // Clear flags handled by this handler
    }

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

    更多数据:  

    仅仅清除中断和退出花费了>1ms 的时间

    void UartIsrHandler(void)
    {
        GPIO_write(CONFIG_GPIO_0,1);
        uint32_t IntStatusBitField = UARTIntStatus(UART0_BASE, 1);              // Get status of enabled interrupts
        UARTIntClear(UART0_BASE, (IntStatusBitField & 0xF0));                   // Clear flags handled by this handler
        GPIO_write(CONFIG_GPIO_0,0);
    }

    这是我的 UART init

        // Turn on power to UART and enable clock gating.
        // Note: Failure to turn on the UART before accessing UART0_BASE reg will result in a memory bus fault !!!
        PRCMPowerDomainOn(PRCM_DOMAIN_SERIAL);                                              // Turn on power to serial domain (UART, etc).
        while (PRCMPowerDomainsAllOn(PRCM_DOMAIN_SERIAL) != PRCM_DOMAIN_POWER_ON) {}        // Wait for serial power domain to start
    
        PRCMPeripheralRunEnable(PRCM_PERIPH_UART0);                                         // Enable UART clock gating in run mode
        PRCMLoadSet();
        while (!PRCMLoadGet()) {}                                                           // Wait for UART clock gate to open
    
        // Now that the UART has power and clock, proceed with configuring its registers:
        UARTDisable(UART0_BASE);                                                            // Disable UART function
        UARTIntDisable(UART0_BASE, 0xFF1);                                                  // Disable all UART module interrupts (see UART IMSC)
    
        IOCPortConfigureSet(CONFIG_GPIO_UART2_0_RX, IOC_PORT_MCU_UART0_RX, IOC_STD_INPUT);  // IOC_STD_INPUT may not be exactly what you want...
        IOCPortConfigureSet(CONFIG_GPIO_UART2_0_TX, IOC_PORT_MCU_UART0_TX, IOC_STD_INPUT);  // IOC_STD_INPUT may not be exactly what you want...
    
        UARTConfigSetExpClk(UART0_BASE, UART0_CLOCK, UART0_BAUD, (UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE)); // Sets the configuration of the UART
        UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);                     // Set number of chars in fifo's that will generate int's when enabled.
                                                                                            // Generate RX int on reception of 1 char.  Generate TX int when fifo has one char left
        UARTIntRegister(UART0_BASE, &UartIsrHandler);                                        // Register combined UART ISR function for the UART0_COMB (combined uart int handler, ie RX, TX, etc.)
    
        // *Clear all UART module interrupt flags
        UARTIntClear(UART0_BASE, (UART_INT_TX | UART_INT_RX |
                UART_INT_RT | UART_INT_OE | UART_INT_BE | UART_INT_PE |
                UART_INT_FE | UART_INT_CTS | UART_INT_EOT));
    
        UARTIntEnable(UART0_BASE, (UART_INT_RX | UART_INT_RT));
        UARTEnable(UART0_BASE);
    

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

    您的"实际"应用是通过 DriverLib 使用 UART、还是在 ti/drivers (UART 或 UART2)中使用"官方"UART 驱动程序? 我强烈建议使用官方驱动程序。 它们 通常是 笨拙和过度设计的,但它们经常包含 某些硬件奇怪的变通办法和有用的评论。 在实施自己的驱动程序之前、至少应该仔细研究它们。

    如果用户真的想执行自己的外设驱动程序并安装自己的 ISR:

    • 不要 直接使用 PCRM 调用、但像 ti/驱动程序一样使用电源驱动程序(Power_setDependency (PowerCC26XX_Periph_UART0)、 Power_setConstraint (PowerCC26XX_disallow _standby)、...
      电源驱动程序必须跟踪已启用的外设以及是否允许其进入待机状态。 否则,调用 Task_yield ()可以很容易地关闭你的 UART 并进入待机状态,而不会注意到它。
    • 不要 通过 DriverLib 调用安装 ISR、但使用 TIRTOS 内核中的 Hwi 模块。  在调用 semaphore_post ()时,为了让内核知道你在一个 ISR 中,这是必要的。

    您可以观看 此线程 、了解如何在使用 TIRTOS 时实现自己的外设驱动程序。

    如果这仍然无法 解决您的问题、您能否进一步减少您的应用? 您可以移除对讲机吗? 可能是堆栈溢出?

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

    再次感谢 Rick。  

    我有如下限制:  

        Power_setConstraint(PowerCC26XX_DISALLOW_IDLE);
        Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY);
        Power_setConstraint(PowerCC26XX_DISALLOW_SHUTDOWN);

    但 我不具有依赖项、因此我添加了  

        Power_setDependency(PowerCC26XX_PERIPH_UART0);
        Power_setDependency(PowerCC26XX_PERIPH_RFCORE);
        Power_setDependency(PowerCC26XX_PERIPH_GPT0);
        Power_setDependency(PowerCC26XX_PERIPH_GPT1);

    我仍然看到 UART ISR 花费了大约1ms。 和相同的硬故障命中。  
    UART ISR 花费这么长的时间看起来像是一个巨大的危险信号。 尤其是在距离故障如此近的情况下发生。  

    接下来、我将尝试使用 HWI API 并按照您的建议检查 UART 驱动程序。  
    我的实际应用一直在使用官方的 UART2驱动程序和计时器驱动程序、但是在看到一些与这些驱动程序相关的硬故障后、我决定根据一位同事的输入来尝试自己的驱动程序、这个同事在使用实际生产中的 driverlib。 性能已经提高(硬故障减少)、但当我启用完整应用程序时、我总是会遇到这个 PC=0问题、即使在使用 driverlib 进行重构之后也是如此。

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

    您只需要设置对 通过 driverlib 直接访问的外设的依赖性。 RFCore 由高电平射频驱动器处理。 您不希望禁止空闲、但只能在 UART 或 GP 计时器处于运行状态时处于待机状态。 关断在此处也不相关。

    我非常确信、高级 TI 驱动程序不是您遇到的硬故障的根本原因、但这在您的应用中又是另一回事。 可能会意外覆盖存储器或跳转到为空的函数指针。 您是否 在 ROV 中检查了堆栈利用率并尝试增加堆栈大小?

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

    再次感谢 Rick。  

    ROV 表示有大量堆栈。  每个任务堆栈剩余大约512个字节。  

    我认为同样的事情,因为,为什么一个被设置和使用了数千次的指针会是无效的?  
    这当然是一个非常糟糕的环境。

    我可以增加所有任务堆栈以及链接器文件中的堆栈大小、看看情况是否有所改善、但我以前肯定已经尝试过。  

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

    堆栈大小似乎不是问题所在。 只需将它们加倍、HWI 堆栈便具有3.5k 的空闲、相同的故障模式。  

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

    更多数据-应额外证明其不是堆栈溢出。

    我知道这不是预期的用途或接口、但我有一些想法、因为我在很长的中断时间被挂起。  

    仍然是通过 driverlib 使用 UART、我简化了 UART ISR、只是清除了它自己的标志而 没有布置一个信标、...... 系统稳定运行数小时。  
    当 UARTCharsAvail ()告诉我的时候,我只是在我的 UART 线程中从 FIFO 中读取数据。  

    那么、我想、如果我最初打算轮询信标、现在我将轮询 FIFO、我需要中断吗?  
    所以我禁用了它、系统看起来也很稳定。  

    我更喜欢使用建议的 API、尤其是因为手动 DMA 配置需要一些时间。  
    在某处是否有比较 UART 与 UART2驱动器的基准? syscfg 似乎会指向 UART2、但也只有一个纯 UART 驱动程序可用。  

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

    您现在是在使用 TIRTOS 内核 Hwi 模块还是仍通过 DriverLib 安装 ISR? 在后一种情况下、大多数内核 API 是禁止的。 你必须使用 Hwi 模块、虽然我不能告诉你它是否会引起你观察到的行为。

    因此我想,如果我原本打算轮询信标,现在我要轮询 FIFO,那么我是否需要中断

    如果轮询 FIFO、那么不会、但它会使 CPU 一直处于忙碌状态、这是您可能不希望发生的情况。