基于MCU的文件系统

以后有机会就更新。

CubeMX配置

配置FATFS

驱动代码对接

user_diskio.c

修改user_diskio.c的初始化函数。因为我们的驱动芯片不需要初始化。

补充代码实现

1.读函数实现

cpp 复制代码
/**
  * @brief  Reads Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT USER_read (
	BYTE pdrv,      /* Physical drive nmuber to identify the drive */
	BYTE *buff,     /* Data buffer to store read data */
	DWORD sector,   /* Sector address in LBA */
	UINT count      /* Number of sectors to read */
)
{
  /* USER CODE BEGIN READ */
	uint32_t i = 0;
	
	for(i=0;i<count;i++)
	{
	 W25QXX_Read_Sector(buff+i*4096,sector+i);
	}
	
    return RES_OK;
  /* USER CODE END READ */
}

2.写函数

cpp 复制代码
/**
  * @brief  Writes Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */
#if _USE_WRITE == 1
DRESULT USER_write (
	BYTE pdrv,          /* Physical drive nmuber to identify the drive */
	const BYTE *buff,   /* Data to be written */
	DWORD sector,       /* Sector address in LBA */
	UINT count          /* Number of sectors to write */
)
{
  /* USER CODE BEGIN WRITE */
	
	uint32_t i = 0;
	
	for(i=0;i<count;i++)
	{
	 
	 W25QXX_Write_Sector((uint8_t *)buff+i*4096,sector+i);
	}
  /* USER CODE HERE */
    return RES_OK;
  /* USER CODE END WRITE */
}
#endif /* _USE_WRITE == 1 */

3.IO控制函数

cpp 复制代码
/**
  * @brief  I/O control operation
  * @param  pdrv: Physical drive number (0..)
  * @param  cmd: Control code
  * @param  *buff: Buffer to send/receive control data
  * @retval DRESULT: Operation result
  */
#if _USE_IOCTL == 1
DRESULT USER_ioctl (
	BYTE pdrv,      /* Physical drive nmuber (0..) */
	BYTE cmd,       /* Control code */
	void *buff      /* Buffer to send/receive control data */
)
{
  /* USER CODE BEGIN IOCTL */
    DRESULT res = RES_OK;
	  
	switch (cmd)
	{
	      case CTRL_SYNC :
            break;
        /* 扇区数量:*/
        case GET_SECTOR_COUNT:
          *(DWORD * )buff = 4096;		
            break;
				
        /* 扇区大小  */
        case GET_SECTOR_SIZE :
          *(WORD * )buff = 4096;
            break;
				
        /* 同时擦除扇区个数 */
        case GET_BLOCK_SIZE :
          *(DWORD * )buff = 1;
            break; 

        case CTRL_TRIM:
            break;			
				
				default: 
					res = RES_PARERR;
		}
    return res;
				
  /* USER CODE END IOCTL */
}
#endif /* _USE_IOCTL == 1 */

ffconf.h修改

将这两个宏修改为对应值。

cpp 复制代码
#define _MIN_SS    512  /* 512, 1024, 2048 or 4096 */
#define _MAX_SS    4096  /* 512, 1024, 2048 or 4096 */

fatfs.c

  1. MX_FATFS_Init()需要修改的地方
  1. 之后在fatfs.c添加的代码
cpp 复制代码
void mkfs(void)
{
 int res = 0;	
	
 printf("make a filesystem\r\n");
	
 res = f_mkfs("\\",1,_MAX_SS);
	
 printf("mkfs res : %d\r\n",res);
}
ZNS_CMD_EXPORT(mkfs,make a filesystem)

FATFS fs;

void mnt(void)
{
 int res = 0;	
	
 printf("mount a filesystem\r\n");
	
 res = f_mount(&fs,"\\",1);
	
 printf("mount res : %d\r\n",res);
}
ZNS_CMD_EXPORT(mnt,mount a filesystem)

FIL file;

void cf(int argc,char **argv)
{
 int res = 0;	
 int bwritten = 0;
	
 printf("Create file :%s\r\n",argv[1]); 
	
 res = f_open(&file,argv[1],FA_WRITE | FA_CREATE_ALWAYS);
	
 printf("Create file res:%d\r\n",res); 
	
 res = f_write(&file,"hello ZN!hello FS!!\r\n",21,&bwritten);
	
 printf("Write file res:%d\r\n",res); 
	
 f_close(&file);
	
}
ZNS_CMD_EXPORT(cf,open or create file)
	
