STM32 SPI接口读写SPI flash实验

454 篇文章 21 订阅
订阅专栏

STM32 SPI flash读写测试实验报告

一、实验目的

1.学习SPI的基本工作原理

2.通过实验加深对STM32SPI的理解

3. 利用STM32的SPI11和SPI接口的flash芯片进行通信,读写测试,并将测试结果用串口打印出来

二、实验原理

1.SPI基础知识

SPI特征

● 3线全双工同步传输

●  带或不带第三根双向数据线的双线单工同步传输

● 8或16位传输帧格式选择

●  主或从操作

●  支持多主模式

● 8个主模式波特率预分频系数(最大为fPCLK/2)

●  从模式频率(最大为fPCLK/2)

●  主模式和从模式的快速通信

●  主模式和从模式下均可以由软件或硬件进行NSS管理:主/从操作模式的动态改变

●  可编程的时钟极性和相位

●  可编程的数据顺序,MSB在前或LSB在前

●  可触发中断的专用发送和接收标志

● SPI总线忙状态标志

●  支持可靠通信的硬件CRC

─  在发送模式下,CRC值可以被作为最后一个字节发送

─  在全双工模式中对接收到的最后一个字节自动进行CRC校验

●  可触发中断的主模式故障、过载以及CRC错误标志

●  支持DMA功能的1字节发送和接收缓冲器:产生发送和接受请求

 

从选择(NSS)脚管理

有2种NSS模式:

图211 ●  软件NSS模式:可以通过设置SPI_CR1寄存器的SSM位来使能这种模式(见 )。在这种

模式下NSS引脚可以用作它用,而内部NSS信号电平可以通过写SPI_CR1的SSI位来驱动

●  硬件NSS模式,分两种情况:

─NSS输出被使能:当STM32F10xxx工作为主SPI,并且NSS输出已经通过SPI_CR2寄存

器的SSOE位使能,这时NSS引脚被拉低,所有NSS引脚与这个主SPI的NSS引脚相连并

配置为硬件NSS的SPI设备,将自动变成从SPI设备。

当一个SPI设备需要发送广播数据,它必须拉低NSS信号,以通知所有其它的设备它是主

设备;如果它不能拉低NSS,这意味着总线上有另外一个主设备在通信,这时将产生一个

硬件失败错误(Hard Fault)。

─NSS输出被关闭:允许操作于多主环境。

 

 

时钟信号的相位和极性可以组合成四种不同的模式,下面为其中来两种模式

数据帧格式

根据SPI_CR1寄存器中的LSBFIRST位,输出数据位时可以MSB在先也可以LSB在先。

根据SPI_CR1寄存器的DFF位,每个数据帧可以是8位或是16位。所选择的数据帧格式对发送和或接收都有效。

 

配置SPI为主模式

在主配置时,在SCK脚产生串行时钟。

配置步骤

1. 通过SPI_CR1寄存器的BR[2:0]位定义串行时钟波特率。

2. 选择CPOL和CPHA位,定义数据传输和串行时钟间的相位关系(见图212)。

3. 设置DFF位来定义8位或16位数据帧格式。

4. 配置SPI_CR1寄存器的LSBFIRST位定义帧格式。

5. 如果需要NSS引脚工作在输入模式,硬件模式下,在整个数据帧传输期间应把NSS脚连接

到高电平;在软件模式下,需设置SPI_CR1寄存器的SSM位和SSI位。如果NSS引脚工作

在输出模式,则只需设置SSOE位。

6. 必须设置MSTR位和SPE位(只当NSS脚被连到高电平,这些位才能保持置位)。

在这个配置中,MOSI引脚是数据输出,而MISO引脚是数据输入。

 

 

SPI模块能够以两种配置工作于单工方式:

● 1条时钟线和1条双向数据线;

● 1条时钟线和1条数据线(只接收或只发送);

 

SPI通信可以通过以下步骤使用CRC:

●  设置CPOL、CPHA、LSBFirst、BR、SSM、SSI和MSTR的值;

●  在SPI_CRCPR寄存器输入多项式;

●  通过设置SPI_CR1寄存器CRCEN位使能CRC计算,该操作也会清除寄存器SPI_RXCRCR

和SPI_TXCRC;

●  设置SPI_CR1寄存器的SPE位启动SPI功能;

