PCB design: ESP32 to CAN supporting ESPHome / Matter

Last update: 2023-04-10

I started to create a PCB to control my heatpump via CAN-bus, basically for this ESPHome project.

After seeing many posts regarding how to properly connect hardware (and of course doing this with jumper wires), I decided to go more public with my design - maybe it will help others.

While drawing the schematics, I realized, that the design is not limited to heatpumps. The design can be used for controlling / monitoring every / generic CAN-attached device.

Current state of development is here: GitHub - mkaiser/ESP32-CAN: PCB with ESP32 and CAN bus. For controlling CAN-devices like heatpumps via ESPHome or Matter

I have a professional background in electrical engineering, but I mostly research FPGA at work. So there may be some mistakes in the schematics. While drawing the schematics I tried to comment my design decisions. If you see any errors or possible pitfalls, please tell me or ask me why :wink:

So, if there is enough interest, I would think about ordering more than 5 and putting the PCB on tindie.com - depends your feedback :slight_smile:

Features

  • ESP C3 Wroom 2-N4
    • ESP Home support
    • hardware also supports the upcoming Matter protocol (over WIFI)
  • USB Type C for programming (CH340C for USB to UART)
  • 2x USB Type C (providing two ways in the prototype: one as backup)
    – for direct ESP programming
    – programming and UART via CH340C
  • Power Supply:
    • Wide range 5…30V switched input via Mornsun K78L03-500R3 (omitting the standard 3V3 LDO, so it should be very energy-efficient!)
    • Short and Reverse input protection
    • resettable input fuse
    • made sure that every component has decoupling capacitors (I was terrified, seeing that most evaluation kits don’t have them)
  • CAN Bus:
    • Input (CAN high/Low, VCC, GND) via screw terminal
    • 3V3 CAN transceiver TI SN65HVD230, compatible with 5V CAN Bus systems very technical link
    • well known and supported MCP2515 CAN Controller (integrated in ESP Home)
    • options to bypass the CAN controller via 0Ohm resistors
  • 4 LEDs (Power, RX, TX and ESP LED)
  • Optional:
    – There are additional spring clamps and one 10p 2mm pin header on the board - I need them for other projects
    – I added one I2C-attached IC to realise 2 analog output ports with 0…10V DC output. In combination with a potential free relay, I can control my ventilation system (Tecalor TVZ 170 E Plus).

Current status

  • Files (Schematic as pdf, BOM as xls and case-drawing) are available here: GitHub - mkaiser/ESP32-CAN: PCB with ESP32 and CAN bus. For controlling CAN-devices like heatpumps via ESPHome or Matter

  • Schematics: done

  • First routing done (silkscreen needs more love)

  • I am used to Altium designer, for this project I tried EasyCAD for the first time. For the schematics it was okay-ish, but I am missing assembly options / variants. Routing was not so easy compared to Altium.

  • Housings to determine the PCB dimensions. I have a sample of a Phoenix Contact UCS 145-125, which is really robust, but with around 25€ it costs would be more than the PCB… Any ideas? It is also possible to do a cheap 3D printed housing includind a strain relief for the CAN-input-wires, but I don’t have a 3D printer and certainly would need help with that.

  • Housing: Designed the PCB to fit a "SONOFF IP66 waterproof Junction Box” from aliexpress.
    Measuring the housing was a bit tricky. I hope it works

Currently looks like this:
2D layout:

3D layout:

Waiting for your feedback :slight_smile:

~Martin

Hey Martin,
I 3D print frequently and do my designs in Autodesk Fusion 360.
I’d like to try coming up with a printable housing. For that i’d need either 2d Drawings with more dimensions or a 3D model of the PCB including parts (e.g. the 3d model of the rendering)
If you upload your EasyEDA files to the repo, i can also try on my own to do the export in the right format. (I’ve never used EasyEDA before and am not sure what export capabilities it has…)
I’d be also interested in getting one of the PCBs, once you’re done :slight_smile:

Any reason you have added the CH340C stuff as the C3 supports programming from USB directly on GPIO 18/19.

@ bullitt186

sounds great!

There are not many constraints on the PCB side. 60x60mm appears to be spacious enough for one sided assembly and routing. I guess the mounting holes should be something like M4 (e.g., 4.2mm inside, 6mm outside diameter of the holes).
I am not sure, if the USB-C and the 5.08mm screw terminal should be directly accessible from the outside (e.g. place the PCBs edge at the chassis edge) or if there should be just a hole with a straint relief for the cable (e.g., J-Y(ST)Y 2 x 2 with an outer diameter of ~8 mm).

