STM32SPI接口的简单实现_第1页
STM32SPI接口的简单实现_第2页
STM32SPI接口的简单实现_第3页
STM32SPI接口的简单实现_第4页
STM32SPI接口的简单实现_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、STM32 SPI 接口的简单实现通常 SPI 通过 4 个引脚与外部器件相连: MISO:主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式 下接收数据。 MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式 下接收数据。 SCK串口时钟,作为主设备的输出,从设备的输入 NSS从设备选择。这是一个可选的引脚,用来选择主/从设备。它的功能是用 来作为“片选引脚”,让主设备可以单独地与特定从设备通讯,避免数据线上的 冲突。从设备的NSS引脚可以由主设备的一个标准I/O引脚来驱动。一旦被使能 (SSOE位),NSS引脚也可以作为输出引脚,并在 SPI处于主模式时拉低

2、;此时, 所有的SPI设备,如果它们的NSS引脚连接到主设备的NSS引脚,则会检测到低 电平,如果它们被设置为NSS硬件模式,就会自动进入从设备状态。当配置为主 设备、NSS配置为输入引脚(MSTR=1 SSOE=0)寸,如果NSS被拉低,则这个SPI 设备进入主模式失败状态:即 MSTR位被自动清除,此设备进入从模式。时钟信号的相位和极性SPI_CR寄存器的CPO和CPHA位,能够组合成四种可能的时序关系。 CPOL时钟 极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下 的设备都有效。如果CPOI被清O, SCK引脚在空闲状态保持低电平;如果CPOL 被置1, SCK引

3、脚在空闲状态保持高电平。如果CPHA时钟相位)位被置1, SCK寸钟的第二个边沿(CPOL位为0时就是下 降沿,CPOL位为1时就是上升沿)进行数据位的采样,数据在第二个时钟边 沿被锁存。如果CPHA位被清O, SCK寸钟的第一边沿(CPOL位为0时就是 下降沿,CPO位为1时就是上升沿)进行数据位采样,数据在第一个时钟边 沿被锁存。CPOIM钟极性和CPHA寸钟相位的组合选择数据捕捉的时钟边沿。图212显示了 SPI传输的4种CPHA和CPOL位组合。此图可以解释为主设备和从 设备的SCKW、MISC脚、MOS脚直接连接的主或从时序图。CPOL寸钟极性和CPHA寸钟相位的组合选择数据捕捉的时

4、钟边沿。上图显示了 SPI传输的4种CPHA和CPOI位组合。此图可以解释为主设备和从设 备的SCKW、MISCW、MOS脚直接连接的主或从时序图。1. 在改变CPOL/CPH位之前,必须清除SPE位将SPI禁止。2. 主和从必须配置成相同的时序模式。3.SCK的空闲状态必须和SPI_CR1寄存器指定的极性一致(CPOL为1时,空闲 时应上拉SCK为高电平;CPOI为0时,空闲时应下拉SCK为低电平)。4.数据帧格式(8位或16位)由SPI_CR1寄存器的DFF位选择,并且决定发送/ 接收的数据长度。我只要知道主机和从机的 CPOL和 CPHA位要一致就够了。有2种NSS模式:软件NSS模式:

5、可以通过设置SPI_CR1寄存器的SSM位来使能这种模式。在这 种模式下NSS引脚可以用作它用,而内部 NSS信号电平可以通过写SPI_CR1的 SSI 位来驱动硬件NSS模式,分两种情况:NSS输出被使能:当STM32F10xx工作为主SPI,并且NSS俞出已经通过SPI_CR2 寄存器的SSOEm使能,这时NSS引脚被拉低,所有NSS引脚与这个主SPI的NSS 引脚相连并配置为硬件NSS的SPI设备,将自动变成从SPI设备。当一个SPI 设备需要发送广播数据,它必须拉低NSS信号,以通知所有其它的设备它是主设 备;如果它不能拉低NSS这意味着总线上有另外一个主设备在通信,这时将产 生一个硬

6、件失败错误 (HardFault) 。NSS输出被关闭:允许操作于多主环境。/我们用软件NSS主从的转换都可借助库来实现数据帧格式根据SPI_CR1寄存器中的LSBFIRST位,输出数据位时可以 MSB在先也可以LSB 在先。根据SPI_CR1寄存器的DFF位,每个数据帧可以是8位或是16位。所选择的数 据帧格式对发送和 /或接收都有效。配置一个 SPI 这里选 SPI2如下:SPI_InitTypeDef SPI_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);SPI_Cmd(SPI2, DISABLE); /

