stm32f407IG SPI通信

Posted

技术标签:

【中文标题】stm32f407IG SPI通信【英文标题】:Stm32f407IG SPI communication 【发布时间】:2015-09-05 11:42:29 【问题描述】:
#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;

我正在尝试在 STM32F407ig 上实现 Spi 我目前正在尝试在同一块板上实现两个 Spi1 和 SPI2 之间的通信。 我尝试了类似的代码来进行板之间的通信。 当我环回主控的 mosi 和 miso 时,我得到了传输的数据。 但从机没有收到任何东西或收到零。 建立的联系是正确的。 像Open_SPI1这样使用的宏也是对的。

我想知道我的SPI主从配置是否正确。

谁能详细说明 NSS 软件的具体工作原理。

【问题讨论】:

【参考方案1】:

我在 STM32F2 系列上遇到了 SPI 问题。我不得不手动切换 NSS 线,之后一切正常。不确定 F4 是否有同样的问题(甚至可能是设计使然)。这是我的代码:

/******************************************************************************/
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 );

【讨论】:

以上是关于stm32f407IG SPI通信的主要内容,如果未能解决你的问题,请参考以下文章

STM32F407IG开启FPU,做开方运算

无法使用 STM32F407 上的 Chan FatFs 库通过 SPI 写入 SD 卡文件

STM32F407 SPI 仅接收 0xFF (255) 或 0

STM32F40x芯片的命名规则

如何将 STM32f4 编程为 SPI 从设备

Keil5创建工程(STM32F407)