About the CAN controller.

User avatar
rudi ;-)
Posts: 1247
Joined: Fri Nov 13, 2015 3:25 pm

Re: About the CAN controller.

Postby rudi ;-) » Thu Jan 18, 2018 1:07 pm

dmaxben wrote:

Code: Select all

byte my_frame[8] = {8, 7, 174, 6, 3, 0, 0, 127, 255};

CAN.sendMsgBuf (291, 0, 8, my_frame);
Two lines of code, versus 12 lines of code.
honest
i write more like 12 lines to show the user for understand and can following the thinking what's going on
with your 2 lines of code - i can not follow your thinking in code - sry


perhabs you can try to write the can driver code in 10 lines?
:D

joke -
understand what you mean. you can optimize the code like you want
i do the msg_frame example with a typedef struct
it is one line :lol:
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

ThomasB
Posts: 38
Joined: Sun Dec 25, 2016 12:11 am

Re: About the CAN controller.

Postby ThomasB » Sun Jan 21, 2018 8:52 pm

Lines of code != number of instructions.
The code looks different but does the same. As u8 is an array you can use the same syntax like you did in your example.
As Rudi says:
i do the msg_frame example with a typedef struct it is one line :lol:
Using a structure that holds all the information necessary to send a frame (and already in an hardware compatible format) is good practice as this driver(API) should not be used without a queue and a corresponding task or similar.

dmaxben
Posts: 30
Joined: Thu Nov 16, 2017 6:04 pm

Re: About the CAN controller.

Postby dmaxben » Mon Jan 22, 2018 6:26 pm

rudi ;-) wrote:
honest
i write more like 12 lines to show the user for understand and can following the thinking what's going on
with your 2 lines of code - i can not follow your thinking in code - sry


perhabs you can try to write the can driver code in 10 lines?
:D
I wish! :lol:
rudi ;-) wrote: joke -
understand what you mean. you can optimize the code like you want
i do the msg_frame example with a typedef struct
it is one line :lol:
I need to read more about using typedef struct, and how I could adapt it to do what I want.

The main thing is just being able to port my existing huge program easily without having to re-write all of the CAN stuff to work with the ESP32.....and I just like having everything "visually" on one line, rather than 12. ;)

Ben

dmaxben
Posts: 30
Joined: Thu Nov 16, 2017 6:04 pm

Re: About the CAN controller.

Postby dmaxben » Mon Jan 22, 2018 6:35 pm

ThomasB wrote:Lines of code != number of instructions.
The code looks different but does the same. As u8 is an array you can use the same syntax like you did in your example.
As Rudi says:
i do the msg_frame example with a typedef struct it is one line :lol:
Using a structure that holds all the information necessary to send a frame (and already in an hardware compatible format) is good practice as this driver(API) should not be used without a queue and a corresponding task or similar.

Yes, I probably didnt phrase that correctly, I guess I should have said "visually" 12 lines in the arduino IDE, vs 1 line.

I tried many different ways to reconfigure the syntax into one "visual" line, using a byte array, but could not get it to compile. Maybe something weird with Arduino? Any suggestions on at least how to format

Code: Select all

    my_frame.MsgID = 291;
      my_frame.FIR.B.DLC = 8;
      my_frame.data.u8[0] = 7;
      my_frame.data.u8[1] = 174;
      my_frame.data.u8[2] = 6;
      my_frame.data.u8[3] = 3;
      my_frame.data.u8[4] = 0;
      my_frame.data.u8[5] = 0;
      my_frame.data.u8[6] = 127;
      my_frame.data.u8[7] = 255;
Into something that is only one line "visually"?

Also, it doesnt seem to let me store messages in the global variables section so I can use one single message in multiple different places throughout the code, only in functions themselves?

dmaxben
Posts: 30
Joined: Thu Nov 16, 2017 6:04 pm

Re: About the CAN controller.

Postby dmaxben » Mon Jan 22, 2018 9:40 pm

Ok finally figured out what I was doing wrong, im stupid...

Code: Select all

      my_frame.FIR.B.FF = CAN_frame_ext;
      my_frame.MsgID = 271732576;
      my_frame.FIR.B.DLC = 8;

    my_frame.data = {4  , 7 , 33, 4, 255, 255, 255, 255};

      ESP32Can.CANWriteFrame(&my_frame);
