FlexCAN_T4 - FlexCAN for Teensy 4

you can comment out and disable if you don't want to receive single frames that you can just handle in your normal callback, if length is less than 7. The bus is assigned in the constructor as well as the callback, so the callback you'd assume the correct bus, but in terms of mailboxes, if the frames come from multiple mailboxes, how can it tell you where it came from? that would need to store even more data and mailbox counts in a bigger payload, making even more complex code.
 
When I parse the DBC file I know what ID's have PIDS associated with them. If there is more than one ID with PIDS then those are assigned to another set of PIDS.

The ID are assigned to mail boxes as normal with 2 at the most. When the ID is matched in memory it also has a flag stating is has PIDS. Those PIDS are stored in it. You can up to 8 ECU's associated with a bus so you could have up to 8 ID of which multiple PIDs may respond to information ID's like CAL ID.CVN/ECU name so you would need the ability to handle this anyways. If you have 8 ECU's you could have 4 to 8 MB's associated with those ID's but you could have 8 ECU names so you would need to be able each of those separately anyways.

Bruce
 
if they have a different CANID, they are assembled in parallel as the frames come in, the data is just appended to the queue, why would you bind a certain mailbox to a payload? i guess you could take the last MB frame issued and use that as a source of the frames before hitting the callback..
 
What's random doing in this method?
https://github.com/tonton81/FlexCAN_T4/blob/master/FlexCAN_T4.tpp#L942

Code:
FCTP_FUNC int FCTP_OPT::read(CAN_message_t &msg) {
  bool _random = random(0, 2);
  if ( ( !_random ) && ( FLEXCANb_MCR(_bus) & FLEXCAN_MCR_FEN ) &&
       !( FLEXCANb_IMASK1(_bus) & FLEXCAN_IMASK1_BUF5M ) &&
       ( FLEXCANb_IFLAG1(_bus) & FLEXCAN_IFLAG1_BUF5I ) ) return readFIFO(msg);
  return readMB(msg);
}

I can see that it would only occasionally trigger return readFIFO(msg), but I don't understand why it's setup this way.
 
it's just to pick between either mailbox or fifo at random.
if fifo isn't enabled it will just fall down to read mailboxes only.
readMB wont do anything as the function returns if you have no reception, only tx mailboxes.

you can either readFIFO or readMB, I decided to pick at random because if one is always receiving, lets say FIFO is always pulling for every check, the mailbox would probably not be read as often, especially with slow user code.

Obviously these 3 methods are for polling only. If you have interrupts enabled, they simply would return as they don't read interrupt enabled mailboxes
 
How do we emit messages with an extended id? Do we just set the CAN_message_t id field or is there some setup that's needed first?
 
Can not receive CAN-Bus Frames with Teensy in conjunction with Waveshare SN65HVD230 C

Hi guys,

I have some basic beginner questions about Teensy 4.0 in conjunction with the FlexCAN_T4 library, since my attempts to read CAN signals have not been successful so far.My experimental setup is as follows:
- Highspeed CAN input (500 kBaud) at the Waveshare SN65HVD230 CAN transceiver board.
- CAN Transceiver Board is connected to a Teensy 4.0: 3.3V --> 3.3V | GND --> GND | CAN-TX --> CAN-RX (Pin 23) | CAN-RX --> CAN-TX (Pin 22)
- 120 Ohm resistor between CAN-H and CAN-L on CAN Transceiver Board
Physically the CAN was also checked by Picoscope -> transmitted signals arrive at CAN-H/CAN-L header

picoscope_teensy.png

As a basis the read_two_channels - program was used:

Code:
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;

CAN_message_t msg;

void setup(void) {
  can1.begin();
  can1.setBaudRate(500000);
}

void loop() {
  

  if ( can1.read(msg) ) {
    Serial.print("CAN1 "); 
    Serial.print("MB: "); Serial.print(msg.mb);
    Serial.print("  ID: 0x"); Serial.print(msg.id, HEX );
    Serial.print("  EXT: "); Serial.print(msg.flags.extended );
    Serial.print("  LEN: "); Serial.print(msg.len);
    Serial.print(" DATA: ");
    for ( uint8_t i = 0; i < 8; i++ ) {
      Serial.print(msg.buf[i]); Serial.print(" ");
    }
    Serial.print("  TS: "); Serial.println(msg.timestamp);
  }

}

