0755-26411760

falsh样例讲解
时间:2018-062820
深圳市盛路物联通讯技术有限公司1
FLASH(SPI) 样例讲解
目的:使用SPI 接口控制读写FLASH 芯片。
开发板上所使用的FLASH 芯片是W25X40,W25X40 外接线路图如下所示:
该FLASH 支持标准的SPI 接口,操作方法与并行接口一致,但其扇区组织类似,从最大到最
小区域分为芯片-块-扇区-页。编程算法则也是通过写命令序列的方式,如发送命令字-发送
字节-发送数据-查询状态寄存器。保护方式是通过存储器中的一些非易失性的位置0 或置1
选择性地以扇区或块为保护单位。
SPI 接口的使用的四个引脚介绍如下:
● MISO:主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据
● MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据
● SCK :串口时钟,作为主设备的输出,从设备的输入
● NSS :从设备选择
步骤:配置并初始化SPI 接口
使用SPI 擦除指定扇区
使用SPI 在相同扇区写入数据
使用SPI 在相同扇区读取数据并比较,检测FLASH 芯片
本样例采用ST 官方库开发,使用spi 外设,记得打开stm8l15x_conf.h 的#include
"stm8l15x_spi.h"
SPI 初始化及FLASH 读写测试代码如下:
/**************************************************************
*
*
* SPI2 初始化配置
*
*
****************************************************************/
void HAL_SPI2_cofig(void)
{
// 配置spi2 的GPIO
GPIO_Init(GPIOD,GPIO_Pin_4,GPIO_Mode_In_FL_No_IT);// MISO-PD4
GPIO_Init(GPIOD,GPIO_Pin_5,GPIO_Mode_Out_PP_High_Fast);// MOSI-PD5
深圳市盛路物联通讯技术有限公司2
GPIO_Init(GPIOD,GPIO_Pin_6,GPIO_Mode_Out_PP_High_Fast);// CLK-PD6
//GPIO_ExternalPullUpConfig(GPIOD, GPIO_Pin_6 | GPIO_Pin_5|GPIO_Pin_4, ENABLE);
GPIO_Init(SPI_CS_GPIO,SPI_CS_PIN,GPIO_Mode_Out_PP_High_Fast);// CS-PD7
CLK_PeripheralClockConfig(CLK_Peripheral_SPI2,ENABLE);// 使能外设时钟
SPI_Init( SPI2,
SPI_FirstBit_MSB,
SPI_BaudRatePrescaler_4,
SPI_Mode_Master,
SPI_CPOL_Low,
SPI_CPHA_1Edge,
SPI_Direction_2Lines_FullDuplex ,
SPI_NSS_Soft,
0X07
);
SPI_Cmd(SPI2, ENABLE);
}
/**************************************************************
*
*
* SPI2 发送指令/数据到w25x40 ,同时读取一个w25x40 返回数据
*
*
****************************************************************/
U8 HAL_SPI2_SendReadByte(U8 data)
{
U8 retry=0;
volatile U8 dat;
while( SPI_GetFlagStatus(SPI2,SPI_FLAG_TXE) == RESET )// 等待发送完成
{
retry++;
if(retry >200)
{
return 0;
}
}
深圳市盛路物联通讯技术有限公司3
SPI_SendData( SPI2, data); //通过SPIx 发送一个byte 数据
while( SPI_GetFlagStatus(SPI2,SPI_FLAG_RXNE) == RESET )// 等待接收一个数据
{
retry++;
if(retry >200)
{
return 0;
}
}
return SPI_ReceiveData(SPI2);//返回SPI2 最近的一个数据
}
/**************************************************************
*
*
* w25x40 读取JEDECID
*
*
****************************************************************/
void SPI_FLASH_ID_check(void)
{
U32 ID = 0;
U32 tmp;
FLASH_SPI_CS_ENABLE(); //使能FLASH 的SPI 通信
HAL_SPI2_SendReadByte(READJEDECID_CMD); //发送获取芯片的JEDEC ID 指令
tmp= HAL_SPI2_SendReadByte(FLASH_DUMMY_BYTE);//读取FLASH ID 的高位
ID |= tmp<<16;
tmp = HAL_SPI2_SendReadByte(FLASH_DUMMY_BYTE);//读取FLASH ID 的中位
ID |= tmp<<8;
tmp= HAL_SPI2_SendReadByte(FLASH_DUMMY_BYTE) ;//读取FLASH ID 的低位
ID |= tmp;
if(FLASH_W25X40_JEDEC_ID == ID)
{//如果获取的ID 与芯片ID 一致
printf("\r\n Flash chip is W25x40\r\n");
}
else
{
深圳市盛路物联通讯技术有限公司4
printf("\r\n Flash chip cann`t recognise\r\n");
}
FLASH_SPI_CS_DISABLE(); //禁止FLASH 的SPI 通信
}
/**************************************************************
*
*
* 操作w25x40 时---写使能
*
*
****************************************************************/
void SPI_Flash_WriteEnable(void)
{
FLASH_SPI_CS_ENABLE();//使能FLASH 的SPI 通信
HAL_SPI2_SendReadByte(WRITEENABLE_CMD);//发送写入使能指令
FLASH_SPI_CS_DISABLE();//失能FLASH 的SPI 通信
}
/**************************************************************
*
*
* 擦除w25x40 的扇区
*
*
****************************************************************/
void HAL_SPI_FLASH_EraseSector(U32 FlashAddr)
{
SPI_Flash_WriteEnable();//FLASH 写入使能
FLASH_SPI_CS_ENABLE();//使能FLASH 的SPI 通信
HAL_SPI2_SendReadByte(SECTORERAS_CMD);//发送扇区擦除指令
HAL_SPI2_SendReadByte( (FlashAddr & 0x00FF0000) >> 16 );//发送擦除扇区起始地址高位
HAL_SPI2_SendReadByte( (FlashAddr & 0x0000FF00) >> 8 );//发送擦除扇区起始地址中位
HAL_SPI2_SendReadByte(FlashAddr & 0x000000FF);//发送擦除扇区起始地址低位
FLASH_SPI_CS_DISABLE();//失能FLASH 的SPI 通信
SPI_FLASH_WaitForWriteEnd();//等待FLASH 写入完成
}
/**************************************************************
*
*
* 等待写/擦除操作完成
*
*
****************************************************************/
深圳市盛路物联通讯技术有限公司5
void SPI_FLASH_WaitForWriteEnd(void)
{
U8 Flash_Write_Status = 1;
FLASH_SPI_CS_ENABLE();//使能FLASH 的SPI 通信
HAL_SPI2_SendReadByte(READSTAREG_CMD);//发送读状态寄存器1 指令
do
{
Flash_Write_Status = HAL_SPI2_SendReadByte(FLASH_DUMMY_BYTE);// 接收状态寄
存器1 的数据
}while((Flash_Write_Status & FLASH_BUSY_FLAG) == SET);//状态寄存器1 的第7 位为1,则
继续循环
FLASH_SPI_CS_DISABLE();//失能FLASH 的SPI 通信
}
/**************************************************************
*
*
* w25x40 页写
* pbuf:指向写入数据数据的缓存区
* addr: w25x40 的地址
* NumByte: 写入数据的字节数
*
*
****************************************************************/
void SPI_FLASH_WritePage(U8* pBuf, U32 Addr, U16 NumByte)
{
SPI_Flash_WriteEnable();//FLASH 写入使能
FLASH_SPI_CS_ENABLE();//使能FLASH 的SPI 通信
HAL_SPI2_SendReadByte(PAGEWRITE_CMD);//发送页写入指令
HAL_SPI2_SendReadByte((Addr & 0x00FF0000) >> 16);//发送该页起始地址高位
HAL_SPI2_SendReadByte((Addr & 0x0000FF00) >> 8);//发送该页地址中位
HAL_SPI2_SendReadByte(Addr & 0x000000FF);//发送该页地址低位
while (NumByte--)
{
HAL_SPI2_SendReadByte(*pBuf);//写入一个byte 数据
pBuf++;//写入数据地址递增
}
FLASH_SPI_CS_DISABLE();//失能FLASH 的SPI 通信
SPI_FLASH_WaitForWriteEnd();//等待FLASH 写入完成
}
深圳市盛路物联通讯技术有限公司6
/**************************************************************
*
*
* w25x40 读数据
* pbuf:指向读取数据放入的缓存区
* addr: w25x40 的地址
* NumByte: 读取数据的字节数
*
*
****************************************************************/
void HAL_SPI_FLASH_ReadBuffer(U8* pBuffer, U32 ReadAddr, U16 NumByteToRead)
{
FLASH_SPI_CS_ENABLE();//使能FLASH 的SPI 通信
HAL_SPI2_SendReadByte(READDATA_CMD);//发送读数据指令
HAL_SPI2_SendReadByte((ReadAddr & 0xFF0000) >> 16);//发送读数据的起始地址高位
HAL_SPI2_SendReadByte((ReadAddr& 0xFF00) >> 8);//发送读数据的起始地址中位
HAL_SPI2_SendReadByte(ReadAddr & 0xFF);//发送读数据的起始地址低位
while (NumByteToRead--)
{//循环读取的数据长度递减
*pBuffer = HAL_SPI2_SendReadByte(FLASH_DUMMY_BYTE);//读取FLASH 数据,存入数
据buff
pBuffer++;//读取数据buff 地址的递增
}
FLASH_SPI_CS_DISABLE();//失能FLASH 的SPI 通信
}
/**************************************************************
*
*
* w25x40 的测试函数
* 功能描述:擦除一个扇区(第一个扇区),读出内容,读取40 个字节
? 再在第一个扇区写入hello,读出内容
*
*
*
****************************************************************/
void flash_test(void)
{
U32 i=0,j=1;
U32 addr=0x00;
U8 tmp[5]={'h','e','l','l','o'};
HAL_SPI_FLASH_EraseSector(addr);
HAL_SPI_FLASH_ReadBuffer(s_buf,addr,40);
深圳市盛路物联通讯技术有限公司7
for(i=0;i<40;i++,j++)
{
printf("0x%x ",s_buf[i]);
if(j%4==0)
printf("\r\n");
}
printf("\r\n");
memset((void*)s_buf,0,40);
SPI_FLASH_WritePage(tmp, addr,5);
HAL_SPI_FLASH_ReadBuffer(s_buf,addr,6);
printf("s_buf:%s\r\n",s_buf);
}
Main 函数中的代码如下:
void main(void)
{
SYSCLK_Init();// 系统时钟初始化, HSI 16Mhz
HAL_USART_config();// 串口1 配置8N1: 8 个数据位,N:没有校验,1:一个停止位
HAL_SPI2_cofig(); // sp2 初始配置
enableInterrupts(); //使能中断
printf("uart is ok\r\n");
SPI_FLASH_ID_check();// 读取w25x40 的jedecid
flash_test();// 测试w25x40
while(1)
{
}
}
深圳市盛路物联通讯技术有限公司8

使用串口调试助手,可以看到如下图所示内容:


推荐阅读

深圳市盛路物联通讯技术有限公司

0755-26411760 (工作时间:周一至周五9 : 00-18:30)

slwl@dda-iot.com

公司地址:深圳市南山区粤海街道高新区社区高新南七道022号高新工业村T2-B栋2层

演示中心:深圳市南山区粤海街道高新区社区高新南七道022号高新工业村T2-B栋2层

微信公众号

手机浏览