Stm32f407IG SPI communication

1.2k views Asked by At
#include <stm32f4xx.h>
#include "stm32f4xx_spi.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "config.h"

void init_GPIO()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOI,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;  
GPIO_Init(GPIOI , &GPIO_InitStructure);
}


void SPI1_Configuration_master(void)
{
SPI_InitTypeDef SPI_InitStruct;  
GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHB1PeriphClockCmd(Open_SPI1_SCK_GPIO_CLK | Open_SPI1_MISO_GPIO_CLK | Open_SPI1_MOSI_GPIO_CLK |Open_SPI1_NSS_GPIO_CLK ,ENABLE);
RCC_APB2PeriphClockCmd(Open_RCC_APB2Periph_SPI1,ENABLE);

GPIO_PinAFConfig(Open_SPI1_SCK_GPIO_PORT, Open_SPI1_SCK_SOURCE,  Open_SPI1_MOSI_AF);
GPIO_PinAFConfig(Open_SPI1_MISO_GPIO_PORT, Open_SPI1_MISO_SOURCE, Open_SPI1_MOSI_AF);
GPIO_PinAFConfig(Open_SPI1_MOSI_GPIO_PORT, Open_SPI1_MOSI_SOURCE, Open_SPI1_MOSI_AF);
GPIO_PinAFConfig(Open_SPI1_NSS_GPIO_PORT, Open_SPI1_NSS_SOURCE, Open_SPI1_NSS_AF);

GPIO_InitStructure.GPIO_Pin = Open_SPI1_SCK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;  
GPIO_Init(Open_SPI1_SCK_GPIO_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = Open_SPI1_MISO_PIN;
GPIO_Init(Open_SPI1_MISO_GPIO_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = Open_SPI1_MOSI_PIN;
GPIO_Init(Open_SPI1_MOSI_GPIO_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = Open_SPI1_NSS_PIN;
GPIO_Init(Open_SPI1_NSS_GPIO_PORT, &GPIO_InitStructure);


SPI_I2S_DeInit(Open_SPI1);
SPI_InitStruct.SPI_Direction= SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; 
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft ;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(Open_SPI1, &SPI_InitStruct);

SPI_Cmd(Open_SPI1, ENABLE);

}
void SPI_Configuration2_slave(void)
{
SPI_InitTypeDef SPI_InitStruct;  
GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHB1PeriphClockCmd(Open_SPI2_SCK_GPIO_CLK | Open_SPI2_MISO_GPIO_CLK | Open_SPI2_MOSI_GPIO_CLK| Open_SPI2_NSS_GPIO_CLK,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);

GPIO_PinAFConfig(Open_SPI2_SCK_GPIO_PORT, Open_SPI2_SCK_SOURCE,  Open_SPI2_MOSI_AF);
GPIO_PinAFConfig(Open_SPI2_MISO_GPIO_PORT, Open_SPI2_MISO_SOURCE, Open_SPI2_MOSI_AF);
GPIO_PinAFConfig(Open_SPI2_MOSI_GPIO_PORT, Open_SPI2_MOSI_SOURCE, Open_SPI2_MOSI_AF);
GPIO_PinAFConfig(Open_SPI2_MOSI_GPIO_PORT, Open_SPI2_NSS_SOURCE, Open_SPI2_MOSI_AF);

GPIO_InitStructure.GPIO_Pin = Open_SPI2_SCK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;  
GPIO_Init(Open_SPI2_SCK_GPIO_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = Open_SPI2_MISO_PIN;
GPIO_Init(Open_SPI2_MISO_GPIO_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = Open_SPI2_MOSI_PIN;
GPIO_Init(Open_SPI2_MOSI_GPIO_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = Open_SPI2_NSS_PIN;
GPIO_Init(Open_SPI2_MOSI_GPIO_PORT, &GPIO_InitStructure);

SPI_I2S_DeInit(Open_SPI2);
SPI_InitStruct.SPI_Direction= SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; 
SPI_InitStruct.SPI_Mode = SPI_Mode_Slave;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft ;
//SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(Open_SPI2, &SPI_InitStruct);

SPI_Cmd(Open_SPI2, ENABLE);

}

u16 SPI2_Send_byte(u16 data)
{
while(SPI_I2S_GetFlagStatus(Open_SPI2, SPI_I2S_FLAG_TXE)==RESET);
SPI_I2S_SendData(Open_SPI2,data);

while(SPI_I2S_GetFlagStatus(Open_SPI2, SPI_I2S_FLAG_RXNE)==RESET);
return SPI_I2S_ReceiveData(Open_SPI2);
}

u16 SPI2_Receive_byte(void)
{/*
while(SPI_I2S_GetFlagStatus(Open_SPI2, SPI_I2S_FLAG_TXE)==RESET);
SPI_I2S_SendData(Open_SPI2,0x00);
*/
while(SPI_I2S_GetFlagStatus(Open_SPI2, SPI_I2S_FLAG_RXNE)==RESET);
return SPI_I2S_ReceiveData(Open_SPI2);
}

u16 SPI_Send_byte(u16 data)
{
GPIO_ResetBits(GPIOI,GPIO_Pin_10);
while(SPI_I2S_GetFlagStatus(Open_SPI1, SPI_I2S_FLAG_TXE)==RESET);
SPI_I2S_SendData(Open_SPI1,data);

while(SPI_I2S_GetFlagStatus(Open_SPI1, SPI_I2S_FLAG_RXNE)==RESET);
GPIO_SetBits(GPIOI,GPIO_Pin_10);
return SPI_I2S_ReceiveData(Open_SPI1);
}

u16 SPI_Receive_byte(u16 data)
{
/*while(SPI_I2S_GetFlagStatus(Open_SPI1, SPI_I2S_FLAG_TXE)==RESET);
SPI_I2S_SendData(Open_SPI1,data);
*/
while(SPI_I2S_GetFlagStatus(Open_SPI1, SPI_I2S_FLAG_RXNE)==RESET);
return SPI_I2S_ReceiveData(Open_SPI1);
}

int main()
{
char a;
init_GPIO();
SPI_Configuration2_slave();
SPI1_Configuration_master();
GPIO_SetBits(GPIOI,GPIO_Pin_10);
while(1)
{
    a =SPI_Send_byte((u16)'a');
    a = SPI2_Receive_byte();
}
return 0;
}

I am trying to implement Spi on STM32F407ig I am currently trying to implement communication between two Spi1 and SPI2 on the same board. I tried the similar code for communication between boards. when i loop back mosi and miso of master i get the data transmitted. but the slave does not receive any thing or it receives zero. The connections made are right. also the Macros used like Open_SPI1 are right.

I want to know if my configuration of SPI master and slave is right.

Could someone also elaborate on how the NSS software exactly work.

1

There are 1 answers

0
rost0031 On

I had an issue with SPI on STM32F2 series. I had to toggle the NSS line manually and everything worked fine after that. Not sure if F4 has the same problem (maybe it's even by design). Here's my code:

/******************************************************************************/
void SPI_GPIO_init( void )
{
   GPIO_InitTypeDef GPIO_InitStructure;

   /* Configure SPI pins SCK and MOSI to be hardware controlled */
   GPIO_InitStructure.GPIO_Pin     = SPI_PIN_SCK | SPI_PIN_MOSI;
   GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AF_PP;
   GPIO_Init( SPI_GPIO_PORT, &GPIO_InitStructure );

   /* Configure SPI pin MISO to be an input pin since we are master */
   GPIO_InitStructure.GPIO_Pin     = SPI_PIN_MISO;
   GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_IN_FLOATING;
   GPIO_Init( SPI_GPIO_PORT, &GPIO_InitStructure );

   /* Configure SPI pin NSS to be a regular GPIO output.  This is due to STM32
    * goofy handling of SPI: NSS stays low for the entire duration of SPI being
    * enabled instead of being released after outgoing data is completed.  This
    * is basically a HW bug but it definitely mentiones this in the Ref Manual.
    *
    * From the reference manual RM0090:
    * - NSS output enabled (SSM = 0, SSOE = 1)
    * This configuration is used only when the device operates in master mode.
    * The NSS signal is driven low when the master starts the communication and
    * is kept low until the SPI is disabled.
    *
    * Instead, we are going to drive this pin manually as CLRC663 chip expects
    * */
   GPIO_InitStructure.GPIO_Pin     = SPI_PIN_NSS;
   GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_Out_PP;
   GPIO_Init( SPI_GPIO_PORT, &GPIO_InitStructure );

   SPI_NSS_high();
   DelayMS(1);

}

/******************************************************************************/
void SPI_NSS_high( void )
{
   GPIO_WriteBit( SPI_GPIO_PORT, SPI_PIN_NSS, Bit_SET);
}

/******************************************************************************/
void SPI_NSS_low( void )
{
   GPIO_WriteBit( SPI_GPIO_PORT, SPI_PIN_NSS, Bit_RESET);
}

/******************************************************************************/
void SPI_init( void )
{
   SPI_I2S_DeInit( SPI1 );

   SPI_NSS_high();

   SPI_InitTypeDef  SPI_InitStructure;

   /* SPI1 configuration */
   SPI_InitStructure.SPI_Direction         = SPI_Direction_2Lines_FullDuplex;
   SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;
   SPI_InitStructure.SPI_DataSize          = SPI_DataSize_8b;
   SPI_InitStructure.SPI_CPOL              = SPI_CPOL_Low;
   SPI_InitStructure.SPI_CPHA              = SPI_CPHA_1Edge;
   SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;
   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
   SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;
   SPI_InitStructure.SPI_CRCPolynomial     = 0;
   SPI_Init( SPI1, &SPI_InitStructure );

   SPI_Cmd( SPI1, ENABLE );

   /* Not using interrupts for SPI communication so don't enable the NVIC and
    * the ISR for it.*/
}

/******************************************************************************/
Error SPI_send( uint8_t *snd_buf, uint8_t snd_buf_len )
{
   uint8_t snd_indx        = 0;
   uint8_t spi_retry       = 0;

   SPI_NSS_low(); /* Assert the NSS pin low to become SPI bus master */

   for ( snd_indx = 0; snd_indx < snd_buf_len; snd_indx++ )
   {
      /* When SPI Tx buffer is empty, send data.  Make sure we don't get
       * stuck in an inf loop while waiting for HW */
      spi_retry = 0;
      while ( SET != SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_TXE ) )
      {
         if ( 0xFF == spi_retry++ )
         {
            err_printf("Reached SPI hardware retries trying to send data over SPI bus\n");
            return ( ERR_HW_SPI_TIMEOUT );
         }
      }
      SPI_I2S_SendData( SPI1, snd_buf[ snd_indx ] );
      //        debug_printf("Sent %02x\n", snd_buf[ snd_indx ]);

      /* Get the dummy byte coming back when SPI Rx buffer is empty. Make sure
       * we don't get stuck in an inf loop while waiting for HW */
      spi_retry = 0;
      while ( SET != SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE ) )
      {
         if ( 0xFF == spi_retry++ )
         {
            err_printf("Reached SPI hardware retries trying to receive data over SPI bus\n");
            return ( ERR_HW_SPI_TIMEOUT );
         }
      }
      SPI_I2S_ReceiveData( SPI1 ); /* Dummy byte so no need to store it */
   }

   SPI_NSS_high(); /* Assert the NSS pin high to release SPI bus master */

   return ( ERR_NONE );
}

/******************************************************************************/
Error SPI_transceive(
                        uint8_t *snd_buf,
                        uint8_t snd_buf_len,
                        uint8_t *rcv_buf,
                        uint8_t rcv_buf_len
                    )
{
   uint8_t snd_indx        = 0;
   uint8_t rcv_indx        = 0;
   uint16_t spi_retry      = 0;

   SPI_NSS_low(); /* Assert the NSS pin low to become SPI bus master */

   if ( snd_buf_len != rcv_buf_len )
   {
      err_printf("SPI expects to receive same amount of data that it is sending\n");
      return ( ERR_HW_SPI_LENGTH_MISMATCH );
   }

   for ( snd_indx = 0; snd_indx < snd_buf_len; snd_indx++, rcv_indx++ )
   {
      /* When SPI Tx buffer is empty, send data.  Make sure we don't get
       * stuck in an inf loop while waiting for HW */
      spi_retry = 0;
      while ( SET != SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_TXE ) )
      {
         if ( 0xFF == spi_retry++ )
         {
            err_printf("Reached SPI hardware retries trying to send data over SPI bus\n");
            return ( ERR_HW_SPI_TIMEOUT );
         }
      }
      SPI_I2S_SendData( SPI1, snd_buf[ snd_indx ] );

      /* Now receive the reply when the Rx buffer is empty. Make sure we don't
       * get stuck in an inf loop while waiting for HW */
      spi_retry = 0;
      while ( SET != SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE ) )
      {
         if ( 0xFF == spi_retry++ )
         {
            err_printf("Reached SPI hardware retries trying to receive data over SPI bus\n");
            return ( ERR_HW_SPI_TIMEOUT );
         }
      }
      uint8_t data = SPI_I2S_ReceiveData( SPI1 );
      rcv_buf[ rcv_indx ] = data;
      //        debug_printf("Got %02x\n", data );
   }

   SPI_NSS_high(); /* Assert the NSS pin high to release SPI bus master */

   return ( ERR_NONE );
}