Electronic – STM32 SPI Slave send data Problem

slavespistm32timing

I am working on a project with the STM32F411 microcontroller. It is set in SPI slave mode and receives data without any problems. When I want to send data over the spi peripheral i works sometimes but most of the time the bits I am trying to send a shifted or there is wrong data sent. I have configured the spi peripheral like it was shown in an example in the standard peripheral drivers for this controller and I also donĀ“t have a chip select line because I only have one slave in the system.

Is there something wrong in my setup or do i refill the tx buffer at a wrong moment?

Here is my code:

void spi1_init(){
SPI_InitTypeDef  SPI_InitStruct;

spi1_gpio_init();

// Enable the SPI periph clock
RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1EN, ENABLE);

// Set data size to 8b 
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;

SPI_I2S_DeInit(SPI1);
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; // 100MHz / 64 = 1.5625MHz
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_Mode = SPI_Mode_Slave;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_CRCPolynomial = 7;

// Mode 0 
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;


// Init SPI 
SPI_Init(SPI1, &SPI_InitStruct);


//---------------------------------------------------------------------

spi1_interrupt_init();

//---------------------------------------------------------------------


   // Enable the SPI peripheral 
   SPI_Cmd(SPI1, ENABLE); 

 }


void spi1_gpio_init(void){
GPIO_InitTypeDef GPIO_InitStruct;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void spi1_interrupt_init(void){
NVIC_InitTypeDef  NVIC_InitStruct;

// Configure the SPI interrupt priority 
NVIC_InitStruct.NVIC_IRQChannel = SPI1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);

// Enable the Rx buffer not empty interrupt 
SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE);

 // Enable the Tx empty interrupt 
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_TXE, ENABLE);
}


void SPI1_IRQHandler(void)
{  
int8_t CmdReceived;
static uint32_t CmdCount = 0;
static int8_t RecArray[SPI_REC_BYTES];
static uint32_t dataCounter = 0;

    // SPI in Transmitter mode 
  if (SPI_I2S_GetITStatus(SPI1, SPI_I2S_IT_TXE) == SET)
 {
    SPI_I2S_SendData(SPI1, 123);

 }

 // SPI in Slave Receiver mode--------------------------------------- 
  if (SPI_I2S_GetITStatus(SPI1, SPI_I2S_IT_RXNE) == SET)
 {
 CmdReceived = SPI_ReceiveData(SPI1);

        if(CmdReceived < -100){
            CmdCount = 0;
            RecArray[CmdCount] = CmdReceived;



        } else if(++CmdCount < SPI_REC_BYTES){

            RecArray[CmdCount] = CmdReceived;

            if(CmdCount == (SPI_REC_BYTES-1)){
                callbackfunction(RecArray);
            }
        }


  }


 }

Best Answer

  1. Sending data using interrupts is quite tricky as if you do not have anything to send you should clear TEIE flag (disable the interrupt), and set it when you have something to send. Otherwise the interrupt will be triggered all the time.
  2. You do not set the number of data bits. At can be any value as your struct may contain garbage data.

  3. To send 8 bit of data you need to force the compiler to write byte (not the half word) to the DR register. Many SPL versions had it done wrong. If you write the halfword - half word is stored into the FIFO and you will send two bytes (not one!!). I do not use those silly libraries for such simply peripheral but I advice to step over the send function and see if it written properly

    1506        *(volatile uint8_t *)&SPIx -> DR = command;
    08005a9c:   strb    r1, [r0, #12]