The Arduino GIGA R1 WiFi has CAN hardware built into its STM32H747XI processor, so you do not need an external CAN controller such as an MCP2515.
You do, however, still need a:
|
1 2 3 4 |
CAN transceiver |
between the GIGA’s logic-level CAN TX/RX pins and the differential CAN bus.
The basic architecture is:
|
1 2 3 4 5 6 7 8 9 10 11 |
Arduino GIGA R1 CAN TX / CAN RX ↓ CAN transceiver ↓ CANH / CANL ↓ CAN bus |
The current Arduino GIGA core exposes the primary CAN interface as:
|
1 2 3 4 5 6 7 8 9 10 |
D93 → CAN RX → PB5 D94 → CAN TX → PB13 |
and Arduino’s standard Arduino_CAN library provides a simple API for classic CAN frames.
Quick GIGA CAN Reference
| Function | GIGA R1 WiFi |
|---|---|
| Primary CAN RX | D93 / PB5 |
| Primary CAN TX | D94 / PB13 |
| CAN controller | STM32H747 FDCAN hardware |
| External transceiver required | Yes |
| Logic level | 3.3 V |
| Arduino standard library | Arduino_CAN |
| Standard CAN ID | 11-bit |
| Extended CAN ID | 29-bit |
| Default Arduino payload limit | 8 bytes |
| Arduino bitrate presets | 125, 250, 500, 1000 kbit/s |
| CAN FD through standard Arduino_CAN API | No |
GIGA Has the CAN Controller, Not the Physical Transceiver
The STM32H747 produces logic-level signals:
|
1 2 3 4 5 |
CAN TX CAN RX |
but a real CAN bus uses:
|
1 2 3 4 5 |
CANH CANL |
as a differential pair.
A transceiver performs the conversion:
|
1 2 3 4 5 6 7 8 9 10 11 |
GIGA TX → transceiver TXD → CANH/CANL CANH/CANL → transceiver → RXD → GIGA RX |
Do Not Connect CANH/CANL Directly to the GIGA
This is one of the most important wiring rules.
|
1 2 3 4 5 6 7 |
CANH CANL ≠ GPIO signals |
Connecting the bus directly to PB5/PB13 would bypass the physical CAN layer and can damage or prevent proper communication.
Choose a 3.3 V-Compatible CAN Transceiver
The GIGA uses:
|
1 2 3 4 |
3.3 V logic |
so choose a transceiver whose logic-side TXD/RXD levels are compatible with 3.3 V MCU pins.
For classic CAN, common choices include 3.3 V-compatible CAN transceivers designed for normal CAN 2.0 networks.
If you intend to use:
|
1 2 3 4 |
CAN FD |
choose a CAN FD-rated transceiver rather than assuming every older classic-CAN transceiver will support the higher data-phase rates.
Basic Wiring
| GIGA | CAN transceiver |
|---|---|
| D94 / CAN TX | TXD |
| D93 / CAN RX | RXD |
| 3.3 V or appropriate supply | VCC / logic supply |
| GND | GND |
On the bus side:
| Transceiver | CAN network |
|---|---|
| CANH | CANH |
| CANL | CANL |
Use a Twisted Pair
CAN is designed around a differential twisted pair:
|
1 2 3 4 5 6 |
CANH twisted with CANL |
This improves immunity to:
- electromagnetic interference;
- common-mode noise;
- motor noise;
- long-cable disturbances.
120-Ohm Termination
A normal CAN bus should have:
|
1 2 3 4 |
120 Ω |
termination at each physical end of the main bus.
That means:
|
1 2 3 4 5 6 |
120 Ω 120 Ω CANH/CANL ================= CANH/CANL end 1 end 2 |
There should normally be:
|
1 2 3 4 |
2 × 120 Ω terminators |
on the complete bus, not one terminator at every node.
Measure About 60 Ohms with Power Off
A useful diagnostic is to disconnect power and measure resistance between:
|
1 2 3 4 5 6 |
CANH and CANL |
on a correctly terminated bus.
Two 120 Ω terminators in parallel give approximately:
|
1 2 3 4 |
60 Ω |
A reading around 120 Ω often indicates one terminator is missing.
A much lower value can indicate too many terminators or another wiring problem.
Keep Stubs Short
CAN works best as a:
|
1 2 3 4 |
linear bus |
rather than a star network.
Connect each node through a short stub to the main twisted pair.
As bitrate and cable length increase, long stubs become increasingly problematic.
Common Ground
For normal non-isolated transceivers, connect a reference ground between nodes unless the physical-layer design explicitly uses galvanic isolation.
CAN is differential, but the transceivers still have a limited common-mode voltage range.
A ground reference helps prevent that range being exceeded.
Install Arduino_CAN
The current Arduino Mbed core for GIGA includes support for:
|
1 2 3 4 |
#include <Arduino_CAN.h> |
The core instantiates:
|
1 2 3 4 |
CAN |
for the primary GIGA CAN controller.
Start the CAN Controller
The library accepts predefined bitrates:
|
1 2 3 4 5 6 7 |
CanBitRate::BR_125k CanBitRate::BR_250k CanBitRate::BR_500k CanBitRate::BR_1000k |
For example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <Arduino_CAN.h> void setup() { Serial.begin(115200); if (!CAN.begin(CanBitRate::BR_500k)) { Serial.println("CAN start failed"); while (1) { } } Serial.println("CAN started"); } void loop() { } |
Every Node Must Use the Same Nominal Bitrate
If one node is configured for:
|
1 2 3 4 |
500 kbit/s |
and another for:
|
1 2 3 4 |
250 kbit/s |
they will not communicate normally.
Match the existing network bitrate before connecting the GIGA.
Standard CAN IDs
Classic standard CAN uses:
|
1 2 3 4 5 |
11-bit identifiers 0x000 to 0x7FF |
Arduino’s API provides:
|
1 2 3 4 |
CanStandardId(id) |
for constructing a standard identifier.
Send a Standard CAN Frame
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include <Arduino_CAN.h> void setup() { Serial.begin(115200); if (!CAN.begin(CanBitRate::BR_500k)) { while (1) { } } } void loop() { uint8_t data[] = { 0x10, 0x20, 0x30, 0x40 }; CanMsg msg( CanStandardId(0x123), sizeof(data), data ); int result = CAN.write(msg); if (result == 1) { Serial.println("Frame queued"); } else { Serial.println("CAN write failed"); } delay(1000); } |
What CAN.write() Means
The Arduino CAN API documents:
|
1 2 3 4 |
CAN.write(msg) |
as enqueuing a frame for transmission.
A return value of:
|
1 2 3 4 |
1 |
means the frame was accepted for transmission by the software/controller path.
It does not necessarily mean another node received and processed it.
CAN Requires Another Active Node for Normal Acknowledgement
On a normal CAN network, transmitted frames are acknowledged by another active CAN controller.
A setup containing only:
|
1 2 3 4 5 6 7 8 |
one GIGA + one transceiver + termination |
is not equivalent to a complete multi-node network.
For first tests, use:
- a second CAN board;
- a USB-CAN adapter;
- another microcontroller CAN node.
Receive CAN Frames
The normal receive pattern is:
|
1 2 3 4 5 6 |
if (CAN.available()) { CanMsg msg = CAN.read(); } |
A simple receiver is:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <Arduino_CAN.h> void setup() { Serial.begin(115200); while (!Serial) { } if (!CAN.begin(CanBitRate::BR_500k)) { Serial.println("CAN start failed"); while (1) { } } } void loop() { if (CAN.available()) { CanMsg const msg = CAN.read(); Serial.println(msg); } } |
Built-In CanMsg Printing
CanMsg implements Arduino’s printable interface.
So:
|
1 2 3 4 |
Serial.println(msg); |
prints the identifier, length and data bytes in a useful debug format.
Read the Identifier Manually
For standard frames:
|
1 2 3 4 5 |
uint32_t id = msg.getStandardId(); |
For extended frames:
|
1 2 3 4 5 |
uint32_t id = msg.getExtendedId(); |
You can check the frame type with:
|
1 2 3 4 5 |
msg.isStandardId() msg.isExtendedId() |
Read the Data Bytes
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
for (int i = 0; i < msg.data_length; i++) { Serial.print( msg.data[i], HEX ); Serial.print(" "); } |
Extended 29-Bit IDs
Extended CAN identifiers use:
|
1 2 3 4 |
29 bits |
Arduino’s API provides:
|
1 2 3 4 |
CanExtendedId(id) |
For example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
uint8_t data[] = { 1, 2, 3, 4 }; CanMsg msg( CanExtendedId(0x18FF50E5), sizeof(data), data ); CAN.write(msg); |
Standard vs Extended IDs
Use standard 11-bit IDs when the network protocol specifies them.
Use extended 29-bit IDs for protocols that require a larger identifier space, such as many:
- automotive protocols;
- J1939-style networks;
- custom industrial protocols.
Do not change ID format arbitrarily; it is part of the network protocol.
Current Arduino_CAN Payload Limit Is 8 Bytes
The current Arduino core defines:
|
1 2 3 4 |
CanMsg::MAX_DATA_LENGTH = 8 |
That means the standard Arduino_CAN API is currently using classic CAN payload sizing:
|
1 2 3 4 |
0-8 bytes |
per data frame.
But STM32H747 Has FDCAN Hardware
This can be confusing.
The STM32H747 peripheral itself is:
|
1 2 3 4 |
FDCAN-capable |
but the current high-level Arduino Arduino_CAN wrapper constructs classic Mbed CAN frames with an 8-byte data limit.
Therefore:
|
1 2 3 4 5 6 |
FDCAN hardware present ≠ CAN FD available through Arduino_CAN |
Classic CAN vs CAN FD
| Feature | Classic CAN | CAN FD |
|---|---|---|
| Maximum data payload | 8 bytes | Up to 64 bytes |
| Arbitration bitrate | One nominal bitrate | Nominal arbitration bitrate |
| Faster data phase | No | Optional |
| Standard Arduino_CAN on GIGA | Yes | No current high-level support |
How to Use CAN FD on GIGA
If your project specifically needs:
|
1 2 3 4 5 6 |
CAN FD 64-byte frames bit-rate switching |
you need a CAN FD-capable software path rather than assuming Arduino_CAN enables it automatically.
Options include:
- a dedicated GIGA FDCAN library;
- lower-level STM32/Mbed work;
- a third-party CAN FD library designed for GIGA.
For example, the third-party:
|
1 2 3 4 |
ACANFD_GIGA_R1 |
library specifically targets the GIGA’s CAN FD hardware.
This is not the same as Arduino’s standard Arduino_CAN API.
Use a CAN FD-Rated Transceiver for CAN FD
Even if the MCU and software support CAN FD, the physical transceiver must also support the required data-phase rate.
For a new CAN FD design, choose a transceiver explicitly specified for:
|
1 2 3 4 |
CAN FD |
rather than relying on an older classic-CAN transceiver.
GIGA Has a Second CAN Controller in the Current Core
The current GIGA Arduino variant defines:
|
1 2 3 4 |
CAN_HOWMANY = 2 |
and instantiates:
|
1 2 3 4 5 |
CAN CAN1 |
The primary interface is:
|
1 2 3 4 5 6 |
CAN TX = PB13 = D94 RX = PB5 = D93 |
Second CAN Mapping
The current core also defines:
|
1 2 3 4 5 6 |
CAN1 TX = PH13 RX = PB8 |
On the GIGA digital map these correspond to:
|
1 2 3 4 5 6 7 8 |
PH13 → D16 PB8 → D8 |
So an advanced application can potentially use a second CAN controller through:
|
1 2 3 4 5 |
D16 D8 |
instead of the dedicated D93/D94 CAN pair.
Second CAN Uses Multiplexed Header Pins
D16 and D8 are not dedicated CAN-only pins.
They also participate in other board functions.
For example:
|
1 2 3 4 5 6 7 8 |
D16 → TX2 / other alternate functions D8 → PWM / SCL2 / other alternate functions |
So using CAN1 requires deliberate pin/peripheral planning.
Primary CAN Is the Simplest Choice
For a normal project, start with:
|
1 2 3 4 5 6 |
D93 D94 CAN |
because those pins are explicitly assigned to the primary CAN interface in the board mapping.
Use CAN1 only when you actually need a second independent CAN channel.
Dual CAN Applications
Two CAN controllers are useful for:
- gateway applications;
- vehicle network bridges;
- isolating machine networks;
- protocol conversion;
- logging one bus while controlling another.
A typical gateway architecture is:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
CAN → machine bus A CAN1 → machine bus B GIGA → inspect → filter → translate → forward |
Each CAN Controller Needs Its Own Transceiver
If you use two independent CAN buses, you need:
|
1 2 3 4 5 6 7 8 |
2 CAN controllers + 2 transceivers + 2 physical buses |
Do not connect two controller TX/RX pairs to one transceiver unless the hardware is intentionally designed for that purpose.
CAN on the M7 vs M4 Core
The GIGA has:
|
1 2 3 4 5 |
M7 M4 |
cores sharing the same hardware.
Give each CAN peripheral one clear processor owner.
For example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
M4 → owns CAN → real-time vehicle/machine traffic M7 → Wi-Fi → USB → logging → UI RPC → exchange CAN data/status |
Do Not Initialise the Same CAN Peripheral from Both Cores
Arduino’s dual-core documentation warns that shared peripheral access can cause interference.
Avoid:
|
1 2 3 4 5 6 7 8 |
M7: CAN.begin(...) M4: CAN.begin(...) |
on the same controller.
Choose one owner and communicate through RPC if the other core needs the data.
Current M4 CAN Caveat
The Arduino core declares CAN support for both GIGA cores, but there have historically been reported issues using the standard Arduino_CAN implementation from the M4 core.
For a production design:
- test the exact current board-core version;
- verify sustained transmit and receive operation;
- prefer a known-good M7 implementation if reliability on M4 has not been validated.
This is especially important for safety-related or industrial applications.
CAN Bus Error Symptoms
Common symptoms include:
- frames never received;
- transmit errors;
- controller repeatedly retrying;
- bus-off state;
- intermittent communication;
- works at low bitrate but not high bitrate.
Check the Physical Layer First
Before changing code, verify:
|
1 2 3 4 5 6 7 8 9 10 |
CANH ↔ CANH CANL ↔ CANL common reference ground correct bitrate 2 × 120 Ω termination transceiver powered TX/RX wiring correct |
Most first-time CAN problems are physical-layer or bitrate problems, not application code.
Use an Oscilloscope or CAN Analyser
Useful diagnostic tools include:
- oscilloscope;
- logic analyser with CAN decoder;
- USB-CAN interface;
- professional CAN analyser.
Measure both:
|
1 2 3 4 |
logic-side TX/RX |
and:
|
1 2 3 4 |
CANH/CANL differential bus |
to determine whether the problem is in the MCU, transceiver or network.
Typical First-Test Setup
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
GIGA R1 D94 TX D93 RX ↓ 3.3 V-compatible transceiver ↓ CANH / CANL ↓ USB-CAN adapter or second CAN node |
Use:
|
1 2 3 4 5 6 |
500 kbit/s standard ID 0x123 4 data bytes |
for a simple first test.
Transmitter Test Code
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include <Arduino_CAN.h> void setup() { Serial.begin(115200); if (!CAN.begin( CanBitRate::BR_500k)) { Serial.println( "CAN init failed" ); while (1) { } } } void loop() { uint8_t payload[4] = { 0x11, 0x22, 0x33, 0x44 }; CanMsg msg( CanStandardId(0x123), 4, payload ); if (CAN.write(msg) == 1) { Serial.println("Sent"); } else { Serial.println("Send error"); } delay(1000); } |
Receiver Test Code
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <Arduino_CAN.h> void setup() { Serial.begin(115200); if (!CAN.begin( CanBitRate::BR_500k)) { Serial.println( "CAN init failed" ); while (1) { } } } void loop() { if (CAN.available()) { CanMsg msg = CAN.read(); Serial.print("ID: 0x"); Serial.println( msg.getStandardId(), HEX ); Serial.print("Data: "); for (int i = 0; i < msg.data_length; i++) { Serial.print( msg.data[i], HEX ); Serial.print(" "); } Serial.println(); } } |
Common Mistake 1: No Transceiver
The GIGA’s CAN pins are:
|
1 2 3 4 |
logic-level CAN controller signals |
not CANH/CANL.
Always use a physical transceiver.
Common Mistake 2: 5 V Logic on GIGA RX
GIGA is a:
|
1 2 3 4 |
3.3 V logic board |
so verify the transceiver’s RXD output is safe for the STM32H747 input.
Common Mistake 3: Wrong Bitrate
All nodes must agree on nominal CAN timing.
Start with one of Arduino’s supported standard bitrates:
|
1 2 3 4 5 6 7 |
125k 250k 500k 1000k |
Common Mistake 4: Too Many Termination Resistors
Do not fit:
|
1 2 3 4 |
120 Ω |
at every node.
Normally terminate only the two physical ends of the main bus.
Common Mistake 5: No Second Active Node
CAN is not UART.
A lone node does not represent a normal acknowledged CAN network.
Use another active CAN controller for meaningful transmission testing.
Common Mistake 6: Assuming Arduino_CAN Means CAN FD
The hardware is FDCAN-capable, but the current standard Arduino message type is limited to:
|
1 2 3 4 |
8 bytes |
and therefore represents classic CAN framing.
Common Mistake 7: Sharing CAN Between M7 and M4
One physical CAN controller should have one clear software owner.
Use:
|
1 2 3 4 |
RPC |
to share higher-level data between cores.
Quick Wiring Reference
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
GIGA primary CAN D94 / PB13 → transceiver TXD D93 / PB5 ← transceiver RXD GND ↔ transceiver GND transceiver CANH ↔ bus CANH transceiver CANL ↔ bus CANL 120 Ω between CANH/CANL at each physical end |
Quick Arduino_CAN Reference
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include <Arduino_CAN.h> CAN.begin( CanBitRate::BR_500k ); uint8_t data[4] = { 1, 2, 3, 4 }; CanMsg msg( CanStandardId(0x123), 4, data ); CAN.write(msg); if (CAN.available()) { CanMsg rx = CAN.read(); } Standard ID: CanStandardId(id) Extended ID: CanExtendedId(id) Payload: 0-8 bytes Bitrates: 125 kbit/s 250 kbit/s 500 kbit/s 1 Mbit/s |
Final Thoughts
The Arduino GIGA R1 WiFi is a strong CAN platform because the STM32H747 already contains the controller hardware.
For a normal classic CAN project you need:
|
1 2 3 4 5 6 7 8 9 10 |
GIGA R1 + 3.3 V-compatible CAN transceiver + CANH/CANL twisted pair + 120 Ω termination at both ends |
The simplest software path is:
|
1 2 3 4 5 6 7 8 9 |
#include <Arduino_CAN.h> CAN.begin(...) CAN.write(...) CAN.available() CAN.read() |
Remember the important distinction:
|
1 2 3 4 5 6 7 8 9 |
STM32H747 → FDCAN-capable hardware Arduino_CAN → current classic CAN API → maximum 8-byte payload |
If you specifically need CAN FD, use a CAN FD-capable transceiver and a software library or lower-level driver that actually exposes the STM32H747 FDCAN features.
For full GIGA pin mapping, see our Arduino GIGA R1 WiFi pinout guide. If you want to place CAN on the M4 while the M7 handles networking or logging, also see the GIGA R1 M7/M4 dual-core guide.