7、 必须先禁能 , 才能改变 MODESPI_InitStructure.SPI_Direction =SPI_Direction_2Lines_FullDuplex; / 两线全双工SPI_InitStructure.SPI_Mode =SPI_Mode_Master; / 主 SPI_InitStructure.SPI_DataSize =SPI_DataSize_8b; /8位SPI_InitStructure.SPI_CPOL =SPI_CPOL_High; /CPOL=1 时钟悬空高 SPI_InitStructure.SPI_CPHA =SPI_CPHA_1Edge; /CPHA=1

8、 数据捕获第 2 个 SPI_InitStructure.SPI_NSS =SPI_NSS_Soft; /软件 NSSSPI_InitStructure.SPI_BaudRatePrescaler =SPI_BaudRatePrescaler_2; /2 分频SPI_InitStructure.SPI_FirstBit =SPI_FirstBit_MSB; /高位在前SPI_InitStructure.SPI_CRCPolynomial =7; /CRC7SPI_Init(SPI2,&SPI_InitStructure);SPI_Cmd(SPI2, ENABLE);/spi 的配置结束了可以使

9、用了。也可用 函数 SPI_StructInit 把 SPI_InitStruct 中的每一个参数按缺省值填入发送缓冲器空闲标志 (TXE)【3.0 SPI_I2S_FLAG_TXE】此标志为 1时表明发送缓冲器为空,可以写下一个待发送的数据进入缓冲器 中。当写入SPI_DR时,TXE标志被清除。接收缓冲器非空 (RXNE)【3.0 SPI_I2S_FLAG_RXNE】此标志为 1时表明在接收缓冲器中包含有效的接收数据。读SPI 数据寄存器可以清除此标志。注意在 2.0 的库中函数SPI_SendData SPI_ReceiveData SPI_GetFlagStatus 等在3.0 的库中

10、变为SPI_I2S_SendData SPI_I2S_ReceiveData SPI_I2S_GetFlagStatus写一个发送 / 接受函数static u8 SPIByte(u8 byte) while(SPI2-SR &SPI_I2S_FLAG_TXE)=RESET);/while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE)=RESET);SPI2-DR = byte;/SPI_I2S_SendData(SPI2,byte);while(SPI2-SR &SPI_I2S_FLAG_RXNE)=RESET);/while(SPI_I2S_Ge

11、tFlagStatus(SPI2,SPI_I2S_FLAG_RXNE)=RESET); return(SPI2-DR);/returnSPI_I2S_ReceiveData(SPI2); 读寄存器用硬件清除标志位。 /SPI_I2S_ClearFlag(SPI2,SPI_I2S_FLAG_RXNE) ; 直接软件清除标志位。 这里有两种写法直接操作寄存器与用库函数, 相对来说直接操作寄存器应该更直 观一些。调试总会遇到这样那样的小问题 和朋友一起进步总会更快 希望对别人能有点 帮助节省些时间 万利的板子板载的M25P80PDF写的这一型号有25MHZ和50MH2两种注意初始 化SPI的设置BA

12、UD至少就要PCLK/2 = 36Mhz即使配置为主模式发送 时钟也不是连产生的 接收的时候同样需要发送无用字 节以维持数据时钟STM32的NSS脚需要配置为软件模式(可以通过寄存器控制NSS高低)硬件模式 下NSS引脚必须+正的逻辑电平 才能将SPE MST位时能配置SPI为主模式先写了一遍 然后借鉴一个 sst25vf08 的应用笔记又写了一遍 看这个笔记省了 不少时间 很感谢同一地址单元 重新写入需先擦除 否者二次写入后读出无效其他按照时序走就可以了程序如下 :#define WREN 0x06#define WRDI 0x04#define RDSR 0x05#define WRSR

13、0x01#define READ 0x03#define FAST_READ 0x06#define PAGE_PROG 0x02#define SECTOR_ERASER 0xd8#define BULK_ERASER 0xc7#define DEEP_SLEEP 0xb9#define RES 0xab#define M25P80_SELECT() GPIOB-BRR |= GPIO_Pin_2#define M25P80_DESELECT() GPIOB-BSRR |= GPIO_Pin_2u8 SPI_SeRe_Byte(u8 data);void M25p80_Cmd1b(u8 cm

