网站开发主管招聘,广东卫视新闻联播,济南槐荫区做网站的,深圳竞价托管一、问题查找 使用的开发版是硬石的H7芯片型号STM32H743IIT6#xff0c;测试时发现如果外面没有连接CAN设备#xff0c;程序调用CAN发送时会一直等待发送反馈#xff0c;导致相关线程挂起。 在线仿真时发现是卡在can.c文件的168行_can_int_tx函数#xff1a;rt_co…一、问题查找 使用的开发版是硬石的H7芯片型号STM32H743IIT6测试时发现如果外面没有连接CAN设备程序调用CAN发送时会一直等待发送反馈导致相关线程挂起。 在线仿真时发现是卡在can.c文件的168行_can_int_tx函数rt_completion_wait((tx_tosnd-completion), RT_WAITING_FOREVER); 代码如下
rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *data, int msgs)
{int size;struct rt_can_tx_fifo *tx_fifo;RT_ASSERT(can ! RT_NULL);size msgs;tx_fifo (struct rt_can_tx_fifo *) can-can_tx;RT_ASSERT(tx_fifo ! RT_NULL);while (msgs){rt_base_t level;rt_uint32_t no;rt_uint32_t result;struct rt_can_sndbxinx_list tx_tosnd RT_NULL;rt_sem_take((tx_fifo-sem), RT_WAITING_FOREVER);level rt_hw_interrupt_disable();tx_tosnd rt_list_entry(tx_fifo-freelist.next, struct rt_can_sndbxinx_list, list);RT_ASSERT(tx_tosnd ! RT_NULL);rt_list_remove(tx_tosnd-list);rt_hw_interrupt_enable(level);no ((rt_uint32_t)tx_tosnd - (rt_uint32_t)tx_fifo-buffer) / sizeof(struct rt_can_sndbxinx_list);tx_tosnd-result RT_CAN_SND_RESULT_WAIT;if (can-ops-sendmsg(can, data, no) ! RT_EOK){/ send failed. */level rt_hw_interrupt_disable();rt_list_insert_after(tx_fifo-freelist, tx_tosnd-list);rt_hw_interrupt_enable(level);rt_sem_release((tx_fifo-sem));continue;}can-status.sndchange 1;rt_completion_wait((tx_tosnd-completion), RT_WAITING_FOREVER);说明一直在等待完成信号而发送完成信号的地方在can.c文件的900行rt_hw_can_isr函数rt_completion_done((tx_fifo-buffer[no].completion)); 源码如下
case RT_CAN_EVENT_TX_DONE:
case RT_CAN_EVENT_TX_FAIL:
{struct rt_can_tx_fifo *tx_fifo;rt_uint32_t no;no event 8;tx_fifo (struct rt_can_tx_fifo *) can- can_tx;RT_ASSERT(tx_fifo ! RT_NULL);if ((event 0xff) RT_CAN_EVENT_TX_DONE){tx_fifo- buffer[no].result RT_CAN_SND_RESULT_OK;}else{tx_fifo- buffer[no].result RT_CAN_SND_RESULT_ERR;}rt_completion_done((tx_fifo- buffer[no].completion));break;
}
二、解决方案 看完can的驱动源码后想到如果can总线没有其他设备CAN发送报文应该属于出错的情况查看drv_fdcan.c文件中关于几种中断的处理发现故障后的回调函数里没有调用rt_hw_can_isr。于是参考HAL_FDCAN_TxBufferCompleteCallback函数的处理方式对HAL_FDCAN_ErrorCallback进行了如下处理。 源码如下
void HAL_FDCAN_ErrorCallback(FDCAN_HandleTypeDef *hfdcan)
{rt_uint32_t tmp_u32Errcount;rt_uint32_t tmp_u32status;uint32_t ret HAL_FDCAN_GetError(hfdcan);if(hfdcan-Instance FDCAN1){#ifdef BSP_USING_FDCAN1//can1if( (ret FDCAN_IT_ARB_PROTOCOL_ERROR) (hfdcan-Instance-CCCR FDCAN_CCCR_INIT_Msk)){//hfdcan-Instance-CCCR | FDCAN_CCCR_CCE_Msk;hfdcan-Instance-CCCR ~FDCAN_CCCR_INIT_Msk;st_DrvCan1.device.status.errcode 0xff;}else{tmp_u32Errcount st_DrvCan1.fdcanHandle.Instance-ECR;tmp_u32status st_DrvCan1.fdcanHandle.Instance-PSR;st_DrvCan1.device.status.rcverrcnt (tmp_u32Errcount8)0x000000ff;st_DrvCan1.device.status.snderrcnt (tmp_u32Errcount)0x000000ff;st_DrvCan1.device.status.lasterrtype tmp_u32status0x000000007;rt_hw_can_isr(st_DrvCan1.device, RT_CAN_EVENT_TX_FAIL);}#endif / BSP_USING_FDCAN1 /}else{#ifdef BSP_USING_FDCAN2if( (ret FDCAN_IT_ARB_PROTOCOL_ERROR) (hfdcan-Instance-CCCR FDCAN_CCCR_INIT_Msk)){//hfdcan-Instance-CCCR | FDCAN_CCCR_CCE_Msk;hfdcan-Instance-CCCR ~FDCAN_CCCR_INIT_Msk;st_DrvCan2.device.status.errcode 0xff;}else{//can2tmp_u32Errcount st_DrvCan2.fdcanHandle.Instance-ECR;tmp_u32status st_DrvCan2.fdcanHandle.Instance-PSR;st_DrvCan2.device.status.rcverrcnt (tmp_u32Errcount8)0x000000ff;st_DrvCan2.device.status.snderrcnt (tmp_u32Errcount)0x000000ff;st_DrvCan2.device.status.lasterrtype tmp_u32status0x000000007;rt_hw_can_isr(st_DrvCan2.device, RT_CAN_EVENT_TX_FAIL);}#endif / BSP_USING_FDCAN2 /}
}经修改后测试发现一切正常发送错误后就会进入错误处理不会卡死发送线程。