STM32单片机SPI总线与FPGA的通信设计

发布时间:2024-04-02  

最近在研究SPI总线,至于协议和硬件描述就不多说了

四线包括时钟、片选、接收、发送


初始化SP

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工

SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式

SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //16bit宽度

SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;


SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //2--18MHz; 4--9MHz; 8--4.5MHz

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //高位在前

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPIx, &SPI_InitStructure);

SPI_Cmd(SPIx, ENABLE);

SPI不能硬件控制CS,只能软件来控,就是通过将NSS设为外部GPIO来控制。

像我所做的项目是使用STM32与FPGA通信,而FPGA的SPI工作在这种一直状态

作为主设备的STM32,CS在传输数据的时候为低,传输完毕后必须拉高,这样FPGA可以判断出SPI的传输起止状态。

FPGA的数据传输格式是16bit地址+16bit数据

对于读16bit,实现如下

uint16_t spi_read(SPI_TypeDef* SPIx,uint32_t addr)

{

uint16_t value;

uint16_t spi_nss;

uint16_t add;

uint32_t level;

if(SPI1 == SPIx)

spi_nss = SPI1_PIN_NSS;

else if(SPI2 == SPIx)

spi_nss = SPI2_PIN_NSS;

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);

GPIO_ResetBits(GPIOA, spi_nss);

SPI_I2S_SendData(SPIx, addr); //0xf014 》》 2

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPIx, 0x0);

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);

SPI_I2S_ReceiveData(SPIx);

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);

GPIO_SetBits(GPIOA, spi_nss);

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);

value = SPI_I2S_ReceiveData(SPIx);

return value;

}

写函数

void spi_write(SPI_TypeDef* SPIx,uint32_t addr, uint16_t value)

{

uint16_t spi_nss;

uint32_t level;

if(SPI1 == SPIx)

spi_nss = SPI1_PIN_NSS;

else if(SPI2 == SPIx)

spi_nss = SPI2_PIN_NSS;

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);

GPIO_ResetBits(GPIOA, spi_nss);

SPI_I2S_SendData(SPIx, addr);

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPIx, value);

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);

SPI_I2S_ReceiveData(SPIx);

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);

GPIO_SetBits(GPIOA, spi_nss);

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);

SPI_I2S_ReceiveData(SPIx);

}

拿write函数举例

只所以这么设计是因为

如果是函数一开始就将NSS脚拉低,然后再去send,如下

GPIO_ResetBits(GPIOA, spi_nss);

while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPIx, addr);

这样在CS拉低一段时间后(时间大概有16个时钟周期),才有CLK,这样延时就会降低SPI的传输效率

之前那种方式会在CS拉底后很快就有clk时钟出来

之所以写两次再读两次而不是读一次写一次也是考虑到效率的问题

如果先写一次再读一次,看波形每个数据之间有比较大的空隙是没有clk的,就是说在传输完一个数据后再

传第二个会要等一段时间,这个对速度要求比较高的设备是不允许的

还有值得注意的是:

如果SPI是主模式,那么GPIO设置为

NSS是GPIO_Mode_Out_PP

CLK是GPIO_Mode_AF_PP

MOSI是GPIO_Mode_AF_PP

MISO是GPIO_Mode_IN_FLOATING

如果SPI是从模式,那么GPIO设置为

NSS是GPIO_Mode_Out_PP

CLK是GPIO_Mode_IN_FLOATING

MOSI是GPIO_Mode_IN_FLOATING

MISO是GPIO_Mode_AF_PP


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>