That compiles and works. But for some reason it wont compile with having that my_frame array as a global variable? Actually I guess it would be a global constant...

I have some CAN messages that are used in many different places, Id rather just have each message defined once in the global variables, so I can call it whenever I want.


EDIT:

I think got it working...

In the global variables area I have:

Code: Select all

CAN_frame_t my_frame = {0  , 0 , 33, 4, 255, 255, 255, 254, 123, 77};
Then anywhere I want to send the message, I just use

Code: Select all

      my_frame.FIR.B.FF = CAN_frame_std;
      my_frame.MsgID = 670;
      my_frame.FIR.B.DLC = 8;
      ESP32Can.CANWriteFrame(&my_frame);
No idea why I need those two leading zero's in the array; If I dont have them, the ESP does not transmit the first two bytes out onto the bus properly, its like the whole thing is shifted left two bytes? So I just figured out to add two extra leading bytes in there and now it sends an 8 byte message properly.

Now it condense this into something that "looks" smaller...

Code: Select all

     my_frame.FIR.B.FF = CAN_frame_std;
      my_frame.MsgID = 670;
      my_frame.FIR.B.DLC = 8;

ESP_Dazz
Posts: 50
Joined: Fri Jun 02, 2017 6:50 am

Re: About the CAN controller.

Postby ESP_Dazz » Tue Jan 23, 2018 7:18 pm

C does not allow initialization of arrays and structures after declaration, therefore the following will not compile

Code: Select all

//Does not compile
CAN_frame_t my_frame;
my_frame.data.u8 = {1 ,2 ,3 ,4 ,5 ,6, 7, 8};

Code: Select all

CAN_frame_t my_frame = {0  , 0 , 33, 4, 255, 255, 255, 254, 123, 77};
The reason this works is because you are initializing my_frame at declaration. Regarding the two leading zeros, you are essentially setting the FIR and MsgID fields of my_frame to zero as they are the first two fields in CAN_frame_t . You can assign values to an array one element at a time after declaration, or via memcpy. For example...

Code: Select all

//Outside of main loop
uint8_t some_data[8] = {0, 1, 2, 3, 4, 5, 6, 7};    //Some message data stored as global
CAN_frame_t my_frame;   //Declaring a global frame

//Funciton to copy data into frame structure element by element
static void can_assem_msg_data(CAN_frame_t *frame, uint8_t dlc, uint8_t *data)
{
    frame->FIR.B.DLC = dlc;
    for(int i = 0; i < dlc; i++){
        frame->data.u8[i] = data[i];
    }
}

void loop()
{
    my_frame.FIR.B.FF = 1;
    my_frame.MsgID = 271732576;
    can_assem_msg_data(&my_frame, 8, some_data);
    ESP32Can.CANWriteFrame(&my_frame);
}

User avatar
rudi ;-)
Posts: 1247
Joined: Fri Nov 13, 2015 3:25 pm

Re: About the CAN controller.

Postby rudi ;-) » Tue Feb 20, 2018 1:15 pm

hi folks,

nice found, for your info:

It is called EVTVESP32CANDue Board
EVTVESP32CANDue.jpg
EVTVESP32CANDue.jpg (142.39 KiB) Viewed 1973 times
watch the Jack Rickard Tv stream at this position

best wishes
rudi ;-)
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

dedvalson
Posts: 3
Joined: Fri Feb 16, 2018 8:21 pm

CAN Controller performance

Postby dedvalson » Fri Feb 23, 2018 11:52 am

Hi,

Debated whether or not to start a new thread for this but decided to keep it all together.

I modified the CAN sample code from the Olimex distribution to do a "ping pong" between two Olimex ESP32-EVB boards. Board A sends a single packet. When B gets it it sends it back to A, which sends it back to B ...

I did this to check for long term reliability, which seems to be good, I have seen well over a million packets go back and forth.

However, I have discovered that the CAN performance I am seeing is pretty bad and it seems to vary from time to time even within the same test run. I am running the CAN bus at 125 kbits/sec. The data size is 8 bytes. According to the following this results in a packet size of 108 bits (64 bits of data plus 44 bits of overhead).

Image

