Linux can总线调试学习记录

时间:2021-11-06 02:58:52

由于最近工作需要,需要用到can总线,自己以前又没有用到过can总线,所以记录下来自己的学习过程。

由于我是在linux下操作can总线的,所以一下内容主要是linux下的can操作过程。

首先,配置linux下can驱动,我所用的平台是AM335x,AM335x有两个can接口,can0和can1,以下为can0的配置过程,can1类似

1:进入mach_omap2目录修改mux33xx.c文件,修改后:

_AM33XX_MUXENTRY(UART1_CTSN,0,

"uart1_ctsn",NULL, "d_can0_tx", "i2c2_sda",

"spi1_cs0", NULL, NULL,"gpio0_12"),

_AM33XX_MUXENTRY(UART1_RTSN,0,

"uart1_rtsn",NULL, "d_can0_rx", "i2c2_scl",

"spi1_cs1", NULL,NULL, "gpio0_13"),



2:修改board-am335xevm.c:

static structpinmux_config d_can_wxudong_pin_mux[] = {

{"uart1_ctsn.d_can0_tx",OMAP_MUX_MODE2 | AM33XX_PULL_ENBL},

{"uart1_rtsn.d_can0_rx",OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP},

{NULL, 0},

};

static voidd_can_init(int evm_id, int profile)

{

lsd_dbg(LSD_DBG,"Enter boardinit:%s\n",__FUNCTION__);

switch (evm_id) {

case LOW_COST_EVM:

setup_pin_mux(d_can_wxudong_pin_mux);

am33xx_d_can_init(0);

break;

}

}

static struct evm_dev_cfg beaglebone_dev_cfg[]= {

{d_can_init, DEV_ON_BASEBOARD, PROFILE_NONE},

{NULL, 0, 0},

};




添加d_can_init函数

修改完之后重新编译内核,烧录内核到AM335x平台上,在命令行中输入ifconfig -a会发现can0设备。

第二部,编写can应用层demo,这里要注意,can单设备可以用示波器测量TX引脚,但是只能用回环模式,

在命令行输入canconfig can0 ctrlmode loopback on,回环模式测试

测试程序:

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<unistd.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<signal.h>

#include<sys/socket.h>

#include<netinet/in.h>

#include<errno.h>

#include<linux/if.h>

#include<linux/sockios.h>

#include<linux/ioctl.h>

#include<getopt.h>

#include<sys/mman.h>

#include"ioctl.h"

#include"can.h"

int signalquit;

void sighandler(intsig)

{

switch(sig){

case SIGINT:

signalquit =1;

break;

}

}

static voidprint_usage(char *prg)

{

fprintf(stderr,

"Usage: %s <can-interface> [Options] \n"

"Options:\n"

" -h, --helpthis help\n"

" -b, --baudrate=BPSbaudrate in bits/sec\n"

" -B, --bittime=BRP:PROP_SEG:PHASE_SEG1:PHASE_SEG2:SJW:SAM\n",

prg);

}

can_baudrate_tstring_to_baudrate(char *str)

{

can_baudrate_t baudrate;

if (sscanf(str, "%i", &baudrate)!= 1)

return -1;

return baudrate;

}

int main(int argc,char *argv[])

