About the CAN controller.
-
- Posts: 6
- Joined: Thu Mar 22, 2018 10:45 pm
Re: About the CAN controller.
Well, you are right...setting that global fixed it. I'd still be interested in learning what the step I need to take is to pull in the values from menuconfig, perhaps Rudi can chime in at some point.
Re: About the CAN controller.
Glad you fixed. Looks like it needs some C preprocessor conditionals.
-
- Posts: 7
- Joined: Tue Aug 08, 2017 12:28 pm
Re: About the CAN controller.
I am unable to get the CAN_isr to work after an esp_restart(). Anyone else have a similar issue?
It was working with the ESP-IDF version 2.1, but does not work with version 3.0. Any ideas on what has changed?
The CAN works fine from a power-on start or restart after it programs via JTAG or push-button restart. Just not if I restart the ESP32 via esp_restart().
It was working with the ESP-IDF version 2.1, but does not work with version 3.0. Any ideas on what has changed?
The CAN works fine from a power-on start or restart after it programs via JTAG or push-button restart. Just not if I restart the ESP32 via esp_restart().
-
- Posts: 7
- Joined: Tue Aug 08, 2017 12:28 pm
Re: About the CAN controller.
I got it working now. I'm not exactly sure what the problem was, but here is what I did...
I went back and re-ran the basic CAN demo, adding periodic esp_restart(). I saw it worked fine with IDF 3.0. So, I figured it was something in my higher level code that wasn't re-initializing correctly.
I added some guards in my main app (not the basic demo) so that
- CAN_write_frame wouldn't be called after a CAN_stop was issued (before esp_restart)
- CAN_write_frame wouldn't be called until after a CAN_init was issued (after esp_restart)
Then I also added called CAN_stop before calling esp_restart (this wasn't needed to get a basic CAN demo working with periodic esp_restart, but figured it would make it more graceful).
I went back and re-ran the basic CAN demo, adding periodic esp_restart(). I saw it worked fine with IDF 3.0. So, I figured it was something in my higher level code that wasn't re-initializing correctly.
I added some guards in my main app (not the basic demo) so that
- CAN_write_frame wouldn't be called after a CAN_stop was issued (before esp_restart)
- CAN_write_frame wouldn't be called until after a CAN_init was issued (after esp_restart)
Then I also added called CAN_stop before calling esp_restart (this wasn't needed to get a basic CAN demo working with periodic esp_restart, but figured it would make it more graceful).
Re: About the CAN controller.
Hi guys,
I am very new to this ESP32 and CAN area.
I am trying to setup a prototype network with multiple units of [ESP32 + WaveShareCAN modules].
Thanks to Rudi and Thomas we now have a running lib. (y)
I just can't get it running. When I am trying to set the parameters via
$ make menuconfig
I does not save any alterations, I can't change anything. Not even "activate" the CAN component. Feels like a stupid little mistake but couldn't figure it out and already read the whole thread without any info which helped me so far :/
Anyone has any idea what I am missing here?
Best Regards,
Enes
I am very new to this ESP32 and CAN area.
I am trying to setup a prototype network with multiple units of [ESP32 + WaveShareCAN modules].
Thanks to Rudi and Thomas we now have a running lib. (y)
I just can't get it running. When I am trying to set the parameters via
$ make menuconfig
I does not save any alterations, I can't change anything. Not even "activate" the CAN component. Feels like a stupid little mistake but couldn't figure it out and already read the whole thread without any info which helped me so far :/
Anyone has any idea what I am missing here?
Best Regards,
Enes
Re: About the CAN controller.
Hi guys, thanks for the can driver codes which works fine on both ESP-wroom and WROVER chips, I'm just wondering if it is possible to do can id mask and filtering with the same library? If it does it'll be so helpful. Please help.
Thank you all
Thank you all
Re: About the CAN controller.
I find that the CAN data obtained from Thomas Barth + Rudi's ESP32 CAN driver (used with ESP32 and MCP2515) has reverse byte order as compared to those obtained by this library https://github.com/sparkfun/SparkFun_CA ... o_Library/ (used with SparkFun CAN Shield based on MCP2515 and MCP2551). The MsgID and DLC seems to match, but the data payload bytes are reversed. It is hard to say which one is "right" because I don't have documentation for the vehicle in question. I realize I can consistently interpret either but I want to know which driver is "reversing" what's on the wire? Or if neither, perhaps it is due to the ESP32 integrated CAN controller (or equivalent on the SparkFun shield)?
Re: About the CAN controller.
ESP32 is little endian but most vehicles I have dealt with put 16 bit values big endian in CAN frames even if their CPU is little endian. 12 bit is also common for torque values.
Re: About the CAN controller.
I have a dramatic performance improvement to share that reduces latency between receiving a frame and transmitting a response from around several milliseconds down to <80us (most of the time <10us which is the resolution with which my Kvaser CAN device can measure). It doesn't do too much in the CAN Rx interrupt and does not increase the RTOS tick rate from 100Hz. I will follow it with a question about transmitting on a busy CAN bus.
I have not produced a modified driver or example as my project is now quite different, but the changes are simple:
At the beginning of CAN_isr then:
needs the final parameter to be changed to &xHigherPriorityTaskWoken and at the end of the ISR, is needed. This is as I understand the correct way to wake up a blocked task in FreeRTOS. Usually there is only 260us between CAN Rx and CAN Tx timestamps, but about 10% of the time is 340us which I've not managed to reduce with different core affinity or task priority, it may simply be a jitter related to FreeRTOS overhead.
should have its final parameter as portMAX_DELAY I think too so that the task is always blocked and immediately unblocks when the queue has an item. It is presently in the example code just a loop anyway.
The question I have is how to improve CAN_write_frame because it makes no check whether the transmit buffer is available, so if you send frequently you lose frames because they are overwritten. Instead I have used a queue with:
but would like to avoid wasting cycles in the while loop waiting for transmit complete or transmit buffer to be available. I tried adding task notification or event group between the CAN interrupt and the CAN_write_frame code, but the former did not work because of an assert as they are not supported on the dual core CPU yet I think, and the latter produced a few milliseconds of latency, so I seek a better solution that will not lose transmit frames. I'm reading the SJA1000 docs to see what I can fathom.
I have not produced a modified driver or example as my project is now quite different, but the changes are simple:
At the beginning of CAN_isr
Code: Select all
BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
Code: Select all
xQueueSendFromISR(CAN_cfg.rx_queue,&__frame,0);
Code: Select all
if( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR ();
Code: Select all
if(xQueueReceive(CAN_cfg.rx_queue,&__RX_frame, 3*portTICK_PERIOD_MS)==pdTRUE)
The question I have is how to improve CAN_write_frame because it makes no check whether the transmit buffer is available, so if you send frequently you lose frames because they are overwritten. Instead I have used a queue with:
Code: Select all
if(xQueueReceive(tx_queue, p_frame, portMAX_DELAY))
{
while (!MODULE_CAN->SR.B.TCS){}
Re: About the CAN controller.
Not waking an activated Task in the RX ISR is on purpose.
Adding an entry to a queue will set the waiting tasks into READY state. However, there will be no task switch, the RUNNING task stays running. We need a rescheduling point (Yield) to switch tasks. You will find rescheduling points e.g. in the Systick-Handler and other places. If you add the code like you did, your force rescheduling, which takes up some time (not really but because this will happen very often it sums up). Depending on your application/data-throughput, you often do not want to task-switch immediately when there is an ISR, thats why queues have a certain length. Instead, you wait for the next rescheduling point and switch at well defined points in time. This reduces the number of task switches and hence optimizes overall performance. (+Its safer if reliability is an issue)
Of course, if you would like to react as fast as possible to an RX frame to improve throughput and accept overall performance loss (again, depending on your application), you can wake up the waiting task immediately.
Well, you need a buffer if you want to write frames in sequential order and as fast as possible.
If a frame shall be send, it has to be checked if there are already entries waiting in the buffer. If yes, the new frame is added to the buffer. If the buffer is empty, the frame is passed to the hardware. An TX interrupt will occur once the frame is send, the ISR checks if there are frames waiting in the buffer and transmits the oldest waiting frame. This repeats until there are no more frames anymore in the buffer, in this case the loop terminates itself. You also might want to use FreeRTOS queues as buffers but you might experience certain OS delays, especially if you want to create an own transmit-task.
Adding an entry to a queue will set the waiting tasks into READY state. However, there will be no task switch, the RUNNING task stays running. We need a rescheduling point (Yield) to switch tasks. You will find rescheduling points e.g. in the Systick-Handler and other places. If you add the code like you did, your force rescheduling, which takes up some time (not really but because this will happen very often it sums up). Depending on your application/data-throughput, you often do not want to task-switch immediately when there is an ISR, thats why queues have a certain length. Instead, you wait for the next rescheduling point and switch at well defined points in time. This reduces the number of task switches and hence optimizes overall performance. (+Its safer if reliability is an issue)
Of course, if you would like to react as fast as possible to an RX frame to improve throughput and accept overall performance loss (again, depending on your application), you can wake up the waiting task immediately.
Well, you need a buffer if you want to write frames in sequential order and as fast as possible.
If a frame shall be send, it has to be checked if there are already entries waiting in the buffer. If yes, the new frame is added to the buffer. If the buffer is empty, the frame is passed to the hardware. An TX interrupt will occur once the frame is send, the ISR checks if there are frames waiting in the buffer and transmits the oldest waiting frame. This repeats until there are no more frames anymore in the buffer, in this case the loop terminates itself. You also might want to use FreeRTOS queues as buffers but you might experience certain OS delays, especially if you want to create an own transmit-task.
my page: http://www.barth-dev.de/
Who is online
Users browsing this forum: No registered users and 101 guests