# CAN via SPI over STM32F103C8T6

Since I could not get CAN to work with the internal CAN of an STM32 (F103C8T6), I bought a few CAN boards working with SPI, like these:

However, when I send something I get the following results using a logic analyzer:

• Channels 1, 2 and 3 are Clock, MISO and MOSI of the receiving SPI
• Channels 4, 5 and 6 are Clock, MISO and MOSI of the transmitting SPI
• Channel 6 and 7 are CANH resp CANL

My relevant code for the sender side:

static void MX_SPI1_Init(void)
{

hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}


main:

  while (1)
{
uint8_t data[] = { 1, 2, 3, 4, 5 };
if (HAL_SPI_Transmit(&hspi1, data, 5, 100) != HAL_OK)
{
Error_Handler();
}
HAL_Delay(1000);
}


(note the Error_Handler is not called, so the return value is HAL_OK.

static void MX_SPI1_Init(void)
{

hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

}


main:

while (1)
{
}


Questions:

1. Why don't I get information on the receiving side? It seems the sending SPI is ok, the sending CANH can be ok, but CANL seems not.

2. There are two jumpers on the CAN PCB, but I'm not sure what they do (when I put jumpers I still get nothing on the receiving SPI side).

3. I put both the Transmitter and Receiver to Master (because later they both need to send messages). I also tried with the Transmitter to Master and Receiver to Slave, but again no difference. What should be the correct setting?

• Comments are not for extended discussion; this conversation has been moved to chat. – Dave Tweed Jul 16 '18 at 13:06

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.

• I found the MAX487 transceiver which might be useful (not wanting to write my own protocol). But if it does not work I can indeed use without it. Not sure if I want to do polling since some of the data needs a very low latency (but I can later replace those by SPI). – Michel Keijzers Jul 16 '18 at 13:23
• SPI is single-master device. Is that what you need? I was under impression that you were building a network of equal nodes. MAX487 is nice chip. However regardless of electrical interface you choose, as long as any node can initiate a transaction at any time you need a protocol. The only exception is using full-duplex (MAX488-MAX491) between two nodes. Same as direct UART connection. – Maple Jul 16 '18 at 15:59
• actually I need a network and for most of the nodes I want to use RS485 (or try at least). But for a few I want to use all 3 UARTs available (for MIDI inputs), and don't want to lose 1 UART for RS485. Also exactly that information is high priority so I will use SPI for it. I also found out I need MAX(3)485 to have full 2 mbps instead of MAX 487's 250 kbps. The protocol can make use of the DE pin. – Michel Keijzers Jul 16 '18 at 16:11
• They all bus network chips. The only difference is wiring - one TWP for half-duplex or two for full-duplex. Full-duplex allows two nodes to start talking at any time, minimum latency. But if you have more than 2 equal nodes then full-duplex becomes pointless, you need conflict-resolution protocol anyway. CAN has that protocol implemented in hardware. – Maple Jul 16 '18 at 17:03
• Re speed, MAX485 and MAX491 have 2.5Mbps and DE pins. However much faster speeds can be achieved by lowering bus voltage, e.g. SP3485 for 10Mbps RS-485 or SN65MLVD206B for 200Mbps M-LVDS. Higher speed can offset latency drop due to protocol delays. But keep in mind that all these high speeds (like 1Gbps of LVDS) are limited by interface you connecting transceiver to. If you connect them to UART then you can't get more bitrate than maximum UART speed. – Maple Jul 16 '18 at 17:37