●  启动通信并且维持通信,直到只剩最后一个字节或者半字;

●  在把最后一个字节或半字写进发送缓冲器时,设置SPI_CR1的CRCNext位,指示硬件在发

送完成最后一个数据之后,发送CRC的数值。在发送CRC数值期间,停止CRC计算;

●  当最后一个字节或半字被发送后,SPI发送CRC数值,CRCNext位被清除。同样,接收到

的CRC与SPI_RXCRCR值进行比较,如果比较不相配,则设置SPI_SR上的CRCERR标志

位,当设置了SPI_CR2寄存器的ERRIE时,则产生中断。

个人理解:CRC校验,计算发送端是CRC值,接收端计算CRC值,然后发送端将计算的CRC值发送出去,接收端接收到之后与接收端计算的值相比较,若不同则返回错误标志

 

 

利用DMA的SPI通信

为了达到最大通信速度,需要及时往SPI发送缓冲器填数据,同样接收缓冲器中的数据也必须及

时读走以防止溢出。为了方便高速率的数据传输,SPI实现了一种采用简单的请求/应答的DMA

机制。

当SPI_CR2寄存器上的对应使能位被设置时,SPI模块可以发出DMA传输请求。发送缓冲器和

接收缓冲器亦有各自的DMA请求(见)。

●  发送时,在每次TXE被设置为’1’时发出DMA请求,DMA控制器则写数据至SPI_DR寄存

器,TXE标志因此而被清除。

●  接收时,在每次RXNE被设置为’1’时发出DMA请求,DMA控制器则从SPI_DR寄存器读出数

据,RXNE标志因此而被清除。

当只使用SPI发送数据时,只需使能SPI的发送DMA通道。此时,因为没有读取收到的数据,

OVR被置为’1’(译注:软件不必理会这个标志)。

当只使用SPI接收数据时,只需使能SPI的接收DMA通道

 

SPI寄存器

SPI控制寄存器1   SPI_CR1

(其中每个位的作用参阅数据手册486页)

 

SPI控制寄存器2(SPI_CR2)

SPI 状态寄存器(SPI_SR)

SPI 数据寄存器(SPI_DR)

SPI CRC多项式寄存器

SPI Rx CRC寄存器(SPI_RXCRCR)

在启用CRC计算时,RXCRC[15:0]中包含了依据收到的字节计算的CRC数值。当在SPI_CR1

的CRCEN位写入’1’时,该寄存器被复位。CRC计算使用SPI_CRCPR中的多项式。

当数据帧格式被设置为8位时,仅低8位参与计算,并且按照CRC8的方法进行;当数据帧格式

为16位时,寄存器中的所有16位都参与计算,并且按照CRC16的标准。

 

SPI Tx CRC寄存器(SPI_TXCRCR)

在启用CRC计算时,TXCRC[15:0]中包含了依据将要发送的字节计算的CRC数值。当在

SPI_CR1中的CRCEN位写入’1’时,该寄存器被复位。CRC计算使用SPI_CRCPR中的多项

式。

当数据帧格式被设置为8位时,仅低8位参与计算,并且按照CRC8的方法进行;当数据帧格式

为16位时,寄存器中的所有16个位都参与计算,并且按照CRC16的标准

 

2.实验电路图

W25X16有8192个可编程页,每页256字节。用“页编程指令”每次可以编程256个字节。用“扇区(sector)指令”每次可以擦除16页,用“块(block)擦除指令”每次可以擦除256页,用“整片擦除指令”即可擦除整个芯片。W25X16有512个可擦除扇区或32个可擦除块。

W25X16支持标准的SPI接口,传输速率最大75MHz。

 

双输出SPI方式

W25X16支持SPI双输出方式,需要使用“快读双输出指令0x3B”,这时,传输速率相当于两倍的标准SPI速率。这个命令非常适合于在需要一上电就快速下载代码到内存中的情况或者需要缓存代码段到内存中运行的情况下。在使用“快速双输出指令”后,DIO引脚变为输出引脚。

指令:写使能(Write Enable),页编程(Page Program),扇区擦除(Sector Erase),块区擦除(Block Erase),芯片擦除(Chip Erase),写状态寄存器指令(Write Status Register)

 

三、实验内容

软件设计

配置STM32 的SPI为主模式来读取SPI  flash实现读写功能。

下面对SPI1部分进行配置。