void list_directory_files(const char* path) 
{
    FILINFO fno;
    DIR dir;
    FRESULT res;
 
    // 打开目录
    res = f_opendir(&dir, path);
    if (res == FR_OK) {
        for (;;) {
            // 读取目录项
            res = f_readdir(&dir, &fno);
            if (res != FR_OK || fno.fname[0] == 0) break; // 结束或文件名为空
 
            // 如果是文件,打印文件名
            //if (!FF_FS_RPATH(&fno)) 
						{
                printf("%s\r\n", fno.fname);
            }
        }
        f_closedir(&dir); // 关闭目录
    }
}

void ls(void)
{
 printf("List All Files\r\n");	
	
 list_directory_files("\\");
}
ZNS_CMD_EXPORT(ls,list all files)

uint8_t file_buf[100] = {0};

void type(int argc,char **argv)
{
 int res = 0;	
 int bread=0;
	
 printf("Show File Content\r\n");	
	
 res = f_open(&file,argv[1],FA_READ);
	
 printf("Open file res : %d\r\n",res);
	
 res = f_read(&file,file_buf,30,&bread);
	
 printf("Read file res : %d\r\n",res);
	
 elog_hexdump("",16,file_buf,bread);
	
 f_close(&file);
}
ZNS_CMD_EXPORT(type,show file content)

25Q128存储芯片驱动

基于25Q128存储芯片

芯片ID的读取

底层驱动代码实现

.c文件
cpp 复制代码
#include "w25q128.h"

#include "stdint.h"
#include "stm32f1xx_hal.h"

#include "shell.h"

#include "elog.h"

extern SPI_HandleTypeDef hspi2; 

uint8_t sector_buf[4096] = {0};

/**
 * @brief    SPI发送指定长度的数据
 * @param    buf  ------ 发送数据缓冲区首地址
 * @param    size ------ 要发送数据的字节数
 * @retval   成功返回HAL_OK
 */
static HAL_StatusTypeDef SPI_Transmit(uint8_t* send_buf, uint16_t size)
{
    return HAL_SPI_Transmit(&hspi2, send_buf, size, 100);
}
/**
 * @brief   SPI接收指定长度的数据
 * @param   buf  ------ 接收数据缓冲区首地址
 * @param   size ------ 要接收数据的字节数
 * @retval  成功返回HAL_OK
 */
static HAL_StatusTypeDef SPI_Receive(uint8_t* recv_buf, uint16_t size)
{
   return HAL_SPI_Receive(&hspi2, recv_buf, size, 100);
}
/**
 * @brief   SPI在发送数据的同时接收指定长度的数据
 * @param   send_buf  ------ 接收数据缓冲区首地址
 * @param   recv_buf  ------ 接收数据缓冲区首地址
 * @param   size ------ 要发送/接收数据的字节数
 * @retval  成功返回HAL_OK
 */
static HAL_StatusTypeDef SPI_TransmitReceive(uint8_t* send_buf, uint8_t* recv_buf, uint16_t size)
{
   return HAL_SPI_TransmitReceive(&hspi2, send_buf, recv_buf, size, 100);
}

/*等待超时时间*/
#define SPIT_FLAG_TIMEOUT         ((uint32_t)0x1000)
#define SPIT_LONG_TIMEOUT         ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
static __IO uint32_t  SPITimeout = SPIT_LONG_TIMEOUT;   
/**
  * @brief  等待超时回调函数
  * @param  None.
  * @retval None.
  */
static  uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
{
  /* 等待超时后的处理,输出错误信息 */
  // printf("SPI 等待超时!errorCode = %d",errorCode);
  return 0;
}
 /**
  * @brief  使用SPI发送一个字节的数据
  * @param  byte:要发送的数据
  * @retval 返回接收到的数据
  */
uint8_t SPI_FLASH_SendByte(uint8_t byte)
{
  SPITimeout = SPIT_FLAG_TIMEOUT;

  /* 等待发送缓冲区为空,TXE事件 */
  while (__HAL_SPI_GET_FLAG( &hspi2, SPI_FLAG_TXE ) == RESET)
   {
    if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
   }

  /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
  WRITE_REG(hspi2.Instance->DR, byte);

  SPITimeout = SPIT_FLAG_TIMEOUT;

  /* 等待接收缓冲区非空,RXNE事件 */
  while (__HAL_SPI_GET_FLAG( &hspi2, SPI_FLAG_RXNE ) == RESET)
   {
    if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(1);
   }

  /* 读取数据寄存器,获取接收缓冲区数据 */
  return READ_REG(hspi2.Instance->DR);
}