I print an output each time I transmit 100 packets, so between two prints 200 packets have traveled on the bus (100 pings and 100 pongs). When I run in the monitor and time this I am seeing between 9.5 and 19.4 seconds for 1000 pings and pongs to take place. This amounts to an effective rate of 11-22 kbits. So the bus must be sitting idle 80-90% of the time.

Here is my test code:

Code: Select all

/*
 * my_olimexikus_CAN.c
 *
 *  Created on: 14.06.2017
 *      Author: rudi ;-)
 *
 *      Olimex EVB REV B
 *      with CAN
 *      CAN Rx = GPIO 35
 *      CAN Tx = GPIO  5
 *      Node   = 197 ( you can change all in Kconfig )
 *
 *      done ;-)
 *      ....
 *      code comes later to olimex github
 *      after PR visit it here
 *      https://github.com/OLIMEX/ESP32-EVB/tree/master/SOFTWARE
 *      have phun
 *      best wishes
 *      rudi ;-)
 */
/*
 * Modified to create a ping pong test program by Don Edvalson
 */


#include "freertos/FreeRTOS.h"
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"

#include "CAN.h"
#include "CAN_config.h"

/* brief  : rudi
 * content: Set the CAN Speed over Kconfig
 * you can use menuconfig for this
 * and you can expand like you need
 * you can also use your own
 * cfg - look in the main/cfg folder
 * you have then change by self
 */
 #ifndef CONFIG_ESPCAN
 #error for this demo you must enable and configure ESPCan in menuconfig
 #endif

#ifdef CONFIG_CAN_SPEED_100KBPS
#define CONFIG_SELECTED_CAN_SPEED CAN_SPEED_100KBPS
#endif

#ifdef CONFIG_CAN_SPEED_125KBPS
#define CONFIG_SELECTED_CAN_SPEED CAN_SPEED_125KBPS
#endif

#ifdef CONFIG_CAN_SPEED_250KBPS
#define CONFIG_SELECTED_CAN_SPEED CAN_SPEED_250KBPS
#endif

#ifdef CONFIG_CAN_SPEED_500KBPS
#define CONFIG_SELECTED_CAN_SPEED CAN_SPEED_500KBPS
#endif

#ifdef CONFIG_CAN_SPEED_800KBPS
#define CONFIG_SELECTED_CAN_SPEED CAN_SPEED_800KBPS
#endif

#ifdef CONFIG_CAN_SPEED_1000KBPS
#define CONFIG_SELECTED_CAN_SPEED CAN_SPEED_1000KBPS
#endif

#ifdef CONFIG_CAN_SPEED_USER_KBPS
#define CONFIG_SELECTED_CAN_SPEED CONFIG_CAN_SPEED_USER_KBPS_VAL /* per menuconfig */
#endif

/* brief  : rudi
 * content: config CAN Speed, Tx, Rx Pins taken from Kconfig
 * over menuconfig you can set the cfg
 * defines are used in the head of code then
 * if you change to user cfg
 * you can change here too by your self
 * how you need this.
*/
CAN_device_t CAN_cfg = {
	.speed		= CONFIG_SELECTED_CAN_SPEED,	// CAN Node baudrade
	.tx_pin_id 	= CONFIG_ESP_CAN_TXD_PIN_NUM,	// CAN TX pin example menuconfig GPIO_NUM_5
	.rx_pin_id 	= CONFIG_ESP_CAN_RXD_PIN_NUM,	// CAN RX pin example menuconfig GPIO_NUM_35 ( Olimex )
	.rx_queue	= NULL,							// FreeRTOS queue for RX frames
};

esp_err_t event_handler(void *ctx, system_event_t *event)
{
    return ESP_OK;
}

void task_CAN( void *pvParameters ){
    (void)pvParameters;

    //frame buffer
    CAN_frame_t __RX_frame;

    //create CAN RX Queue
    CAN_cfg.rx_queue = xQueueCreate(10,sizeof(CAN_frame_t));

    //start CAN Module
    CAN_init();
    printf("Can Init done - wait now..\n");
	uint32_t counter = 0;
    while (1){
        //receive next CAN frame from queue
        if(xQueueReceive(CAN_cfg.rx_queue,&__RX_frame, 3*portTICK_PERIOD_MS)==pdTRUE){
			counter++;
			if (counter % 100 == 0) {
				printf("Frame from : 0x%08x, DLC %d count %u \n", __RX_frame.MsgID, __RX_frame.FIR.B.DLC, counter);
			}
        	//loop back frame
	        __RX_frame.MsgID = CONFIG_ESP_CAN_NODE_ITSELF;
        	CAN_write_frame(&__RX_frame);
        }
    }
}