在主模式时,SCK脚输出串行时钟。

 

配置步骤:

1)配置SPI串行时钟比特率

2)定义数据传输和串行间的相位关系

3)设置8位或16位数据帧格式

4)如果需要NSS引脚工作在输入模式,硬件模式下,在整个数据帧传输期间应该把NSS脚连接到高电平,在软件模式下,需要设置SPI1_CR1的SSM位和SSI位。如果NSS引脚工作在输出模式,则需要设置SSOE位。

5)必须设置MSTR和SPE位(只有当NSS脚被连接到高电平,这些为才能保持置位)

//串行外设接口SPI的初始化,SPI配置成主模式                                                          

//本例程选用SPI1对W25X16进行读写操作,对SPI1进行初始化

void SPIx_Init(void)

{

        SPI_InitTypeDef  SPI_InitStructure;

        GPIO_InitTypeDef GPIO_InitStructure;

        

        /* Enable SPI1 and GPIOA clocks */

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOC|RCC_APB2Periph_SPI1|RCC_APB2Periph_AFIO, ENABLE);

        

        /* Configure SPI1 pins: NSS, SCK, MISO and MOSI */

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

        GPIO_Init(GPIOA, &GPIO_InitStructure);

        

        //SPI1 NSS

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOC, &GPIO_InitStructure);

 

        GPIO_SetBits(GPIOC, GPIO_Pin_4);

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_SetBits(GPIOA, GPIO_Pin_4);   

 

        /* SPI1 configuration */

        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI1设置为两线全双工

        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                           //设置SPI1为主模式

        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                  //SPI发送接收8位帧结构

        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                                        //串行时钟在不操作时,时钟为高电平

        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                               //第二个时钟沿开始采样数据

        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                       //NSS信号由软件(使用SSI位)管理

        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为8

        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                                   //数据传输从MSB位开始

        SPI_InitStructure.SPI_CRCPolynomial = 7;                                                   //CRC值计算的多项式

        SPI_Init(SPI1, &SPI_InitStructure);

        /* Enable SPI1  */

        SPI_Cmd(SPI1, ENABLE);                                                                                           //使能SPI1外设

}   

 

 

 

SPI接口读写Flash一个字节

//SPIx 读写一个字节

//返回值:读取到的字节

u8 SPIx_ReadWriteByte(u8 TxData)

{                

        u8 retry=0;                                

        while((SPI1->SR&1<<1)==0)//等待发送区空        

        {

                retry++;

                if(retry>200)return 0;

        }                          

        SPI1->DR=TxData;                   //发送一个byte

        retry=0;

        while((SPI1->SR&1<<0)==0) //等待接收完一个byte  

        {

                retry++;

                if(retry>200)return 0;

        }                                                             

        return SPI1->DR;          //返回收到的数据                                   

}

 

 

获取SPI flash ID

//读取芯片ID W25X16的ID:0XEF14

u16 SPI_Flash_ReadID(void)

{

        u16 Temp = 0;          

        SPI_FLASH_CS=0;                                   

        SPIx_ReadWriteByte(0x90);//发送读取ID命令           

        SPIx_ReadWriteByte(0x00);            

        SPIx_ReadWriteByte(0x00);            

        SPIx_ReadWriteByte(0x00);                                     

        Temp|=SPIx_ReadWriteByte(0xFF)<<8;  

        Temp|=SPIx_ReadWriteByte(0xFF);        

        SPI_FLASH_CS=1;                                   

        return Temp;

}  

 

 

在指定位置开始读取指定长度的数据

//读取SPI FLASH  

//在指定地址开始读取指定长度的数据

//pBuffer:数据存储区

//ReadAddr:开始读取的地址(24bit)

//NumByteToRead:要读取的字节数(最大65535)

void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   

{

        u16 i;                                                                                                       

        SPI_FLASH_CS=0;                            //使能器件   

    SPIx_ReadWriteByte(W25X_ReadData);         //发送读取命令   

    SPIx_ReadWriteByte((u8)((ReadAddr)>>16));  //发送24bit地址   

    SPIx_ReadWriteByte((u8)((ReadAddr)>>8));   

    SPIx_ReadWriteByte((u8)ReadAddr);   

    for(i=0;i<NumByteToRead;i++)

        {

        pBuffer[i]=SPIx_ReadWriteByte(0XFF);   //循环读数  

    }

        SPI_FLASH_CS=1;                            //取消片选                   

}  

 

 