The placement of the 4 LEDs is also completely free.

I would leave that all to you with more mechanical expertise :slight_smile:

Hopefully I will have some “routing time” next weekend.

@ gaz99Gaz
good catch! I previously thought the USB lanes were more for USB OTG stuff. It is really great, that the IC supports direct USB UART/ programming and the expensive external CH340C part can be ommitted

Is there something more to know, or is it just like “connect the USB of the ESP to the USB connector” and it will show one serial device for programming and one for UART after connecting to the PC?

(just hat a peek into the TRM)

~Martin

@ bullitt186

I just ordered 3 “SONOFF IP66 waterproof Junction Boxes” from aliexpress. They look quiet good and are with 5€/pcs cheap and come with a PG7 cable gland. Lets see in around two-three weeks, when they arrive

Unfortunately, I could not find a dimensioned drawing with the mounting holes, yet. But it seems to be a common case, which is also quiet prominent on alibaba (keywords “junction box transparent”)

I have tried the USB for uploading new firmware on one of the SEEED Xaio C3 modules and it worked fine, it shows up as a JTAG serial port on the box running ESPHome. At the time there were some issues with using the port for viewing the logs with a wired connection.

My view is if the end product does not need to use the USB for power and the USB would only be used for programming then get rid of it. I just put a 4 pin header on the board connected to power and the uart pins and use an external USB-serial converter for programming.

My latest board used an ESP32-C3-01M to save a bit of space, it has a 4 pin header and a switch on GPIO 9 for programming.


prog

I have used a similar flanged case from Ebay that is 130mm x 68mm x 50mm outside with a 93.5mm x 61.5mm inside compartment.

I have a Visio drawing of it if it matches your AliEx ones.

thank you for the drawing. Looking at alibaba, the cases are basically made by one manufacturer and sold in customized versions (like the box for SONOFF switches). Unfortunately, I found several drawings and most of them differ in size :confused:

So I will just wait until I can properly measure the boxes :slight_smile:

About USB. At the first shot, I will try to support both (direct USB programming and USB/UART), selectable by jumpers. For the “end product” in mind, I guess this will be more a “more professional” evaluation kit for ESP32 to general CAN devices. So if someone wants to develop for a new device, it is always good to have a UART directly on board. The additional costs are around 1.5€, if 10 boards are assembled.

Next two weeks are stressful at work / home, so I cannot promise updates, until the boxes arrive

1 Like

Finished placement and routing. Updated the first post with images and updated features

Switched to 2x USB 2.0 Type C (one is directly attached to the ESP, one goes to the CH340C USB → UART IC

I just was about to order the PCB at JLCPCB, but the MCP2515 CAN controller is not in stock any more. Will wait a couple of days. If it is still out of stock, I will hand-solder it (ETA ~ 2-4 weeks for first prototypes)

In the git repo there are schematics as pdf, the BOM as excel and the case drawing with my measurements.

@gaz99 : Apparently our boxes do not match. Here is what I measured - sorry for the bad drawing :slight_smile:

Next ToDo: Read about licensing before pushing the EasyEDA project to github

FYI - rough pricing indication:

For 5 PCBs JLCPCB charges around 100€ including economy shipment to germany.
Excluding:

  • ESP Wroom (~3€/pc, if JLCPCB assembles this, the assembly would be labeled as “standard”, not “economy”, adding additional 23€ to setup costs). Will buy them separately and solder manually for the 5 prototypes
  • CAN controller (out of stock, ~2€),
  • 5.08mm screw terminals (~1€)
  • Relay and 0…10V controller
  • connectors for testing (push- in and the 2x5p 2mm headers)

Hardware prices could drop by down to 23 € / fully assembled PCB if more than 10 pcs are ordered. So if you are interested, write me a PM and I will consider a second, cost optimised version

~Martin

Looks good, only comment from a quick look is that the DC in trace is very small.

Design is now ready for manufacturing. Increased the DC power traces a bit (0.508 mm)

All design files are in the github repo. Will do the open hardware licencing stuff later

  • found & fixed some bugs
    – use ideal diodes instead of simple diodes to prevent voltage drop from 5V below 4.75V (min voltage reg). Simulation files are in the github
    – use 50V capable capacitors instead of 6.3V capable for 10V analog output stuff and its 24V power supply
    – use MCP2515 in a larger SO package (TSSOP was not available any more)

Will order at JLCPCB, soon. Already ordered 5 C3 Wroom modules at mouser :wink:

little update:

  • got all parts
  • JLCPCB order will hopefully arrive next week:)

