0
\$\begingroup\$

I've spent a couple of days to find answer to my problem. Currently I'm working on a project where an STM32L432KC microcontroller board and a Raspberry Pi 3B need to communicate over SPI. The OS on the PI is Rasbian stretch, the microcontroller code is bare metal.

The microcontroller's code is the following:

#include <stm32l432xx.h>
#include "spi.h"
#include "uart.h"
#include "systick.h"
#include "clocks.h"
uint8_t rx_byte = 0x3;
uint8_t tx_byte = 0x5;
int main(void)
{
 init_PLL(20, 2, 0, HSI16); //set the system clock to 80MHz
 uart_init(); //for serial monitoring
 spi1_slave_init();
 while(1)
 {
 // send a byte
 if(SPI1->SR & SPI_SR_TXE)
 {
 //printf("%x\n\r", tx_byte);
 SPI1->DR = tx_byte++;
 }
 //receive a byte
 if(SPI1->SR & SPI_SR_RXNE)
 {
 rx_byte = SPI1->DR;
 //printf("%x\n\r", rx_byte);
 }
 }
 return 0;
}

Edit: I forgot to share the SPI initialization code, here it is:

#include "spi.h"
void spi1_slave_init(void)
{
 /***** clock configuration ******/
 //enable clock for port B
 RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
 //enable clock for port A
 RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
 // enable clock to the peripheral
 RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
 /*****pin configuration********/
 /*set alternate function mode*/
 //MISO: PA_11
 GPIOA->MODER &= ~(0b11 << (2 * 11));
 GPIOA->MODER |= (0b10 << (2 * 11));
 //MOSI: PA_12
 GPIOA->MODER &= ~(0b11 << (2 * 12));
 GPIOA->MODER |= (0b10 << (2 * 12));
 //SCKL: PA_5
 GPIOA->MODER &= ~(0b11 << (2 * 5));
 GPIOA->MODER |= (0b10 << (2 * 5));
 //SSEL: PB_0
 GPIOB->MODER &= ~(0b11);
 GPIOB->MODER |= 0b10;
 /*set the output speed to very high*/
 GPIOA->OSPEEDR &= ~((0b11 << (2 * 11)) | (0b11 << (2 * 12)) | (0b11 << (2 * 5)));
 GPIOA->OSPEEDR |= ((0b11 << (2 * 11)) | (0b11 << (2 * 12)) | (0b11 << (2 * 5)));
 GPIOB->OSPEEDR &= ~(0b11);
 GPIOB->OSPEEDR |= 0b11;
 /* set alternate function 5 */
 GPIOA->AFR[1] &= ~((0xF << (4 * 3)) | (0xF << (4 * 4)));
 GPIOA->AFR[1] |= ((0x5 <<(4 * 3)) | (0x5 << (4 * 4)));
 GPIOA->AFR[0] &= ~(0xF << (4 * 5));
 GPIOA->AFR[0] |= (0x5 << (4 * 5));
 GPIOB->AFR[0] &= ~(0xF);
 GPIOB->AFR[0] |= 0x5;
 /*****SPI1 configuration********/
 // disable SPI1
 SPI1->CR1 &= ~(SPI_CR1_SPE);
 // set CPHA and CPOL to zero
 SPI1->CR1 &= ~(SPI_CR1_CPHA | SPI_CR1_CPOL);
 // disable software slave management
 SPI1->CR1 &= ~(SPI_CR1_SSM);
 // recive and send message with MSB first configuration
 SPI1->CR1 &= ~(SPI_CR1_LSBFIRST);
 // configure the MCU as slave device
 SPI1->CR1 &= ~(SPI_CR1_MSTR);
 // select 8bit datasize
 SPI1->CR2 |= (0x7 << SPI_CR2_DS_Pos);
 // set RXNE (recive buffer is not empty) event's threshold to 8 bit
 SPI1->CR2 |= SPI_CR2_FRXTH;
 // TX DMA request enable
 SPI1->CR2 |= SPI_CR2_TXDMAEN;
 // enable the peripherial
 SPI1->CR1 |= SPI_CR1_SPE;
}