在指定位置写入指定长度的数据

 

//写SPI FLASH  

//在指定地址开始写入指定长度的数据

//该函数带擦除操作!

//pBuffer:数据存储区

//WriteAddr:开始写入的地址(24bit)

//NumByteToWrite:要写入的字节数(最大65535)                     

u8 SPI_FLASH_BUF[4096];

void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   

{

        u32 secpos;

        u16 secoff;

        u16 secremain;           

        u16 i;  

        secpos=WriteAddr/4096;//扇区地址 0~511 for w25x16

        secoff=WriteAddr%4096;//在扇区内的偏移

        secremain=4096-secoff;//扇区剩余空间大小   

        if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节

        while(1)

        {        

                SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容

                for(i=0;i<secremain;i++)//校验数据

                {

                        if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除            

                }

                if(i<secremain)//需要擦除

                {

                        SPI_Flash_Erase_Sector(secpos);//擦除这个扇区

                        for(i=0;i<secremain;i++)           //复制

                        {

                                SPI_FLASH_BUF[i+secoff]=pBuffer[i];          

                        }

                        SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区  

 

                }else SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                    

                if(NumByteToWrite==secremain)break;//写入结束了

                else//写入未结束

                {

                        secpos++;//扇区地址增1

                        secoff=0;//偏移位置为0         

 

                           pBuffer+=secremain;  //指针偏移

                        WriteAddr+=secremain;//写地址偏移           

                           NumByteToWrite-=secremain;                                //字节数递减

                        if(NumByteToWrite>4096)secremain=4096;        //下一个扇区还是写不完

                        else secremain=NumByteToWrite;                        //下一个扇区可以写完了

                }        

        };                 

}

 

 

 

在main函数中,先向Flash中写入指定长度的数据,然后在读出并打印到串口,比较读出和写入的数据,并将结果显示到串口

int main(void)

{

        u8 i=0;

        u8 datatemp[SIZE];

        

        GPIO_Configuration();

        USART_Configuration();

        GPIO_SetBits(GPIOF, GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);

        

        

        

        SPI_Flash_Init();   

        

        while(SPI_Flash_ReadID()!=FLASH_ID)//检测不到W25X16

        {           

                i=SPI_Flash_ReadID();

                printf("\n\r ID:%d",i);

                printf("\n\r没有读到正确的W25X16芯片ID,请检查硬件连接");

                Delay(0xaFFFF);

                Delay(0xaFFFF);

                GPIO_ResetBits(GPIOF,  GPIO_Pin_7);

                GPIO_SetBits(GPIOF,  GPIO_Pin_7);

        

        }

        

        printf("\n\r开始写入W25X16 SPI FLASH芯片....");

        SPI_Flash_Write((u8*)TEXT_Buffer,1000,SIZE);//从1000字节处开始,写入SIZE长度的数据

        printf("\n\r写入完成!");//提示传送完成

        printf("\n\r");

        Delay(0xFFFFFF);

        printf("\n\r");

        

        printf("\n\r开始从W25X16 SPI FLASH芯片读取数据.... ");

        SPI_Flash_Read(datatemp,1000,10000);//从1000地址处开始,读出SIZE个字节

        printf("\n\r读取完成,读出的数据为: %s  ",datatemp);//提示传送完成

        

        while(1)

        {

                

                i++;

                Delay(0xFFFF);

                if(i>0&& i<100)

                {

                        GPIO_SetBits(GPIOF, GPIO_Pin_6);;//提示系统正在运行        

                }

                else if(i >= 100 && i < 200)

                {

                        GPIO_ResetBits(GPIOF, GPIO_Pin_6);;//提示系统正在运行        

                }        

                i = i % 200;           

                }

        

        }

SPI FLASH--驱动部分
彭令鹏(bripengandre)的专栏
03-20 2万+
    最近花了一个多星期了一个SPI驱动。这个驱动是用来SPI接口的BIOS Flash的。貌似这个FLASHSPI对端(及主控制端)是与其它设备共同通过一个PCI桥接设备挂在PCI总线上。    SPI接口四条线,一个时钟CLK,一个片选CE,以及两数据线MOSI和MISO(主出从入和主入从出)。由于这里的SPI时序等都已经由SPI控制器做好了,所以我要做的就是些那些控制器上的寄