Looking forward to your success message :). nice project

…TADAAA!

Used to control my ventilation system (second use for the PCB):

I fully assembled three of the PCBs (waiting for a delivery with more 2mm pin headers …)

Made several (minor) mistakes, but nothing some thread wire could not fix :slight_smile:

Findings in a nutshell:

  • I apparently suck at measuring things, but I guess 2 screws are enough to stabilize the PCB.
  • Programming via UART (CH340) and native USB works. (Fun-fact: DOUBLE-crossing UART is not better than NOT crossing them, but that was thread-wire-able…)
  • More minor stuff:
    – Chose inductors for smoothing the power supply with too small current capability (3mA, should be >200mA).
    – Switched Labels for USB Prog and UART
    – connected wrong pin for the relay (fixed by thread wire…)
    – RX Led is on by default, because the CAN bus RX is at logical ‘1’ when no dominant bits are send (–> invert LED)
  • Alive LED should be driven by a transistor and not directly by Pin0

Will do some documentation / cleanup the next weeks. At the moment I am not sure, if I will do the next revision with EasyEDA or better try KiCAD. Compared to my bread-and-butter Altium designer EasyEDA was okay-ish at first while doing the Schematics but a nightmare routing…

I already implemented the second usage of the board (control my ventilation system. ESP32 sketch is here: GitHub - mkaiser/ESPHome_ventilation_system_ctrl: Control ventilation systems (e.g. Tecalor TVZ170 TVZ 370, Wolf CWL-300/400 Excellent)

Back to CAN-Bus:

  • Connection to MCP2515 CAN controller works. Used a CAN-Listener sketch to sniff the Heatpump’s communication.

When trying to compile my code for the ESP32-C3, I get linker errors, because appartently there are issues with gcc vs.IDF data type declaration stuff:

Linking /data/heatpump-c3/.pioenvs/heatpump-c3/firmware.elf
/data/cache/platformio/packages/[email protected]+2021r2-patch5/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/heatpump-c3/.pioenvs/heatpump-c3/src/main.cpp.o: in function `esphome::api::ExecuteServiceArgument* std::__uninitialized_copy<false>::__uninit_copy<__gnu_cxx::__normal_iterator<esphome::api::ExecuteServiceArgument const*, std::vector<esphome::api::ExecuteServiceArgument, std::allocator<esphome::api::ExecuteServiceArgument> > >, esphome::api::ExecuteServiceArgument*>(__gnu_cxx::__normal_iterator<esphome::api::ExecuteServiceArgument const*, std::vector<esphome::api::ExecuteServiceArgument, std::allocator<esphome::api::ExecuteServiceArgument> > >, __gnu_cxx::__normal_iterator<esphome::api::ExecuteServiceArgument const*, std::vector<esphome::api::ExecuteServiceArgument, std::allocator<esphome::api::ExecuteServiceArgument> > >, esphome::api::ExecuteServiceArgument*)':
/data/cache/platformio/packages/[email protected]+2021r2-patch5/riscv32-esp-elf/include/c++/8.4.0/bits/stl_uninitialized.h:82: undefined reference to `long esphome::api::get_execute_arg_value<long>(esphome::api::ExecuteServiceArgument const&)'

/data/cache/platformio/packages/[email protected]+2021r2-patch5/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/heatpump-c3/.pioenvs/heatpump-c3/src/main.cpp.o: in function `std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::vector(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&)':
/data/cache/platformio/packages/[email protected]+2021r2-patch5/riscv32-esp-elf/include/c++/8.4.0/bits/stl_vector.h:462: undefined reference to `long esphome::api::get_execute_arg_value<long>(esphome::api::ExecuteServiceArgument const&)'

/data/cache/platformio/packages/[email protected]+2021r2-patch5/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/heatpump-c3/.pioenvs/heatpump-c3/src/main.cpp.o: in function `void esphome::api::UserServiceBase<long, long, long>::execute_<0, 1, 2>(std::vector<esphome::api::ExecuteServiceArgument, std::allocator<esphome::api::ExecuteServiceArgument> >, esphome::seq<0, 1, 2>)':
/config/esphome/.esphome/build/heatpump-c3/src/esphome/components/api/user_services.h:57: undefined reference to `long esphome::api::get_execute_arg_value<long>(esphome::api::ExecuteServiceArgument const&)'

/data/cache/platformio/packages/[email protected]+2021r2-patch5/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/heatpump-c3/.pioenvs/heatpump-c3/src/main.cpp.o: in function `esphome::api::ListEntitiesServicesArgument::ListEntitiesServicesArgument()':
/config/esphome/.esphome/build/heatpump-c3/src/esphome/components/api/api_pb2.h:836: undefined reference to `esphome::api::enums::ServiceArgType esphome::api::to_service_arg_type<long>()'

/data/cache/platformio/packages/[email protected]+2021r2-patch5/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /data/heatpump-c3/.pioenvs/heatpump-c3/src/main.cpp.o: in function `esphome::api::UserServiceBase<long, long, long>::encode_list_service_response()':
/config/esphome/.esphome/build/heatpump-c3/src/esphome/components/api/user_services.h:35: undefined reference to `esphome::api::enums::ServiceArgType esphome::api::to_service_arg_type<long>()'


/data/cache/platformio/packages/[email protected]+2021r2-patch5/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld: /config/esphome/.esphome/build/heatpump-c3/src/esphome/components/api/user_services.h:35: undefined reference to `esphome::api::enums::ServiceArgType esphome::api::to_service_arg_type<long>()'
collect2: error: ld returned 1 exit status
*** [/data/heatpump-c3/.pioenvs/heatpump-c3/firmware.elf] Error 1
========================= [FAILED] Took 211.38 seconds =========================

It looks like the issues described here, but I did not have time to investigate / test more.

Any help would be much appreciated and I could focus more on the fun-hardware-stuff :slight_smile:

My test yaml is here: ESPHome config for CAN at ESP32 C3 . Results in linker errors :/ · GitHub
Just copy / paste the yaml and compile it. The error should be the one shown above

~Martin

2 Likes

Hey there,

Mostly finished the PCB bringup and documentation before going on vacation.

See here for the schematic errata: GitHub - mkaiser/ESP32-CAN: PCB with ESP32 and CAN bus. For controlling CAN-devices like heatpumps via ESPHome

Altough the first revision runs great after minor PCB fixes, I will make a new revision in a couple of month.

For this I want to use the new ESP32 C6 Mini, which is getting “more available” now

I am also considering the MCP251863 CAN FD Controller with included transceivers. Selecting the CAN mode (internal ESP32 or MCP2518) is still possible by Jumper. But I am a bit afraid of the ESPHome Software support, that will be required. But taken into the consideration that the well-known and widely-used MCP2515 chip is at EOL, this will be the future proof solution.

Could someone help me with the MCP2518?

Any more suggestions / ideas?

Also I did not have any time to fix the linker issues described in my last posts…

2 Likes

little update:
got it compiling and working with this workaround: api services remote_transmitter compile error esp32c3 #2 · Issue #3564 · esphome/issues · GitHub

Could not test the internal CAN controller, yet, because the ESPHomes ESP32_CAN component does not support the 20kbit/s, which is required by the heatpump:

It is a an internal ESP issue, as the ESP32-C3 actually supports this speed (the old ESP32 do not).

See Two-Wire Automotive Interface (TWAI) - ESP32-C3 - — ESP-IDF Programming Guide latest documentation

(search for " TWAI_TIMING_CONFIG_20KBITS"

1 Like

code using INTERNAL CAN controller is compiling now.

(we need 20 Kbit/s for the heatpump, which is supported, yet)

Will test soon and hopefully go upstream fast

2 Likes

internal CAN is working now :slight_smile:

when the ESPHome component changes (ESP CAN) are accepted upstream (takes me 1-2weeks I guess), the external CAN controller can be completely omitted

One issue came up today: When the CAN PCB is powered via 16-18V heatpump CAN Bus and the heatpumps power is switched on, the CAN Bus power supplied by the heatpump dropps and causes the heatpump to reboot.

That never happens, if the CAN PCB is powered via USB or the external FEK sensor is attached. So I guess Tecalor /Stiebel used a highly cost-optimized power supply, which cannot take on additional 200mW (est. max @ boot for the CAN PCB)

1 Like

So external Power Supply will be needed? Correct me if I’m wrong, but the CAN bus is not designed to supply devices with power, so such problems are to be expected. How is an external control panel connected to the heat pump? Is there not still somewhere a power source to tap?