# CAN Bus Support

**URL:** https://community.simplefoc.com/t/can-bus-support/407
**Category:** hardware support
**Created:** [January 2, 2021, 9:25am UTC](https://community.simplefoc.com/t/can-bus-support/407 "2021-01-02T09:25:54Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![erwin74](https://community.simplefoc.com/letter_avatar_proxy/v4/letter/e/5f9b8f/32.png) [@erwin74](https://community.simplefoc.com/u/erwin74)
#### Post date: [January 2, 2021, 9:25am UTC](https://community.simplefoc.com/t/can-bus-support/407/1 "2021-01-02T09:25:54Z")

</div>

@Owen_Williams First of all, thanks for the amazing port for the G431-ESC device! On that base i added simple CAN-bus features to it.  
If anyone is interested at it, here is the code for it - i know not the best way to publish source-code in that form 😉, anyhow here it is:  
SimpleCan.h:

```
#pragma once

#include "Arduino.h"
#include <stm32g4xx_hal_fdcan.h>

enum CanSpeed
{
	Mbit1 = 10,
	Kbit500 = 20,
	Kbit250 = 40,
	Kbit125 = 80	
};

/**
 CAN wrapper for G431 board.
*/
class SimpleCan
{
public:
	class RxHandler
	{
	public:
		RxHandler(uint16_t dataLength, void(*callback)(FDCAN_RxHeaderTypeDef rxHeader, uint8_t *rxData));
		~RxHandler();

		void notify(FDCAN_HandleTypeDef *hfdcan);
	private:
		FDCAN_RxHeaderTypeDef _rxHeader;
		uint8_t *_rxData;
		void(*_callback)(FDCAN_RxHeaderTypeDef, uint8_t *);
	};
	
	SimpleCan(bool terminateTransceiver);

	HAL_StatusTypeDef init(CanSpeed speed);
	HAL_StatusTypeDef configFilter(FDCAN_FilterTypeDef *filterDef);
	HAL_StatusTypeDef configGlobalFilter(
		uint32_t nonMatchingStd,
		uint32_t nonMatchingExt,
		uint32_t rejectRemoteStd,
		uint32_t rejectRemoteExt);
	HAL_StatusTypeDef activateNotification(RxHandler *rxHandler);
	HAL_StatusTypeDef deactivateNotification();
	HAL_StatusTypeDef start();
	HAL_StatusTypeDef stop();
	HAL_StatusTypeDef addMessageToTxFifoQ(
		FDCAN_TxHeaderTypeDef *pTxHeader,
		uint8_t *pTxData);
//private: interrupt handler needs access to it
	static FDCAN_HandleTypeDef _hfdcan1;
	static RxHandler *_rxHandler;
};

```

SimpleCan.cpp:

```
#include "SimpleCan.h"

// will be called from: HAL_FDCAN_Init
extern "C" void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef *hfdcan);
extern "C" void FDCAN1_IT0_IRQHandler();
extern "C" void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs);

FDCAN_HandleTypeDef SimpleCan::_hfdcan1 = { };
SimpleCan::RxHandler* SimpleCan::_rxHandler = NULL;

SimpleCan::SimpleCan(bool terminateTransceiver)
{
	if (_hfdcan1.Instance != NULL)
	{
		Error_Handler();
	}

	_hfdcan1.Instance = FDCAN1;

	pinMode(CAN_SHDN, OUTPUT);
	pinMode(CAN_TERM, OUTPUT);

	digitalWrite(CAN_TERM, terminateTransceiver ? HIGH : LOW);
}

HAL_StatusTypeDef SimpleCan::start(void)
{
	digitalWrite(CAN_SHDN, LOW);
	return HAL_FDCAN_Start(&_hfdcan1);
}

HAL_StatusTypeDef SimpleCan::stop(void)
{
	digitalWrite(CAN_SHDN, HIGH);
	return HAL_FDCAN_Stop(&_hfdcan1);
}

HAL_StatusTypeDef SimpleCan::init(CanSpeed speed)
{
	FDCAN_InitTypeDef *init = &_hfdcan1.Init;
	
	init->ClockDivider = FDCAN_CLOCK_DIV1;
	init->FrameFormat = FDCAN_FRAME_FD_BRS;
	init->Mode = FDCAN_MODE_NORMAL;
	init->AutoRetransmission = DISABLE;
	init->TransmitPause = ENABLE;
	init->ProtocolException = DISABLE;
	
	// 1 MBit: NominalPrescaler = 10
	// see: http://www.bittiming.can-wiki.info/
	// 170MHz / Prescaler / SyncJumpWith / (TimeSeg1 + TimeSeg2 + SyncSeg) 
	// SyncSeg = SYNC_SEG = 1, TimeSeg1 = PROP_SEG + PHASE_SEG1, TimeSeg2 = PHASE_SEG2
	init->NominalPrescaler = (uint16_t) speed;
	init->NominalSyncJumpWidth = 1;
	init->NominalTimeSeg1 = 14;
	init->NominalTimeSeg2 = 2;

	init->DataPrescaler = 1;
	init->DataSyncJumpWidth = 4;
	init->DataTimeSeg1 = 5;
	init->DataTimeSeg2 = 4;
	init->StdFiltersNbr = 1;
	init->ExtFiltersNbr = 0;
	init->TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
	
	return HAL_FDCAN_Init(&_hfdcan1);
}

HAL_StatusTypeDef SimpleCan::configFilter(FDCAN_FilterTypeDef *filterDef)
{
	return HAL_FDCAN_ConfigFilter(&_hfdcan1, filterDef);
}

HAL_StatusTypeDef SimpleCan::configGlobalFilter(
	uint32_t nonMatchingStd,
	uint32_t nonMatchingExt,
	uint32_t rejectRemoteStd,
	uint32_t rejectRemoteExt)
{
	return HAL_FDCAN_ConfigGlobalFilter(&_hfdcan1, nonMatchingStd, nonMatchingExt, rejectRemoteStd, rejectRemoteExt);
}

HAL_StatusTypeDef SimpleCan::activateNotification(RxHandler *rxHandler)
{
	if (_rxHandler != NULL)
	{
		return HAL_ERROR;
	}
#if USE_HAL_FDCAN_REGISTER_CALLBACKS
	// This would make interrupt handling much easier and cleaner.
	// But how to activate it on Arduino platform?
	//_hfdcan1.Instance->RxFifo0Callback = ...;
#endif
	_rxHandler = rxHandler;
	return HAL_FDCAN_ActivateNotification(&_hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
}

HAL_StatusTypeDef SimpleCan::deactivateNotification()
{
	_rxHandler = NULL;
	return HAL_FDCAN_DeactivateNotification(&_hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE);
}

HAL_StatusTypeDef SimpleCan::addMessageToTxFifoQ(
	FDCAN_TxHeaderTypeDef *pTxHeader,
	uint8_t *pTxData)
{
	return HAL_FDCAN_AddMessageToTxFifoQ(&_hfdcan1, pTxHeader, pTxData);
}

void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef *hfdcan)
{
	if (hfdcan == NULL || hfdcan->Instance != FDCAN1)
	{
		return;
	}

	RCC_PeriphCLKInitTypeDef periphClkInit = { };
	
	HAL_RCCEx_GetPeriphCLKConfig(&periphClkInit);
	
	// Initializes the peripherals clocks
	periphClkInit.PeriphClockSelection |= RCC_PERIPHCLK_FDCAN;
	periphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1;
	if (HAL_RCCEx_PeriphCLKConfig(&periphClkInit) != HAL_OK)
	{
		Error_Handler();
	}
	
	// Peripheral clock enable
	__HAL_RCC_FDCAN_CLK_ENABLE();

	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	
	// FDCAN1 GPIO Configuration
	// PA11 ------> FDCAN1_RX
	GPIO_InitTypeDef GPIO_InitStruct = { 0 };
	GPIO_InitStruct.Pin = GPIO_PIN_11;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	// PB9 ------> FDCAN1_TX 
	GPIO_InitStruct.Pin = GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	// FDCAN1 interrupt Init
	HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
}

void FDCAN1_IT0_IRQHandler(void)
{
	HAL_FDCAN_IRQHandler(&SimpleCan::_hfdcan1);
}

void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
	if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET)
	{
		if (SimpleCan::_rxHandler == NULL)
		{
			return;
		}
		SimpleCan::_rxHandler->notify(hfdcan);
	}
}

SimpleCan::RxHandler::RxHandler(uint16_t dataLength, void (*callback)(FDCAN_RxHeaderTypeDef, uint8_t *))
{
	_rxData = new byte[dataLength];
	_callback = callback;
}

SimpleCan::RxHandler::~RxHandler()
{
	delete[] _rxData; 
}

void SimpleCan::RxHandler::notify(FDCAN_HandleTypeDef *hfdcan)
{
	if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &_rxHeader, _rxData) != HAL_OK)
	{
		Error_Handler();
	}

	if (_callback != NULL)
	{
		_callback(_rxHeader, _rxData);
	}
}

```

---

<div class="post-metadata">

### Author: ![erwin74](https://community.simplefoc.com/letter_avatar_proxy/v4/letter/e/5f9b8f/32.png) [@erwin74](https://community.simplefoc.com/u/erwin74)
#### Post date: [January 2, 2021, 9:27am UTC](https://community.simplefoc.com/t/can-bus-support/407/2 "2021-01-02T09:27:39Z")

</div>

usage SimpleFocForG431Esc.ino:

```
#include <Arduino.h>
#include <SimpleFOC.h>
#include <math.h>
#include <SimpleCan.h>

const int MotorPolePairs = 4;
const Direction MotorNaturalDirection = CCW;
const float MotorZeroElectricAngle = 5.235;

static void handleCanMessage(FDCAN_RxHeaderTypeDef rxHeader, uint8_t *rxData);
static void init_CAN(void);
static String serialReceiveUserCommand(void);
static void Button_Down(void);
static float readNtc(void);
static float readVbus(void);

HardwareSerial Serial1(USART2_RX, USART2_TX);
BLDCDriver6PWM driver(PHASE_UH, PHASE_UL, PHASE_VH, PHASE_VL, PHASE_WH, PHASE_WL);
BLDCMotor motor(MotorPolePairs);
HallSensor sensor(HALL1, HALL2, HALL3, motor.pole_pairs);
SimpleCan can1(/*terminateTransceiver:*/true);
SimpleCan::RxHandler can1RxHandler(8, handleCanMessage);

FDCAN_TxHeaderTypeDef TxHeader;
uint8_t TxData[8];

static void hallA() { sensor.handleA(); }

static void hallB() { sensor.handleB(); }

static void hallC() { sensor.handleC(); }

void setup() {
	Serial1.begin(115200);
	Serial1.println();
	
	pinMode(LED_BUILTIN, OUTPUT);
	attachInterrupt(digitalPinToInterrupt(BUTTON), Button_Down, LOW);

	delay(100);

	sensor.enableInterrupts(hallA, hallB, hallC);
	sensor.init();

	motor.linkDriver(&driver);
	motor.linkSensor(&sensor);
	motor.controller = ControlType::voltage;

	driver.voltage_power_supply = 24;
	motor.foc_modulation = FOCModulationType::Trapezoid_120;
	motor.voltage_limit = 5;
	motor.voltage_sensor_align = 1;
	motor.useMonitoring(Serial1);

	driver.init();
	motor.init();
	//motor.initFOC();
	//Serial1.printf("zero electric angle: %10.4f\r\n", motor.zero_electric_angle);
	motor.initFOC(MotorZeroElectricAngle, MotorNaturalDirection);

	init_CAN();
}

void loop()
{
	static uint32_t triggerT1;
	static uint32_t triggerT2;
	uint32_t nowT = millis();

	if ((nowT - triggerT1) >= 1000)
	{
		Serial1.println();
		Serial1.printf("VBUS: %3.1f V\r\n", readVbus());
		Serial1.printf("TEMP: %4.1f C\r\n", readNtc());
		//Serial1.printf("POTI: %d\r\n", analogRead(POTENTIOMETER));
		triggerT1 = nowT;
	}
	if ((nowT - triggerT2) >= 100)
	{
		motor.monitor();
		triggerT2 = nowT;
	}

	motor.loopFOC();

	String command = serialReceiveUserCommand();
	motor.move();
	motor.command(command);
}

// utility function enabling serial communication the user
static String serialReceiveUserCommand() {
	// a string to hold incoming data
	static String received_chars;
	String command = "";

	while (Serial1.available()) {
		char inChar = (char)Serial1.read();
		received_chars += inChar;

		if (inChar == '\r')
		{
			command = received_chars;
			received_chars = "";
			Serial1.println(".");
		}
		else
		{
			Serial1.write(inChar);
		}
	}
	return command;
}

static float readVbus()
{
	const int AdcMaxValue = 1023;
	const float Factor = 3.3 / AdcMaxValue * (169.0 + 18.0) / 18.0;

	return analogRead(VBUS) * Factor;
}

static float readNtc() 
{
	const float ResistorBalance = 4700.0;
	const int AdcMaxValue = 1023;
	const float Beta = 3425;
	const float RoomTemp = 298.15; //[K]
	const float ResistorNtcRoomTemp = 10000.0;
	const float Factor1 = ResistorBalance * AdcMaxValue;
	const float Factor2 = Beta * RoomTemp;
		
	float adcValue = analogRead(TEMPERATURE);
	float resistorNtc = Factor1 / adcValue - ResistorBalance;
	float temperature = Factor2 / (Beta + RoomTemp * log(resistorNtc / ResistorNtcRoomTemp));

	return temperature - 273.15;
}

static void init_CAN()
{
	Serial1.println(can1.init(CanSpeed::Mbit1) == HAL_OK
		? "CAN: initialized."
		: "CAN: error when initializing.");

	FDCAN_FilterTypeDef sFilterConfig;

	// Configure Rx filter
	sFilterConfig.IdType = FDCAN_STANDARD_ID;
	sFilterConfig.FilterIndex = 0;
	sFilterConfig.FilterType = FDCAN_FILTER_MASK;
	sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
	sFilterConfig.FilterID1 = 0x321;
	sFilterConfig.FilterID2 = 0x7FF;

	can1.configFilter(&sFilterConfig);
	can1.configGlobalFilter(FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE);
	can1.activateNotification(&can1RxHandler);
	
	Serial1.println(can1.start() == HAL_OK
		? "CAN: started."
		: "CAN: error when starting.");
}

static void handleCanMessage(FDCAN_RxHeaderTypeDef rxHeader, uint8_t *rxData)
{
	if ((rxHeader.Identifier != 0x321) || (rxHeader.IdType != FDCAN_STANDARD_ID) || (rxHeader.DataLength != FDCAN_DLC_BYTES_2))
	{
		return;
	}

	digitalToggle(LED_BUILTIN);
}

static void Button_Down()
{
	TxHeader.Identifier = 0x321;
	TxHeader.IdType = FDCAN_STANDARD_ID;
	TxHeader.TxFrameType = FDCAN_DATA_FRAME;
	TxHeader.DataLength = FDCAN_DLC_BYTES_2;
	TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
	TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
	TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
	TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
	TxHeader.MessageMarker = 0;

	TxData[0] = 0x13;
	TxData[1] = 0xAD;

	Serial1.print("CAN: sending message ");
	Serial1.println(can1.addMessageToTxFifoQ(&TxHeader, TxData) == HAL_OK
		? "was ok."
		: "failed.");
}

```

---

<div class="post-metadata">

### Author: ![Owen\_Williams](https://community.simplefoc.com/user_avatar/community.simplefoc.com/owen_williams/32/105_2.png) [@Owen\_Williams](https://community.simplefoc.com/u/Owen_Williams)
#### Post date: [January 2, 2021, 4:49pm UTC](https://community.simplefoc.com/t/can-bus-support/407/3 "2021-01-02T16:49:47Z")

</div>

@erwin74 - welcome and thankyou!

I’ve split this message because I want to see if there is any interest in spinning off a separate repo for a generic CAN library that supports many architectures.

STM32 for example has two implementations for CAN and FDCAN and esp32 does it a different way and I suspect there are generic SPI solutions our there too. A common API with multiple hardware implementations would be great!

I don’t have the bandwidth to start this right now but it is something I’d like to work on in 2021.

BTW: I tried and failed to get FDCAN working on this board. It was silently failing to send messages for me - so I’ll be looking at your code at some point!

---

<div class="post-metadata">

### Author: ![Roiki](https://community.simplefoc.com/user_avatar/community.simplefoc.com/roiki/32/498_2.png) [@Roiki](https://community.simplefoc.com/u/Roiki)
#### Post date: [January 3, 2021, 3:29pm UTC](https://community.simplefoc.com/t/can-bus-support/407/4 "2021-01-03T15:29:28Z")

</div>

CAN-FD could be useful for talking to duet3 controllers in the future.

---

<div class="post-metadata">

### Author: ![Owen\_Williams](https://community.simplefoc.com/user_avatar/community.simplefoc.com/owen_williams/32/105_2.png) [@Owen\_Williams](https://community.simplefoc.com/u/Owen_Williams)
#### Post date: [January 16, 2021, 1:39pm UTC](https://community.simplefoc.com/t/can-bus-support/407/5 "2021-01-16T13:39:17Z")

</div>

@erwin74 - I got a chance to try out your fdcan code. Works! Thank you for helping me out.

I’m wondering whether my failed efforts were because I’d not terminated the other end of CAN? I didn’t think this would be necessary when running loopback internal.

I’m guessing you uncommented  
`//#define HAL_FDCAN_MODULE_ENABLED`  
in variant.h. I think I should push this to stm32duino so others don’t have to? It’s a non obvious step and without it you get loads of reference errors during linking.

Also I guess you added  
`#define VBUS PA0`  
What do you think this is for? It always comes up with 12V (in your code) even if I’m supplying 5 or 14V

Next step is to send more complex data and then see if I can link up a cheapo CAN tranceiver to an esp32 ‘master’.

Longer term we could try to create a CAN HAL library. This would probably mean that your SimpleFOC.h must have no dependency on `stm32g4xx_hal_fdcan.h` and we’d have several implementations.

---

<div class="post-metadata">

### Author: ![erwin74](https://community.simplefoc.com/letter_avatar_proxy/v4/letter/e/5f9b8f/32.png) [@erwin74](https://community.simplefoc.com/u/erwin74)
#### Post date: [January 16, 2021, 4:34pm UTC](https://community.simplefoc.com/t/can-bus-support/407/6 "2021-01-16T16:34:30Z")

</div>

Oh yes, CAN can be a diva.

Yes, you are right we need `HAL_FDCAN_MODULE_ENABLED`, forgot to tell.

I tried to measure the input voltage (PA0 is connected to the input voltage over a voltage divider) and the temperature (PB14 is connected to the NTC). Temperature seems to work, but the input voltage also doesn’t work in my sample - no idea, no time to investigate.

I do not work with Arduino often, mainly i use mbed or bare metal (HAL) to realize my projects. So i do not know if there exists a good CAN library in the Arduino ecosystem. But if there is, then we should better use this and add the leaking support for the boards to it (ESP32, STM32G431). I would not recomment to use my simple example as base for a new Arduino CAN library - CAN (FD) is a broad field, with all its possibilities (filters, fifo, …) @Owen_Williams What do you think?

---

<div class="post-metadata">

### Author: ![Owen\_Williams](https://community.simplefoc.com/user_avatar/community.simplefoc.com/owen_williams/32/105_2.png) [@Owen\_Williams](https://community.simplefoc.com/u/Owen_Williams)
#### Post date: [January 19, 2021, 5:03pm UTC](https://community.simplefoc.com/t/can-bus-support/407/7 "2021-01-19T17:03:03Z")

</div>

> [@erwin74](#):
>
> HAL\_FDCAN\_MODULE\_ENABLED

I’ve pushed that change to stm32duino. My PR is still waiting for 2.0 release but they are almost done.

@erwin74 - I hope you don’t mind but I’ve used your code sample here:  
[https://github.com/owennewo/youtube\_can](https://github.com/owennewo/youtube_can)

And mentioned it in a youtube video:  
[https://www.youtube.com/watch?v=c\_iQgfNlFz8](https://www.youtube.com/watch?v=c_iQgfNlFz8)

I’d like to acknowledge you - if that is OK? Are you ok with me putting MIT license on that repo?

---

<div class="post-metadata">

### Author: ![JorgeMaker](https://community.simplefoc.com/user_avatar/community.simplefoc.com/jorgemaker/32/546_2.png) [@JorgeMaker](https://community.simplefoc.com/u/JorgeMaker)
#### Post date: [January 19, 2021, 7:52pm UTC](https://community.simplefoc.com/t/can-bus-support/407/8 "2021-01-19T19:52:32Z")

</div>

Hi @Owen_Williams, @erwin74

You make my day with [eXoCAN] :I I have spent / wasted a couple of days trying to figure out how to get CAN from Arduino on my STM32 Blue :).

Unfortunately, it seems that this MCU shares CAN pins with USB and it is not having both at the same time ☹

Do you know if eXoCAN works with STM32F407 or if there is a another equivalent library allowing CAN from Arduino that woks on this MCU?

---

<div class="post-metadata">

### Author: ![Owen\_Williams](https://community.simplefoc.com/user_avatar/community.simplefoc.com/owen_williams/32/105_2.png) [@Owen\_Williams](https://community.simplefoc.com/u/Owen_Williams)
#### Post date: [January 19, 2021, 8:34pm UTC](https://community.simplefoc.com/t/can-bus-support/407/9 "2021-01-19T20:34:45Z")

</div>

I don’t have a blue pill (stm32f103) but if I did then I’d probably try the following:

1. Don’t use the USB for programming - use the stlink instead. They’ve broken out the PA11 and PA12 pins separately which may suggest that they can be used for other things??
2. This [PeripheralPins.h](https://github.com/stm32duino/Arduino_Core_STM32/blob/0303f55b40ef23aa23694c5a400856dc7f416513/variants/PILL_F103XX/PeripheralPins.c#L244) (if this is the board/variant you are using?) suggests you can use an alternative CAN pins of PB8 and PB9

I’ve a jlcpcb board with an stm32f407 + can transceiver on order. If it doesn’t go up in a puff of smoke, I’ll give it a try in a few weeks.

The closes I have right now is a blackpill (stm32f411) but I’ve not played with it much.

---

<div class="post-metadata">

### Author: ![JorgeMaker](https://community.simplefoc.com/user_avatar/community.simplefoc.com/jorgemaker/32/546_2.png) [@JorgeMaker](https://community.simplefoc.com/u/JorgeMaker)
#### Post date: [January 19, 2021, 9:40pm UTC](https://community.simplefoc.com/t/can-bus-support/407/10 "2021-01-19T21:40:18Z")

</div>

I program the board using an STlink and use the USB as serial output for which I have to put some build\_flags that I guess are causing the error since moving to PB8 and PB9 mdos not remve the issue until build\_flags are removed.  
The same behavior occurs by programming the board directly at the HAL level with CubeIDE … I guess it is related to some interrupts shared by both peripherals. I assumed that if you did not configure the USB, there would be no interference, but it seems that is not the case.

 ![Captura de pantalla 2021-01-19 a las 22.37.22](https://community.simplefoc.com/uploads/default/original/1X/ee9362a4e559f2ef7c644bb8fca1d45e0bd99bc6.png)

---

<div class="post-metadata">

### Author: ![Owen\_Williams](https://community.simplefoc.com/user_avatar/community.simplefoc.com/owen_williams/32/105_2.png) [@Owen\_Williams](https://community.simplefoc.com/u/Owen_Williams)
#### Post date: [January 19, 2021, 10:50pm UTC](https://community.simplefoc.com/t/can-bus-support/407/11 "2021-01-19T22:50:31Z")

</div>

Not sure of what errors you are getting. You can upload but get errors/hangs using CAN?

Perhaps you can use an ftdi → usb dongle and print to Serial1 instead of Serial. Serial1 I think will default to rx=PA10, tx=PA9. I’m not sure if this gets you anywhere though.

---

<div class="post-metadata">

### Author: ![JorgeMaker](https://community.simplefoc.com/user_avatar/community.simplefoc.com/jorgemaker/32/546_2.png) [@JorgeMaker](https://community.simplefoc.com/u/JorgeMaker)
#### Post date: [January 20, 2021, 12:53am UTC](https://community.simplefoc.com/t/can-bus-support/407/12 "2021-01-20T00:53:18Z")

</div>

> [@Owen\_Williams](#):
>
> Perhaps you can use an ftdi → usb dongle and print to Serial1 instead of Serial. Serial1 I think will default to rx=PA10, tx=PA9. I’m not sure if this gets you anywhere thoug

Everything was solved thanks to your “magic pointer” to [eXoCAN](https://github.com/exothink/eXoCAN) library 🙂

I ordered a USB to TTL dongle from AliExpress per week, … the solution to have CAN and Serial communications it is comming from China 🙂 In the mid term I will migrate to STM32F407 since is the MCU I chosen to develo may board.

---

<div class="post-metadata">

### Author: ![erwin74](https://community.simplefoc.com/letter_avatar_proxy/v4/letter/e/5f9b8f/32.png) [@erwin74](https://community.simplefoc.com/u/erwin74)
#### Post date: [January 20, 2021, 6:34pm UTC](https://community.simplefoc.com/t/can-bus-support/407/13 "2021-01-20T18:34:39Z")

</div>

@Owen_Williams definitively use the code for whatever you need, as long it is helpfull - and doesn’t make any troubles 😉

Good video btw.

---

<div class="post-metadata">

### Author: ![runger](https://community.simplefoc.com/user_avatar/community.simplefoc.com/runger/32/395_2.png) [@runger](https://community.simplefoc.com/u/runger)
#### Post date: [January 23, 2021, 10:53pm UTC](https://community.simplefoc.com/t/can-bus-support/407/14 "2021-01-23T22:53:39Z")

</div>

> [@JorgeMaker](#):
>
> Unfortunately, it seems that this MCU shares CAN pins with USB and it is not having both at the same time ☹

Is it an original STM32F103? I haven’t tried, but it should be possible to route both CAN and USB to different pins… in fact it is the default. Here a pic from the STM32CubeIDE…

 ![image](https://community.simplefoc.com/uploads/default/original/1X/59f455d4021a04d775fec60b2a4536896c1a708c.jpeg)

---

<div class="post-metadata">

### Author: ![JorgeMaker](https://community.simplefoc.com/user_avatar/community.simplefoc.com/jorgemaker/32/546_2.png) [@JorgeMaker](https://community.simplefoc.com/u/JorgeMaker)
#### Post date: [January 23, 2021, 11:21pm UTC](https://community.simplefoc.com/t/can-bus-support/407/15 "2021-01-23T23:21:18Z")

</div>

> [@runger](#):
>
> n fact it is the default. Here a pic from

Yes, it is an original STM32F103. The default assignment is PA12/PA11, but if you previously assign it to another peripheral, the alternative assignment is PB9 / PB9.

In my case even but even without assigning any pin to USB if you connect a USB then CAN it stops working. …so I have to chose between USB or CAN … or migrate to another MCU 🙂

---

<div class="post-metadata">

### Author: ![JorgeMaker](https://community.simplefoc.com/user_avatar/community.simplefoc.com/jorgemaker/32/546_2.png) [@JorgeMaker](https://community.simplefoc.com/u/JorgeMaker)
#### Post date: [February 10, 2021, 10:41pm UTC](https://community.simplefoc.com/t/can-bus-support/407/16 "2021-02-10T22:41:27Z")

</div>

> [@erwin74](#):
>
> `DCAN_TxHeaderTypeDef TxHeader;`

Hi @ erwin74 quote=“erwin74, post:2, topic:407”]  
`DCAN_TxHeaderTypeDef TxHeader;`  
[/quote]

Hi @erwin74 I am trying to re implement your library so it can run on STM32F405RTG6. I have been able to get my implementation to work properly for sending messages but when I turn on notifications, if there are messages to receive it hangs. It happens indistinctly when there are messages generated by another device or when I put it in loopbkac mode. If you had a moment to review what I am doing wrong, would truly appreciate it 🙂

PS: I have not come to implement the hadler part since just putting the callbakc crashes. The debugger says it receives an “unexpected exception” and goes into an infinite loop.

* * *

## **SimpleCan.h**

```auto
#ifndef __CAN__ H
#define __CAN__ H

#include "Arduino.h"
#include "stm32f4xx_hal_can.h"

// Value needed for prescaler. depends 
// on CLK configuration
enum CanSpeed
{
	Kbit500 = 5,
	Kbit250 = 10,
	Kbit125 = 20,
	Kbit100 = 25,
  Kbit50 = 50,
  Kbit20 = 125

};

enum CanMode
{
	NormalCAN = CAN_MODE_NORMAL,
	SilentCAN = CAN_MODE_SILENT,
	LoopBackCan = CAN_MODE_LOOPBACK,
	SilentLoopBackCAN = CAN_MODE_SILENT_LOOPBACK
};

typedef struct{
  uint8_t dlc;
  uint32_t msgID;
  bool isRTR;
  bool isStandard;
  uint8_t data[8];
}CanMessage;

CanMessage createMessage(void);
/**
 CAN wrapper for STM32F405RGT6 board.
*/
class SimpleCan
{
public:
/*
	class RxHandler
	{
	public:
		RxHandler(uint16_t dataLength, void(*callback)(CAN_RxHeaderTypeDef rxHeader, uint8_t *rxData));
		~RxHandler();
		void notify(CAN_HandleTypeDef *hcan1);
	
  private:
		CAN_RxHeaderTypeDef _rxHeader;
		uint8_t *_rxData;
		void(*_callback)(CAN_RxHeaderTypeDef, uint8_t *);
	};
*/
	SimpleCan();
	HAL_StatusTypeDef init(CanSpeed speed, CanMode mode);
	HAL_StatusTypeDef configFilter(CAN_FilterTypeDef *filterDef);
  HAL_StatusTypeDef configSnniferFilter();
	HAL_StatusTypeDef activateNotification(/*RxHandler *rxHandler*/);
	HAL_StatusTypeDef deactivateNotification();
	HAL_StatusTypeDef begin();
	HAL_StatusTypeDef stop();
	HAL_StatusTypeDef send(CanMessage message);
  //private: interrupt handler needs access to it
  CAN_HandleTypeDef hcan;
  //static RxHandler *_rxHandler;

};
#endif

```

* * *

## **SimpleCan.cpp**

```auto
#include <SimpleCan.h>
#include <Arduino.h>

extern "C" HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *);
extern "C" HAL_StatusTypeDef HAL_CAN_Stop (CAN_HandleTypeDef *);
extern "C" HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef *);
extern "C" HAL_StatusTypeDef HAL_CAN_ActivateNotification(CAN_HandleTypeDef *, uint32_t );
extern "C" void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *);

void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan1)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hcan1->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspInit 0 */

  /* USER CODE END CAN1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_CAN1_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**CAN1 GPIO Configuration
    PB8 ------> CAN1_RX
    PB9 ------> CAN1_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* CAN1 interrupt Init */
    HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
    /* USER CODE BEGIN CAN1_MspInit 1 */

    /* USER CODE END CAN1_MspInit 1 */
  }

}

CanMessage createMessage(){
  CanMessage message;
  message.dlc = 8;
  message.msgID = 200;
  message.isRTR = false;
  message.isStandard = true;
  uint8_t messageLoadBuffer[8] ={0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x23};
  memcpy(message.data, messageLoadBuffer, 8);
  
  return message;
}

SimpleCan::SimpleCan(){
    return;
}
HAL_StatusTypeDef SimpleCan::init(CanSpeed speed, CanMode mode){
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = speed;
  hcan.Init.Mode = mode;
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_8TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_1TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = DISABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = DISABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;
  
  return HAL_CAN_Init(&hcan);

}
HAL_StatusTypeDef SimpleCan::begin(){
    return HAL_CAN_Start(&hcan);

}
HAL_StatusTypeDef SimpleCan::stop(){
   	return HAL_CAN_Stop(&hcan);

}
HAL_StatusTypeDef SimpleCan::configFilter(CAN_FilterTypeDef *filterDef){

    // Default filter - accept all to CAN_FIFO*
    CAN_FilterTypeDef sFilterConfig;
    sFilterConfig.FilterBank = 0;
    sFilterConfig.FilterIdHigh = 0x00005;
    sFilterConfig.FilterBank = 0x0000;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x00 ; // HE TOCADO ESTO !!!!!!!
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
    sFilterConfig.FilterActivation = ENABLE;

    return HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
}
HAL_StatusTypeDef SimpleCan::configSnniferFilter(){

    // Default filter - accept all to CAN_FIFO*
	  CAN_FilterTypeDef sFilterConfig;
	  sFilterConfig.FilterBank = 0;
	  sFilterConfig.FilterIdHigh = 0x00005;
	  sFilterConfig.FilterBank = 0x0000;
	  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
	  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
	  sFilterConfig.FilterIdHigh = 0x200 << 5; //11-bit ID, in top bits
	  sFilterConfig.FilterIdLow = 0x0000;
	  sFilterConfig.FilterMaskIdHigh = 0x0000;
	  sFilterConfig.FilterMaskIdLow = 0x0000;
	  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
	  sFilterConfig.FilterActivation = ENABLE;

    return HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);
}

HAL_StatusTypeDef SimpleCan::send(CanMessage message){
	uint32_t TxMailbox;
	CAN_TxHeaderTypeDef pHeader;
    pHeader.DLC= message.dlc;
    message.isStandard ? pHeader.IDE=CAN_ID_STD : pHeader.IDE=CAN_ID_EXT;
    message.isRTR ? pHeader.RTR=CAN_RTR_REMOTE : pHeader.RTR=CAN_RTR_DATA;
    message.isStandard ? pHeader.StdId=0x200 : pHeader.ExtId=0x200;

    return HAL_CAN_AddTxMessage(&hcan, &pHeader, (uint8_t*)message.data, &TxMailbox);
}

HAL_StatusTypeDef SimpleCan::activateNotification( /*RxHandler *rxHandler*/)
{/*
    
	if (_rxHandler != NULL)
	{
		return HAL_ERROR;
	}
	_rxHandler = rxHandler;
    */
	return HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
}

HAL_StatusTypeDef SimpleCan::deactivateNotification(){
   // _rxHandler = NULL;
    return HAL_CAN_DeactivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
}
// RxHandler Implementation
/*
SimpleCan::RxHandler::RxHandler(uint16_t dataLength, void (*callback)(CAN_RxHeaderTypeDef, uint8_t *))
{
	_rxData = new byte[dataLength];
	_callback = callback;
}
SimpleCan::RxHandler::~RxHandler()
{
	delete[] _rxData;
}

void SimpleCan::RxHandler::notify(CAN_HandleTypeDef *hcan1)
{

    if (SimpleCan::_rxHandler == NULL)
    {
        return;
    }
    SimpleCan::_rxHandler->notify(hcan1);
}
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan1)
{
   digitalToggle(PC13);
/*
    if (SimpleCan::_rxHandler == NULL)
    {
        return;
    }
    SimpleCan:_rxHandler->notify(hcan1);
*/
}
---------

```

## **TestCan.cpp**

```auto

#include <Arduino.h>
#include "stm32f4xx_hal_can.h"
#include <SimpleCan.h>

// This SystemClock_Config is copy&paste from CubeIDE
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  // Configure the main internal regulator output voltage
  //
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  // Initializes the RCC Oscillators according to the specified parameters
  // in the RCC_OscInitTypeDef structure.
  //
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 100;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  // Initializes the CPU, AHB and APB buses clocks

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}
/*
static void handleCanMessage(CAN_RxHeaderTypeDef rxHeader, uint8_t *rxData)
{
	digitalToggle(PC13);
}

SimpleCan::RxHandler can1RxHandler(8, handleCanMessage);
*/
SimpleCan can;

void setup() {
    Serial1.begin(115200);
    pinMode(PC13,OUTPUT);
    can.init(Kbit250,LoopBackCAN);
    can.configSnniferFilter();
    can.activateNotification( /*&can1RxHandler*/);
    can.begin();
   

}
void loop() {
  Serial1.println("Hola Can !!!");
  //digitalToggle(PC13);
  CanMessage msg = createMessage();
  can.send(msg);
  delay(10);
}

´´´
platformio.ini

```

[env:genericSTM32F405RG]  
platform = ststm32  
board = genericSTM32F405RG  
board\_build.f\_cpu = 100000000L  
framework = arduino  
debug\_tool = stlink  
upload\_protocol = stlink  
build\_flags =  
-D HSE\_VALUE=8000000

```
-D HAVE_HWSERIAL1

-D PIN_WIRE_SDA=PB11
-D PIN_WIRE_SCL=PB10

-D PIN_SPI_MOSI=PA7
-D PIN_SPI_MISO=PA6
-D PIN_SPI_SCK=PA5
-D PIN_SPI_SS=PA4

-D HAL_CAN_MODULE_ENABLED

```

monitor\_speed = 115200  
lib\_deps =  
askuric/Simple FOC@^2.0.2  
Wire  
SPI

```auto

```

---

<div class="post-metadata">

### Author: ![Owen\_Williams](https://community.simplefoc.com/user_avatar/community.simplefoc.com/owen_williams/32/105_2.png) [@Owen\_Williams](https://community.simplefoc.com/u/Owen_Williams)
#### Post date: [February 10, 2021, 11:31pm UTC](https://community.simplefoc.com/t/can-bus-support/407/17 "2021-02-10T23:31:07Z")

</div>

Have you tried polling instead of interrupts.

I.e use HAL\_CAN\_GetRxFifoFillLevel() and HAL\_CAN\_GetRxMessage()  
Instead of callback.

I realise callback is preferable

I watched a (stmcubeide) [video](https://youtu.be/ymD3F0h-ilE) that suggested you have to implement  
EXTI0\_IRQHandler

@erwin74 wrote this code because an fdcan library for Arduino doesn’t exist.

I think librarys exist for normal CAn on stm32. Have you checked what is out there?  
E.g  
“GitHub - nopnop2002/Arduino-STM32-CAN: Can Example for Arduino Core STM32” [GitHub - nopnop2002/Arduino-STM32-CAN: Can Example for Arduino Core STM32](https://github.com/nopnop2002/Arduino-STM32-CAN)

That said, It would be cool if you could use erwins interface as then it would be cross compatible!

---

<div class="post-metadata">

### Author: ![JorgeMaker](https://community.simplefoc.com/user_avatar/community.simplefoc.com/jorgemaker/32/546_2.png) [@JorgeMaker](https://community.simplefoc.com/u/JorgeMaker)
#### Post date: [February 11, 2021, 11:59am UTC](https://community.simplefoc.com/t/can-bus-support/407/19 "2021-02-11T11:59:13Z")

</div>

Hi @Owen_Williams ,

Thanks for the suggestion . It worked 🙂 Finally I have bidirectional CAN communication from the board.

I have tried to simulate busy conditions and I have found that the size of the circular FIFO queue is 3 elements. It works perfectly as long as you are able to have a reading frequency at least up to 3 times lower than the arrival frequency.

Yes, if I have seen that there are some libraries but I have not found any that have the capacity to support callbackack as @erwin74 semms to support. Do not know how to receive CAN1\_RX0\_IRQHandler related interrups without crashing.

Road stone removed;) Let’s see if hopefully I can be able to pay attention to interruption as an improvement. Thanks again.

---

<div class="post-metadata">

### Author: ![erwin74](https://community.simplefoc.com/letter_avatar_proxy/v4/letter/e/5f9b8f/32.png) [@erwin74](https://community.simplefoc.com/u/erwin74)
#### Post date: [February 11, 2021, 8:26pm UTC](https://community.simplefoc.com/t/can-bus-support/407/20 "2021-02-11T20:26:57Z")

</div>

Actual i only took an example from stm and wrote a wrapper for it - no magic at all. A discovery board with similar chip should be at home, and at weekend possibly i can find som time to take a look into it.

---

<div class="post-metadata">

### Author: ![JorgeMaker](https://community.simplefoc.com/user_avatar/community.simplefoc.com/jorgemaker/32/546_2.png) [@JorgeMaker](https://community.simplefoc.com/u/JorgeMaker)
#### Post date: [February 11, 2021, 9:30pm UTC](https://community.simplefoc.com/t/can-bus-support/407/21 "2021-02-11T21:30:28Z")

</div>

Hi @erwin74, It would be great to have a SimpleCan library to work aside with SimpleFOC devices that support interrupts, as what I can been able to implement only supports reception by pooling and forces polling with at least 1/3 of the expected arrival message rate for do not lose any message.

[Next page](https://community.simplefoc.com/t/can-bus-support/407.md?page=2)