STM32 SPI方式flash
09-09
STM32以SPI方式FLASH中的数据。
FLASH驱动stm32 SPI 驱动FLASH C语言
11-17
stm32驱动SPI flashFlash型号为sst25vf512,驱动连接快速,提供给驱动的朋友参考,虽然基于freeRTOS,但是容易移植,只需要替换很少的几句代码就可以了。亲测可用,稳定性也不错。
关于STM32的SPI外设时钟分频对应的速率
最新发布
qq_51182593的博客
05-06 328
系统默认配置是fPCLK2=72MHz,fPCLK1=36MHz。SPI最大能达到的速率是fPCLK/2,也就是SPI1最大能达到36M,SPI2最大能达到18M。我们一些喜欢嵌入式的朋友一起建立的一个技术交流平台,本着大家一起互相学习的心态而建立,不太成熟,希望志同道合的朋友一起来。QQ群372991598。上述的fPCLK对于SPI1来说是fPCLK2,对于SPI2来说是fPCLK1。可见:SPI1是在挂APB2上的,SPI2是挂在APB1上的。SPI的波特率控制有8种分频可选。
STM32-F407使用SPI通讯协议取与Flash数据
12-31
基于STM32-F407芯片外设SPI取、FLASH中存储的数据,FLASH选用型号为W25Q128.
STM32—SPI详解入门(使用SPI通讯W25Q128模块)
Ai1101224的博客
06-06 9055
(句柄结构体)SPI_HandleTypeDef/* SPIx *//* SPI初始化结构体:通信参数 */(初始化结构体)SPI_InitTypeDefSPI/* SPI模式(主机模式。从机模式) *//* 工作方式(全双工方式、半双工、只、只) *//* 数据格式(8bit、16bit) *//* 时钟极性(CPOL) *//* 时钟相位(CPHA) *//* SS控制方式(软件) *//* SPI波特率预分频值 *//* 数据传输顺序(MSB、LSB) */
ZYNQ-Linux开发之(七)国产化复旦微电子FMQL平台uboot和kernel无法识别国产SPI Flash 芯片以及分区的问题
qq_38584212的博客
08-01 2733
这里面我添加了几行打印信息,打印的是uboot启动后取的spi flash芯片实际的ID值,系统启动后进入uboot指令,输入:sf probe,即可查看,一共是6个值,分为两组,前三个为flash芯片的Manufacture ID,也就是0x010219,后三个为Device ID的值,也就是0x4d0180,或者是0x4d01,具体情况跟芯片的型号有关,同时可以查看芯片手册来确定上面的两个ID的值。(1)进入到SDK中,找到如下目录中的spi_flash.c文件,双击打开,找到如下函数。
STM32在使用SPI时,你真的使用了CRC功能吗?
奥丁的博客
06-15 1万+
在进行STM32的SPI使用时,如果使用的是库函数版本,经常会用CRC的设置,其实很多时候没有使用CRC的功能。
FLASH存储器系列五】SPI NOR FLASH芯片使用指导之一
highman110的博客
11-02 8118
详细描述华邦某款spi nor flash的芯片特性及器件操作
STM32】HAL库中的SPI传输(可利用中断或DMA进行连续传输)
网易独家音乐人Mike Zhou的博客
11-30 1万+
STM32】HAL库中的SPI传输(可利用中断或DMA进行连续传输)
w25q128 优化函数
weixin_30566149的博客
06-18 1209
#include "w25qxx.h" #include "spi.h" #include "delay.h" #include "usart.h" u16 W25QXX_TYPE=W25Q128; //默认是W25Q128 //4Kbytes为一个Sector //16个扇区为1个Block //W25Q128 //容量为16M字节,共有128个Block,40...
stm32 spi方式EEPROM
08-23
stm32 spi方式EEPROM,有c源码。完成对at25128芯片的基本配置,实现对at25128的单字节的以及多字节的
STM32 I2C(SPIEEPROM
04-18
在ST官网下载了一个I2CEEPROM的例子,MDK5和IAR都能打开,并且有图纸、详尽的说明文件,这个文档作为STM32F4xx_HAL_Driver库的补充,既然官方发布了补充文档,说明之前的文档存在不足,此补充文档是否能全面解决...
016 - STM32学习笔记 - SPIFLASH(一)
guanxiaozhi的博客
07-09 1714
SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线。在SPI总线中,一共有四条线:SCLK:同步时钟信号线,用于通讯数据同步。由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如 STM32 的 SPI 时钟频率最大为fpclk/2,两个设备之间通讯时,通讯速率由最低速率设备决定。
2022-10-6 SPI实验(数码管)(复习)
m0_58344947的博客
10-06 554
4.时钟由Master控制,在时钟移位脉 冲下,数据按位传输,高位在前,低位在后(MSB first) 5.SPI接口有2根单向数据线,为全双工 通信,目前应用中的数据速率可达几Mbps的水平。• (4)/SS:从器件使能信号,由主器件控制(片选)7.本次实验:SOC数码管。• (1)MOSI:主器件数据输出,从器件数据输入。• (2)MISO:主器件数据输入,从器件数据输出。• (3)SCLK :时钟信号,由主器件产生。SPI硬件的连接有如下。最后是主函数的调用部分。
STM32的SPI硬件CRC校验(个人学习记录)
XUEXIDEXIAOhai的博客
05-10 4592
同样,接收到的CRC与SPI_RXCRCR值进行比较,如果比较不相配,则设置SPI_SR上的CRCERR标志位,当设置了SPI_CR2寄存器的ERRIE时,则产生中断。● 在把最后一个字节或半字进发送缓冲器时,设置SPI_CR1的CRCNext位,指示硬件在发送完成最后一个数据之后,发送CRC的数值。不知道为啥,SPI传输的第一个数据总是不正确,后面的数据不会有影响,我不理解。● 通过设置SPI_CR1寄存器CRCEN位使能CRC计算,该操作也会清除寄存器SPI_RXCRCR 和SPI_TXCRC;
STM32CubeMX学习笔记(10)——SPI接口使用(SPI Flash W25Q64)
热门推荐
Leung的博客
01-27 2万+
一、SPI简介 SPI(Serial Peripheral Interface) 协议是由摩托罗拉公司提出的通讯协议,即串行外围设备接口,是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间,要求通讯速率较高的场合。 芯片的管脚上只占用四根线。 MISO: 主器件数据输出,从器件数据输入。 MOSI:主器件数据输入,从器件数据输出。 SCK: 时钟信号,由主设备控制发出。 NSS(CS): 从设备选择信号,由主设备控制。当NSS为低电平则选中从器件。 二、引脚分布 ST
stm32spi实战(硬件+模拟)
qq_51426845的博客
07-07 3433
接着开始的信号,开始信号拉低了ss,这个时候就能把数据发出去了(只管主机,从机代码不是我们的)发出去之后拉高时钟线(这里我们用的模式0,时钟线空闲时为0,所以第一个操作只能是拉高)拉高之后就能执行取的操作了,就是讲函数入的字节,一位一位的发出去,我们将发送的数据与0x80相与就能发出最高位,之后在与0x40相与就能发出第二位,这样我们直接一个循环,让0x80依次右移一位,0x1000 0000 这样有数据的位就能发送出去了。就是刚好只变最后一个字节的存储计数为255字节。
STM32 SPI协议过程
05-10
STM32 SPI协议的过程大致如下: 1. 配置SPI控制器 首先需要配置SPI控制器,包括时钟极性、时钟相位、数据位长度、传输模式等参数。 2. 配置SPI从设备 需要配置SPI从设备的参数,包括从设备的地址、数据格式、传输速率等等。 3. 发送数据 通过SPI控制器发送数据到从设备,可以使用SPI发送寄存器(SPI_DR)来发送数据。 4. 接收数据 从设备将数据传输回来后,可以使用SPI接收寄存器(SPI_DR)来取数据。 5. 等待传输完成 等待数据传输完成,可以使用SPI状态寄存器(SPI_SR)来检查传输是否完成。如果传输完成,SPI_SR寄存器的TXE(传输空闲)和RXNE(接收缓冲区非空)位将会被置位。 6. 关闭SPI控制器 传输完成后,需要关闭SPI控制器以释放资源。 以上是SPI协议的基本过程,不同的应用场景可能需要做出一些微调。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • MOS管驱动电路,看这里就啥都懂了! 115302
  • stm32深入浅出——由GPIO谈谈寄存器配置 71238
  • 构造函数的作用和特点 37902
  • 电力电子仿真软件对比分析 27230
  • 希尔伯特(Hilbert)空间和巴拿赫(Banach)空间 27204

分类专栏

  • 困难公式推导 2篇
  • slam 12篇
  • 机器视觉 87篇
  • embedded 454篇
  • 感悟 4篇
  • 编程 4篇
  • 经验分享 5篇
  • 机器学习 84篇

最新评论

  • RuntimeError: CUDA error: CUBLAS_STATUS_NOT_SUPPORTED when calling `cublasSgemmStridedBatched` 报错解决

    小猪_sun: 有用,解决了我遇到的问题

  • 200+ 特征提取匹配方案

    啥也不会的研究僧: 博主,请问上述实验中的pose estimation AUC是什么意思呢?应该如何计算呢?

  • Stm32的TFT LCD显示器控制学习笔记

    C2291252737: 这种高质量文章真的巨难找

  • 图像的三种分形维数的计算方法

    甜司康饼哟: 甚至专门加上了ばか表情包

  • 图像的三种分形维数的计算方法

    甜司康饼哟: 哈哈哈哈哈

大家在看

  • 文件系统与日志分析
  • 《软件项目管理》
  • 虚拟户,代付系统,第三方支付通道
  • XCPC常用算法 249
  • Spring Boot中整合Jasypt 使用自定义注解+AOP实现敏感字段的加解密 1885

最新文章

  • FAST-LIO 雅可比推导方法二
  • FAST-LIO 雅可比推导方法一
  • win10 opencv4.9.0 + contrib 编译安装 ffmpeg ippicv boostdesc vgg_generated 下载失败及 setlocal 错误解决(附文件下载)
2024年24篇
2023年22篇
2021年33篇
2020年58篇
2019年62篇
2018年216篇
2017年226篇
2016年39篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

聚圣源夏知星想起个公司名称求推荐起名字测试打分易经性生活观看五行缺少什么起名亦起名新超越极限2.44闭锁病栋羊蝎子火锅加盟婴儿起名大全女人的武器分集剧情关于艾的公司起名闽南日报关于成长的作文辐射4修改器梦见开车向命运挑战盛字怎么起名字农产品方面的品牌起名梦见牛群专业起名称文化公司的起名广州萤火虫侵犯个人名誉权可以起诉吗免费女宝宝起名恐怖邮差2月2日是什么星座醋葫芦宫洺扮演者给女孩起名楚辞淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻让美丽中国“从细节出发”清明节放假3天调休1天男孩疑遭霸凌 家长讨说法被踢出群国产伟哥去年销售近13亿网友建议重庆地铁不准乘客携带菜筐雅江山火三名扑火人员牺牲系谣言代拍被何赛飞拿着魔杖追着打月嫂回应掌掴婴儿是在赶虫子山西高速一大巴发生事故 已致13死高中生被打伤下体休学 邯郸通报李梦为奥运任务婉拒WNBA邀请19岁小伙救下5人后溺亡 多方发声王树国3次鞠躬告别西交大师生单亲妈妈陷入热恋 14岁儿子报警315晚会后胖东来又人满为患了倪萍分享减重40斤方法王楚钦登顶三项第一今日春分两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?周杰伦一审败诉网易房客欠租失踪 房东直发愁男子持台球杆殴打2名女店员被抓男子被猫抓伤后确诊“猫抓病”“重生之我在北大当嫡校长”槽头肉企业被曝光前生意红火男孩8年未见母亲被告知被遗忘恒大被罚41.75亿到底怎么缴网友洛杉矶偶遇贾玲杨倩无缘巴黎奥运张立群任西安交通大学校长黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发妈妈回应孩子在校撞护栏坠楼考生莫言也上北大硕士复试名单了韩国首次吊销离岗医生执照奥巴马现身唐宁街 黑色着装引猜测沈阳一轿车冲入人行道致3死2伤阿根廷将发行1万与2万面值的纸币外国人感慨凌晨的中国很安全男子被流浪猫绊倒 投喂者赔24万手机成瘾是影响睡眠质量重要因素春分“立蛋”成功率更高?胖东来员工每周单休无小长假“开封王婆”爆火:促成四五十对专家建议不必谈骨泥色变浙江一高校内汽车冲撞行人 多人受伤许家印被限制高消费

聚圣源 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化