//=======================================================================

uint16_t W25Q128_ReadID(void)
{
 uint8_t send_cmd[4] = {ManufactDeviceID_CMD,0X00,0X00,0X00};
 uint8_t recv_data[2];
 
 SPI_FLASH_CS_LOW();
 
 SPI_Transmit(send_cmd,4);
 
 SPI_Receive(recv_data,2);
 
 return ((uint16_t *)recv_data)[0];
 
}

static uint8_t W25QXX_ReadSR()
{
 uint8_t result = 0; 
 uint8_t send_buf[4] = {READ_STATU_REGISTER_1,0x00,0x00,0x00};

 SPI_FLASH_CS_LOW();
    
 if(HAL_OK == SPI_Transmit(send_buf, 4)) 
 {
  if(HAL_OK == SPI_Receive(&result, 1)) 
  {
   SPI_FLASH_CS_HIGH();
		
   return result;
  }
 }
 
 SPI_FLASH_CS_HIGH();

 return 0;
}

static void W25QXX_Wait_Busy(void)
{
 while((W25QXX_ReadSR() & 0x01) == 0x01);
}

void W25QXX_Write_Enable(void)
{
 uint8_t cmd = WRITE_ENABLE_CMD;
    
 SPI_FLASH_CS_LOW();
    
 SPI_Transmit(&cmd, 1);
    
 SPI_FLASH_CS_HIGH();
    
 W25QXX_Wait_Busy();
}

void W25QXX_Erase_Sector(uint32_t sector_addr)
{   
 W25QXX_Write_Enable();  //擦除操作即写入0xFF,需要开启写使能
 W25QXX_Wait_Busy();     //等待写使能完成
 
 /* 使能片选 */
 SPI_FLASH_CS_LOW();
 
 /* 发送扇区擦除指令*/
 SPI_FLASH_SendByte(SECTOR_ERASE_CMD);
	
 /*发送擦除扇区地址的高位*/
 SPI_FLASH_SendByte((sector_addr & 0xFF0000) >> 16);
	
 /* 发送擦除扇区地址的中位 */
 SPI_FLASH_SendByte((sector_addr & 0xFF00) >> 8);
	
 /* 发送擦除扇区地址的低位 */
 SPI_FLASH_SendByte(sector_addr & 0xFF);
 
 /* 取消片选 */
 SPI_FLASH_CS_HIGH();
 
 W25QXX_Wait_Busy();       //等待扇区擦除完成
}

void W25QXX_Read_Sector(uint8_t* pBuffer, uint32_t nSector)
{  
 uint32_t ReadAddr = nSector << 12;	
	
 W25QXX_Wait_Busy();
    
 /* 选择FLASH: CS低电平 */
 SPI_FLASH_CS_LOW();

 /* 发送 读 指令 */
 uint8_t cmd = READ_DATA_CMD;
 SPI_Transmit(&cmd, 1);
    
 uint8_t addr;
 HAL_StatusTypeDef status;
 /* 发送 读 地址高位 */
 addr = (ReadAddr & 0xFF0000) >> 16;
 status = SPI_Transmit(&addr, 1);
 /* 发送 读 地址中位 */
 addr = (ReadAddr& 0xFF00) >> 8;
 status = SPI_Transmit(&addr, 1);
 /* 发送 读 地址低位 */
 addr = ReadAddr & 0xFF;
 status = SPI_Transmit(&addr, 1);
    
 if(HAL_OK == status)
 {
  SPI_Receive(pBuffer, 4096);
 }

 /* 停止信号 FLASH: CS 高电平 */
 SPI_FLASH_CS_HIGH();
}


void W25QXX_PageProgram(uint8_t* dat, uint32_t WriteAddr)
{
 uint8_t cmd = PAGE_PROGRAM_CMD;

 W25QXX_Write_Enable();
 
 /* 使能片选 */
 SPI_FLASH_CS_LOW();
 
 SPI_Transmit(&cmd, 1);

 uint8_t addr;
 HAL_StatusTypeDef status;
	
 /* 发送 地址高位 */
 addr = (WriteAddr & 0xFF0000) >> 16;
 status = SPI_Transmit(&addr, 1);
	
 /* 发送 地址中位 */
 addr = (WriteAddr & 0xFF00) >> 8;
 status = SPI_Transmit(&addr, 1);
	
 /* 发送 地址低位 */
 addr = WriteAddr & 0xFF;
 status = SPI_Transmit(&addr, 1);
 
 SPI_Transmit(dat, 256);
    
 /* 取消片选 */
 SPI_FLASH_CS_HIGH();
    
 W25QXX_Wait_Busy();
}


