CAN Protocol - Yes, We Can!

Introduction: CAN Protocol - Yes, We Can!

About: Do you like technology? Follow my channel on Youtube and my Blog. In them I put videos every week of microcontrollers, arduinos, networks, among other subjects. New tutorials on Tuesdays and Fridays.

Another subject recently suggested by my YouTube channel’s followers was CAN (Controller Area Network) protocol, which is what we’ll focus on today. It’s important to explain that CAN is a simultaneous serial communication protocol. This means the synchronism between the modules connected to the network is performed in relation to the beginning of each message sent to the bus. We’ll start off by introducing the basic concepts of the CAN protocol and perform a simple assembly with two ESP32s.

In our circuit, the ESPs can act as both Master and Slave. You can have multiple microcontrollers transmitting simultaneously, because the CAN deals with the collision of everything automatically. The source code of this project is super simple. Check it out!

Step 1: Resources Used

  • Two modules of ESP WROOM 32 NodeMcu
  • Two CAN transceivers from WaveShare
  • Jumpers for connections
  • Logical analyzer for capture
  • Three USB cables for ESPs and analyzer
  • 10 meters of twisted pair to serve as a bus

Step 2: CAN (Controller Area Network)

  • It was developed by Robert Bosch GmbH in the 1980s to serve the automotive industry.
  • It has become widespread over the years due to its robustness and flexibility of implementation. It’s being used with military equipment, agricultural machinery, industrial and building automation, robotics, and medical equipment.

Step 3: CAN - Features

  • Two-wire serial communication
  • Maximum of 8 bytes of useful information per frame, with fragmentation possible
  • Address directed to the message and not to the node
  • Assigning priority to messages and relaying of "on hold" messages
  • Effective ability to detect and signal errors
  • Multi-master capability (all nodes can request bus access)
  • Multicast capability (one message for multiple receivers at the same time)
  • Transfer rates of up to 1Mbit / s on a 40-meter bus (reduction of the rate with increase of busbar length)
  • Flexibility of configuration and introduction of new nodes (up to 120 nodes per bus)
  • Standard hardware, low cost, and good availability
  • Regulated protocol: ISO 11898

Step 4: Circuit Used

Here, I have the Transceivers. There is one on each side, and they’re connected by a pair of wires. One is responsible for sending and the other for receiving data.

Step 5: Transmission Line Voltages (Differential Detection)

In CAN, the dominant bit is Zero.

Line Differential Detection Reduces Noise Sensitivity (EFI)

Step 6: CAN Standards and Frames Format

Standard format with 11-bit identifier

Step 7: CAN Standards and Frames Format

Extended format with 29-bit identifier

Step 8: CAN Standards and Frames Format

It is important to note that a protocol already calculates the CRC and sends ACK and EOF signals, which are things that are already done by the CAN protocol. This guarantees that the message sent won’t arrive in the wrong way. This is because if it gives a problem in the CRC (Redundant Cyclic Check or Redundancy Check), which is the same as an information check digit, it will be identified by the CRC.

Step 9: Four Types of Frames (frames)

It is important to note that a protocol already calculates the CRC and sends ACK and EOF signals, which are things that are already done by the CAN protocol. This guarantees that the message sent won’t arrive in the wrong way. This is because if it gives a problem in the CRC (Redundant Cyclic Check or Redundancy Check), which is the same as an information check digit, it will be identified by the CRC.

Four types of frames (frames)

The transmission and reception of data in the CAN are based on four types of frames. The frame types will be identified by variations in the control bits or even by changes in the frame writing rules for each case.

  • Data Frame: Contains the transmitter data for the receiver (s)
  • Remote Frame: This is a request for data from one of the nodes
  • Error Frame: It is a frame sent by any of the nodes when identifying an error in the bus and can be detected by all nodes
  • Overload Frame: Serves to delay traffic on the bus due to data overload or delay on one or more nodes.

Step 10: Circuit - Details of Connections

Step 11: Circuit - Data Capture

Wavelengths obtained for standard CAN with 11-bit ID

Step 12: Circuit - Data Capture

Wavelengths obtained for extended CAN with 29-bit ID

Step 13: Circuit - Data Capture

Data obtained by the logic analyzer

Step 14: Arduino Library - CAN

I show here the two options where you can install the CAN Driver Library

Arduino IDE Library Manager

Step 15: Github

https://github.com/sandeepmistry/arduino-CAN

Step 16: Transmitter Source Code

Source Code: Includes and Setup ()

We’ll include the CAN library, start the serial for debugging, and start the CAN bus at 500 kbps.