Interesting is that my CAN transmitter (restbus simulation from Windows PC) shows a Not Ackknowledge Error, which normally means that there is no receiver on the bus.
The serial output remains empty.
Do I have to set anything else to listen to my CAN messages?
When do I use FIFO, when do I use mailboxes?
What influence do the RX_SIZE and TX_SIZE parameters have?
Do you see any discrepancies in my setup?
 
Hi Samduino,

The data lines from Teensy to CAN transceiver should be:
CAN-RX --> CAN-RX | CAN-TX --> CAN-TX
They don't cross over like a serial connection.

The ACK bit is sent by the Teensy hardware, so without proper connection between Teensy transceiver, incoming frames cannot be received or ACK'd.
 
Hi msadie,
in fact youre right - thanks! Now I am getting Data
I tried it before, but there was presumably another mistake
 
Hey guys,

My intention is to build a gateway that splits a CAN-FD frame into several CAN frames.
My approach would be:
If there is a CAN-FD frame with DLC = 15 (64 byte payload), I divide the content into 8 CAN frames with 8 bytes each, with DLC = 14 in 6 frames, with DLC = 13 in 4 frames and so on.
My question is whether there is already a function for this that I could use?

Could someone also explain to me how the onReceive function and the events () function work?
Help is very much appreciated. Thanks in advance
 
there are private functions the library uses internally to convert length to dlc for transmit and dlc to length for receive. You can move them to public or copy them to your own sketch.

onReceive callback is when your receiving data from interrupts, unless when you are polling you can send the frames to that callback as well.

events() is used for dequeuing transmits or interrupt based messages in queue towards the callback.

FD mode requires events() for interrupt receptions to work, as direct firing wasn't implemented yet like the CAN2.0 side
 
Perfect, the len_to_dlc-functions helps me to go on

Only for my understanding:
- receiving data from interrupts happens when using onReceive() instead of the read()?
- events() is the basis of onReceive() because it cares about routing e.g. CAN-FD Frames (which triggered interrupts) to the callback function (e.g. the canSniff-function)?
I'm sorry about maybe very basic questions, but I'm new to C++

Do you mean with "direct firing" the read()-function or FIFO registers? Because I thought I've read that CAN-FD does not support FIFO...
 
correct. CANFD has no FIFO on this processor. canSniff is just a function called when set in onReceive when a frame is received via interrupts. You can also if wanted, if not using interrupts, poll the frames via read() and send it to same function

Code:
Can0.read(msg);
canSniff(msg);

If you are polling, you don't need to use onReceive at all. It's there for interrupt usage

direct firing I meant the callback gets fired immediately with data, without using the queue system in the library
 
Alright, thanks.
I have another question regarding the mailboxes for transmitting.

Now my program is able to split a CAN-FD message into the right amount of necessary CAN messages with the corresponding payload. The problem is that when I am calling CAN.mailboxStatus() the content does not change fitting to the incoming CAN-FD payload. It contains still the payload from the first time I started the program

Do I have to delete the payload of the mailbox after calling CAN.write() again?
 
mailboxStatus() is there for legacy CAN3 CAN2.0 mode, the CANFD version is not added yet
 
Last edited:
I don't really understand this. Does it mean that I can use mailboxStatus() only by sending or receiving CAN at CAN3 (Pins 30, 31 on Teensy 4.0)?
In the following serial-prints maybe I can show my problem in a better way:

Incoming CAN-FD message:
Code:
MB 1  OVERRUN: 0  LEN: 48 EXT: 0  EDL: 1 TS: 40614 ID: 2 Buffer: FF 1 2 3 4 5 6 8 2 A 0 0 0 0 0 0 3 B 0 0 0 0 0 0 4 C 0 0 0 0 0 0 5 D 0 0 0 0 0 0 6 E 0 0 0 0 0 0