void W25QXX_Write_Sector(uint8_t* pBuffer, uint32_t nSector)
{
 uint32_t WriteAddr = nSector << 12;
 uint32_t i = 0;	
 
 for(i=0;i<16;i++)
  W25QXX_PageProgram(pBuffer, WriteAddr+i*256);

}

void sfrd(void)
{
 uint16_t id = 0;	
 id = W25Q128_ReadID();
	
 printf("chipid = %04X\r\n",id);
}

ZNS_CMD_EXPORT(sfrd,read spiflash chipid)

void sfes(int argc,char **argv)
{
	uint32_t addr = atoi(argv[1]);
	
	printf("To erase sector No.(%d)\r\n",addr);
	
	printf("erase sector addr : %d\r\n",addr<<12);
	
	W25QXX_Erase_Sector(addr<<12);
}

ZNS_CMD_EXPORT(sfes,erase sector with sector_no 0~4095)

void sfrs(int argc,char **argv)
{
	uint32_t addr = atoi(argv[1]);
	
	printf("To read sector No.(%d)\r\n",addr);
	
	printf("read sector addr : %d\r\n",addr<<12);
	
	W25QXX_Read_Sector(sector_buf,addr<<12);
	
	elog_hexdump("",16,sector_buf,4096);
}

ZNS_CMD_EXPORT(sfrs,read sector with sector_no 0~4095)

void sfws(int argc,char **argv)
{
	uint32_t addr = atoi(argv[1]);
	uint32_t i = 0;
	
	printf("To write sector No.(%d)\r\n",addr);
	
	printf("write sector addr : %d\r\n",addr<<12);
	
	for(i=0;i<4096;i++) sector_buf[i] = i;
	
	W25QXX_Write_Sector(sector_buf,addr<<12);

}

ZNS_CMD_EXPORT(sfws,write sector with sector_no 0~4095)
.h文件
cpp 复制代码
#ifndef _W25Q128_H_
#define _W25Q128_H_

#include "stdint.h"

#define SPI_FLASH_PageSize              256
#define SPI_FLASH_PerWritePageSize      256

#define ManufactDeviceID_CMD    0x90
#define READ_STATU_REGISTER_1   0x05
#define READ_STATU_REGISTER_2   0x35
#define READ_DATA_CMD           0x03
#define WRITE_ENABLE_CMD        0x06
#define WRITE_DISABLE_CMD       0x04
#define SECTOR_ERASE_CMD        0x20
#define CHIP_ERASE_CMD          0xc7
#define PAGE_PROGRAM_CMD        0x02
                  
#define SPI_FLASH_CS_LOW()      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
#define SPI_FLASH_CS_HIGH()     HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);

void W25QXX_Write_Sector(uint8_t* pBuffer, uint32_t nSector);
void W25QXX_Read_Sector(uint8_t* pBuffer, uint32_t nSector);


#endif

SFUD移植

相关推荐
爱隐身的官人4 小时前
Linux配置Java/JDK(解决Kali启动ysoserial.jar JRMPListener报错)暨 Kali安装JAVA8和切换JDK版本的详细过程
java·linux·kali
Algebraaaaa5 小时前
Linux 基本命令超详细解释第三期 grep | wc | 管道符‘|’ | echo | tail | 重定向符
linux
小生不才yz7 小时前
(三)命令管理-命令历史-history命令的使用
linux
DIY机器人工房8 小时前
关于解决 libwebsockets 库编译时遇到的问题的方法:
服务器·stm32·单片机·嵌入式硬件·tcp
aramae9 小时前
Linux开发工具入门:零基础到熟练使用(二)
linux·运维·服务器·网络·笔记
nassi_9 小时前
I/O详解
linux·php
GilgameshJSS9 小时前
STM32H743-ARM例程3-SYSTICK定时闪烁LED
arm开发·stm32·单片机·嵌入式硬件·学习
泡沫冰@10 小时前
shell编程:sed - 流编辑器(6)
linux
爱吃喵的鲤鱼10 小时前
仿muduo库One Thread One Loop主从Reactor模型实践——介绍
linux·c++