编写SPI FALSH的读写擦除函数
/**
* @brief W25Qxx 擦除整个扇区
* @retval uint32_t First_Addr : 第几块
*/
int32_t W25Qxx_SPI_EraseSector(uint32_t addrNb)
{
addrNb*=4096;
uint8_t CommandArray[4] = {0};
int32_t res;
CommandArray[0] = 0x20; //擦除扇区指令 命令为0x20,在手册的21页
CommandArray[1] = First_Addr>>16;
CommandArray[2] = First_Addr>>8;
CommandArray[3] = First_Addr;//地址
res = W25Qxx_SPI_TransmitOneBaye(0x06); //write enable 命令为0x06,在手册的21页
if(!res)
{
W25Qxx_SPI_WaitBusy();
W25Qxx_SPI_CS_LOW();
res = HAL_SPI_Transmit(&w25qxx_spi,CommandArray,4,10);
W25Qxx_SPI_CS_HIGH();
W25Qxx_SPI_WaitBusy();
W25Qxx_SPI_TransmitOneBaye(0x04);//write disenable 命令为0x06,在手册的21页
}
return res;
}
/**
* @brief 使用DMA读取 W25Qxx 中的数据
* @retval uint32_t addr : 数据地址
uint8_t *readBuf : 读取数据的存储地址
uint16_t size : 读取数据的存储地址
*/
int32_t W25Qxx_SPI_ReadData(uint32_t addr,uint8_t *readBuf,uint16_t size)
{
int32_t res;
uint8_t CommandArray[4];
CommandArray[0] = 0x03; //读指令 命令为0x20,在手册的21页
CommandArray[1] = addr>>16;
CommandArray[2] = addr>>8;
CommandArray[3] = addr;//地址
W25Qxx_SPI_CS_LOW();
res = HAL_SPI_Transmit(&w25qxx_spi,CommandArray,4,10);
if(!res)
{
res = HAL_SPI_Receive_DMA(&w25qxx_spi,readBuf,size);
if(res) //如果失败,关闭片选引脚
W25Qxx_SPI_CS_HIGH();
else
W25Qxx_SPI_WaitDMARx();
}
else
W25Qxx_SPI_CS_HIGH();
return res;
}
/**
* @brief 使用DMA写 W25Qxx 的数据
* @retval uint32_t addr : 数据地址
uint8_t *pxData : 写数据的存储地址
uint16_t size : 读取数据的存储地址
*/
int32_t W25Qxx_SPI_WriteData(uint32_t addr,uint8_t *pxData,uint16_t size)
{
int32_t res;
uint8_t CommandArray[4];
CommandArray[0] = 0x02; //写指令 命令为0x20,在手册的21页
CommandArray[1] = addr>>16;
CommandArray[2] = addr>>8;
CommandArray[3] = addr;//地址
res = W25Qxx_SPI_TransmitOneBaye(0x06); //write enable 命令为0x06,在手册的21页
if(!res)
{
W25Qxx_SPI_WaitBusy();
W25Qxx_SPI_CS_LOW();
res = HAL_SPI_Transmit(&w25qxx_spi,CommandArray,4,10);
if(!res)
{
res = HAL_SPI_Transmit_DMA(&w25qxx_spi,pxData,size);
if(res)
W25Qxx_SPI_CS_HIGH();
}
else
W25Qxx_SPI_CS_HIGH();
W25Qxx_SPI_WaitDMATx();
W25Qxx_SPI_WaitBusy();
W25Qxx_SPI_TransmitOneBaye(0x04);//write disenable 命令为0x06,在手册的21页
}
return res;
}
挂载Littlefs
#include "Littlefs_W25Qxx.h"
#include "W25Qxx_SPI.h"
#include "lfs.h"
#include "cmsis_os.h"
//#include "bsp_error.h"
uint16_t DviceID = 0;
int error_code = 0;
lfs_t lfs;
lfs_file_t file;
static int user_provided_block_device_read(
const struct lfs_config *lfsc, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
{
W25Qxx_SPI_ReadData((block * lfsc->block_size + off),(uint8_t *)buffer,size);
return LFS_ERR_OK;
}
static int user_provided_block_device_prog(
const struct lfs_config *lfsc, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
{
W25Qxx_SPI_WriteData((block * lfsc->block_size + off),(uint8_t*)buffer,size);
return LFS_ERR_OK;
}
static int user_provided_block_device_erase(const struct lfs_config *lfsc, lfs_block_t block)
{
W25Qxx_SPI_EraseSector(block);
return LFS_ERR_OK;
}
static int user_provided_block_device_sync(const struct lfs_config *lfsc)
{
return LFS_ERR_OK;
}
static uint8_t lfs_read_cache_buf[256];
static uint8_t lfs_prog_cache_buf[256];
static uint8_t lfs_lookahead_buf[16]; // 128/8=16
char WriteBuf[] = {"Hi,Budy! if you get this Message......Congratulations!You have succeeded!!"};
char ReadBuf[80];
// configuration of the filesystem is provided by this struct
const struct lfs_config cfg = {
// block device driver context data
.context = NULL,
// block device operations
.read = user_provided_block_device_read, //读取数据
.prog = user_provided_block_device_prog, //编程一个扇区
.erase = user_provided_block_device_erase,//擦除一个扇区
.sync = user_provided_block_device_sync,
// block device configuration
.read_size = 256,//FLASH_PAGE_SIZE 页大小,读取块的最小大小。所有读取操作都将是
.prog_size = 256,//FLASH_PAGE_SIZE 页大小,块程序的最小大小。所有程序操作都将是
.block_size = 4096,//FLASH_SECTOR_SIZE 扇区大小
.block_count = 1024,//扇区数量
.cache_size = 256,//缓存大小
.block_cycles = 200,// 范围在100-1000之间,值越大,性能越好,但磨损分布不均匀。
.lookahead_size = 128,//前瞻缓冲区的大小(以字节为单位)。较大的超前缓冲区会增加分配过程中找到的块数。前瞻缓冲区存储为紧凑位图,因此RAM的每个字节可以跟踪8个块。必须是8的倍数。
.read_buffer = lfs_read_cache_buf,//长度必须是cache
.prog_buffer = lfs_prog_cache_buf,//长度必须是cache
.lookahead_buffer = lfs_lookahead_buf,
};
void Littlefs_Main(void *argument)
{
W25Qxx_Init();
W25Qxx_SPI_ReadDviceID(&DviceID);
int err = lfs_mount(&lfs, &cfg);
if (err)
{
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
}
//写一个文件的流程
// /*
lfs_file_open(&lfs, &file, "my_file", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, &WriteBuf, sizeof(WriteBuf));
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs);
// */
//删除一个文件的流程
/*
error_code = lfs_remove(&lfs,"my_file");
lfs_unmount(&lfs);
// */
for(;;)
{
//读一个文件的流程
// /*
lfs_file_open(&lfs, &file, "my_file", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, &ReadBuf, sizeof(ReadBuf));
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs);
// */
osDelay(1000);
}
}
/**
* @brief 写一个文件
*/
void fs_write(const char *file_name,const void *buffer,uint32_t size)
{
lfs_file_t file;
lfs_file_open(&lfs, &file, file_name, LFS_O_RDWR | LFS_O_CREAT);
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, buffer, size);
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs);
}
/**
* @brief 读一个文件
*/
void fs_read(const char *file_name,void *buffer,uint32_t size)
{
lfs_file_t file;
lfs_file_open(&lfs, &file, file_name, LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, buffer, size);
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs);
}
void app_mian(void *argument)
{
Littlefs_mount();
fs_write("config.txt",WriteBuf,sizeof(WriteBuf));
for(;;)
{
fs_read("config.txt",ReadBuf,sizeof(WriteBuf));
osDelay(1000);
}
}