the python code which runs on the PI is the following:

import spidev
import struct
from time import sleep
#setup SPI
spi_bus = 0
spi_device = 0
spi_max_rate_hz = 100000
spi = spidev.SpiDev()
spi.open(spi_bus, spi_device)
spi.max_speed_hz = spi_max_rate_hz
#spi.bits_per_word = 8
spi.mode = 0b00
byte2send = 0xA
recv_byte = spi.xfer2([byte2send], spi_max_rate_hz, 200)
#recv_byte = spi.xfer2([byte2send])
print(hex(recv_byte[0]))

And now the problem: the received bytes on the PI side are not what I would expect after I ran the code repeatedly: enter image description here

Why this sequence is not 0x5, 0x6, 0x7...? Is this a correct behaviour of the SPI communication? I even don't know where is the problem, the PI side with SPIdev or my code on the STM32 side? Is there any way that I could achieve a syncronous communication without these 0x0 bytes between the correct ones?

I really appriciate your help!

asked Feb 6, 2022 at 20:03
\$\endgroup\$
8
  • 1
    \$\begingroup\$ SPI is not like uart. The master controls the transfer. When the master sends a byte, it is receiving a byte from the slave at the same time. This means the first slave byte has to be preloaded into the spi peripheral. When the slave gets the first byte from the master, it has to load the next byte to send back before the master starts sending it’s next byte. So the slave side can be a bit tricky as there is no handshake. \$\endgroup\$ Commented Feb 7, 2022 at 1:12
  • \$\begingroup\$ @Kartman I thought the same, but then if(SPI1->SR & SPI_SR_TXE) probably evaluates to true out of reset, so that value in the DR register will be pre-loaded, assuming the MCU gets there first, before the PC master sends something. Isn't the problem rather that SPI1->DR is 16 bits or such? That's what I would bet on. \$\endgroup\$ Commented Feb 7, 2022 at 14:31
  • \$\begingroup\$ I bet there's a setting 8 vs 16 bit SPI data. I don't remember all the details but not all STM32 are the same here I think. Please post the highly relevant spi1_slave_init() code. \$\endgroup\$ Commented Feb 7, 2022 at 14:32
  • \$\begingroup\$ I just RTFM, in SPI1_CR2 there's a DS field. What does it say? You need 0111 there for 8 bit (default setting). \$\endgroup\$ Commented Feb 7, 2022 at 14:37
  • \$\begingroup\$ Never use magic numbers, I will not read this kind of code \$\endgroup\$ Commented Feb 7, 2022 at 21:23

1 Answer 1

2
\$\begingroup\$

Your micro has TX & RX FIFOs and you need to force the correct access size to place the data (ot read the data from) to the FIFO.

*(volatile uint8_t *)&SPI1->DR = tx_byte++

same reading

tr_byte = *(volatile uint8_t *)&SPI1->DR;

You need init code to:

  1. Initialize GPIOs as Alternate to the proper mode.
  2. Start the SPI clock
  3. Set the FIFO threshold
  4. Set the SPI mode + data length.

Best show us your SPI init code.

answered Feb 7, 2022 at 14:45
\$\endgroup\$
3
  • \$\begingroup\$ This won't matter in case the DR is set to 16 bits which I suspect. You'll then get data according to the MSB/LSB setting, big or little endian. \$\endgroup\$ Commented Feb 7, 2022 at 15:02
  • \$\begingroup\$ @Lundin it makes a lot of difference. 1. Default RPI spidev && STM32 SPI word length is 8 bits. 2. Using 32 bits access will place 32 bits to the FIFO. \$\endgroup\$ Commented Feb 7, 2022 at 16:10
  • 1
    \$\begingroup\$ Hello! Sorry for the missing SPI initialization code, I added to my question. \$\endgroup\$ Commented Feb 7, 2022 at 17:34

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.