void app_main(void)
{
	// wait for all print Infos
	vTaskDelay( 1000 / portTICK_PERIOD_MS);
    // Create CAN receive task
    // xTaskCreate(&task_CAN, "CAN", 2048, NULL, 5, NULL);

	/*brief: rudi
	* if you have "activate ESPCan"
	* then the code here runs..
	*
	*/
	#ifdef CONFIG_ESPCAN
	 printf("**********   CAN TESTINGS **********\n");
	 printf("Olimex EVB Rev B Board \n");
	 printf("ESPCan configured by this Data:\n");
	 printf("Node           : 0x%03x\n", CONFIG_ESP_CAN_NODE_ITSELF);
	 printf("CAN RXD PIN NUM: %d\n", CONFIG_ESP_CAN_RXD_PIN_NUM);
	 printf("CAN TXD PIN NUM: %d\n", CONFIG_ESP_CAN_TXD_PIN_NUM);
	 printf("CAN SPEED      : %d KBit/s\n", CONFIG_SELECTED_CAN_SPEED);

	 #ifdef CONFIG_CAN_SPEED_USER_KBPS
	  printf("kBit/s setting was done by User\n");
	 #endif

	 //Create CAN receive task
     xTaskCreate(&task_CAN, "CAN", 2048, NULL, 5, NULL);
     
     // if we are the "master" send a single frame to start the ping pong
	 if (CONFIG_ESP_CAN_NODE_ITSELF == 0xc5) {
	   printf("Sending a single test frame to start the ping pong\n");
	   CAN_frame_t __TX_frame;

      __TX_frame.MsgID = CONFIG_ESP_CAN_NODE_ITSELF;
      __TX_frame.FIR.B.DLC   =  8;
      __TX_frame.data.u8[0]  = 'E';
      __TX_frame.data.u8[1]  = 'S';
      __TX_frame.data.u8[2]  = 'P';
      __TX_frame.data.u8[3]  = '-';
      __TX_frame.data.u8[4]  = 'C';
      __TX_frame.data.u8[5]  = 'A';
      __TX_frame.data.u8[6]  = 'N';
      __TX_frame.data.u8[7]  = '.';
      CAN_write_frame(&__TX_frame);
	}
#endif
}
It has only a single task that waits for a packet and then transmits the packet back. I can't see anywhere the code could be being held up.

I would be very interested in input on why this is running about 1/5th of the speed I would expect.

Thanks,

Don

jcsbanks
Posts: 116
Joined: Tue Mar 28, 2017 8:03 pm

Re: About the CAN controller.

Postby jcsbanks » Wed Mar 07, 2018 1:02 pm

It might be because you are using an RTOS queue to receive. I had a similar problem on page 8 and Thomas suggested replying in an interrupt. When I did this the latency went from multiple milliseconds to less than 10 microseconds which is the clock of the Kvaser tool.

Hollie_Maea
Posts: 6
Joined: Thu Mar 22, 2018 10:45 pm

Re: About the CAN controller.

Postby Hollie_Maea » Fri Mar 23, 2018 12:24 am

Great work everyone in this thread.

I'm brand new to all of this, so this is probably a stupid question. I've never done any programming in the ESP-IDF environment and I'm not a particularly experienced programmer in general. I got myself a development board (Geekworm ESP32-C1) and spent the morning going through the setup guide and getting the IDF installed. I set up Eclipse as well for editing. I had no problem getting a couple of the example programs up and running, so everything seems to be working fine. But when I downloaded Thomas' Can Demo, I ran into problems. The main program compiles fine, but the can.c file has a bunch of errors in the CAN_init() function due to unresolved variables. I presume this is related to "unresolved inclusion" warnings for several of the include statements.

Any hints to get me pointed in the right direction? I'm sure there's something basic I'm missing due to my inexperience. :oops:

Thanks!

Return to “Hardware”

Who is online

Users browsing this forum: No registered users and 3 guests