Skip to main content
Associate
February 9, 2026
Question

STM32 HAL_SPI_Library on Blue Pill

  • February 9, 2026
  • 5 replies
  • 1223 views

Title edited to note that this relates to a Blue Pill board.


Hello everyone,
I'm starting a learning journey into the STM32 world, specifically studying the HAL library (my past programming experiences didn't rely on ready-made libraries).
Right now (after tinkering with GPIOs, LCD management, etc.) I'm working on the SPI dialogue. I have two STM32F103CBT6A development boards, one configured for "Full Duplex Master" and one for "Full Duplex Slave."
When trying to send 10 static bytes (10, 20, 30, 100) from both the master and slave sides using the "HAL_SPI_TransmitReceive_IT(&hspi1, TX_Buffer, RX_Buffer, 10)" function, I expect the oscilloscope to see the MOSI line equal to the MISO line without any offsets. This happens for a few seconds after resetting the slave (image 1), but then the bytes on the MISO line shift (image 2). Furthermore (I'm viewing the data received from the slave on an LCD) when this problem occurs, the slave also doesn't receive correctly.
After adjusting the codes for 10-byte transmission, I wanted to expand it to 150 bytes.
Thanks in advance to anyone who can point out where I'm going wrong.

5 replies

TDK
Super User
February 9, 2026

The slave has to be ready to send before the master starts clocking SCK. This is a code issue. How are you ensuring the slave is ready to send before the master starts?

"If you feel a post has answered your question, please click ""Accept as Solution""."
NicoNX650Author
Associate
February 9, 2026

Dear TDK,

thanks a lot for your reply.

How can I load data into the slave's buffer before the master starts generating the clock?

Best Regards

 

Ozone
Principal
February 9, 2026

I don't know the exact Cube/HAL example you talk about here.
But historically, the F103 is a very early model, and most examples published by ST utilized the SPL, a predecessor of the current library.
I'm still using SPL code for many of my examples, because it's much less complicated, less resource-intensive, and better readable - and the examples were usually tested well.

Anyway, most of the SPL firmware packages I reviewed (F0, F3, F4) contained a SPI/DMA example with two identical boards, one as slave and one as master. The example is usually named "SPI_TwoBoards" (or similiar).

Even if you stick with your Cube code, I would recommend to download such a package (usually the more generic one named "STM32xxxx_DSP_StdPeriph_Lib_Vx.x.x"), and compare the configuration process and setup sequence of your code with the example.

TDK
Super User
February 9, 2026
"If you feel a post has answered your question, please click ""Accept as Solution""."
NicoNX650Author
Associate
February 9, 2026

Dear TDK,

I'm sorry to bother you again, but I can't figure out what I'm doing wrong in your example. I've attached the code for my master and slave. Any help would be greatly appreciated.

MASTER CODE:

 
while (1)
{
 /* USER CODE END WHILE */
 /* USER CODE BEGIN 3 */

 Lcd_cursor(&lcd, 0,0);
 Lcd_int(&lcd, RX_Buffer[0]);
 Lcd_cursor(&lcd, 0,4);
 Lcd_int(&lcd, RX_Buffer[1]);
 Lcd_cursor(&lcd, 0,8);
 Lcd_int(&lcd, RX_Buffer[2]);
 Lcd_cursor(&lcd, 0,12);
 Lcd_int(&lcd, RX_Buffer[3]);
 Lcd_cursor(&lcd, 0,16);
 Lcd_int(&lcd, RX_Buffer[4]);
 Lcd_cursor(&lcd, 1,0);
 Lcd_int(&lcd, RX_Buffer[5]);
 Lcd_cursor(&lcd, 1,4);
 Lcd_int(&lcd, RX_Buffer[6]);
 Lcd_cursor(&lcd, 1,8);
 Lcd_int(&lcd, RX_Buffer[7]);
 Lcd_cursor(&lcd, 1,12);
 Lcd_int(&lcd, RX_Buffer[8]);
 Lcd_cursor(&lcd, 1,16);
 Lcd_int(&lcd, RX_Buffer[9]);

 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
 HAL_SPI_TransmitReceive_IT(&hspi1, TX_Buffer, RX_Buffer, 10);
 HAL_Delay(1);
 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);

 HAL_Delay(500);
}

/* USER CODE END 3 */
}

SLAVE CODE:

 
while (1)
{
 /* USER CODE END WHILE */
 /* USER CODE BEGIN 3 */
 
 Lcd_cursor(&lcd, 0,0);
 Lcd_int(&lcd, RX_Buffer[0]);
 Lcd_cursor(&lcd, 0,4);
 Lcd_int(&lcd, RX_Buffer[1]);
 Lcd_cursor(&lcd, 0,8);
 Lcd_int(&lcd, RX_Buffer[2]);
 Lcd_cursor(&lcd, 0,12);
 Lcd_int(&lcd, RX_Buffer[3]);
 Lcd_cursor(&lcd, 0,16);
 Lcd_int(&lcd, RX_Buffer[4]);
 Lcd_cursor(&lcd, 1,0);
 Lcd_int(&lcd, RX_Buffer[5]);
 Lcd_cursor(&lcd, 1,4);
 Lcd_int(&lcd, RX_Buffer[6]);
 Lcd_cursor(&lcd, 1,8);
 Lcd_int(&lcd, RX_Buffer[7]);
 Lcd_cursor(&lcd, 1,12);
 Lcd_int(&lcd, RX_Buffer[8]);
 Lcd_cursor(&lcd, 1,16);
 Lcd_int(&lcd, RX_Buffer[9]);

 HAL_SPI_TransmitReceive_IT(&hspi1, TX_Buffer, RX_Buffer, 10);
 }

/* USER CODE END 3 */
}

Best Regards


Edited to apply source code formatting - please see How to insert source code for future reference.

TDK
Super User
February 9, 2026

In the example, a button press is used to start the communication after a 100ms delay. The slave has already called HAL_SPI_TransmitReceive_IT by this time.

In your code, there is nothing to ensure the slave has already called HAL_SPI_TransmitReceive_IT before the master has. You could use a gpio pin to signal between the two. Or a sufficient delay.

On the slave side, you should poll for the status to ensure the previous transaction has completed before you call HAL_SPI_TransmitReceive_IT again. You're updating values on the LCD before that data has even been received.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Andrew Neil
Super User
February 9, 2026

Welcome to the forum.

Please see How to write your question to maximize your chances to find a solution for best results.

 


@NicoNX650 wrote:

 I have two STM32F103CBT6A development boards, .


What boards are they, exactly ?

 

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
NicoNX650Author
Associate
February 9, 2026

Dear Andrew,

thanks for your reply.

The boards are two STM32F103CBT6A.

Best Regards

Andrew Neil
Super User
February 9, 2026

@NicoNX650 wrote:

The boards are two STM32F103CBT6A.


That's not a board - that's just the part number of the MCU chip.

You need to give details of the board on which the chip is mounted.

 

How to write your question to maximize your chances to find a solution

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Community Manager
March 4, 2026

Hello @NicoNX650,

The product you are using is a clone of a genuine ST product.

To get the support you need, please contact the third party you purchased this product from.

For assurance of buying authentic ST products, we recommend purchasing exclusively through our official distributors, which you can find listed here: ST Official Distributors.

Best regards,

Maxime

NicoNX650Author
Associate
March 5, 2026

Dear Maxime,

thanks for your reply.

As I told in the last post, now I bought NUCLEO-F401RE boards. So in the next days I will continue my tests with genuine ST parts.

Best Regards