Now my program splits the CAN-FD frame in 6 CAN frames with increasing IDs (1 to 6) and sends them out with CAN.write(msg_c);

Mailbox status after second time receiving the CAN-FD Frame above - remember I sent 2 times each seperate generated CAN-frame (so in theory 12 sent CAN-frames).
You clearly see, that it fills up the mailboxes until there is no free left.
Code:
ID: 6 Buffer: 6 E 0 0 0 0 0 0 
FIFO Disabled
	Mailboxes:
		MB0 code: RX_EMPTY	(Standard Frame)
		MB1 code: RX_EMPTY	(Standard Frame)
		MB2 code: RX_EMPTY	(Standard Frame)
		MB3 code: RX_EMPTY	(Standard Frame)
		MB4 code: RX_EMPTY	(Extended Frame)
		MB5 code: RX_EMPTY	(Extended Frame)
		MB6 code: RX_EMPTY	(Extended Frame)
		MB7 code: RX_EMPTY	(Extended Frame)
		MB8 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x1)(Payload: FF 1 2 3 4 5 6 8)
		MB9 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x2)(Payload: 2 A 0 0 0 0 0 0)
		MB10 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x3)(Payload: 3 B 0 0 0 0 0 0)
		MB11 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x4)(Payload: 4 C 0 0 0 0 0 0)
		MB12 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x5)(Payload: 5 D 0 0 0 0 0 0)
		MB13 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x6)(Payload: 6 E 0 0 0 0 0 0)
		MB14 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x1)(Payload: FF 1 2 3 4 5 6 8)
		MB15 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x2)(Payload: 2 A 0 0 0 0 0 0)

Next strange behavior is that my picoscope monitors continuously the first frame [(ID: 0x1)(Payload: FF 1 2 3 4 5 6 8)].

There my question, do I have to delete the payload of the mailbox after calling CAN.write() again or is there another reason?
Maybe I should try FIFO?

Thanks for help!
 
mailboxStatus() only works on CAN1 to CAN3 in legacy CAN2.0 mode, in CANFD mode if you try to use it currently it reads the legacy mailboxes which is not the same memory region as the CANFD mailboxes, so don't expect the data to be returned properly if at all
 
mailboxStatus() only works on CAN1 to CAN3 in legacy CAN2.0 mode, in CANFD mode if you try to use it currently it reads the legacy mailboxes which is not the same memory region as the CANFD mailboxes, so don't expect the data to be returned properly if at all

Sorry, but I think you did not understand my problem because the answer does not match my question correctly.

Do you, or somebody else need further information to help me with sending CAN-messages correctly?
Do I have to clear the mailboxes manually. Once again, my program logic:
1. Receiving a CAN-FD frame
2. Splitting it up into necessary amount of CAN frames
3. Calling CAN.write(msg)
--> Mailbox "memory" fills up until no space left
 
oh ok I see, you are sending and the TX is just filling, and you only see the first frame being constantly sent. This is because there is no node ACKing on the network. This is a hardware thing not software. Make sure 2 or more nodes are on the network for transmissions to work, at least 1 node needs to ACK for the transmits to send and remove themselves from the mailbox, hardware removes them not you :)
 
I have Byte2 (FF) and Byte3 (FF) sent as a signed integer but using CAN_message_t it's showing as a large number instead of negative. How can I get it show as negative?

Code:
int32_t val4 = ((int32_t)msgcan1.buf[3] << 8) | (int32_t)msgcan1.buf[2];   //read current values and convert to Dec.
actCurrent = val4;

shows val4 as 65535
 
how are you setting it before sending, and how are you reading it back after, what type is actCurrent, there is alot of discrepancies here to guess why it doesn't work, I can't see the rest of your code
 
Sorry the code is pretty long and I think would complicate it.

I'm not sending the data it's from a battery pack. The manual says '16 bits signed int' . actCurrent is an integer and is the current into and out of the battery.

I was using this code on an Arduino Mega where actCurrent showed it as a negative value when it was negative and positive when it was positive.

Code:
if (can1.read(msgcan1))
 
Back
Top