CAN IoT Card driver

Progress update :

echo 13 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio13/direction
echo 1 > /sys/class/gpio/gpio13/value

pin SPI1_CLK / SPI1_MISO / SPI1_MOSI follow the state on GPIO13 on WP76…

SPI bus seems don’t work. mcp2515 is not probed.

Asyal any idea ?

@Francis.duhaut I’ll build this on Friday and get back to you with the right steps.

ok thanks :slight_smile:

@asyal any progress on the CAN for the WP76 ?

I ran into the same issues you did and will work on resolving it next week.

Thank’s a lot for your help.

  1. Reflash new image with CAN driver module support to the target board
    FDT command: fdt yocto_wp85.cwe

When I run it I get: command not found: fdt
What do I need?

Use :
cfglegato
fwupdate download yocto_wp85.cwe 192.168.2.2

Thanks, Francis, I got one step closer but I am a bit confused about next one. When should I remove the card and how? I tried different ways but
echo 2 > /sys/class/gpio/export
gives me
sh: write error: Device or resource busy

Finally, saw the can0 line with ifconfig command after all those steps:

echo 2 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio2/direction
echo 1 > /sys/class/gpio/gpio2/value

// Enable level shifter on the CAN IoT card
echo 13 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio13/direction
echo 1 > /sys/class/gpio/gpio13/value

modprobe can
modprobe can-dev
modprobe can-raw
modprobe mcp251x
ip link set can0 type can bitrate 125000 triple-sampling on
ifconfig can0 up

And after restarting MangOH red board I can not get it up and running again, why?
cannot find device “can0”

Hello

You must start a script who intialize the CAN.
You can do that at startup or include this script into your application.

In your project create a folder “script” , inside create a file “can_init.sh”

copy/paste this code into “can_init.sh”

#!/bin/sh

export PATH=$PATH:/sbin

ifconfig can0 down

echo 2 > /sys/class/gpio/export

echo out > /sys/class/gpio/gpio2/direction

echo 1 > /sys/class/gpio/gpio2/value

echo 13 > /sys/class/gpio/export &&

echo out > /sys/class/gpio/gpio13/direction &&

echo 1 > /sys/class/gpio/gpio13/value &&

modprobe can &&

sleep 1 &&

modprobe can-dev &&

sleep 1 &&

modprobe can-raw &&

sleep 1 &&

modprobe mcp251x &&

sleep 1

CAN=ifconfig | cut -c -4 | sed 's/^\s\+//' | sort | uniq | grep can0

if [ -z “$CAN” ]; then

ip link set can0 type can bitrate 500000 triple-sampling on &&

sleep 1 &&

ifconfig can0 up

fi

In your app create this function :

#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define INTERFACE_NAME_SIZE 15

#define SOCKET_ERROR 1
#define SOCK_IOCTL_ERROR 2
#define SOCK_BINDING_ERROR 3
#define SOCK_WRITING_ERROR 4
#define SOCK_READING_ERROR 5
#define WRONG_DLC 6
#define WRONG_ID 7

int bitrate;
int sdw; // socket descriptor write
int sdr; // socket descriptor read
int nbytesReceive;
bool canwrite;
char name[INTERFACE_NAME_SIZE];
struct can_frame frameRead;
struct can_frame frameWrite;

