SimpleFOC and STM32CubeIDE


I would like to share my impressions about PlatformIO and STM32CubeIDE with you.
I’m kind of person, who needs to know everything deeply when working with something, so i fell in love with STM32CubeIDE, where I can: set every pin, clock, prescaler, option of module etc. clearly and i would easly see what it is set if I see some project at 1st time. It has perfect debugger also.

That’s why i don’t like arduino, there are much ambiguities, it is not clear what some project is configurated (clocks, pins, communication etc.). I’ve been dealing with PlatformIO for some weeks, solving problems which was a results of for example not including some build flags or sth like that.

If i want for example use SPI in project that i didn’t start from scratch i’m not sure if i don’t break some, among others, clock configuration by settings clock for my application.

Do you agree with me?
How do you handle with configuring ICs like STM in your projects?

I’m working on my project and i need SimpleFOC, do you thing porting it on STMCube is it worthwhile? Maybe someone already done it? What problems i can meet? Any tips?

Have a nice day!

The STM32duino abstraction is built on the (STM32) HAL. If you want to use HAL functions, you can. If you don’t want to use the Arduino version of a peripheral, you can just use -DHAL_XYZ_MODULE_DISABLED build flag, then you can instantiate using the same code from CubeIDE. For some things (like FDCAN) there is no abstraction in Arduino, so you can just use the peripheral without disabling anything else. So you can still set every pin, clock, prescaler, etc just as you like.

If you mean that you like the GUI for peripheral config, you can still use that - I use CubeMX to find the pinout of the chip and set all the peripherals I want, then I generate code. You can carry over the bits and pieces you need from the generated HAL stuff into Arduino.

I haven’t had any issues with PIO debugger. What is different from CubeIDE?

It has been asked many times whether we can/should port simplefoc to a non-arduino base. Feel free to try it but simplefoc is an Arduino library so your changes won’t be merged back into main. Might be possible create a separate simplefoc repo if it is popular.

As @VIPQualityPost said, it is common to use cube to generate pins and peripheral code. Most of this can be copied into Arduino as the hal_ code is supported by stm32duino.

1 Like

My two cents:

  1. STM32CubeIDE: the best way to optimize pin setup for STM32;
  2. PlatformIO+Arduino libraries: the fastest way to start a project + mostly hardware-agnostic.

As much as I love the STM32CubeIDE GUI, and despite some issues with Arduino libraries, point 2 is a game-changer. It all depends on what you want to achieve, though.

1 Like

The STM32duino project is built on top of STME32CubeIDE and the STM HAL library, so it’s not too hard to mix and match between the two environments as needed. Just replace the files you want to customize. It makes it harder in the future to upgrade to a new build of STM32duino, but not impossible.

I also use STM32CubeIDE as a code-generator and configuration tool.

Then I take that code over into platformIO to combine it into Arduino code.

For most motor driver projects I think the codebase is not (and should not be) very large. So it’s also not worth obsessing too much about IDE and build system. A simple system like Arduino is sufficient, really.

If I were doing the code for a complex device involving graphics and many peripherals, like a car radio or set-top box or something like this, then I would be more concerned about the build system and environment, because the codebase will grow large and need good management.

But for small projects I think you have to consider whether it’s worth spending more time on environment setup than on the codebase itself :wink:

Okay, thanks for answers, I’ll give you an example - I wrote code in stmcubeide, worked.

It is for mu150 encoder.

then put it in PIO

#include "mu150.h"

SPI_HandleTypeDef hspi1;

static void MX_SPI1_Init(void)

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  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_32;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
    // Error_Handler();
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */


