①SPI—串行外设接口
(1)SDK;
(2)MOSI;
(3)MISO;
(4)时钟极性(CPOL):
< 1 > 0— 低电平开始;
< 2 > 1— 高电平开始;
(5)时钟相位(CPHA);
< 1 > 0— 第一边沿;
< 2 > 1— 第二边沿;
②SPI Flash(NorFlash)
(1)W25Q128
< 1 > CHIP—65536 pages—256 Blocks—256 BYtes / page—16 Mbytes;
< 2 > Sector—16 pages—4KB ytes(擦除最小单位);
< 3 > 128 Mbits—16 MBytes(擦除单位);
< 4 > HalfBlock—128 pages—8 sectors—32 KBytes(擦除单位);
< 5 > Block—256pages—16 sectors—64 KByte(擦除单位);
(2)通信—以指令方式进行交互
< 1 > SPI
1、时钟速度;
2、极性和相位;
3、有效位;
< 2 > CS
使用低电平保证每个操作都是低电平;
(3)指令
< 1 >写
1、写使能;
2、获取状态寄存器忙标志位;
3、页写(判定为非忙状态);
4、扇区擦除;
< 2 >读
1、读数据(判定为非忙状态);
< 3 >读ID
③ 任务使用SPI实现通信
代码:
#include "spi_use.h"
#include <string.h>
#define GetID 0xAB
#define WrEN 0x06
#define GetSR 0x05
#define PagePro 0x02
#define SecEr 0x20
#define ReData 0x03
#define PageSize 256
#define SecSize 4096
uint8_t SectorBuf[4096]={0};
int part = 0;
uint8_t Part_Buf[4][20]={"Hello,world !\r\n", "Hello,Sean !\r\n", "Hello,Tom !\r\n", "Hello,Billy !\r\n"};
void SPI5_Enable(void)
{
(SPI5->CR1)|=(1<<6);
}
/********************
实现SPI5 发送接收函数
********************/
uint8_t SPI5_RxTx_Byte(uint8_t data)
{
SPI5->DR = data; // 发送数
while(((SPI5->SR) &(1<<1))==0); //发送状态位判定
while(((SPI5->SR) &(1<<0))==0);
return SPI5->DR;
}
uint8_t Flash_GetID(void)
{
uint8_t temp;
Flash_cs_L();
SPI5_RxTx_Byte(GetID);
SPI5_RxTx_Byte(0xFF);
SPI5_RxTx_Byte(0xFF);
SPI5_RxTx_Byte(0xFF);
temp = SPI5_RxTx_Byte(0xFF);
Flash_cs_H();
return temp;
}
/***************
忙状态等待
**************/
void Wait_Busy(void)
{
uint8_t temp;
do
{
Flash_cs_L();
SPI5_RxTx_Byte(GetSR);
temp = SPI5_RxTx_Byte(0xFF);
Flash_cs_H();
}while(temp&0x01);
}
/*****************
写使能
*****************/
void Wirte_Enable(void)
{
Flash_cs_L();
SPI5_RxTx_Byte(WrEN);
Flash_cs_H();
}
/**********************
连续读数据
********************/
void Flash_Read(uint32_t Addr,uint8_t *buf,uint32_t size)
{
uint32_t i;
Wait_Busy();
Flash_cs_L();
SPI5_RxTx_Byte(ReData);
SPI5_RxTx_Byte((Addr>>16)&0xFF);
SPI5_RxTx_Byte((Addr>>8)&0xFF);
SPI5_RxTx_Byte((Addr>>0)&0xFF);
for(i=0;i<size;i++)
buf[i] = SPI5_RxTx_Byte(0xFF);
Flash_cs_H();
}
/******************
扇区擦除
******************/
void Sector_Erase(uint32_t Addr)
{
Wait_Busy();
Wirte_Enable();
Flash_cs_L();
SPI5_RxTx_Byte(SecEr);
SPI5_RxTx_Byte((Addr>>16)&0xFF);
SPI5_RxTx_Byte((Addr>>8)&0xFF);
SPI5_RxTx_Byte((Addr>>0)&0xFF);
Flash_cs_H();
}
/********************
页写
不用限制 数据大小
******************/
void Page_Write(uint32_t Addr,uint8_t *buf,uint32_t size)
{
uint32_t i;
Wait_Busy();
Wirte_Enable();
Flash_cs_L();
SPI5_RxTx_Byte(PagePro);
SPI5_RxTx_Byte((Addr>>16)&0xFF);
SPI5_RxTx_Byte((Addr>>8)&0xFF);
SPI5_RxTx_Byte((Addr>>0)&0xFF);
for(i=0;i<size;i++)
SPI5_RxTx_Byte(buf[i]);
Flash_cs_H();
}
/*****************
扇区内写
****************/
void Sector_Wirte(uint32_t Addr,uint8_t *buf,uint32_t size)
{
uint32_t temp;
while(1)
{
temp = PageSize -(Addr%PageSize);
if(temp>size)
temp = size;
Page_Write(Addr,buf,temp);
Addr += temp;
buf += temp;
size -= temp;
if(size == 0)
break;
}
}
/*****************
连续写
*******************/
void Flash_Write(uint32_t Addr,uint8_t *buf,uint32_t size)
{
uint32_t temp;
uint32_t Addr_S;
while(1)
{
temp = SecSize - (Addr%SecSize);
if(temp>size)
temp = size;
Addr_S = (Addr/SecSize)*SecSize;
Flash_Read(Addr_S,SectorBuf,SecSize); //读
Sector_Erase(Addr_S);
memcpy(&SectorBuf[Addr%SecSize],buf,temp); //改
Sector_Wirte(Addr_S,SectorBuf,SecSize);
Addr += temp;
buf += temp;
size -= temp;
if(size == 0)
break;
}
}
void Flash_Tel()
{
uint8_t buf[20];
switch(part)
{
case 0:
Flash_Write(0,Part_Buf[0],15);
memset(buf,0,20);
Flash_Read(0,buf,15);
printf("%s",buf);
break;
case 1:
Flash_Write(16,Part_Buf[1],14);
memset(buf,0,20);
Flash_Read(16,buf,14);
printf("%s",buf);
break;
case 2:
Flash_Write(32,Part_Buf[2],13);
memset(buf,0,20);
Flash_Read(32,buf,13);
printf("%s",buf);
break;
case 3:
Flash_Write(48,Part_Buf[3],15);
memset(buf,0,20);
Flash_Read(48,buf,15);
printf("%s",buf);
break;
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_0)
{
part ++;
if(part > 3)
part = 0;
Flash_