CAN via SPI over STM32F103C8T6
From what I've seen so far in your code, you are not trying to communicate with specific sensors or devices, you are sending some bytes between several STM32 nodes at relatively short distance.

If that is the case, the simple solution would be to slap differential transceivers onto UART ports and be done with it. Any interface would do, like RS-485, M-LVDS, LVDS in wired-OR configuration etc.

You need to design your own protocol to deal with collisions though, which is something that CAN does for you. With only 7 nodes on the network (if I recall correctly) this can be easily done by either using one node as master orchestrating the communication, or using any kind of scheduling, time slots etc.

UPDATE

Here is one thing that should clear the confusion. All these different transceivers are not that different. In fact, you can use CAN transceiver TJA1050 from your previous experiments and get the same result. They simply convert single-ended signals to differential and back.

Whenever you have more than one node that can initiate the communication you have potential for collision. Most of these chips have protection, i.e. they won't be damaged if two nodes start talking simultaneously. But the data will be garbled. Something has to take care of this. CAN controller is exactly that "something". You don't need to invent your own protocol but the cost is more complex configuration/communication with the controller.

Alternatively you can skip the controller and connect to transceiver directly. Then you need some bare minimum of control. One simple way to do this (used by CAN controller, BTW) is to use wired-OR electrical connection, and transmit and receive simultaneously, comparing each transmitted bit with received one. If there is a difference it means someone is also transmitting, so one of the nodes yields communication to the other and waits until the bus is idle. To do this in software you need very fast MCU.

You can come up with simple protocol that does not need special wiring. For example you can pass "the right to transmit" between the nodes. If node has nothing to say it transmits "Node #n: I am done" code. Then next node takes turn, and so on. If node needs a response it can transmit a request and get response back immediately, or it can yield the line and get response when the responding node takes its turn.

In short - any multi-tiered network implementation requires coding. Whether you apply your efforts to adapt robust existing solutions or invent your own is up to you.

I suggest reading this excellent article to better understand the variety of options.