One Teensy 4.1 to send/receive information to six Teensy 4.1s

Status
Not open for further replies.
the PIC18F26Q84 is a microcontroller just like the Teensy
it's made by microchip who also now own the microcontrollers used in most of the Arduino boards.

the PIC18F26Q84-I/SP is 28pin through hole which makes it easy to solder and use in breadboards,
the downside is that it needs a programmer, the cheapest one is called PicKit3.

to connect a PIC18F26Q84 to a CAN network you will still need a SN65HVD230 CAN Bus Transceiver.

example code is here
https://github.com/microchip-pic-avr-examples/pic18f47q84-can-fd-basic-operation
 
So I would connect a small sensor to PIC18F26Q84 that would connect to SN65HVD230 CAN Bus Transceiver that connects to a CAN 2.0 network of SN65HVD230 CAN Bus Transceiver in which each is connected to a Teensy 4.1?
 
yes, all devices (teensies, pics, or sensors) need a transceiver if they don't already have one. but yeah all run in parallel transceiver to transceiver

if a sensor isn't CAN capable, you could just put it on one of your teensies and have that teensy act as the device on the network hosting the data you need
 
I just think it's overkill and high price to use a teensy 4.x for such a simple task,
not to mention the power requirements.
I don't say that the Teensy 4.x have a high price (I really like the price), but for that task it is.

Ok then it's easier to program a teensy with a simple SDK, but small 8-bit PIC micros are not that complicated either.

I believe that a Teeensy should take care of more heavy things,
not be used as a "blink a led" project.

It's also better to use a smaller cheaper MCU, as they can easily be replaced when they break,
and you don't have to cry about the money loss.

note. the PIC18F26Q84 (just like other new variants of PIC) have a internal oscillator, so that the required external components can be kept to a minimum.
 
@tonton81

I tried using code from https://forum.pjrc.com/threads/56035-FlexCAN_T4-FlexCAN-for-Teensy-4/page13 with the image setup I have. I am using the latest CAN code so I think the reason it isn't work for me is due to incompatibility.

20211128_140837.jpg

Screenshot 2021-11-28 142554.jpg

Receiver Code
Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_64> Can0;

void setup(void) {
  Serial.begin(115200); delay(400);
  pinMode(6, OUTPUT); digitalWrite(6, LOW); /* optional tranceiver enable pin */
  Can0.begin();
  Can0.setBaudRate(500000);
  Can0.setMaxMB(16);
  Can0.enableFIFO();
  Can0.enableFIFOInterrupt();
  Can0.onReceive(canSniff);
  Can0.mailboxStatus();
  Can0.enableMBInterrupts();
  pinMode(13, OUTPUT);
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" RTR: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
  static uint32_t _time = millis();
  Serial.print("Time between frames: ");
  Serial.println(millis() - _time);
  _time = millis();
}


void loop() {
}

Sender

Code:
#include <FlexCAN_T4.h>
#include <elapsedMillis.h>

FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_128> LCAN;
elapsedMillis tsk1000msCounter;
CAN_message_t msg0E0;

void setup() {
  LCAN.begin();
  LCAN.setClock(CLK_60MHz);
  LCAN.setBaudRate(500000);
  LCAN.setMaxMB(10);
  LCAN.setMB(MB0, RX);   /* Set Mailbox RX Direction */
  LCAN.setMB(MB1, RX);   /* Set Mailbox RX Direction */
  LCAN.setMB(MB2, RX);   /* Set Mailbox RX Direction */
  for (int i = 4; i < 10; i++) LCAN.setMB((FLEXCAN_MAILBOX)(i), TX); /* Set Mailbox TX Direction */

  msg0E0.id = 0x0E0;
  msg0E0.len = 5;     // Data length

  Serial.begin(500000); delay(1000);
  LCAN.onReceive(canSniff);
  LCAN.enableMBInterrupts();
  Serial.print("LCAN Setup: ");
  LCAN.mailboxStatus();
}

void loop() {
  if (tsk1000msCounter >= 1000) {
    tsk1000msCounter = 0;  // Reset 1000ms timer
    msg0E0.buf[0]++;
    LCAN.write(msg0E0);
  }
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" RTR: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
  static uint32_t _time = millis();
  Serial.print("Time between frames: ");
  Serial.println(millis() - _time);
  _time = millis();
}
 
pins 0 and 1 is CAN2
pins 22 and 23 is CAN1
pins 30 and 31 is CAN3

You should be using CAN1 on constructor

also i don't think your transceivers are wired to 3.3v, they're left unconnected in the photo
 
Last edited:
I wired my transceivers to 3.3volts.

20211128_160206.jpg

I am not sure what you meant by CAN1 on constructor. I instead tried changing all CAN0s to CAN1. Still produced no results.
 
Code:
FlexCAN_T4<[COLOR="#FF0000"]CAN3[/COLOR], RX_SIZE_256, TX_SIZE_128> LCAN;

That is the peripheral BUS specifier in the constructor (CAN1,CAN2,CAN3). It has no relation to Can0/Can1/LCAN. Those are just your custom name of the object that uses that specific bus.