14、d);u8 M25p80_Cmd1b_R1b(u8 cmd);void M25p80_Cmd1b_S1b(u8 cmd , u8 data);void M25p80_WP_En(void);void M25p80_Write_En(void);u8 M25p80_Busy(void);u8 M25p80_Read_1Byte(u32 addr );void M25p80_Read_Bytes(u32 addr , u8* re_buf_p , u16 no);void M25p80_Write_1Byte(u32 addr , u8 data);void M25p80_Write_Bytes(

15、u32 addr , u8* wr_buf_p , u16 no);void M25p80_Section_Erase(u32 addr);void M25p80_Bulk_Erase(void);* op-code for M25P80 SPI EEROM* 8Mbit = 1,048,576 bytes = 16 sectors (512 Kbits, 65536 bytes each) = 4096 pages (256 bytes each)* 1sector = 256 page* address range 00000 fffffh*/ u8 SPI_SeRe_Byte(u8 da

16、ta)u8 re_data;while(! (SPI1-SR & 0x0002) );/*TXE?*/ SPI1-DR = data;while(! (SPI1-SR & 0x0001) );/*RXNE?*/ re_data = SPI1-DR;return re_data;* 函数名称:M25p80_cmd1b_r1b/M25p80_Cmd1b_S1b C命令发送 返回 1BYTE命 令发送跟送 1BYTE*/void M25p80_Cmd1b(u8 cmd)M25P80_SELECT();SPI_SeRe_Byte(cmd);M25P80_DESELECT();u8 M25p80_Cmd

17、1b_R1b(u8 cmd) u8 data;M25P80_SELECT();SPI_SeRe_Byte(cmd);data = SPI_SeRe_Byte(0xff);M25P80_DESELECT();return data;void M25p80_Cmd1b_S1b(u8 cmd , u8 data)M25P80_SELECT();SPI_SeRe_Byte(cmd);SPI_SeRe_Byte(data);M25P80_DESELECT();/*/* 函数名称:M25p80_WP_En/M25p80_Write_EM25p80写保护使能 / 写使能 status 寄存器修改*/void

18、 M25p80_WP_En(void)u8 sta;sta = M25p80_Cmd1b_R1b(RDSR) | 0x1c;M25p80_Cmd1b_S1b(WRSR, sta);M25p80_Cmd1b(WRDI);void M25p80_Write_En(void)u8 sta;sta = M25p80_Cmd1b_R1b(RDSR) & (0x1c);M25p80_Cmd1b_S1b(WRSR, sta);M25p80_Cmd1b(WREN);/*/ u8 M25p80_Busy(void)u8 sta;sta = M25p80_Cmd1b_R1b(RDSR);return (sta &

19、 0x01);u8 M25p80_Read_1Byte(u32 addr ) u8 ad3 , data;ad0 = (addr & 0x00ff0000) 16;ad1 = (addr & 0x0000ff00) 8;ad2 = (addr & 0x000000ff);M25P80_SELECT();SPI_SeRe_Byte(READ);SPI_SeRe_Byte(ad0);SPI_SeRe_Byte(ad1);SPI_SeRe_Byte(ad2); data = SPI_SeRe_Byte(0xff);M25P80_DESELECT(); return data;void M25p80_

20、Read_Bytes(u32 addr , u8* re_buf_p , u16 no) u8 ad3 ;ad0 = (addr & 0x00ff0000) 16;ad1 = (addr & 0x0000ff00) 8;ad2 = (addr & 0x000000ff);M25P80_SELECT();SPI_SeRe_Byte(READ);SPI_SeRe_Byte(ad0);SPI_SeRe_Byte(ad1);SPI_SeRe_Byte(ad2);for(; no 0; no-)*re_buf_p+ = SPI_SeRe_Byte(0xff);M25P80_DESELECT();/*/v

