如何解决因CC2530重复触发串口回调函数导致程序卡死的问题

本文解决CC2530串口使用中,因重复触发串口回调函数导致程序卡死的问题。通过修改_hal_uart_dma.c文件中的HalUARTPollDMA函数,注释掉特定代码段,防止回调函数重复调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何解决因CC2530重复触发串口回调函数导致程序卡死的问题

https://blog.youkuaiyun.com/zzz_xxj/article/details/80389531

 

        原因:当使用CC2530的串口时,协议栈会生成一个串口发送事件,在执行该事件的时候也会触发相应的串口回调函数,导致回调函数被重复调用。

 

      解决方法:在_hal_uart_dma.c文件中找到static void HalUARTPollDMA(void)函数,然后找到if (dmaCfg.txMT)语句,将这个判断语句注释掉,即可解决回调函数重复调用问题。

 

        详细代码如下:

 
  1. /******************************************************************************

  2. * @fn HalUARTPollDMA

  3. *

  4. * @brief Poll a USART module implemented by DMA.

  5. *

  6. * @param none

  7. *

  8. * @return none

  9. *****************************************************************************/

  10. static void HalUARTPollDMA(void)

  11. {

  12. uint16 cnt = 0;

  13. uint8 evt = 0;

  14.  
  15. if (HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead))

  16. {

  17. uint16 tail = findTail();

  18.  
  19. // If the DMA has transferred in more Rx bytes, reset the Rx idle timer.

  20. if (dmaCfg.rxTail != tail)

  21. {

  22. dmaCfg.rxTail = tail;

  23.  
  24. // Re-sync the shadow on any 1st byte(s) received.

  25. if (dmaCfg.rxTick == 0)

  26. {

  27. dmaCfg.rxShdw = ST0;

  28. }

  29. dmaCfg.rxTick = HAL_UART_DMA_IDLE;

  30. }

  31. else if (dmaCfg.rxTick)

  32. {

  33. // Use the LSB of the sleep timer (ST0 must be read first anyway).

  34. uint8 decr = ST0 - dmaCfg.rxShdw;

  35.  
  36. if (dmaCfg.rxTick > decr)

  37. {

  38. dmaCfg.rxTick -= decr;

  39. dmaCfg.rxShdw = ST0;

  40. }

  41. else

  42. {

  43. dmaCfg.rxTick = 0;

  44. }

  45. }

  46. cnt = HalUARTRxAvailDMA();

  47. }

  48. else

  49. {

  50. dmaCfg.rxTick = 0;

  51. }

  52.  
  53. if (cnt >= HAL_UART_DMA_FULL)

  54. {

  55. evt = HAL_UART_RX_FULL;

  56. }

  57. else if (cnt >= HAL_UART_DMA_HIGH)

  58. {

  59. evt = HAL_UART_RX_ABOUT_FULL;

  60. PxOUT |= HAL_UART_Px_RTS;

  61. }

  62. else if (cnt && !dmaCfg.rxTick)

  63. {

  64. evt = HAL_UART_RX_TIMEOUT;

  65. }

  66.  
  67. /****************以下代码会重复触发串口回调函数,所以注释掉*************************/

  68. // if (dmaCfg.txMT)

  69. // {

  70. // dmaCfg.txMT = FALSE;

  71. // evt |= HAL_UART_TX_EMPTY;

  72. // }

  73. /*********************************************************************************/

  74.  
  75. if (dmaCfg.txShdwValid)

  76. {

  77. uint8 decr = ST0;

  78. decr -= dmaCfg.txShdw;

  79. if (decr > dmaCfg.txTick)

  80. {

  81. // No protection for txShdwValid is required

  82. // because while the shadow was valid, DMA ISR cannot be triggered

  83. // to cause concurrent access to this variable.

  84. dmaCfg.txShdwValid = FALSE;

  85. }

  86. }

  87.  
  88. if (dmaCfg.txDMAPending && !dmaCfg.txShdwValid)

  89. {

  90. // UART TX DMA is expected to be fired and enough time has lapsed since last DMA ISR

  91. // to know that DBUF can be overwritten

  92. halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX);

  93. halIntState_t intState;

  94.  
  95. // Clear the DMA pending flag

  96. dmaCfg.txDMAPending = FALSE;

  97.  
  98. HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]);

  99. HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]);

  100. dmaCfg.txSel ^= 1;

  101. HAL_ENTER_CRITICAL_SECTION(intState);

  102. HAL_DMA_ARM_CH(HAL_DMA_CH_TX);

  103. do

  104. {

  105. asm("NOP");

  106. } while (!HAL_DMA_CH_ARMED(HAL_DMA_CH_TX));

  107. HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_TX);

  108. HAL_DMA_MAN_TRIGGER(HAL_DMA_CH_TX);

  109. HAL_EXIT_CRITICAL_SECTION(intState);

  110. }

  111. else

  112. {

  113. halIntState_t his;

  114.  
  115. HAL_ENTER_CRITICAL_SECTION(his);

  116. if ((dmaCfg.txIdx[dmaCfg.txSel] != 0) && !HAL_DMA_CH_ARMED(HAL_DMA_CH_TX)

  117. && !HAL_DMA_CHECK_IRQ(HAL_DMA_CH_TX))

  118. {

  119. HAL_EXIT_CRITICAL_SECTION(his);

  120. HalUARTIsrDMA();

  121. }

  122. else

  123. {

  124. HAL_EXIT_CRITICAL_SECTION(his);

  125. }

  126. }

  127.  
  128. if (evt && (dmaCfg.uartCB != NULL))

  129. {

  130. dmaCfg.uartCB(HAL_UART_DMA-1, evt);

  131. }

  132. }

 