static void MX_GPIO_Init(void)
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(soft_ss_GPIO_Port, soft_ss_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin : led_Pin */
  GPIO_InitStruct.Pin = led_Pin;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(led_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : soft_ss_Pin */
  GPIO_InitStruct.Pin = soft_ss_Pin;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(soft_ss_GPIO_Port, &GPIO_InitStruct);


void mu150_init( void ){

uint8_t mu150_read_register(uint8_t reg)

	uint8_t tx1[2] = { OPCODE_READ, reg};
	uint8_t rx1[2];
	HAL_GPIO_WritePin(soft_ss_GPIO_Port, soft_ss_Pin, GPIO_PIN_RESET);
	HAL_SPI_TransmitReceive(&hspi1, tx1, rx1, 2, HAL_MAX_DELAY);
	HAL_GPIO_WritePin(soft_ss_GPIO_Port, soft_ss_Pin, GPIO_PIN_SET);
	uint8_t tx2[3] = { 0xAD, 0 ,0};
	uint8_t rx2[3];
	HAL_GPIO_WritePin(soft_ss_GPIO_Port, soft_ss_Pin, GPIO_PIN_RESET);
	HAL_SPI_TransmitReceive(&hspi1, tx2, rx2, 3, HAL_MAX_DELAY);
	HAL_GPIO_WritePin(soft_ss_GPIO_Port, soft_ss_Pin, GPIO_PIN_SET);

	return rx2[2];

void mu150_write_register(uint8_t addr, uint8_t data){
	uint8_t tx[3]={OPCODE_WRITE,addr, data};
	HAL_GPIO_WritePin(soft_ss_GPIO_Port, soft_ss_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, tx, 3, HAL_MAX_DELAY);
	HAL_GPIO_WritePin(soft_ss_GPIO_Port, soft_ss_Pin, GPIO_PIN_SET);

float mu150_read_sdad( void ){

	uint8_t tx[1] = {OPCODE_SDAD_TRANSMITION};
	uint8_t rx[5];
	HAL_GPIO_WritePin(soft_ss_GPIO_Port, soft_ss_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, tx, 1, HAL_MAX_DELAY);
	HAL_SPI_Receive(&hspi1, rx, 5, HAL_MAX_DELAY);
	HAL_GPIO_WritePin(soft_ss_GPIO_Port, soft_ss_Pin, GPIO_PIN_SET);
	uint32_t out = (rx[0]<<16 | rx[1]<<8 | rx[2])>>6 ;
	float outdeg = out*360.0/(262144);
    return outdeg;
	// printf("%lu    %f skurwysynskich stopni \r\n", out, outdeg );

#include "stm32g4xx_hal.h"

#define OPCODE_ACTIVATE             0xB0
#define OPCODE_SDAD_STATUS          0xF5
#define OPCODE_READ                 0x97
#define OPCODE_WRITE                0xD2
#define OPCODE_STATUS               0xAD

#define led_Pin                     GPIO_PIN_2
#define led_GPIO_Port               GPIOC
#define soft_ss_Pin                 GPIO_PIN_9
#define soft_ss_GPIO_Port           GPIOB

static void MX_SPI1_Init(void);
static void MX_GPIO_Init(void);
void mu150_init( void );

uint8_t mu150_read_register(uint8_t reg);
void mu150_write_register(uint8_t addr, uint8_t data);
float mu150_read_sdad( void );

setting pin using HAL works, but using SPI doesn’t, trasmit do nothing, recieve stops programm

I tried to use same clock config

void SystemClock_Config(void)
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage

  /** 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.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

  /** Initializes the CPU, AHB and APB buses clocks
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)

but it also didn’t help

how would you figure out what’s wrong?

That IC-MU150 from ichaus is a bit unusual! It works differently to the radial magnetic sensors I’ve seen before (it uses a nonius disc instead of a diametric magnet) . Do you attach that nonius disc to the rotor and then align the chip? Any reason you’ve gone for this over the ones we tend to use e.g. AS5047? In chosing an unsupported sensor - you’ll have more work to do. :slight_smile:

What errors are you seing when you try to read/write over SPI?

Whilst your code might work, it is unusual to copy SPI (or I2C) code from cubemx to arduino. Instead we’d normally use the arduino SPI library. What board have you put in your platformio.ini?

Have you followed these steps from STM32duino (last paragraph)?

Also, why configure your own SPI rather than just use the Arduino one? Do you have really special requirements for running the bus?