Higher busload with SocketCAN

Hello all,

we are using Colibri iMX6s with Linux.
When I try to send CAN-frames with SocketCAM as fast as possible, I can see each frame taking about 440us with gaps of 300us between them.

What happens in that 300us?
How can I generate a higher busload, even up to 100%?

Thanks

hi @Grimme

Welcome to the Toradex Community!!!

Could you provide the version of the hardware and software of your module? Which carrier board are you using?

Concerning your issue with CAN, how are you sending the CAN Messages? What is the Bit rate? Could you provide a sample code, so we can reproduce error?

Thanks and best regards, Jaski

Hi Jaski,

I’m using an evaluation board V3.2B.

uname -a says:
Linux colibri-imx6 4.9.87-rt62-dirty #4 PREEMPT RT Wed Aug 8 17:32:48 CEST 2018 armv7l GNU/Linux

I’m using a bitrate of 2500000.

This is my complete code, I hope there is nothing wrong with it:

// std stuff
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// socket stuff
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
// can stuff
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/can/error.h>
// pthread stuff
#include <pthread.h>
#ifdef GPIO
// gpio stuff
#include "gpio.h"
#define GPIO_PIN_NO 7
#endif

#ifndef COUNT
#define COUNT 1
#endif

static void *read_thread(void *arg)
{
    int fd=(int)arg;
    struct can_frame data;

    while( read(fd, &data, sizeof(data)) > 0 )
        if( data.can_id & CAN_ERR_FLAG )
        {
            if( data.can_id & CAN_ERR_TX_TIMEOUT)
                printf("TX timeout (by netdevice driver)\n");
            if( data.can_id & CAN_ERR_LOSTARB   )
                printf("lost arbitration: 0x%02hhx\n",data.data[0]);
            if( data.can_id & CAN_ERR_CRTL      )
                printf("controller problems: 0x%02hhx\n",data.data[1]);
            if( data.can_id & CAN_ERR_PROT      )
                printf("protocol violations: 0x%02hhx 0x%02hhx\n",data.data[2],data.data[3]);
            if( data.can_id & CAN_ERR_TRX       )
                printf("transceiver status: 0x%02hhx\n",data.data[4]);
            if( data.can_id & CAN_ERR_ACK       )
                printf("received no ACK on transmission\n");
            if( data.can_id & CAN_ERR_BUSOFF    )
                printf("bus off\n");
            if( data.can_id & CAN_ERR_BUSERROR  )
                printf("bus error (may flood!)\n");
            if( data.can_id & CAN_ERR_RESTARTED )
                printf("controller restarted\n");
        }
        else
            printf("data frame received\n");

    return NULL;
}

int main(int argc, char **argv)
{
    int status=-1;
    int fd;

    // get a socket from os
    fd=socket(AF_CAN, SOCK_RAW, CAN_RAW);
    if(fd > 0)
    {
        struct ifreq ifr;

        // get the interface index
        strcpy(ifr.ifr_name, "can0");
        if( !ioctl(fd, SIOCGIFINDEX, &ifr) )
        {
            struct sockaddr_can addr;

            // bind the socket to the interface
            addr.can_family=AF_CAN;
            addr.can_ifindex=ifr.ifr_ifindex;
            if( !bind(fd, (struct sockaddr *)&addr,sizeof(addr)) )
            {
                //can_err_mask_t mask=0x01ff; // gimme everything
                can_err_mask_t mask=CAN_ERR_MASK; // gimme everything
                pthread_t thread;

                // set error filter
                setsockopt(fd, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &mask, sizeof(mask));

                // start receive thread
                if( !pthread_create(&thread, NULL, read_thread, (void *)fd) )
                {
                    struct can_frame data={
                                            0x0100,     // can_id
                                            8,          // payload length
                                            0,0,0,      // padding
                                            {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}
                                        };
                    ssize_t n;
                    int count;
#ifdef GPIO
                    GPIO_PIN_DAT gpio_pin;
                    gpio_pin.gpio_pin_no=GPIO_PIN_NO;
                    gpio_pin.gpio_set_dir=GPIO_DIR_OUT;
                    gpio_setup(&gpio_pin);
                    gpio_write_pin(&gpio_pin, LOW);
#endif
                    while(1)
                    {
#ifdef STEP
                        getchar();
#endif
#ifdef GPIO
                        gpio_write_pin(&gpio_pin, HIGH);
#endif
                        for(count=0; count<COUNT; count++)
                        {
                            n=write(fd, &data, sizeof(data));
                            //printf("%d bytes written\n",n);
                        }
#ifdef GPIO
                        gpio_write_pin(&gpio_pin, LOW);
#endif
                    }
                }
            }
            else
                perror("bind() failed");
        }
        else
            perror("ioctl() failed");
        close(fd);
    }
    else
        perror("socket() failed");

    return status;
}

Thanks.

Hi Jaski,

I also tried a kernel without realtime-patch as provided by the toradex-git:

# uname -a
Linux colibri-imx6 4.9.87 #1 SMP PREEMPT Tue Jul 10 13:50:10 CEST 2018 armv7l GNU/Linux

but it’s still the same.

Maybe there’s something wrong with my device-tree:

diff -c imx6dl-colibri-eval-v3.dts imx6dl-colibri-grimme.dts
*** imx6dl-colibri-eval-v3.dts	2018-07-10 11:51:56.887519190 +0200
--- imx6dl-colibri-grimme.dts	2018-08-15 10:04:58.018627966 +0200
***************
*** 101,106 ****
--- 101,107 ----
  &ecspi4 {
  	status = "okay";
  
+ #if 0
  	mcp258x0: mcp258x@1 {
  		compatible = "microchip,mcp2515";
  		reg = <0>;
***************
*** 110,121 ****
--- 111,132 ----
  		spi-max-frequency = <10000000>;
  		status = "okay";
  	};
+ #endif
  	spidev0: spidev@1 {
  		compatible = "toradex,evalspi";
  		reg = <0>;
  		spi-max-frequency = <23000000>;
  		status = "disabled";
  	};
+ 	can0: can@1 {
+ 		compatible = "microchip,mcp2515";
+ 		reg = <0>;
+ 		clocks = <&clk16m>;
+ 		interrupt-parent = <&gpio3>;
+ 		interrupts = <27 0x2>;
+ 		spi-max-frequency = <10000000>;
+ 		status = "okay";
+ 	};
  };
  
  /*

or are there any module-parameters I can try?

Thanks

hi

Thanks for the code and the device tree.

Actually CAN supports a Bit rate up to 1Mb/s, and not 2.5Mb/s as you set in your application.
Further, you are using the mcp2515 (CAN over SPI) Controller. For a higher can load, you should try to use Flexcan as described here.

I am not sure, that it will be possible to have 100% Bus Load since the kernel will need to load the data from ram to the CanBuffer and this cannot run without any interruption all the time. Anyway, try to use to flexcan first.

Best regards, Jaski

Hi Jaski,

2.5Mbit/s was a typo (too many zeros).

I tried Flexcan and I got a load around 97%, that’s what I wanted.

Thanks

2.5Mbit/s was a typo (too many zeros).
Yeah, I thought it. It can happen.

I tried Flexcan and I got a load around 97%, that’s what I wanted.
Pefect that it works. Thanks for the feedback.

Thanks
You are welcome.