<think>好的,我现在需要解决用户提到的输入捕获中断回调函数导致程序卡死问题。首先,我应该理解这个问题的背景。用户可能在嵌入式系统或实时应用中使用了输入捕获功能,当触发中断时,回调函数执行时间过长或者处理不当,导致系统无法及时响应其他中断或任务,进而卡死。 接下来,我需要回顾中断处理的基本原则。中断服务例程(ISR)应该尽量简短,避免执行耗时操作,比如复杂的计算或阻塞调用。如果回调函数中有这样的操作,可能导致中断无法及时返回,系统资源被占用,引发死锁或优先级反转等问题。 然后,结合用户提供的引用内容。引用[1]提到了AVFormatContext的中断回调处理,这可能涉及到设置回调函数来检测超时或外部中断信号。类似地,在输入捕获中断中,可能需要设置合理的超时机制或状态检查,防止回调函数长时间占用资源。引用[3]提到Ubuntu死机问题与硬件兼容性相关,虽然用户的问题可能不同,但可以考虑硬件中断触发频率是否过高,或者是否存在硬件冲突,比如中断请求(IRQ)共享导致的中断风暴。 接下来,可能的解决方案包括: 1. **优化中断回调函数**:确保回调函数尽可能简短,只做必要的操作,如设置标志位或记录时间戳,将复杂处理移至主循环或任务中。这可以避免在中断上下文中长时间执行。 2. **检查中断优先级和嵌套**:如果系统支持中断优先级,需确保输入捕获中断的优先级设置合理,避免被更高优先级的中断持续抢占,或自身阻塞其他关键中断。 3. **使用双缓冲或队列机制**:在中断中快速将数据存入缓冲区,由主程序异步处理,防止数据丢失或处理延迟。例如,使用环形缓冲区来暂存输入捕获的数据。 4. **超时机制和状态监控**:类似引用[1]中的中断回调,可以设置超时检查,若处理时间超过预期,则强制退出或重置硬件模块。例如,在回调开始时记录时间,若超时则触发恢复操作。 5. **排查硬件问题**:如引用[3]提到的硬件兼容性问题,检查输入捕获的硬件配置是否正确,是否存在信号干扰或电气问题导致异常中断触发。使用示波器或逻辑分析仪监测输入信号是否正常。 6. **调试和日志记录**:添加调试信息,记录中断触发的频率和回调执行时间,分析是否有异常情况,比如中断过于频繁导致系统负载过高。 此外,用户可能未正确初始化硬件或配置中断相关寄存器,比如未清除挂起的中断标志位,导致中断重复触发。需要检查初始化代码,确保在退出中断前清除相应的标志。 最后,生成相关问题时要考虑用户可能进一步需要了解的中断处理优化方法、具体调试步骤,或者硬件配置注意事项。例如,如何测量中断处理时间,如何使用RTOS管理任务优先级等。</think>### 解决输入捕获中断回调函数导致程序卡死的方案 #### 1. **优化中断回调函数的执行时间** - **问题根源**:中断回调函数若执行时间过长,会阻塞其他中断或主程序的运行,导致系统卡死。 - **解决方案**: - 仅保留关键操作(如记录时间戳、设置标志位),将复杂逻辑(如数据处理)移至主循环或低优先级任务中。 - 使用轻量级操作,避免在中断中调用阻塞函数(如`printf`、动态内存分配)或浮点运算。 - **示例代码**: ```c volatile uint32_t capture_time = 0; void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) { capture_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // 仅记录值 } } ``` #### 2. **检查中断优先级配置** - **问题根源**:中断优先级冲突可能导致嵌套中断或抢占失败。 - **解决方案**: - 在支持优先级的中断控制器(如ARM NVIC)中,将输入捕获中断设为合理优先级,避免与关键系统中断(如看门狗)冲突。 - 禁用无关中断嵌套(如STM32中通过`HAL_NVIC_SetPriority`配置)。 #### 3. **使用缓冲区和异步处理** - **问题根源**:高频中断可能压垮实时处理能力。 - **解决方案**: - 使用环形缓冲区暂存数据,主程序异步处理。 - **代码示例**: ```c #define BUFFER_SIZE 64 volatile uint32_t time_buffer[BUFFER_SIZE]; volatile uint8_t buffer_index = 0; void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { time_buffer[buffer_index++] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); buffer_index %= BUFFER_SIZE; // 循环写入 } ``` #### 4. **添加超时和错误恢复机制** - **问题根源**:硬件异常或信号干扰可能导致中断持续触发。 - **解决方案**: - 在回调函数中增加超时判断,若超时则复位定时器模块。 - 参考引用[1]中`interrupt_callback`的设计,定期检查外部终止条件[^1]。 - **伪代码**: ```c uint32_t last_interrupt_time = 0; void interruptCallBack() { if (current_time - last_interrupt_time > MAX_ALLOWED_DELAY) { TIM_Deinit(); // 强制复位硬件 } last_interrupt_time = current_time; } ``` #### 5. **排查硬件兼容性与信号问题** - **问题根源**:硬件设计缺陷(如信号毛刺、电气噪声)可能导致异常中断。 - **解决方案**: - 检查输入信号波形,添加滤波电路(如RC低通滤波)。 - 参考引用[3]中提到的硬件兼容性问题[^3],确认MCU与输入捕获模块的匹配性(如时钟配置、电气特性)。 #### 6. **调试与日志记录** - **方法**: - 在中断入口/出口添加GPIO电平翻转,用示波器测量中断频率和占空比。 - 记录最大中断间隔,分析是否超过系统承载能力。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值