About the CAN controller.

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

Re: About the CAN controller.

Postby jcsbanks » Mon Jun 18, 2018 8:44 pm

Really good idea to send from CAN Tx interrupt, will try that, thanks. I was sending a wake up from the interrupt to a task and getting undesirable latency.

Latency massively affects throughput in my application, CAN bus is by far my only bottleneck. If a CAN packet is 0.25ms, I want a response on the CAN bus in the same millisecond window to transfer lots of data.

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

Re: About the CAN controller.

Postby ThomasB » Mon Jun 18, 2018 8:50 pm

You also might want to try placing the application in the ISR. This is the fastest yet nastiest solution. You might mess up the complete timing behavior of the chip or experience stack overflows. But hey, it would be very fast 8-)

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

Re: About the CAN controller.

Postby jcsbanks » Mon Jun 18, 2018 8:59 pm

That would be very nasty, it is going very fast now with 100% CAN bus loads over many millions of frames whilst running WiFI without errors. My peak load will be about 50% in actual use.

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

Re: About the CAN controller.

Postby jcsbanks » Tue Jun 19, 2018 10:43 am

To implement the CAN Tx queue using interrupt:

Code: Select all

int CAN_write_frame(CAN_frame_t* p_frame)
{
	if (MODULE_CAN->SR.B.TBS && !uxQueueMessagesWaiting(tx_queue))
	{
		CAN_Tx(p_frame);
		return 0;
	}	
	return xQueueSend( tx_queue, p_frame, 10/portTICK_PERIOD_MS );
}
Original CAN_write_frame is renamed to CAN_Tx.

In the ISR:

Code: Select all

	// Handle TX complete interrupt
	CAN_frame_t frame;
	if (interrupt & __CAN_IRQ_TX)
	{
		if(xQueueReceiveFromISR(tx_queue, &frame, NULL))
			CAN_Tx(&frame);
	}
This works really well, but I'm considering whether to make a critical/atomic section to avoid problems where a transmit complete interrupt may arrive at the wrong time. No one likes these, so thinking carefully.

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

Re: About the CAN controller.

Postby ThomasB » Tue Jun 19, 2018 3:02 pm

Nice. Yes, critical sections might make sense. You only need to temporarily deactivate the TX interrupt so no need to disable global interrupts.

PS : you might to want to compare tbs against a value or use TCS. Simply for clean code if people use your snippet.

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

Re: About the CAN controller.

Postby jcsbanks » Tue Jun 19, 2018 3:16 pm

Code: Select all

int CAN_write_frame(CAN_frame_t* p_frame)
{
	int status = 0;
	MODULE_CAN->IER.B.TIE = 0;
	if (uxQueueMessagesWaiting(tx_queue))
		status = xQueueSend( tx_queue, p_frame, 0 );
	else if (MODULE_CAN->SR.B.TBS)
		CAN_Tx(p_frame);
	MODULE_CAN->IER.B.TIE = 1;
	return status;
}
Somehow this is missing 1% of transmit frames when the bus loads increase and sometimes the Tx queue just fills up, whereas the other example was not. By trying to stop one race I think I've made a block where a transmit interrupt is lost when it was needed to service the queue as the Tx queue runs at low capacity and then suddenly fills apparently randomly. Edit: I think that this method of disabling the interrupt is not suitable because it means the SJA1000 doesn't trigger an interrupt, whereas I just want the ESP32 CPU to defer responding to this interrupt during the critical section.

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

Re: About the CAN controller.

Postby jcsbanks » Tue Jun 19, 2018 4:56 pm

This does work if heavy handed, but applicable to my application in particular. Maybe there is a way to get it just to defer CAN_isr.

Was this what you mean about comparing to a value? I use TBS instead of TCS because it seems analogous to the TIE, the buffer is available even if the previous transmission is not complete.

Code: Select all

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
int CAN_write_frame(CAN_frame_t* p_frame)
{
	portENTER_CRITICAL(&mux);

	if (MODULE_CAN->SR.B.TBS==1 && !uxQueueMessagesWaiting(tx_queue))
	{
		CAN_Tx(p_frame);
	}   
	else
	{
		xQueueSend( tx_queue, p_frame, 0 );
	}

	portEXIT_CRITICAL(&mux);
	return 0;
}

Walkramis
Posts: 1
Joined: Tue Jul 03, 2018 4:03 pm

Re: About the CAN controller.

Postby Walkramis » Thu Jul 05, 2018 12:48 pm

Hello everyone!

First I would like to direct a big thanks to @ThomasB and @rudi for their work on the library, truly wonderful!

However I am having some issues regarding the speed of receiving messages. I am running a bus at 500kbps with quite a heavy load (just above 1000 messages per second, extended frames). Currently I'm running it from a logfile from a raspberry in order to do some validation tests to make sure all messages arrive.
Currently (running the example code) I am able to receive messages for between 10-20 seconds before I start dropping frames.
I have experimented some with the example code as well as tried to increase the frequency of the board which have made some improvements, but not enough. In my final application it is not likely that these loads will occur constantly, but I would like to optimize for it.
I am using a sn65hvd230 chip together with the esp32.

Now for my questions:
1. Is this load at all possible with the esp32?
2. Would another transceiver help?
3. If possible, what changes would I need to do to the code in order for it to work (and how much cpu power would be left for other purposes).
4. I read something on an earlier page about moving from FreeRTOS to ISR which dropped the latency significantly for @jcsbanks. How would I go about doing this? (I am very new to the esp32 chip, the espressif IDF as well as FreeRTOS)

Thanks in advance!

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

Re: About the CAN controller.

Postby jcsbanks » Thu Jul 05, 2018 1:27 pm

The changes I am using are in my post in page 15. This way it handles a full CAN bus for hours on end with no dropped frames, with SN65HVD230. I have not measured CPU load but not had any problems.

Gnatz_
Posts: 4
Joined: Wed Jul 25, 2018 10:49 am

Re: About the CAN controller.

Postby Gnatz_ » Wed Jul 25, 2018 11:02 am

jcsbanks wrote:Bit more info after playing all afternoon.

The Tx pin is connected to the tranceiver from pin on ESP32 Devkit C to pin on the tranceiver chip, but the ESP32 cannot transmit. Pulling either Tx or Rx connection from ESP32 to tranceiver stops reception. The ECU only sends a single packet (but repeatedly) when powered up to the ESP32, until the Kvaser joins the CAN bus, then the ECU transmits its usual variety of IDs, so it looks like it is also diagnosing CAN off. I have swapped the Tx and Rx pins on ESP32 both physically and also in the software and I can still receive, so it doesn't seem like a faulty GPIO. It could be a faulty tranceiver I guess. Or some setting I'm missing or have messed up.
HI there!
I am trying my luck on having a CAN connection (obviously posting here) on an ESP32 WROOM, external SN65HVD230. THis is my first ESP CAN. I do very much have the issue @jcsbanks described before. I tried 2 ESP modules and 2 transceivers...
I can only _receive_ on my test setup on a 500kB CAN (like from Thomas B. example). I have a stable CAN with 2 other participants (arduino) and want to add my ESP32 to this CAN. When I try to send, I get following error interrupts
0x80 __CAN_IRQ_BUS_ERR
0x4 __CAN_IRQ_ERR
0x20 __CAN_IRQ_ERR_PASSIVE
0x4 __CAN_IRQ_ERR .

Did anyone experience this? What could I have messed up here?

Best Regards
Bernd

Who is online

Users browsing this forum: No registered users and 7 guests