Should be CAN1 (on both teensies)
 
is CTX to CTX and CRX to CRX correct? I can't tell from the image, unlike UART, they shouldn't be crossed, only direct
 
I switched one of the CAN Bus Transceivers with no luck. Here are the code and the photos of what I have so far.
Receiver:
Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_64> Can0;

void setup(void) {
  Serial.begin(115200); delay(400);
  pinMode(6, OUTPUT); digitalWrite(6, LOW); /* optional tranceiver enable pin */
  Can0.begin();
  Can0.setBaudRate(500000);
  Can0.setMaxMB(16);
  Can0.enableFIFO();
  Can0.enableFIFOInterrupt();
  Can0.onReceive(canSniff);
  Can0.mailboxStatus();
  Can0.enableMBInterrupts();
  pinMode(13, OUTPUT);
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" RTR: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
  static uint32_t _time = millis();
  Serial.print("Time between frames: ");
  Serial.println(millis() - _time);
  _time = millis();
}

Sender:
void loop() {
}

Code:
#include <FlexCAN_T4.h>
#include <elapsedMillis.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_128> LCAN;
elapsedMillis tsk1000msCounter;
CAN_message_t msg0E0;

void setup() {
  LCAN.begin();
  LCAN.setClock(CLK_60MHz);
  LCAN.setBaudRate(500000);
  LCAN.setMaxMB(10);
  LCAN.setMB(MB0, RX);   /* Set Mailbox RX Direction */
  LCAN.setMB(MB1, RX);   /* Set Mailbox RX Direction */
  LCAN.setMB(MB2, RX);   /* Set Mailbox RX Direction */
  for (int i = 4; i < 10; i++) LCAN.setMB((FLEXCAN_MAILBOX)(i), TX); /* Set Mailbox TX Direction */

  msg0E0.id = 0x0E0;
  msg0E0.len = 5;     // Data length

  Serial.begin(500000); delay(1000);
  LCAN.onReceive(canSniff);
  LCAN.enableMBInterrupts();
  Serial.print("LCAN Setup: ");
  LCAN.mailboxStatus();
}

void loop() {
  if (tsk1000msCounter >= 1000) {
    tsk1000msCounter = 0;  // Reset 1000ms timer
    msg0E0.buf[0]++;
    LCAN.write(msg0E0);
  }
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" RTR: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
  static uint32_t _time = millis();
  Serial.print("Time between frames: ");
  Serial.println(millis() - _time);
  _time = millis();
}

20211128_200635.jpg

20211128_200643.jpg

20211128_200648.jpg

20211128_200653.jpg
 
But the RT1062 datasheet (page2518) defines can1rx as a input and can1tx as output.
Then they must be crossed as the canrx of the hvd230 is an input.
(Or is that a error in the datasheet?)

Also in the "description" of can2rx it say this is the CAN transmit signal ( is that a error in the datasheet?)

Which case is the correct description? It's very confusing.
 
I have 6 slave teensy 4.1 and one master teensy 4.1. Each slave needs to be able to receive commands from the master and be able to send information to the master if requested. However, each slave needs to be able to send information to the master when there is an issue without the master requesting it. This means I need to prevent collisions if multiple slaves detect issues. From how I understand each proposal so far, I will need each teensy to communicate equivalently and not as a master/slave configuration. I could be wrong so correct me here, I need a full-duplex RS485 configuration with what @manicksan suggested or a CAN network as both mentioned before. Which would be more appropriate for my application?

I think point-to-point serial links would be so much easier. You can prototype and develop software with direct connections from Teensy-to-Teensy (no other chips). The host T4.1 can easily support simultaneous point-to-point serial links with each of the 6 or 7 other micros, probably at 115200 baud. Is there any description of how much and how often data needs to be transmitted? Maybe a T4.1 in the middle and the others T3.2 or even TLC would work, and you would just be using UARTs and eventually RS-232. No need to mess with CAN, which is a bus, and can never be "simultaneous" for all 6 or 7 devices.
 
No need to mess with CAN, which is a bus, and can never be "simultaneous" for all 6 or 7 devices.

It can read/write to hundreds of devices simultaneously even if one goes down, what happens when you pull the power on a serial version when others talk to it? if it's wired in series the remaining nodes are lost, and traffic ends there
 
What I was suggesting is 7 point-to-point serial links, as opposed to a bus. The host T4.1 would dedicate a separate UART to each of the other micros. That could be wired up on a breadboard with no additional chips. It's true that CAN is capable of connecting many devices, but they can't all communicate simultaneously, simply because it's a bus. It does support multi-master, which is fine, but there is only one master at a time. If the T4.1 host wants to get data from all 7 of the other micros, it must do so sequentially. I agree that's probably fast enough, but the OP used the word "simultaneous", so I thought I would ask.
 
Throw this out there... why not use the Ethernet adapters? ( unless missed it in this thread )

Static IP setup each device and A simple network switch? or DHCP things with A simple router?

I am using the NativeEthernet, ArduinoJson ... and using XML and JSON in the mix to things with pretty good results.

Using simple TCPIP to handle the communications?

