查看MM32F0140的MiniBoard原理图,SPI挂载了W25Q80。
一、SPI介绍
串行外设接口,Serial Peripheral Interface。一种高速的、全双工、同步的串行通信总线。主要应用于EEPROM、FLASH、AD转换器,还有数字信号处理器和数字信号解码器之间。
SPI 支持同时发送和接收数据,采用主从工作方式。SPI 通过 4 个引脚与外部器件相连,分别是:
MOSI:主设备输出、从设备输入引脚。传输方向为主设备发送到从设备。
MISO:主设备输入、从设备输出引脚。传输方向为从设备发送到主设备。
NSS:片选信号,从设备选择。
下图示意主、从设备之间一对一通信时的连接情况:
主设备负责发起通信请求,从设备负责响应,从设备通过 SCK 引脚得到主设备提供的时钟信号,从而使得主、从设备均使用同一个时钟进行同步的全双工通信。对于从设备而言,MOSI 引脚输入来自主设备的发送数据,MISO 引脚输出响应数据传给主设备。
SPI 需要根据从机特性,选配时钟极性(CPOL)和时钟相位(CPHA),比如从机时钟空闲时为低电平,且在时钟信号的第一个跳变沿采样,此时时序见下图:
二、W25Q80介绍
W25Q80是一种串行闪存存储器,主要特点包括:
容量:8 Mbit(1 MB)的存储容量,可以存储大量数据。
SPI接口:采用SPI接口进行数据通信,具备高速的数据传输能力。
快速读取:支持快速的连续读取操作,可提供高效的读取性能。
块擦除:支持块擦除功能,可以批量擦除数据,提高擦除效率。
低功耗:采用低功耗设计,适用于对功耗要求较高的应用场景。
W25Q80可以划分为 4096 个扇区,每个扇区包含 256 个页,每个页的大小为 256 字节。
下图为W25Q80的指令:
三、例程
1.介绍
本例程实现SPI与W25Q80通信,SPI查询W25Q80的设备号,并全片擦除后写入数据,再读取出来,看写入的数据与读取的数据是否一致。
2.编码详情
1)初始化配置SPI,速度为PCLK1(36MHz)的32分频,约为1.125MHz;
? ?SPI_InitStructure.SPI_Mode?=?SPI_Mode_Master;
????SPI_InitStructure.SPI_DataSize?=?SPI_DataSize_8b; ????SPI_InitStructure.SPI_DataWidth?=?8; ????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_32; ????SPI_InitStructure.SPI_FirstBit?=?SPI_FirstBit_MSB; ????SPI_Init(SPI2,?&SPI_InitStructure); ????exSPI_DataEdgeAdjust(SPI2,?SPI_DataEdgeAdjust_FAST); ????SPI_BiDirectionalLineConfig(SPI2,?SPI_Direction_Tx); ????SPI_BiDirectionalLineConfig(SPI2,?SPI_Direction_Rx); ????SPI_Cmd(SPI2,?ENABLE);
2)编写SPI发送和读取数据的函数
uint32_t?writeAndReadData(uint8_t?data) { ????SPI_SendData(SPI2,?data); ????while?(1)?{ ????????if(SPI_GetFlagStatus(SPI2,?SPI_FLAG_TXEPT))?{ ????????????break; ????????} ????} ????while?(1)?{ ????????if(SPI_GetFlagStatus(SPI2,?SPI_FLAG_RXAVL))?{ ????????????return?SPI_ReceiveData(SPI2); ????????} ????} }
3)获取W25Q80的设备ID
????SPI_CSInternalSelected(SPI2,?ENABLE);?//?片选 ????writeAndReadData(0x9F);?//?读ID指令 ????ID?|=?writeAndReadData(0x00)?<16; ????ID?|=?writeAndReadData(0x00)?<8; ????ID?|=?writeAndReadData(0x00); ????SPI_CSInternalSelected(SPI2,?DISABLE);?//?取消片选 ????printf(" read?device?id:?%X",?ID);
4)全片擦除W25Q80,并检查状态等待擦除完成
????SPI_CSInternalSelected(SPI2,?ENABLE);? ????writeAndReadData(0x06);?//?写使能 ????SPI_CSInternalSelected(SPI2,?DISABLE); ????SPI_CSInternalSelected(SPI2,?ENABLE); ????writeAndReadData(0xC7);?//?全片擦除指令 ????SPI_CSInternalSelected(SPI2,?DISABLE); ????SPI_CSInternalSelected(SPI2,?ENABLE);? ????writeAndReadData(0x05);?//?读状态寄存器 ????while(1)?{ ????????temp?=?writeAndReadData(0x00); ????????if((temp?&?0x01)?==?0x0)?//?擦除完成 ????????????break; ????} ????SPI_CSInternalSelected(SPI2,?DISABLE);? ????printf(" erase?complete");
5)写数据,并检查状态等待写完
????for?(i?=?0;?i?256;?i++)?txData[i]?=?i; ????SPI_CSInternalSelected(SPI2,?ENABLE); ????writeAndReadData(0x06);//?写使能 ????SPI_CSInternalSelected(SPI2,?DISABLE);? ????SPI_CSInternalSelected(SPI2,?ENABLE); ????writeAndReadData(0x02);?//?页编程 ????writeAndReadData(0x00);?//?页地址 ????writeAndReadData(0x00); ????writeAndReadData(0x00); ????for?(i?=?0;?i?256;?i++) ????{ ????????writeAndReadData(txData[i]); ????} ????SPI_CSInternalSelected(SPI2,?DISABLE);? ????SPI_CSInternalSelected(SPI2,?ENABLE); ????writeAndReadData(0x05);?//?读状态寄存器 ????while(1)?{ ????????temp?=?writeAndReadData(0x00); ????????if((temp?&?0x01)?==?0x0)?//?页编程完成 ????????????break; ????} ????SPI_CSInternalSelected(SPI2,?DISABLE); ????printf(" page?programm?complete");
6)读数据,并打印出来
????SPI_CSInternalSelected(SPI2,?ENABLE); ????writeAndReadData(0x03);?//?读数据 ????writeAndReadData(0x00);?//?页地址 ????writeAndReadData(0x00); ????writeAndReadData(0x00); ????for?(i?=?0;?i?10;?i++) ????{ ????????rxData[i]?=?writeAndReadData(0x00); ????} ????SPI_CSInternalSelected(SPI2,?DISABLE);? ????printf(" read?data?completely "); ????for?(i?=?0;?i?10;?i++)? ????????printf(" rxDate[%d]?=?%d",?i,?rxData[i]);
3.串口输出结果
下图为串口输出数据,基本符合程序流程和结果。
4.逻辑分析仪
下图为逻辑分析仪截取的发送接收图片,可以清楚的看到当前SCK速度接近1.125MHz,以及发送数据也符合预期。
编辑:黄飞
评论