Open Maxding001 opened 4 years ago
Sorry, 最近没上 github 回复晚了 我记得以前是不用指定 hdr 的,hdr 是下面自动确定的,以前确实是这么用的。如果现在要自己指定,你可以手动生成一下 filter 结构体。 好久没玩 can 了,一时想不起是哪里确定的 hdr,你可以跟踪一下 rt_device_control(candev, RT_CAN_CMD_SET_FILTER, canpara->filter); 如果指定了rt_event_recv参数RT_WAITING_FOREVER,这个函数应该是不会返回的,表现应该是永远收不到数据
谢谢你的回复。 1,我更改了 can.h里的
{(id), (ide), (rtr), (mode), (mask), **1**, (ind), (args)}
把原来的-1改为了1,程序就不会死循环了。 2,在can_rtthread.c里我发现 static rt_err_t can1ind(rt_device_t dev, void args, rt_int32_t hdr, rt_size_t size) { rt_event_t pevent = (rt_event_t)args; rt_event_send(pevent, 1 << (hdr)); return RT_EOK; } 这个can的接收回调函数没有地方调用 我自己手动增加了 rt_device_set_rx_indicate(candev, canpara->filter->items[0].ind);//后来添加的 void canopen_recv_thread_entry(void parameter) { struct can_app_struct canpara = (struct can_app_struct ) parameter; struct rt_can_msg msg; rt_uint32_t e; Message co_msg; rt_err_t err;
/* set LED0 pin mode to output */
rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
candev = rt_device_find(canpara->name);
RT_ASSERT(candev);
rt_event_init(&canpara->event, canpara->name, RT_IPC_FLAG_FIFO);
rt_device_open(candev, (RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX));
rt_device_control(candev, RT_CAN_CMD_SET_FILTER, canpara->filter);
**rt_device_set_rx_indicate(candev, canpara->filter->items[0].ind);**//后来添加的
while (1)
{
err = rt_event_recv(&canpara->event,
( 1 <<canpara->filter->items[0].hdr),//(1 << canpara->filter->items[0].hdr),
canpara->eventopt,
RT_WAITING_FOREVER, &e) ;
if (err!= RT_EOK)
{
continue;
}
if (e & (1 << canpara->filter->items[0].hdr))
{
msg.hdr = canpara->filter->items[0].hdr;
while (rt_device_read(candev, 0, &msg, sizeof(msg)) == sizeof(msg))
{
co_msg.cob_id = msg.id;
co_msg.len = msg.len;
co_msg.rtr = msg.rtr;
memcpy(co_msg.data, msg.data, msg.len);
EnterMutex();
canDispatch(OD_Data, &co_msg);
LeaveMutex();
}
}
}
}
rt_device_set_rx_indicate(candev, canpara->filter->items[0].ind) 这句话发现参数类型不匹配。 这个地方应该怎么修改才可以。请大神赐教一下。
RT_CAN_USING_HDR
,我以前使用的时候是在 can 接收回调里面调用的can1ind
rt_err_t (*ind)(rt_device_t dev, void *args , rt_int32_t hdr, rt_size_t size);
,rt_device_set_rx_indicate
中回调函数定义rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size)
,这两个函数是不匹配的,没有event和hdr信息,如果要强制改的话可以写一个wrap函数,rt_device_set_rx_indicate(candev, wrap)
,然后在wrap里调用canpara->filter->items[0].ind
1,can的filter设置我大概有个概念,对原始数据针的过滤 这应该是硬件层面的参数设置。 2,can的回调函数在rtthread里都需要调用rt_device_set_rx_indicate来指定,但是为什么例子的程序里没有呢? 3, 我在用其他rtthread的sample基本不用改代码就可以直接使用,很冒昧的问一下,我总感觉这个例子还不是很完善,对于像我这样的小白来讲不能拿来直接用。 4,如果需要修改地方 应该怎么改合理,需要改那些地方。我用的是正点原子 stm32f767的开发板。
RT_CAN_USING_HDR我已经打开了,如果不打开编译错误会有很多。
期待本问题的根本解决方案~
bsp/stm32f10x
,其中的bxcan.c
中是会自动对hdr赋值的
https://github.com/RT-Thread/rt-thread/blob/76431f6b00cb2558f072acf01c442e756c481ad1/bsp/stm32f10x/drivers/bxcan.c#L869-L876bsp/stm32f10x
,使用了 HAL 驱动,HAL 驱动中看起来没有对 hdr 进行赋值,而是采用了用户设置的值
https://github.com/RT-Thread/rt-thread/blob/27ed5ee61cf77b67e5bb03a7822e46d723082e54/bsp/stm32/libraries/HAL_Drivers/drv_can.c#L289-L303
我对 HAL 驱动的 can 代码不太熟悉,不知道能不能改,所以现在只能临时手动设置 hdrrt_hw_can_isr
,然后调用 filter 中设置的回调函数
https://github.com/RT-Thread/rt-thread/blob/76431f6b00cb2558f072acf01c442e756c481ad1/components/drivers/can/can.c#L836-L847rt_hw_can_isr
https://github.com/RT-Thread/rt-thread/blob/dab737f6375f5cdd86ad3bc6d166657b17364948/bsp/stm32/libraries/HAL_Drivers/drv_can.c#L551-L554
可能因为什么条件没有满足,所以没有调用到 @Maxding001 你可以跟踪一下rt_hw_can_isr
看看是什么条件收起的谢谢大神回复 1.1,因为默认的hdr设置在can.h里的
{(id), (ide), (rtr), (mode), (mask), -1, (ind), (args)}
其中的-1 就是把can_data.filter->items[0].hdr 变成-1.
1.2,在can.c里有 291行
for (int i = 0; i < filter_cfg->count; i++)
{
drv_can->FilterConfig.FilterBank = filter_cfg->items[i].hdr;
drv_can->FilterConfig.FilterIdHigh = (filter_cfg->items[i].id >> 13) & 0xFFFF;
drv_can->FilterConfig.FilterIdLow = ((filter_cfg->items[i].id << 3) |
(filter_cfg->items[i].ide << 2) |
(filter_cfg->items[i].rtr << 1)) & 0xFFFF;
drv_can->FilterConfig.FilterMaskIdHigh = (filter_cfg->items[i].mask >> 16) & 0xFFFF;
drv_can->FilterConfig.FilterMaskIdLow = filter_cfg->items[i].mask & 0xFFFF;
drv_can->FilterConfig.FilterMode = filter_cfg->items[i].mode;
/ Filter conf /
HAL_CAN_ConfigFilter(&drv_can->CanHandle, &drv_can->FilterConfig);
}
其中的HAL_CAN_ConfigFilter对硬件filter进行了设置但是我发现FilterBank 的说明是
uint32_t FilterBank; /!< Specifies the filter bank which will be initialized.
For single CAN instance(14 dedicated filter banks),
this parameter must be a number between Min_Data = 0 and Max_Data = 13.
For dual CAN instances(28 filter banks shared),
this parameter must be a number between Min_Data = 0 and Max_Data = 27. /
所以hdr的能设置的参数只能是0到27,为什么在官方文件里can.h要把hdr默认初始化为-1?
1.3,在can_rtthread.c里面的
err = rt_event_recv(&canpara->event,
( 1 <
continue;
}
因为rt_event_recv的set参数不能是1<<-1 因为初始化时把items[0].hdr变成了-1 所以程序一直死循环,我的感觉是在
struct rt_can_filter_item filter1item[1] =
{
RT_CAN_FILTER_ITEM_INIT(0x181, 0, 0, 1, 0, can1ind, &can_data.event)//不能用
{0x181, 0, 0, 1, 0,**1**, can1ind, &can_data.event} //用于替代
}; 第一行不能用,用第二行的初始化来代替。这样理解对吗?
2.1我追踪了一下程序 用PC的can测试设备发送了一针内容为 ID是0x180 EID:0 rtr:0 DLC:2 DATA1:1 DATA2:1 就是标准针 数据针 目标1号的PDO发送 数据带2个字节分别是1和2 我的程序能进入到rt_hw_can_isr,并且收到了以上的数据针。 2.2 数据从链表listmsg = rt_list_entry(rx_fifo->freelist.next, struct rt_can_msg_list, list);里得到 2.3但是 hdr = tmpmsg.hdr;的赋值一直是0;所以程序一直运行不下去,无法调用回调ind if (can->hdr != RT_NULL && can->hdr[hdr].connected && can->hdr[hdr].filter.ind) //can->hdr =RT_NULL { rt_size_t rx_length; RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0);
level = rt_hw_interrupt_disable();
rx_length = can->hdr[hdr].msgs * sizeof(struct rt_can_msg);
rt_hw_interrupt_enable(level);
if (rx_length)
{
can->hdr[hdr].filter.ind(&can->parent, can->hdr[hdr].filter.args, hdr, rx_length);
}
}
2.4我发现在drv_can.c 的static int _can_recvmsg(struct rt_can_device can, void buf, rt_uint32_t fifo)里面
status = HAL_CAN_GetRxMessage(hcan, fifo, &rxheader, pmsg->data); if (HAL_OK != status) return -RT_ERROR; / get id / if (CAN_ID_STD == rxheader.IDE) { pmsg->ide = RT_CAN_STDID; pmsg->id = rxheader.StdId; } else { pmsg->ide = RT_CAN_EXTID; pmsg->id = rxheader.ExtId; } / get type / if (CAN_RTR_DATA == rxheader.RTR) { pmsg->rtr = RT_CAN_DTR; } else { pmsg->rtr = RT_CAN_RTR; } / get len / pmsg->len = rxheader.DLC; / get hdr / if (hcan->Instance == CAN1) { pmsg->hdr = (rxheader.FilterMatchIndex + 1) >> 1; } 在can的301标准格式里面数据针不带pmsg->hdr = (rxheader.FilterMatchIndex + 1) >> 1
我不理解的地方在hdr为什么包含在原始针里,而标准里没有提到?我哪里理解错了?
pmsg->hdr = (rxheader.FilterMatchIndex + 1) >> 1;
pmsg->hdr = (1+1)>>1 = 4
除非你设置的就-1
谢谢 我有点明白了. 1,目前我的做法是关闭了RT_CAN_USING_HDR然后用rt_device_set_rx_indicate(candev,can_rx_call);重新制定了一个回调,现在可以正常处理canDispatch(OD_Data, &co_msg);了。 2,在master402_canopen.c里面 int canopen_init(void) { OD_Data->heartbeatError = master402_heartbeatError; OD_Data->initialisation = master402_initialisation; OD_Data->preOperational = master402_preOperational; OD_Data->operational = master402_operational; OD_Data->stopped = master402_stopped; OD_Data->post_sync = master402_post_sync; OD_Data->post_TPDO = master402_post_TPDO; OD_Data->storeODSubIndex = (storeODSubIndex_t)master402_storeODSubIndex; OD_Data->post_emcy = (post_emcy_t)master402_post_emcy;
canOpen(&agv_board, OD_Data);
initTimer();
// Start timer thread
StartTimerLoop(&InitNodes);
return 0;
} INIT_APP_EXPORT(canopen_init);
void InitNodes(CO_Data* d, UNS32 id) { setNodeId(OD_Data, 0x01); setState(OD_Data, Initialisation); } 程序一直不会执行InitNodes()函数,这是什么原因呢?
InitNodes 是在定时器里回调的,要检查一下你的 hwtimer 配置了
我在rtconfig.h里设定了
然后我测试了 perpheral_samples里面的 hwtimer_sample 没有问题
可是用timer_rtthred.c里面的initTimer一直不能调用到timer_timeout_cb 好奇怪?
void initTimer(void)
{
rt_thread_t tid;
rt_err_t err;
rt_hwtimer_mode_t mode;
rt_hwtimerval_t timeout_s;
int freq = 1000000;
canfstvl_mutex = rt_mutex_create("canfstvl",RT_IPC_FLAG_FIFO);
canfstvl_timer_sem = rt_sem_create("canfstvl", 0, RT_IPC_FLAG_FIFO);
canfstvl_timer_dev = rt_device_find(CANFESTIVAL_TIMER_DEVICE_NAME);
RT_ASSERT(canfstvl_timer_dev != RT_NULL);
err = rt_device_open(canfstvl_timer_dev, RT_DEVICE_OFLAG_RDWR);
if (err != RT_EOK)
{
rt_kprintf("CanFestival open timer Failed! err=%d\n", err);
return;
}
rt_device_set_rx_indicate(canfstvl_timer_dev, timer_timeout_cb);
err = rt_device_control(canfstvl_timer_dev, HWTIMER_CTRL_FREQ_SET, &freq);
if (err != RT_EOK)
{
rt_kprintf("Set Freq=%dhz Failed\n", freq);
return;
}
mode = HWTIMER_MODE_PERIOD;//HWTIMER_MODE_PERIOD HWTIMER_MODE_ONESHOT
err = rt_device_control(canfstvl_timer_dev, HWTIMER_CTRL_MODE_SET, &mode);
if (err != RT_EOK)
{
rt_kprintf("set mode failed! ret is :%d\n", err);
return ;
}
timeout_s.sec = 1;
timeout_s.usec = 0;
if (rt_device_write(canfstvl_timer_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
{
rt_kprintf("set timeout value failed\n");
return;
}
rt_device_read(canfstvl_timer_dev, 0, &last_timer_val, sizeof(last_timer_val));
tid = rt_thread_create("cf_timer",
canopen_timer_thread_entry, RT_NULL,
1024, CANFESTIVAL_TIMER_THREAD_PRIO, 20);
if (tid != RT_NULL) rt_thread_startup(tid);
}
我在rtconfig.h里设定了
define CANFESTIVAL_TIMER_DEVICE_NAME "timer13"
define BSP_USING_TIM
define BSP_USING_TIM13
define BSP_USING_TIM11
然后我测试了 perpheral_samples里面的 hwtimer_sample 没有问题
可是用timer_rtthred.c里面的initTimer一直不能调用到timer_timeout_cb 好奇怪? void initTimer(void) { rt_thread_t tid; rt_err_t err; rt_hwtimer_mode_t mode; rt_hwtimerval_t timeout_s; int freq = 1000000;
canfstvl_mutex = rt_mutex_create("canfstvl",RT_IPC_FLAG_FIFO); canfstvl_timer_sem = rt_sem_create("canfstvl", 0, RT_IPC_FLAG_FIFO); canfstvl_timer_dev = rt_device_find(CANFESTIVAL_TIMER_DEVICE_NAME); RT_ASSERT(canfstvl_timer_dev != RT_NULL); err = rt_device_open(canfstvl_timer_dev, RT_DEVICE_OFLAG_RDWR); if (err != RT_EOK) { rt_kprintf("CanFestival open timer Failed! err=%d\n", err); return; } rt_device_set_rx_indicate(canfstvl_timer_dev, timer_timeout_cb); err = rt_device_control(canfstvl_timer_dev, HWTIMER_CTRL_FREQ_SET, &freq); if (err != RT_EOK) { rt_kprintf("Set Freq=%dhz Failed\n", freq); return; } mode = HWTIMER_MODE_PERIOD;//HWTIMER_MODE_PERIOD HWTIMER_MODE_ONESHOT err = rt_device_control(canfstvl_timer_dev, HWTIMER_CTRL_MODE_SET, &mode); if (err != RT_EOK) { rt_kprintf("set mode failed! ret is :%d\n", err); return ; } timeout_s.sec = 1; timeout_s.usec = 0; if (rt_device_write(canfstvl_timer_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s)) { rt_kprintf("set timeout value failed\n"); return; } rt_device_read(canfstvl_timer_dev, 0, &last_timer_val, sizeof(last_timer_val)); tid = rt_thread_create("cf_timer", canopen_timer_thread_entry, RT_NULL, 1024, CANFESTIVAL_TIMER_THREAD_PRIO, 20); if (tid != RT_NULL) rt_thread_startup(tid);
}
没有开启定时器,需要自己开启,在StartTimerLoop(&InitNodes)语句执行完成之后开启,因为该函数会调用SetAlarm(NULL, 0, init_callback, 0, 0),该函数又会调用setTimer(real_timer_value),real_timer_value=value=0,从而定时器关闭。
本人刚接触RT-Thread,最近有个项目需要控制一台变频器,通信方式是CANOpen CIA402的方式。 硬件是正点原子的 阿波罗stm32F767开发版
1,首先我在ENV里只激活了CAN 并且用周立功的CAN测试仪器 测试了can的通讯口,可以正常收发。 2,然后再在ENV里激活了CANFentival的组件
想测试一下系统自带的例子CIA402。 3,程序编译通过 下载后运行发现FINSH不能正常工作。 4,监控程序后发现程序在can_rtthread.c里面死循环 void canopen_recv_thread_entry(void parameter) { struct can_app_struct canpara = (struct can_app_struct *) parameter; struct rt_can_msg msg; rt_uint32_t e; Message co_msg;
}
5,分析原因发现在can.h里
define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,ind,args) \
把HDR定义为-1 导致 上面的 rt_event_recv 返回报错。
6,首先问题是,can.h里的初始化对吗?给的例子程序难道不能使用吗? 请高人指点一下。