int can_connect(const char *interface)
{
struct sockaddr_can addr;
struct ifreq ifr;
int sock_buf_size;

sock_buf_size = 1000;


// Run the can-init.sh before advertising the service to ensure that the CAN device is
// available before we allow it to be used.
char line[256];
FILE* fp = popen("can_init.sh 2>&1", "r");
LE_ASSERT(fp != NULL);
while (fgets(line, sizeof(line), fp) != NULL)
{
	LE_INFO("can_init.sh output: %s", line);
}
int canInitResult = pclose(fp);
LE_FATAL_IF(!WIFEXITED(canInitResult), "Could not run can_init.sh");
const int canInitExitCode = WEXITSTATUS(canInitResult);
LE_FATAL_IF(canInitExitCode != 0, "can_init.sh failed with exit code %d", canInitExitCode);


// if interface string is long we will cut it
if(strlen(interface)>INTERFACE_NAME_SIZE)
{
	memcpy(name,interface,INTERFACE_NAME_SIZE);
	name[INTERFACE_NAME_SIZE-1]='\0';
}
else
{
	strcpy(name,interface);
}

// SOCKET FOR READING
if ((sdr = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
{
	return SOCKET_ERROR;
}

addr.can_family = PF_CAN;

strcpy(ifr.ifr_name, name);
if (ioctl(sdr, SIOCGIFINDEX, &ifr) < 0)
{
	return SOCK_IOCTL_ERROR;
}

addr.can_ifindex = ifr.ifr_ifindex;


if (bind(sdr, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
	return SOCK_BINDING_ERROR;
}

// Filter
struct can_filter rfilter[7]; int i = 0;
rfilter[i].can_id  = CHG_TX_STS;
rfilter[i].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG; i++;
rfilter[i].can_id   = CHG_TX_ACT;
rfilter[i].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG; i++;
rfilter[i].can_id   = BMS_CHRGR_CTL;
rfilter[i].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG; i++;
rfilter[i].can_id   = BMS_SOC_DATA;
rfilter[i].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG; i++;
rfilter[i].can_id   = BMS_BATTP_DATA;
rfilter[i].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG; i++;
rfilter[i].can_id   = BMS_BATP_DATA;
rfilter[i].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG; i++;
rfilter[i].can_id   = BMS_BATU_DATA;
rfilter[i].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG; i++;
setsockopt(sdr, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));

// SET SOCKET BUFFER SIZE
setsockopt(sdr, SOL_CAN_RAW, SO_RCVBUF, (char *)&sock_buf_size, sizeof(sock_buf_size));

// SOCKET FOR WRITING
if ((sdw = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
{
	return SOCKET_ERROR;
}
addr.can_family = PF_CAN;

strcpy(ifr.ifr_name, name);
if (ioctl(sdw, SIOCGIFINDEX, &ifr) < 0)
{
	return SOCK_IOCTL_ERROR;
}
addr.can_ifindex = ifr.ifr_ifindex;


if (bind(sdw, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
	return SOCK_BINDING_ERROR;
}

// SET SOCKET BUFFER SIZE
setsockopt(sdw, SOL_CAN_RAW, SO_SNDBUF, (char *)&sock_buf_size, sizeof(sock_buf_size));

//READ SOCKET NON-BLOCKING
int flags;
if (-1 == (flags = fcntl(sdr, F_GETFL, 0))) flags = 0;
fcntl(sdr, F_SETFL, flags | O_NONBLOCK);

return 0;

}

int can_disconnect(void)
{
close(sdw);
close(sdr);
return 0;
}

int can_send(void)
{
int nbytesWrite;

// USE SEND STANDARD FRAME
frameWrite.can_id = 0x600;
frameWrite.can_id &= CAN_SFF_MASK;

frameWrite.can_dlc = 8;
strcpy((char *)frameWrite.data, "MangoH  ");

if ((nbytesWrite = write(sdw, &frameWrite, sizeof(frameWrite))) != sizeof(frameWrite))
{
    canwrite = false;
    LE_INFO ("Writing error");
	return SOCK_WRITING_ERROR;
}


canwrite = true;
return 0;

}

int can_receive(void)
{
nbytesReceive = 1;
while (nbytesReceive != 0)
{
if ((nbytesReceive = read(sdr, &frameRead, sizeof(frameRead))) != sizeof(frameRead))
{
return SOCK_READING_ERROR;
}
/else
LE_INFO(“Receive message %X %X %X %X %X %X %X %X %X”, frameRead.can_id, frameRead.data[0], frameRead.data[1], frameRead.data[2], frameRead.data[3]
, frameRead.data[4], frameRead.data[5], frameRead.data[6], frameRead.data[7]);
/
}

return 0;

}

You just now to call it in your main :

COMPONENT_INIT
{
can_connect(“can0”);
can_send();
can_receive();

}

1 Like

Dont forget :

to run can_init.sh as a Linux script :

chmod 755 can_init.sh

I almost figured that one out, I can use some of your suggested code, very helpful, thanks a lot.
There’s one thing that I need to understand, what is the
triple-sampling on ?

I think it’s around the CAN SPI driver setting to sure that not lost can frame when you use SocketCAN.

@asyal,

Isn’t it about time to make a single, accurate, up-to-date guide to using CAN on a MangOH Red, with ALL of the CORRECT steps in ONE place, as well as a sample app?

1 Like

@abrothman yes, it is.
We will look at providing a much more simpler way for this. Will work with our linux experts and find a more easier way on this .

HI Francis ,

Thanks for your source code.
I was trying Talon CAN interface over MangoH red + WP7502 combo, it is giving me some error.
Running legato version 16.10.4 . Source compile over Developer studio.

Description Resource Path Location Type
Symbol ‘BMS_BATP_DATA’ could not be resolved sreetestcanComponent.c /sreetestcan/sreetestcanComponent line 101 Semantic Error
Symbol ‘BMS_BATTP_DATA’ could not be resolved sreetestcanComponent.c /sreetestcan/sreetestcanComponent line 99 Semantic Error
Symbol ‘BMS_BATU_DATA’ could not be resolved sreetestcanComponent.c /sreetestcan/sreetestcanComponent line 103 Semantic Error
Symbol ‘BMS_CHRGR_CTL’ could not be resolved sreetestcanComponent.c /sreetestcan/sreetestcanComponent line 95 Semantic Error
Symbol ‘BMS_SOC_DATA’ could not be resolved sreetestcanComponent.c /sreetestcan/sreetestcanComponent line 97 Semantic Error
Symbol ‘CHG_TX_ACT’ could not be resolved sreetestcanComponent.c /sreetestcan/sreetestcanComponent line 93 Semantic Error
Symbol ‘CHG_TX_STS’ could not be resolved sreetestcanComponent.c /sreetestcan/sreetestcanComponent line 91 Semantic Error

Also attaching the screenshot of my developer studio compiler error.

Please let me know which header file contain CHG parameters ??
Can you share your whole project directory ( developer studio ) ?

Thanks and Regards,

Hello

Ah this is define for message ID. It’s just a example. You can replace this message by your own message ID.

Regards,

hi @abrothman , we have simplified the experience
https://github.com/mangOH/mangOH/wiki/Running-the-MCP2515-CAN-driver-for-mangOH-for-mangOH-Red

We will also hold a Google hangout on July 18th to walk you through the process on how we built it ground up

Thanks @asyal.

I try it but I not have the mcp251x.ko into the build.

I follow instruction to update the git into the VM

cd ~/mangOH git pull && git submodule update --init
$ make red_wp76xx

The build is complete but the driver is not in the image…