I am waiting on parts for the USB, SD-Card, Ethernet and Modules so the next task I can work on is the CAN interface. The actual barebone CAN interface is autogenerated by STM32CubeIDE in C, so all we need to do is to create a proper IO queue, deal with timing and error handling. Most of this is easiest done on HAL layer in C. The one you need to watch out for is error handling because STβs CAN interface have error counters that will stop the interface unless you process that correctly and you might be running for a long time before reaching 255 Errors on send or receive.
And sorry to say β setting up CAN is a fiddle if you have never done it before β if I am lucky it work within a day, but I would estimate a weeks work to be sure knowing that I sometimes have used 2-3 weeks in the past.
Galvanic Isolation
As mentioned before all ports except USB are fully galvanic isolated . 24V, Ethernet and all CAN ports. The isolation level on CAN is actually 1500V for 1 minute. My weakest point here is the SSR used for 120Ohm, but I will look into that. The CAN Tranceiver itself handles 5000++V for 1 minute. What you need to know about galvanic isolation is that it will protect you ports against spikes and mistakes, but it will not protect them forever. I older equipment or very low cost equipment they still uses diodes and chokes which also protect to some level, but not even close to what a galvanic isolation will do. Also β with full galvanic isolation on CAN we can let CAN be a twisted pair and ignore ground. But, I have output Ground and Shield for those who insist (or need) on it. Ground was mostly needed because of diodes that ancored the H and L lines to 12V etc. Galvanic Isolation cost between 5-10USD rather than 1 USD, but these are the bucks you donβt want to save.
Noise
Galvanic isolation do not remove noise, so if you run wires close to a noisy motor etc you might need to shield the cable. You will detect noise as CRC errors on incoming messages. I accept to loose about 1 message per hour, but you need to evaluate your own cabling and situation.
Timing
To set up CAN you also need to set a few timers that decide then the CAN interface read bits. These decide your bitrate and you need to use a standard that is very close to what the rest of the CAN network uses to achieve arbitration. The recomendation that many uses is CANopen so I will stick to that. The tricky part here is that every MCU have their own clock system and you have a clock speed set by Clock Configuration in STM32CubeIDE in my case and a prescaler on each CAN interface β and to complicate things these are FD-CAN ports capable of 12Mbps speed. At precent I want to stick to βclassic CANβ capable of 1Mbs. I notice that my maximum default speed setting is almost 46Mbps which will not work so we will need to configure the following correctly:
CAN Clock Speed. On some older MCUβs I needed to adjust the MCU speed itself for this to use a speed/precaler combination that generated a similar speed. I have not done this on H723 yet. I notice that my current CAN Clock Speed is 137.5Mhz (Maximum) and that H723 can adjust this separately from main clock speed.
Nominal Prescaler will set your bitrate by dividing the CAN Clock Speed and keep in mind that this needs to give a bitrate that is the same for the entire CAN network which will consist of devices with complete different clock settings. I notice that to achieve 1Mbps I will need a Prescaler between 45 and 46 β so I might need to look into CAN Clock Speed to get this accurate. Keep in mind that the CAN receiver most likely will work as long as you set a bitrate it can receive since the silicon is most likely to check CAN frames and ignore speed on receive β so if you have a 1:1 bus you can actually set one device to 1Mbps and the second to 500Kbps and it will βkind ofβ work as long as you donβt need arbitration β this is an actual error I corrected on a mobile vehicle for 1,5 years ago that took me by surprice.
Nominal Time Quantum is calculated for you.
Nominal Time Seq1 and Nominal Time Seq2 are the timers that is a bit tricky as they should follow CANopen standard.
Nominal Time for one Bit is calculated and should be 1ms for 1Mbps.
Nominal Baud Rate should be 1000000 bit/s for 1Mbps.
So to summarize on Timing β you will need to fiddle with CAN Clock Speed and Prescaler to get correct bitrate and once that is done set Seq1 and Seq2 correct. I have done this before, but every MCU is so different that I sit and fiddle every time β my tools are searching the internet and asking OpenAI + testing. And you have to do this for every bitrate you support. But, keep it simple (1) set bitrate through clock speed and prescaler and (2) set timers.
Testing
In my case I will create a CAN Network with 4 CAN Nodes (1) My Laptop through some standard CAN/USB Adapter β I hav access to Peak and IXXAT so I can use those as reference. The three others are the three CAN ports on the board. This allows me to do some clever arbitration tests as I can insert messages simultaneously and see whom comes out first.
Termination
I have added a 120Ohm termination resistor that is SW configurable on every port so I switch this on for every endpoint.
Barebone Queue
CAN interfaces always have a small queue for sending/receiving in Hardware that we need to service. I always read/write those with longer SW queues inside β that said CAN is usually so fast even on slow bitrates that it is seldom I use much queues. It is mostly if you want to support hard bursting. Bursting is the capability for one device to send continiously and expect that the receiver will cope β so we add a in/out SW queue on 100 or 1000 entries as per need. The only tricky part with this queue is that one end will be in HAL C Code and the other end in C++ code, so we use a C FIFO module as base. And this 2-way queue needs to be message orriented with age timers added.
Age timers are actually nonsence since we in most cases will send/process messages within 50ys, but they are there for the rare case that we donβt. We have control over receiving, but we might be delayed on sending due to arbitration β and we need error handling for arbitration errors (messages that do not send due to low priority on a busy system).
The CAN IO Queue should be in ISO 11892 format β I know what that is for CAN 2.0 A/B, but CAN-FD is new for me, so I need to check if it is more than extending from 8 byte to 64 byte payload.
The βother endβ of a CAN queue is the switch which in reality will forward to host βas isβ or to a protocol like CANopen, J1939 or custom depending on how you use this board.
Error handling
Auto Retransmission allows the CAN HW to re-transmit a few times before it gives up. We still need to handle the case where it gives up which most times are arbitration error. But we also need to remove messages that never send to avoid that our out queue overflows.
Send/Receive error counters will trigger callback if they reach thresholds.
And it might be some that I have forgotten β On most HAL interfaces I just use the HAL, but on CAN I read the registers looking for error settings due to past experiences with weird errors that are raised. You could say I have trust issues with ST HAL and CAN 
C++ Class Model
The diagram below is a simplified class model.
Barebone CAN
CAN is one of the exceptions where I read the barebone interface and check if I need to do something. HAL is usually good, but I have experienced issues with lack of proper error handling here in the past- usually I end up adding a few bits to HAL.
HAL CAN
HAL implement an interface and I prefer to us this βas isβ.
alCAN
I add my own CAN low level class that pick up barebone access, register settings and added HAL work. The interface to this is C++ SW queues and a seperate Send & Receive task called by RTOS.
RemoteIOCAN, CANopen, J1939 are just examples of the next level. Actuall the switch that is not shown here will receive messages from alCAN and forward them as requested.
One important note is message hand-shaking. Due to the nature of the RTOS I use that is most likely instant. Assume you receive a SDO Read request you will receive the message, process it and send the responce within 200ys or something.
Thanks for reading the mega rant 