Then what is nice, I can use my dev PC to connect in and monitor and debug/test things too. As the teensy doesn't care... its tcpip traffic.

Seems fast and when I don't write bad code, it seems pretty reliable too.
 
I did try your transmitter code on my teensy 4.1
even the example code from
https://github.com/tonton81/FlexCAN_T4/tree/master/examples/CAN2.0_example_FIFO_with_interrupts

but both examples don't output anything when measuring with my oscilloscope,
the output is a steady high level so the CAN module is active.

I have tried all CAN interfaces (CAN1, CAN2, CAN3)
but same result on the respective pins (both RX & TX)

I can see sent data on Serial2 (pin8) so nothing is wrong with the connections (or a bad scope wire)

I'm using TD 1.55 with fresh "install" of Arduino 1.8.13
 
Hi! I am bringing back this thread because I got new transceivers that should work. I think the old ones I had were broken, since I found a lot of negatives reviews.

https://www.amazon.com/SN65HVD230-CAN-Board-Communication-Development/dp/B00KM6XMXO
I used these transceivers.

Here's the wiring I have done so far:
https://imgur.com/a/pqIbFpV

I used the same code as above:
Receiver:
Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_64> Can0;

void setup(void) {
  Serial.begin(115200); delay(400);
  pinMode(6, OUTPUT); digitalWrite(6, LOW); /* optional tranceiver enable pin */
  Can0.begin();
  Can0.setBaudRate(500000);
  Can0.setMaxMB(16);
  Can0.enableFIFO();
  Can0.enableFIFOInterrupt();
  Can0.onReceive(canSniff);
  Can0.mailboxStatus();
  Can0.enableMBInterrupts();
  pinMode(13, OUTPUT);
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" RTR: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);  
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
  static uint32_t _time = millis();
  Serial.print("Time between frames: ");
  Serial.println(millis() - _time);
  _time = millis();
}


void loop() {
}

Sender:
Code:
#include <FlexCAN_T4.h>
#include <elapsedMillis.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_128> LCAN;
elapsedMillis tsk1000msCounter;
CAN_message_t msg0E0;

void setup() {
  LCAN.begin();
  LCAN.setClock(CLK_60MHz);
  LCAN.setBaudRate(500000);
  LCAN.setMaxMB(10);
  LCAN.setMB(MB0, RX);   /* Set Mailbox RX Direction */
  LCAN.setMB(MB1, RX);   /* Set Mailbox RX Direction */
  LCAN.setMB(MB2, RX);   /* Set Mailbox RX Direction */
  for (int i = 4; i < 10; i++) LCAN.setMB((FLEXCAN_MAILBOX)(i), TX); /* Set Mailbox TX Direction */

  msg0E0.id = 0x0E0;
  msg0E0.len = 5;     // Data length

  Serial.begin(500000); delay(1000);
  LCAN.onReceive(canSniff);
  LCAN.enableMBInterrupts();
  Serial.print("LCAN Setup: ");
  LCAN.mailboxStatus();
}

void loop() {
  if (tsk1000msCounter >= 1000) {
    tsk1000msCounter = 0;  // Reset 1000ms timer
    msg0E0.buf[0]++;
    LCAN.write(msg0E0);
  }
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" RTR: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
  static uint32_t _time = millis();
  Serial.print("Time between frames: ");
  Serial.println(millis() - _time);
  _time = millis();
}

This is the message I am getting:
https://imgur.com/a/6xfF0Uc

My goal right now is to send a simple message from one Teensy 4.1 to another. I think the code I am working with right now is too complicated for what I am working with. However, I am unfamiliar with the syntax and process of how to set it up.
 
Last edited:
I got it to work and now I got a flurry of questions!

In the code, it specifies the data length.
How many bits can my message be?
Can I just send numbers instead of bits? Or do I have to do a conversion?

For sending a message, I assume I change LCAN.write(msg.buf). Is there a limited type of data to put in LCAN.write()? I see msg0E0.buf[0]++ appears to sending ever increasing larger bits.

For receiving the message, I notice that it is printing out the bits received in HEX using msg.buf. I am assuming the frame has multiple bits and the buffer is the last chunk of it and it is reading from where it is starting. Correct me if I am wrong.

I am not familiar with the properties of either msg or CAN. Is there a summary explaining what they do and examples?

When it comes to ID in msg.ID, how do we know the ID of the sender and receiver?
 
Last edited:
well you can give each device an ID, or have devices process different IDs during reception. CAN is broadcasting so all nodes see the data. Each payload is 8 bytes max, so you have up to 64 bits to play with. If you plan on sending arrays, you can use the built in plugin isotp.h, example on repo. Since all nodes broadcast, all your teensies see the same data with their respective IDs, and can act upon it. If one node is down, it wont interrupt the rest of the network. So depending on your project, you can customize the traffic how you want
 
Ok. I managed to assign an ID to the sender Teensy and have the receiver Teensy display the ID. If I were to have multiple Teensy on the same CAN, what part of the current receiver code would I have to edit to cherry pick which ID to read? I was thinking for a test run, I would alternate between two sender Teensy frames.
 
Status
Not open for further replies.
Back
Top