Two STM32F767 Nucleo Boards Via SPI
Two STM32F767 Nucleo Boards Via SPI
Four Wires:
o MOSI (Master Out, Slave In): Data line from Master to Slave.
o MISO (Master In, Slave Out): Data line from Slave to Master.
Clock Polarity (CPOL) & Clock Phase (CPHA): These define how
data is sampled relative to the clock signal. They must match between
Master and Slave.
Prerequisites:
1. Hardware Setup:
We will connect the two Nucleo boards directly using jumper wires. One
board will be configured as the Master, and the other as the Slave.
Pin Connections (using SPI1 on both boards):
Important Note:
You will create two separate projects in STM32CubeIDE, one for the Master
board and one for the Slave board.
o Give your first project a name (e.g., SPI_Master) and the second
one SPI_Slave. Click Finish.
1. Configure SPI1:
3. Generate Code: Save your .ioc file (Ctrl+S). Click Yes to generate
code.
1. Configure SPI1:
o Enable the SPI1 global interrupt. This is crucial for the Slave to
receive data in a non-blocking manner.
3. Generate Code: Save your .ioc file (Ctrl+S). Click Yes to generate
code.
Add the following printf redirection code to Core/Src/main.c (if you chose the
UART redirection method):
#ifdef __GNUC__
#else
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
return ch;
/* Infinite loop */
while (1)
if (status == HAL_OK)
else
memset(master_rx_buffer, 0, sizeof(master_rx_buffer));
if (hspi->Instance == SPI1)
// The slave needs to be ready to receive data before the master sends
while (1)
if (spi_rx_cplt_flag == 1)
// Now, transmit data back to the Master (this will happen during the
Master's next TransmitReceive)
// For full-duplex, the slave's transmit buffer should be ready before the
master initiates the transfer
// The actual transmission happens when the master initiates the next
HAL_SPI_TransmitReceive
// For a more robust system, you'd manage this with a state machine or a
dedicated transmit buffer.
// You might add a small delay here if the loop is too tight without much
work
// HAL_Delay(1);
Master Code:
o HAL_SPI_TransmitReceive(&hspi1, master_tx_buffer,
master_rx_buffer, sizeof(master_tx_buffer), HAL_MAX_DELAY);:
This is the core SPI transaction. It sends master_tx_buffer and
simultaneously receives data into master_rx_buffer. The
sizeof(master_tx_buffer) determines the number of bytes
exchanged. HAL_MAX_DELAY means it will block until the transfer
is complete.
Slave Code:
o HAL_SPI_Receive_IT(&hspi1, slave_rx_buffer,
sizeof(slave_rx_buffer));: This initiates a non-blocking receive
operation. The Slave will wait for incoming data from the Master.
When data arrives and the specified number of bytes are
received, HAL_SPI_RxCpltCallback will be called.
o Go to Run > Debug (this will flash the board and start a debug
session). Once flashed, you can terminate the debug session and
run it normally, or just let it run.
2. Configure each terminal to connect to the COM port associated with its
respective Nucleo board's ST-LINK Virtual COM Port (check Device
Manager on Windows, or ls /dev/ttyACM* or ls /dev/ttyUSB* on
Linux/macOS).
Slave Terminal: You'll see "Slave: Received from Master: Hello Slave
from Master!". This will also repeat every second, indicating it's
successfully receiving data.
Objective: Modify the code so that the Master sends a counter value, and
the Slave receives it, increments its own counter, and sends that back to the
Master.
Solution:
/* Infinite loop */
while (1)
else
{
if (hspi->Instance == SPI1)
// The slave needs to be ready to receive data before the master sends
// The slave's transmit buffer must also be ready for the master's
simultaneous receive
/* Infinite loop */
while (1)
if (spi_rx_cplt_flag == 1)
{
slave_tx_buffer[0] = slave_tx_counter;
Explanation of Solution:
Slave:
Hints:
Master:
o The Master will need to send the command byte, then potentially
send dummy bytes to clock out the Slave's response.
Slave: