STM32H743的FDCAN发送线程卡死的处理方法

芯片型号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发送报文应该属于出错的情况,查看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
//can1
if( (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_u32errcount>>8)&0x000000ff;
st_drvcan1.device.status.snderrcnt = (tmp_u32errcount)&0x000000ff;
st_drvcan1.device.status.lasterrtype = tmp_u32status&0x000000007;
rt_hw_can_isr(&st_drvcan1.device, rt_can_event_tx_fail);
}
#endif / bsp_using_fdcan1 /
}
else
{
#ifdef bsp_using_fdcan2
if( (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
{
//can2
tmp_u32errcount = st_drvcan2.fdcanhandle.instance->ecr;
tmp_u32status = st_drvcan2.fdcanhandle.instance->psr;
st_drvcan2.device.status.rcverrcnt = (tmp_u32errcount>>8)&0x000000ff;
st_drvcan2.device.status.snderrcnt = (tmp_u32errcount)&0x000000ff;
st_drvcan2.device.status.lasterrtype = tmp_u32status&0x000000007;
rt_hw_can_isr(&st_drvcan2.device, rt_can_event_tx_fail);
}
#endif / bsp_using_fdcan2 /
}
}
经过测试发现即使can总线上没有别的设备,调用发送函数也不会一直等待,而是返回发送失败。

LM系列激光测量传感器的特点以及主要性能参数解析
PostgreSQL 14中两阶段提交的逻辑解码正文
索尼半导体还涉足了哪些业务?
六个绝对不能触碰的win10默认文件夹
人工智能为什么是第四次工业革命
STM32H743的FDCAN发送线程卡死的处理方法
宏达电计划在2020年推出5G手机
基于计算机串口实现红外无线PPM发射机的应用方案
日本市场开始清仓锐龙Threadripper二代 价格最高跌幅将近1/3
思岚科技机器人解决方案亮相第23届高交会
罗德与施瓦茨和紫光展锐IoT NTN方向上取得突破性进展
三家企业电池模组焊接方法对比分析
平板发展风向标,华为平板M5青春版成春节居家必备神器
怎样使用PiBakery配置树莓派安装
不充电就能一直使用的核电池能用来干什么?
应该如何有效地防范互联网的安全威胁
亚马逊已停止社交平台Parler的AWS服务
成都强化优势产业,推动数字化网络化智能化转型
英特尔助力汽车制造商脱颖而出
什么是plc控制系统? plc是什么意思 什么是plc