#include <CAN.h>//Inclui a biblioteca CAN
void setup() { Serial.begin(9600); //inicia a serial para debug while (!Serial); Serial.println("Transmissor CAN"); // Inicia o barramento CAN a 500 kbps if (!CAN.begin(500E3)) { Serial.println("Falha ao iniciar o controlador CAN"); //caso não seja possível iniciar o controlador while (1); } }

Step 17: Source Code: Loop (), Sending a Standard CAN 2.0 Packet

Using the standard CAN 2.0, we send a package. The 11-bit ID identifies the message. The data block must have up to 8 bytes. It starts the packet with ID 18 in hexadecimal. It packs 5 bytes and closes the function.

void loop() {
// Usando o CAN 2.0 padrão //Envia um pacote: o id tem 11 bits e identifica a mensagem (prioridade, evento) //o bloco de dados deve possuir até 8 bytes Serial.println("Enviando pacote..."); CAN.beginPacket(0x12); //id 18 em hexadecimal CAN.write('h'); //1º byte CAN.write('e'); //2º byte CAN.write('l'); //3º byte CAN.write('l'); //4º byte CAN.write('o'); //5º byte CAN.endPacket(); //encerra o pacote para envio Serial.println("Enviado."); delay(1000);

Step 18: Source Code: Loop (), Sending an Extended CAN 2.0 Package

In this step, the ID has 29 bits. It starts sending 24 bits of ID and, once more, packs 5 bytes and quits.

//Usando CAN 2.0 Estendido
//Envia um pacote: o id tem 29 bits e identifica a mensagem (prioridade, evento) //o bloco de dados deve possuir até 8 bytes Serial.println("Enviando pacote estendido..."); CAN.beginExtendedPacket(0xabcdef); //id 11259375 decimal ( abcdef em hexa) = 24 bits preenchidos até aqui CAN.write('w'); //1º byte CAN.write('o'); //2º byte CAN.write('r'); //3º byte CAN.write('l'); //4º byte CAN.write('d'); //5º byte CAN.endPacket(); //encerra o pacote para envio Serial.println("Enviado."); delay(1000); }

Step 19: Receiver Source Code

Source Code: Includes and Setup ()

Again, we will include the CAN library, start the serial to debug, and start the CAN bus at 500 kbps. If an error occurs, this error will be printed.

#include <CAN.h>//Inclui a biblioteca CAN
void setup() { Serial.begin(9600); //inicia a serial para debug while (!Serial); Serial.println("Receptor CAN"); // Inicia o barramento CAN a 500 kbps if (!CAN.begin(500E3)) { Serial.println("Falha ao iniciar o controlador CAN"); //caso não seja possível iniciar o controlador while (1); } }

Step 20: Source Code: Loop (), Getting the Package and Checking the Format

We tried to check the size of the packet received. The CAN.parsePacket () method shows me the size of this package. So if we have a package, we’ll check whether it is extended or not.

void loop() {
// Tenta verificar o tamanho do acote recebido int packetSize = CAN.parsePacket(); if (packetSize) { // Se temos um pacote Serial.println("Recebido pacote. "); if (CAN.packetExtended()) { //verifica se o pacote é estendido Serial.println("Estendido"); }

Step 21: Source: Loop (), Checks to See If It Is a Remote Package

Here, we check if the received packet is a data request. In this case, there is no data.

if (CAN.packetRtr()) {
//Verifica se o pacote é um pacote remoto (Requisição de dados), neste caso não há dados Serial.print("RTR "); }

Step 22: Source Code: Loop (), Data Length Requested or Received

If the received packet is a request, we indicate the requested length. We then obtain the Data Length Code (DLC), which indicates the length of the data. Finally, we indicate the length received.

Serial.print("Pacote com id 0x");
Serial.print(CAN.packetId(), HEX); if (CAN.packetRtr()) { //se o pacote recebido é de requisição, indicamos o comprimento solicitado Serial.print(" e requsitou o comprimento "); Serial.println(CAN.packetDlc()); //obtem o DLC (Data Length Code, que indica o comprimento dos dados) } else { Serial.print(" e comprimento "); // aqui somente indica o comprimento recebido Serial.println(packetSize);

Step 23: Source Code: Loop (), If Data Is Received, It Then Prints

We print (on the serial monitor) the data, but only if the received packet is not a request.

//Imprime os dados somente se o pacote recebido não foi de requisição
while (CAN.available()) { Serial.print((char)CAN.read()); } Serial.println(); } Serial.println(); } }

Step 24: Download the Files

Share

    Recommendations

    • Tiny Home Contest

      Tiny Home Contest
    • Fix It! Contest

      Fix It! Contest
    • Water Contest

      Water Contest

    Discussions