21、oid M25p80_Write_1Byte(u32 addr , u8 data)u8 ad3 ;ad0 = (addr & 0x00ff0000) 16;ad1 = (addr & 0x0000ff00) 8;ad2 = (addr & 0x000000ff);M25p80_Write_En();M25P80_SELECT();SPI_SeRe_Byte(PAGE_PROG);SPI_SeRe_Byte(ad0);SPI_SeRe_Byte(ad1);SPI_SeRe_Byte(ad2);SPI_SeRe_Byte(data);M25P80_DESELECT();M25p80_WP_En(

22、);while(M25p80_Busy();void M25p80_Write_Bytes(u32 addr , u8* wr_buf_p , u16 no) /*u8 ad3 ;ad0 = (addr & 0x00ff0000) 16;ad1 = (addr & 0x0000ff00) 8;ad2 = (addr & 0x000000ff);写操作过本页地址从本页首地址循环if( no 0; no-) *wr_buf_p+ = SPI_SeRe_Byte(0xff);M25P80_DESELECT();M25p80_Cmd1b(WRDI);return 1;*/for(; no 0; no-

23、)M25p80_Write_1Byte(addr , *wr_buf_p); addr+;wr_buf_p+;M25p80_WP_En();*/*void M25p80_Section_Erase(u32 addr)u8 ad3 ;ad0 = (addr & 0x00ff0000) 16;ad1 = (addr & 0x0000ff00) 8;ad2 = (addr & 0x000000ff);M25p80_Write_En();M25P80_SELECT();SPI_SeRe_Byte(SECTOR_ERASER);SPI_SeRe_Byte(ad0);SPI_SeRe_Byte(ad1);

24、SPI_SeRe_Byte(ad2);M25P80_DESELECT(); while(M25p80_Busy();M25p80_WP_En();void M25p80_Bulk_Erase(void)M25p80_Write_En();M25p80_Cmd1b(BULK_ERASER);while(M25p80_Busy();M25p80_WP_En();这里的多字节写函数 void M25p80_Write_Bytes(u32 addr , u8* wr_buf_p , u16 no) 调用了单字节写函数 实际上还是一个一个写 主要因为用页写操作的话 当 数据到达页底会返回本页从头开始写

25、会破坏数据 而且没有字节写操作码感觉 比 sst25vf08 麻烦很多。关于STM32 SPI NSS问题的探讨。对于 STM32的 SPI , Referenee Manual 中是给出的 schematic 如下:按照标准的SPI协议,当SPI被配置为主机模式后,通过SPI对从设备进行操作 时,其NSS应该自动置低,从而选中(使能)从设备;一旦不对从设备进行操作, NSS立刻置为高。但是,我在实际调试过程中却发现:STM32 SPI NSS无法自动实现跳变。一旦SPI初始化完成并使能SPI,NSS立刻置低,然后保持不变。这个问题一直无法解决,直到我在 ST官方论坛上看到国外有些技术人员也在

26、讨 论这个问题,他们得出的结论是:STM32 SPI NSS无法自动跳变。RichardE Posted 24-07-2009 at 16:07Registered on :11-05-2005From UK (United Kingdom)Messages : 19OFF-LineIve just hit this NSS problem.What is good:That the discussion is here on the forum to stop mespending hours trying to work out what I have done wrong. Thanks

27、 guys!What is not good:hat NSS doesnt behave as expected.What I expected to happen:Im expecting to see on myscope what I see in Figure 208 of RM008Reference Manual, i.e. NSS goes high after the transfer.Why a working NSS would be very helpful:Im using the SPI (with DMA) to clock data into shift regi

28、sters. If NSS went high after the transfer (as indicated by Figure 208), I could use that edge as the strobe to latch the data across into the shift register outputs. Everything would be done by the peripheral. Fire and forget. As it is with the broken NSS, I have to generate an interrupt and use th

29、at to strobe the gpio output (I hate controlling gpio from within interrupt routines).Any update as to when this will be fixed?ST官方技术人员也证实:STM32SPI NSS是不会自动置位和复位的。按照官方说 法,ST已经将其列入了改进计划。对于这个问题,可以采用下面的方法解决:在SPI初始化时,采用NSS soft模式,然后使能NSS俞出功能。从而将NSS当 做GPIO使用,通过软件set和reset来实现NSS的置位和复位。具体代码如下:/* SPI1 confi

30、guration*/SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;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_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; /SPI_InitSt

31、ructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;/SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI1, &SPI_InitStructure);/*Enable SPI1.NSS as a GPIO*/SPI_SSOutputCmd(SPI1, ENABLE);/*Configure PA.4(NSS)*/GPIO_InitStructure.

32、GPIO_Pin =GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);通过将NSS配置为GPIQ在通过SPI操作从设备时,就可以通过软件来选中和 释放从设备了。虽然比起硬件自动置位要麻烦,但问题毕竟解决了。进一步阅读长达900页的Manual,我发现,文中对于SPI hard模式的描述并非 大多数人所认为的硬件SPI,原文如下:Slave select (NSS) pin managementThere are two NSS modes: Software NSS mode: this mode is enabled by setting the SSM bit in theSPI_CR1register (see Figure 209). In this mode, the external NSSpin is free for otherapplication uses and the i

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论