1
\$\begingroup\$

I'm trying to learn about microcontrollers in general and at this point I'm trying to learn about the CAN bus standard by using it with an STM32 MCU in a NUCLEO-F767ZI board.

For that end I want to send a message from an STM32 in the board to an Arduino Uno with a CAN module, and have it reply something based on what I send.

The first step in this process was to achieve CAN bus communication between two Arduinos using two CAN MCP2515 modules that interface with the Arduino through SPI. It worked perfectly when I flashed one Arduino with transmitter code and the other with receiver code and exchanged messages as described above.

The second step was to replace the transmitter Arduino with the STM32, which is where things stopped working. First I realized I needed a CAN transceiver, so I got a MCP2551 transciver and connected the VCC to STM32 5 V, GND to STM32 GND, CANTX and CANRX to CANTX and CANRX. The CANH lines and CANL lines I connected to the CANH and CANH on the arduino's MCP2515 module. I then flashed the STM32 with the following code:

MX_CAN1_Init();

CAN_FilterTypeDef canfilterconfig;

canfilterconfig.FilterActivation = CAN_FILTER_ENABLE;
canfilterconfig.FilterBank = 18; // which filter bank to use from the assigned ones
canfilterconfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
canfilterconfig.FilterIdHigh = 0x446<<5;
canfilterconfig.FilterIdLow = 0;
canfilterconfig.FilterMaskIdHigh = 0x446<<5;
canfilterconfig.FilterMaskIdLow = 0x0000;
canfilterconfig.FilterMode = CAN_FILTERMODE_IDMASK;
canfilterconfig.FilterScale = CAN_FILTERSCALE_32BIT;
canfilterconfig.SlaveStartFilterBank = 20; 
CAN_TxHeaderTypeDef   TxHeader;

uint8_t TxData;
uint32_t TxMailbox = 1;

TxHeader.IDE = CAN_ID_STD;
TxHeader.StdId = 0x0F6;
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.DLC = 1;
TxData = 0x11;

HAL_CAN_ConfigFilter(&hcan1, &canfilterconfig);
HAL_CAN_Start(&hcan1);
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);

while (1)
{
  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, &TxData, &TxMailbox) ;
  delay(500);
}

static void MX_CAN1_Init(void)
{
  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 9;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_3TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = DISABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = DISABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan1) != HAL_OK) //Edit: I had ommitted this section
  {
    Error_Handler();
  }
}

I then attempted to receive the commands on the Arduino but, I couldn't. I couldn't figure out why, so I bought a logic analyzer. I tested it on the CANRX line by analyzing that signal when the transceiver is connected to a transmitting Arduino, so everything is working, but what I cannot understand is why when I try to analyze the CANTX line (going out of the STM32) the line is idle as high. I have not been so able to analyze this signal and I suspect the STM32 isn't outputting anything, but I don't know why. Does anyone know?

I don't know if at this stage (just looking at CANTX) this is required, but I hooked up the CAN connection between STM32 and the Arduino again and put 120 Ω resistors between the CANH and CANL lines at both ends, but still nothing is shown.

When interfacing an STM32 and an Arduino for other protocols I needed to use a level shifter, since the STM32 operates at 3.3 V and the Arduino at 5 V, but I think that shouldn't be an issue if I'm only trying to get something on the CANTX.

I don't believe there is anything wrong with my code since it seems to be pretty standard in all implementations I've seen, so that means the problem must be in the hardware, but I've run out of ideas, so if someone could help I would really appreciate it.

\$\endgroup\$
4
  • \$\begingroup\$ Just curious, where did you get your MX_CAN1_Init() from? The name implies it was generated by CubeMX but in this case it should've included the call to HAL_CAN_Init() as Flexz mentioned. \$\endgroup\$
    – floppydisk
    Commented Jan 9, 2023 at 16:14
  • \$\begingroup\$ @floppydisk I did auto generate it by changing the .ioc, I had just ommited the call to HAL_CAN_Init(), but I've edited it now so it's clearer \$\endgroup\$ Commented Jan 9, 2023 at 18:52
  • \$\begingroup\$ Did you find the solution I'm facing the same problem. \$\endgroup\$
    – cvcv
    Commented Sep 11, 2023 at 17:32
  • \$\begingroup\$ @cvcv No, sadly I just moved on and didn't use CAN with STM32. If you do find it please add a comment or answer here as I'm also curious! \$\endgroup\$ Commented Sep 21, 2023 at 9:16

1 Answer 1

2
\$\begingroup\$

The MX_CAN1_Init() function is missing a call to HAL_CAN_Init, which will move settings from a temporary Init structure to the registers.

HAL_CAN_MspInit function (if you are following ST project structure) must enable peripheral's clocks, initilize GPIO and interrupts.

\$\endgroup\$
3
  • \$\begingroup\$ Why do you think so? We don't see the actual MX_CAN1_Init() but by default it does include a call to HAL_CAN_Init() \$\endgroup\$
    – floppydisk
    Commented Jan 9, 2023 at 15:42
  • \$\begingroup\$ Oh you're right, I didn't scroll the code. \$\endgroup\$
    – floppydisk
    Commented Jan 9, 2023 at 16:12
  • \$\begingroup\$ Hi Flexz it's you again saving me :) Thanks for your reply, but I simply ommited it, in the actual code there is a call to HAL_CAN_Init(). I still don't know what's wrong so I've included it in the original post to avoid confusion for anyone trying to help. \$\endgroup\$ Commented Jan 9, 2023 at 18:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.