首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >可以在CAN总线上模拟仲裁吗?

可以在CAN总线上模拟仲裁吗?
EN

Stack Overflow用户
提问于 2019-07-18 07:36:45
回答 1查看 815关注 1票数 2

设置

我有两个节点连接到一个CAN总线上。第一个节点是一个黑匣子,由一些实时硬件控制.第二个节点是带有峰值USB CAN控制器的Linux机器:

代码语言:javascript
复制
+--------+               +----------+
| HW CAN |--- CAN BUS ---| Linux PC |
+--------+               +----------+

为了研究与偶有帧丢失有关的一些问题,我想模仿CAN仲裁过程。为此,我将CAN比特率设置为125 To /s,并以1ms延迟的随机CAN帧淹没它,从can-utils控制can总线负载。我还监视运行candump can0,0~0,#ffffffff的CAN错误帧,以及使用ip -s -d link show can进行的总体can统计。

代码语言:javascript
复制
26: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 10
    link/can  promiscuity 0
    can state ERROR-ACTIVE restart-ms 0
          bitrate 125000 sample-point 0.875
          tq 500 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
          pcan_usb: tseg1 1..16 tseg2 1..8 sjw 1..4 brp 1..64 brp-inc 1
          clock 8000000
          re-started bus-errors arbit-lost error-warn error-pass bus-off
          0          0          0          0          0          0
    RX: bytes  packets  errors  dropped overrun mcast
    120880     15110    0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    234123     123412   0       0       0       0

问题

现在的问题是,当负载为99%时,给定的设置在零冲突(仲裁)或任何其他类型的错误帧下工作数小时。当我减少延迟以增加总线负载时,write(2)失败了,"ENOBUFS 105没有可用的缓冲区空间“或"EAGAIN 11 Resource临时不可用”--实际错误取决于我是修改qlen参数还是设置为默认值。

据我所知,我的负担不是不够就是太多。让两个节点进入仲裁的正确方式是什么?一个成功的结果将是一个接收到的CAN错误帧,该帧对应于来自CAN_ERR_LOSTARB常量的can/error.h排序规则的值,而不是。

源代码

HW节点(Arduino应与CAN板)

代码语言:javascript
复制
#include <due_can.h>

CAN_FRAME input, output;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(9600);
  Serial.println("start");

//  Can0.begin(CAN_BPS_10K);
  Can0.begin(CAN_BPS_125K);
//  Can0.begin(CAN_BPS_250K);


  output.id = 0x303;
  output.length = 8;
  output.data.low = 0x12abcdef;
  output.data.high = 0x24abcdef;
}

// the loop function runs over and over again forever
void loop() {    
    Can0.sendFrame(output);
    Can0.read(input);

    delay(1);
}

Linux节点

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <linux/can.h>
#include <linux/can/raw.h>

int main(int argc, char *argv[])
{
  int s;
  int nbytes;
  struct sockaddr_can addr;
  struct can_frame frame;
  struct ifreq ifr;

  const char *ifname = "can0";

  if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
    perror("Error while opening socket");
    return -1;
  }

  strcpy(ifr.ifr_name, ifname);
  ioctl(s, SIOCGIFINDEX, &ifr);

  addr.can_family  = AF_CAN;
  addr.can_ifindex = ifr.ifr_ifindex;

  printf("%s at index %d\n", ifname, ifr.ifr_ifindex);

  if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
    perror("Error in socket bind");
    return -2;
  }

  frame.can_id  = 0x304;
  frame.can_dlc = 2;
  frame.data[0] = 0x11;
  frame.data[1] = 0x22;

  int sleep_ms = atoi(argv[1]) * 1000;

  for (;;) {
    nbytes = write(s, &frame, sizeof(struct can_frame));
    if (nbytes == -1) {
      perror("write");
      return 1;
    }
    usleep(sleep_ms);
  }
  return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-07-19 08:26:59

文档小节4.1.2原始套接字选项CAN_RAW_ERR_FILTER中,它指出在默认情况下错误不是激活的,这就是为什么ip中丢失的仲裁字段没有增加的原因。

为了切换所有错误,您需要添加这两行:

代码语言:javascript
复制
can_err_mask_t err_mask = CAN_ERR_MASK;
setsockopt(socket_can, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask));

但是这个特性并不适用于所有的驱动程序和设备,因为它需要从硬件上有一个回送模式。在峰值USB的情况下,如果来自设备的固件版本小于4.x,则没有回环[来源]。因此,SocketCAN将无法检测丢失的仲裁。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57089352

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档