{

char ifname[16];

int can_fd = -1;

int new_baudrate = -1;

int bittime_count = 0, bittime_data[6];

struct ifreq ifr;

struct sockaddr_can addr;

struct can_frame frame;

can_baudrate_t*baudrate;

structcan_bittime *bittime;

intopt, ret;

char*ptr;

int nbytes,i;

struct option long_options[] = {

{ "help",no_argument, 0, 'h' },

{ "baudrate",required_argument, 0, 'b'},

{ "bittime",required_argument, 0, 'B'},

{ 0, 0, 0, 0},

};

while((opt = getopt_long(argc, argv, "hb:B:",long_options, NULL)) != -1) {

switch (opt) {

case 'h':

print_usage(argv[0]);

exit(0);

case 'b':

new_baudrate =string_to_baudrate(optarg);

if (new_baudrate ==-1) {

print_usage(argv[0]);

exit(0);

}

break;

case 'B':

ptr = optarg;

while (1) {

bittime_data[bittime_count++]= strtoul(ptr, NULL, 0);

if (!(ptr = strchr(ptr,':')))

break;

ptr++;

}

if (bittime_count!= 6) {

print_usage(argv[0]);

exit(0);

}

break;

default:

fprintf(stderr,"Unknown option %c\n", opt);

break;

}

}

/* Get CAN interface name */

if (optind != argc - 1 &&optind != argc - 2) {

print_usage(argv[0]);

return 0;

}

strncpy(ifname,argv[optind], IFNAMSIZ);

strncpy(ifr.ifr_name,ifname, IFNAMSIZ);

can_fd= socket(PF_CAN, SOCK_RAW, CAN_RAW);

if(can_fd < 0) {

perror("socket");

return can_fd;

}

ret= ioctl(can_fd, SIOCGIFINDEX, &ifr);

if(ret) {

perror("ioctl:SIOCGIFINDEX");

return ret;

}

addr.can_family = PF_CAN;

addr.can_ifindex = ifr.ifr_ifindex;

if(new_baudrate != -1) {

printf("baudrate:%d\n", new_baudrate);

baudrate = (can_baudrate_t*)&ifr.ifr_ifru;

*baudrate = new_baudrate;

ret = ioctl(can_fd,SIOCSCANBAUDRATE, &ifr);

if (ret) {

perror("ioctl:SIOCSCANBAUDRATE");

gotoabort;

}

}

if(bittime_count) {

bittime = (structcan_bittime *)&ifr.ifr_ifru;

bittime->type =CAN_BITTIME_STD;

bittime->std.brp =bittime_data[0];

bittime->std.prop_seg =bittime_data[1];

bittime->std.phase_seg1 =bittime_data[2];

bittime->std.phase_seg2 =bittime_data[3];

bittime->std.sjw =bittime_data[4];

bittime->std.sam =bittime_data[5];

printf("bit-time:brp=%d prop_seg=%d phase_seg1=%d "

"phase_seg2=%d sjw=%dsam=%d\n",

bittime->std.brp,

bittime->std.prop_seg,

bittime->std.phase_seg1,

bittime->std.phase_seg2,

bittime->std.sjw,

bittime->std.sam);

ret = ioctl(can_fd,SIOCSCANCUSTOMBITTIME, &ifr);

if (ret) {

perror("ioctl:SIOCSCANCUSTOMBITTIME\n");

goto abort;

}

}

if(bind(can_fd,(struct sockaddr*)&addr,sizeof(addr))){

perror("bind\n");

goto abort;

}

memset(&frame,0x0,sizeof(frame));

frame.can_id = 0x123;

frame.can_dlc =8;

strncpy(frame.data,"12345678",8);

while(!signalquit){

nbytes =write(can_fd,&frame,sizeof(frame));

if(nbytes < 0){

perror("write");

goto abort;

}

if(nbytes < sizeof(structcan_frame)){

printf("write:incompletecan frame\n");

goto abort;

}

printf("write a canframe:can_id=0x%x,can_dlc=%d,data=%s\n",frame.can_id,frame.can_dlc,frame.data);

for(i=0;i<10000;i++);

}

close(can_fd);

return0;

abort:

close(can_fd);

returnret;

}




然后再用candump can0 或者示波器测量tx脚即可看到输出波形。

参考文献

http://processors.wiki.ti.com/index.php/Talk:AM335X_DCAN_Driver_Guide

以上就是Linux can总线调试学习记录的全文介绍,希望对您学习和使用linux系统开发有所帮助.


from:http://www.zhimengzhe.com/linux/74777.html