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

最近在研究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

PS-2205S-RS螺丝扭力测试仪的架构
通过PROFINET通信实现V90 PN基本定位控制
腾讯地图、腾讯位置服务发布2019十一出行大数据预测报告
干货满满:寒冬下如何从电池容量的角度谈动力电池
光纤网络向IP路由器演进全解
STM32单片机SPI总线与FPGA的通信设计
微软与BBC等合作研发解决信息欺诈技术
4K蓝光真的是刚需吗
卡曼滤波器入门教程一维卡曼滤波器 1
数字电视视频服务器的设计与实现
热电偶和热电阻的区别及设计方案
帷幕燃烧测试仪上海徽涛自动化
如何做好防晒?避开紫外线让皮肤更完美!
深度学习基础知识(2)
IMX6 MfgTool烧录的详细步骤
Cypress全球线上嵌入式设计大会将于12月12日至13日举行
魅族Pro7换上高通骁龙835,你能够接受吗?
如何把HEIC格式转化jpg?
Teledyne e2v 推出其下一个超紧凑高级计算模块
不断发展的语音和人工智能是进入心理健康的窗口