修复若干bug&完善fatfs服务&完善app
This commit is contained in:
166
mkrtos_user/server/fs/fatfs/ext_disk_drv/diskio.c
Normal file
166
mkrtos_user/server/fs/fatfs/ext_disk_drv/diskio.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* If a working storage control module is available, it should be */
|
||||
/* attached to the FatFs via a glue function rather than modifying it. */
|
||||
/* This is an example of glue functions to attach various exsisting */
|
||||
/* storage control modules to the FatFs module with a defined API. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include "ff.h" /* Obtains integer types */
|
||||
#include "diskio.h" /* Declarations of disk functions */
|
||||
#include "w25q64.h"
|
||||
#include <stdio.h>
|
||||
/* Definitions of physical drive number for each drive */
|
||||
#define DEV_EXT_FLASH 0 /* Example: Map Ramdisk to physical drive 0 */
|
||||
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
u16 FLASH_SECTOR_COUNT = 2048; // W25Q64,前12M字节给FATFS占用
|
||||
#define FLASH_BLOCK_SIZE 1 // 每个BLOCK有8个扇区
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status(
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
DSTATUS stat;
|
||||
int result;
|
||||
|
||||
switch (pdrv)
|
||||
{
|
||||
case DEV_EXT_FLASH:
|
||||
result = 0;
|
||||
if (W25QXX_ReadID() != W25Q64)
|
||||
{
|
||||
stat = RES_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
stat = RES_OK;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
return STA_NOINIT;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Inidialize a Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize(
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
DSTATUS stat;
|
||||
int result;
|
||||
|
||||
switch (pdrv)
|
||||
{
|
||||
case DEV_EXT_FLASH:
|
||||
result = 0;
|
||||
W25QXX_Init();
|
||||
// translate the reslut code here
|
||||
return disk_status(pdrv);
|
||||
}
|
||||
return STA_NOINIT;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read(
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
LBA_t sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
DRESULT res;
|
||||
|
||||
switch (pdrv)
|
||||
{
|
||||
case DEV_EXT_FLASH:
|
||||
for (; count > 0; count--)
|
||||
{
|
||||
W25QXX_Read(buff, sector * FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE);
|
||||
sector++;
|
||||
buff += FLASH_SECTOR_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#if FF_FS_READONLY == 0
|
||||
|
||||
DRESULT disk_write(
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
LBA_t sector, /* Start sector in LBA */
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
int result;
|
||||
|
||||
switch (pdrv)
|
||||
{
|
||||
case DEV_EXT_FLASH:
|
||||
for (; count > 0; count--)
|
||||
{
|
||||
W25QXX_Erase_Sector(sector); // 擦除这个扇区
|
||||
W25QXX_Write_NoCheck((u8 *)buff, sector * FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE);
|
||||
sector++;
|
||||
buff += FLASH_SECTOR_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_ioctl(
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
DRESULT res;
|
||||
int result;
|
||||
|
||||
switch (pdrv)
|
||||
{
|
||||
case DEV_EXT_FLASH:
|
||||
switch (cmd)
|
||||
{ // fatfs内核使用cmd调用
|
||||
case GET_SECTOR_COUNT: // sector count, 传入sect_cnt
|
||||
*(DWORD *)buff = FLASH_SECTOR_COUNT;
|
||||
return RES_OK;
|
||||
case GET_SECTOR_SIZE: // sector size, 传入block size(SD),单位bytes
|
||||
*(DWORD *)buff = FLASH_SECTOR_SIZE;
|
||||
return RES_OK;
|
||||
case GET_BLOCK_SIZE: // block size, 由上文可得,对于SD2.0卡最大8192,最小 1
|
||||
*(DWORD *)buff = FLASH_BLOCK_SIZE; // 单位为 sector(FatFs)
|
||||
return RES_OK;
|
||||
case CTRL_SYNC: // 同步命令,貌似FatFs内核用来判断写操作是否完成
|
||||
return RES_OK;
|
||||
}
|
||||
default:
|
||||
// printf("No device %d.\n", pdrv);
|
||||
break;
|
||||
}
|
||||
return RES_PARERR; // 默认返回参数错误
|
||||
}
|
||||
77
mkrtos_user/server/fs/fatfs/ext_disk_drv/diskio.h
Normal file
77
mkrtos_user/server/fs/fatfs/ext_disk_drv/diskio.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*-----------------------------------------------------------------------/
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2019 /
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
RES_NOTRDY, /* 3: Not Ready */
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
|
||||
DSTATUS disk_initialize (BYTE pdrv);
|
||||
DSTATUS disk_status (BYTE pdrv);
|
||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||
#define CTRL_EJECT 7 /* Eject media */
|
||||
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
||||
|
||||
/* MMC/SDC specific ioctl command */
|
||||
#define MMC_GET_TYPE 10 /* Get card type */
|
||||
#define MMC_GET_CSD 11 /* Get CSD */
|
||||
#define MMC_GET_CID 12 /* Get CID */
|
||||
#define MMC_GET_OCR 13 /* Get OCR */
|
||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
|
||||
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
|
||||
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
|
||||
|
||||
/* ATA/CF specific ioctl command */
|
||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||
#define ATA_GET_MODEL 21 /* Get model name */
|
||||
#define ATA_GET_SN 22 /* Get serial number */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
58
mkrtos_user/server/fs/fatfs/ext_disk_drv/spi1.c
Normal file
58
mkrtos_user/server/fs/fatfs/ext_disk_drv/spi1.c
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "stm32_sys.h" // Device header
|
||||
#include "spi1.h"
|
||||
void MySPI_Init(void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
GPIO_SetBits(GPIOB, GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7); // PB13/14/15上拉
|
||||
|
||||
SPI_InitTypeDef SPI_InitStructure;
|
||||
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
|
||||
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 设置SPI工作模式:设置为主SPI
|
||||
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 设置SPI的数据大小:SPI发送接收8位帧结构
|
||||
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // 串行同步时钟的空闲状态为高电平
|
||||
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // 串行同步时钟的第二个跳变沿(上升或下降)数据被采样
|
||||
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
|
||||
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // 定义波特率预分频的值:波特率预分频值为256
|
||||
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
|
||||
SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC值计算的多项式
|
||||
SPI_Init(SPI1, &SPI_InitStructure);
|
||||
|
||||
SPI_Cmd(SPI1, ENABLE);
|
||||
MySPI_SwapByte(0xff);
|
||||
}
|
||||
|
||||
void MySPI_SetSpeed(uint8_t SPI_BaudRatePrescaler)
|
||||
{
|
||||
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
|
||||
SPI1->CR1 &= 0XFFC7;
|
||||
SPI1->CR1 |= SPI_BaudRatePrescaler; // 设置SPI2速度
|
||||
SPI_Cmd(SPI1, ENABLE);
|
||||
}
|
||||
uint8_t MySPI_SwapByte(uint8_t ByteSend)
|
||||
{
|
||||
u8 retry = 0;
|
||||
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) // 检查指定的SPI标志位设置与否:发送缓存空标志位
|
||||
{
|
||||
retry++;
|
||||
if (retry > 200)
|
||||
return 0;
|
||||
}
|
||||
SPI_I2S_SendData(SPI1, ByteSend); // 通过外设SPIx发送一个数据
|
||||
retry = 0;
|
||||
|
||||
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) // 检查指定的SPI标志位设置与否:接受缓存非空标志位
|
||||
{
|
||||
retry++;
|
||||
if (retry > 200)
|
||||
return 0;
|
||||
}
|
||||
return SPI_I2S_ReceiveData(SPI1); // 返回通过SPIx最近接收的数据
|
||||
}
|
||||
5
mkrtos_user/server/fs/fatfs/ext_disk_drv/spi1.h
Normal file
5
mkrtos_user/server/fs/fatfs/ext_disk_drv/spi1.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void MySPI_Init(void);
|
||||
void MySPI_SetSpeed(uint8_t SPI_BaudRatePrescaler);
|
||||
uint8_t MySPI_SwapByte(uint8_t ByteSend);
|
||||
268
mkrtos_user/server/fs/fatfs/ext_disk_drv/w25q64.c
Normal file
268
mkrtos_user/server/fs/fatfs/ext_disk_drv/w25q64.c
Normal file
@@ -0,0 +1,268 @@
|
||||
#include "stm32_sys.h" // Device header
|
||||
#include "spi1.h"
|
||||
#include "w25q64.h"
|
||||
|
||||
u16 W25QXX_TYPE = W25Q64; // 默认是W25Q128
|
||||
|
||||
// 4Kbytes为一个Sector
|
||||
// 16个扇区为1个Block
|
||||
// W25Q128
|
||||
// 容量为16M字节,共有128个Block,4096个Sector
|
||||
|
||||
// 初始化SPI FLASH的IO口
|
||||
void W25QXX_Init(void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // PORTB时钟使能
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // PA4 推挽
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
GPIO_SetBits(GPIOA, GPIO_Pin_4);
|
||||
|
||||
W25QXX_CS = 1; // SPI FLASH不选中
|
||||
MySPI_Init(); // 初始化SPI
|
||||
MySPI_SetSpeed(SPI_BaudRatePrescaler_2); // 设置为18M时钟,高速模式
|
||||
W25QXX_TYPE = W25QXX_ReadID(); // 读取FLASH ID.
|
||||
}
|
||||
|
||||
// 读取W25QXX的状态寄存器
|
||||
// BIT7 6 5 4 3 2 1 0
|
||||
// SPR RV TB BP2 BP1 BP0 WEL BUSY
|
||||
// SPR:默认0,状态寄存器保护位,配合WP使用
|
||||
// TB,BP2,BP1,BP0:FLASH区域写保护设置
|
||||
// WEL:写使能锁定
|
||||
// BUSY:忙标记位(1,忙;0,空闲)
|
||||
// 默认:0x00
|
||||
u8 W25QXX_ReadSR(void)
|
||||
{
|
||||
u8 byte = 0;
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_ReadStatusReg); // 发送读取状态寄存器命令
|
||||
byte = MySPI_SwapByte(0Xff); // 读取一个字节
|
||||
W25QXX_CS = 1; // 取消片选
|
||||
return byte;
|
||||
}
|
||||
// 写W25QXX状态寄存器
|
||||
// 只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
|
||||
void W25QXX_Write_SR(u8 sr)
|
||||
{
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_WriteStatusReg); // 发送写取状态寄存器命令
|
||||
MySPI_SwapByte(sr); // 写入一个字节
|
||||
W25QXX_CS = 1; // 取消片选
|
||||
}
|
||||
// W25QXX写使能
|
||||
// 将WEL置位
|
||||
void W25QXX_Write_Enable(void)
|
||||
{
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_WriteEnable); // 发送写使能
|
||||
W25QXX_CS = 1; // 取消片选
|
||||
}
|
||||
// W25QXX写禁止
|
||||
// 将WEL清零
|
||||
void W25QXX_Write_Disable(void)
|
||||
{
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_WriteDisable); // 发送写禁止指令
|
||||
W25QXX_CS = 1; // 取消片选
|
||||
}
|
||||
// 读取芯片ID
|
||||
// 返回值如下:
|
||||
// 0XEF13,表示芯片型号为W25Q80
|
||||
// 0XEF14,表示芯片型号为W25Q16
|
||||
// 0XEF15,表示芯片型号为W25Q32
|
||||
// 0XEF16,表示芯片型号为W25Q64
|
||||
// 0XEF17,表示芯片型号为W25Q128
|
||||
u16 W25QXX_ReadID(void)
|
||||
{
|
||||
u16 Temp = 0;
|
||||
W25QXX_CS = 0;
|
||||
MySPI_SwapByte(0x90); // 发送读取ID命令
|
||||
MySPI_SwapByte(0x00);
|
||||
MySPI_SwapByte(0x00);
|
||||
MySPI_SwapByte(0x00);
|
||||
Temp |= MySPI_SwapByte(0xFF) << 8;
|
||||
Temp |= MySPI_SwapByte(0xFF);
|
||||
W25QXX_CS = 1;
|
||||
return Temp;
|
||||
}
|
||||
// 读取SPI FLASH
|
||||
// 在指定地址开始读取指定长度的数据
|
||||
// pBuffer:数据存储区
|
||||
// ReadAddr:开始读取的地址(24bit)
|
||||
// NumByteToRead:要读取的字节数(最大65535)
|
||||
void W25QXX_Read(u8 *pBuffer, u32 ReadAddr, u16 NumByteToRead)
|
||||
{
|
||||
u16 i;
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_ReadData); // 发送读取命令
|
||||
MySPI_SwapByte((u8)((ReadAddr) >> 16)); // 发送24bit地址
|
||||
MySPI_SwapByte((u8)((ReadAddr) >> 8));
|
||||
MySPI_SwapByte((u8)ReadAddr);
|
||||
for (i = 0; i < NumByteToRead; i++)
|
||||
{
|
||||
pBuffer[i] = MySPI_SwapByte(0XFF); // 循环读数
|
||||
}
|
||||
W25QXX_CS = 1;
|
||||
}
|
||||
// SPI在一页(0~65535)内写入少于256个字节的数据
|
||||
// 在指定地址开始写入最大256字节的数据
|
||||
// pBuffer:数据存储区
|
||||
// WriteAddr:开始写入的地址(24bit)
|
||||
// NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
|
||||
void W25QXX_Write_Page(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
|
||||
{
|
||||
u16 i;
|
||||
W25QXX_Write_Enable(); // SET WEL
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_PageProgram); // 发送写页命令
|
||||
MySPI_SwapByte((u8)((WriteAddr) >> 16)); // 发送24bit地址
|
||||
MySPI_SwapByte((u8)((WriteAddr) >> 8));
|
||||
MySPI_SwapByte((u8)WriteAddr);
|
||||
for (i = 0; i < NumByteToWrite; i++)
|
||||
MySPI_SwapByte(pBuffer[i]); // 循环写数
|
||||
W25QXX_CS = 1; // 取消片选
|
||||
W25QXX_Wait_Busy(); // 等待写入结束
|
||||
}
|
||||
// 无检验写SPI FLASH
|
||||
// 必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
|
||||
// 具有自动换页功能
|
||||
// 在指定地址开始写入指定长度的数据,但是要确保地址不越界!
|
||||
// pBuffer:数据存储区
|
||||
// WriteAddr:开始写入的地址(24bit)
|
||||
// NumByteToWrite:要写入的字节数(最大65535)
|
||||
// CHECK OK
|
||||
void W25QXX_Write_NoCheck(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
|
||||
{
|
||||
u16 pageremain;
|
||||
pageremain = 256 - WriteAddr % 256; // 单页剩余的字节数
|
||||
if (NumByteToWrite <= pageremain)
|
||||
pageremain = NumByteToWrite; // 不大于256个字节
|
||||
while (1)
|
||||
{
|
||||
W25QXX_Write_Page(pBuffer, WriteAddr, pageremain);
|
||||
if (NumByteToWrite == pageremain)
|
||||
break; // 写入结束了
|
||||
else // NumByteToWrite>pageremain
|
||||
{
|
||||
pBuffer += pageremain;
|
||||
WriteAddr += pageremain;
|
||||
|
||||
NumByteToWrite -= pageremain; // 减去已经写入了的字节数
|
||||
if (NumByteToWrite > 256)
|
||||
pageremain = 256; // 一次可以写入256个字节
|
||||
else
|
||||
pageremain = NumByteToWrite; // 不够256个字节了
|
||||
}
|
||||
};
|
||||
}
|
||||
// 写SPI FLASH
|
||||
// 在指定地址开始写入指定长度的数据
|
||||
// 该函数带擦除操作!
|
||||
// pBuffer:数据存储区
|
||||
// WriteAddr:开始写入的地址(24bit)
|
||||
// NumByteToWrite:要写入的字节数(最大65535)
|
||||
// u8 W25QXX_BUFFER[4096];
|
||||
// void W25QXX_Write(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
|
||||
// {
|
||||
// u32 secpos;
|
||||
// u16 secoff;
|
||||
// u16 secremain;
|
||||
// u16 i;
|
||||
// u8 *W25QXX_BUF;
|
||||
// W25QXX_BUF = W25QXX_BUFFER;
|
||||
// secpos = WriteAddr / 4096; // 扇区地址
|
||||
// secoff = WriteAddr % 4096; // 在扇区内的偏移
|
||||
// secremain = 4096 - secoff; // 扇区剩余空间大小
|
||||
// // printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用
|
||||
// if (NumByteToWrite <= secremain)
|
||||
// secremain = NumByteToWrite; // 不大于4096个字节
|
||||
// while (1)
|
||||
// {
|
||||
// W25QXX_Read(W25QXX_BUF, secpos * 4096, 4096); // 读出整个扇区的内容
|
||||
// for (i = 0; i < secremain; i++) // 校验数据
|
||||
// {
|
||||
// if (W25QXX_BUF[secoff + i] != 0XFF)
|
||||
// break; // 需要擦除
|
||||
// }
|
||||
// if (i < secremain) // 需要擦除
|
||||
// {
|
||||
// W25QXX_Erase_Sector(secpos); // 擦除这个扇区
|
||||
// for (i = 0; i < secremain; i++) // 复制
|
||||
// {
|
||||
// W25QXX_BUF[i + secoff] = pBuffer[i];
|
||||
// }
|
||||
// W25QXX_Write_NoCheck(W25QXX_BUF, secpos * 4096, 4096); // 写入整个扇区
|
||||
// }
|
||||
// else
|
||||
// W25QXX_Write_NoCheck(pBuffer, WriteAddr, secremain); // 写已经擦除了的,直接写入扇区剩余区间.
|
||||
// if (NumByteToWrite == secremain)
|
||||
// break; // 写入结束了
|
||||
// else // 写入未结束
|
||||
// {
|
||||
// secpos++; // 扇区地址增1
|
||||
// secoff = 0; // 偏移位置为0
|
||||
|
||||
// pBuffer += secremain; // 指针偏移
|
||||
// WriteAddr += secremain; // 写地址偏移
|
||||
// NumByteToWrite -= secremain; // 字节数递减
|
||||
// if (NumByteToWrite > 4096)
|
||||
// secremain = 4096; // 下一个扇区还是写不完
|
||||
// else
|
||||
// secremain = NumByteToWrite; // 下一个扇区可以写完了
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// 擦除整个芯片
|
||||
// 等待时间超长...
|
||||
void W25QXX_Erase_Chip(void)
|
||||
{
|
||||
W25QXX_Write_Enable(); // SET WEL
|
||||
W25QXX_Wait_Busy();
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_ChipErase); // 发送片擦除命令
|
||||
W25QXX_CS = 1; // 取消片选
|
||||
W25QXX_Wait_Busy(); // 等待芯片擦除结束
|
||||
}
|
||||
// 擦除一个扇区
|
||||
// Dst_Addr:扇区地址 根据实际容量设置
|
||||
// 擦除一个山区的最少时间:150ms
|
||||
void W25QXX_Erase_Sector(u32 Dst_Addr)
|
||||
{
|
||||
// 监视falsh擦除情况,测试用
|
||||
Dst_Addr *= 4096;
|
||||
W25QXX_Write_Enable(); // SET WEL
|
||||
W25QXX_Wait_Busy();
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_SectorErase); // 发送扇区擦除指令
|
||||
MySPI_SwapByte((u8)((Dst_Addr) >> 16)); // 发送24bit地址
|
||||
MySPI_SwapByte((u8)((Dst_Addr) >> 8));
|
||||
MySPI_SwapByte((u8)Dst_Addr);
|
||||
W25QXX_CS = 1; // 取消片选
|
||||
W25QXX_Wait_Busy(); // 等待擦除完成
|
||||
}
|
||||
// 等待空闲
|
||||
void W25QXX_Wait_Busy(void)
|
||||
{
|
||||
while ((W25QXX_ReadSR() & 0x01) == 0x01)
|
||||
; // 等待BUSY位清空
|
||||
}
|
||||
// 进入掉电模式
|
||||
void W25QXX_PowerDown(void)
|
||||
{
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_PowerDown); // 发送掉电命令
|
||||
W25QXX_CS = 1; // 取消片选
|
||||
// delay_us(3); // 等待TPD
|
||||
}
|
||||
// 唤醒
|
||||
void W25QXX_WAKEUP(void)
|
||||
{
|
||||
W25QXX_CS = 0; // 使能器件
|
||||
MySPI_SwapByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
|
||||
W25QXX_CS = 1; // 取消片选
|
||||
// delay_us(3); // 等待TRES1
|
||||
}
|
||||
53
mkrtos_user/server/fs/fatfs/ext_disk_drv/w25q64.h
Normal file
53
mkrtos_user/server/fs/fatfs/ext_disk_drv/w25q64.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include "stm32_sys.h"
|
||||
// W25X系列/Q系列芯片列表
|
||||
// W25Q80 ID 0XEF13
|
||||
// W25Q16 ID 0XEF14
|
||||
// W25Q32 ID 0XEF15
|
||||
// W25Q64 ID 0XEF16
|
||||
// W25Q128 ID 0XEF17
|
||||
#define W25Q80 0XEF13
|
||||
#define W25Q16 0XEF14
|
||||
#define W25Q32 0XEF15
|
||||
#define W25Q64 0XEF16
|
||||
#define W25Q128 0XEF17
|
||||
|
||||
extern u16 W25QXX_TYPE; // 定义W25QXX芯片型号
|
||||
|
||||
#define W25QXX_CS PAout(4) // W25QXX的片选信号
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 指令表
|
||||
#define W25X_WriteEnable 0x06
|
||||
#define W25X_WriteDisable 0x04
|
||||
#define W25X_ReadStatusReg 0x05
|
||||
#define W25X_WriteStatusReg 0x01
|
||||
#define W25X_ReadData 0x03
|
||||
#define W25X_FastReadData 0x0B
|
||||
#define W25X_FastReadDual 0x3B
|
||||
#define W25X_PageProgram 0x02
|
||||
#define W25X_BlockErase 0xD8
|
||||
#define W25X_SectorErase 0x20
|
||||
#define W25X_ChipErase 0xC7
|
||||
#define W25X_PowerDown 0xB9
|
||||
#define W25X_ReleasePowerDown 0xAB
|
||||
#define W25X_DeviceID 0xAB
|
||||
#define W25X_ManufactDeviceID 0x90
|
||||
#define W25X_JedecDeviceID 0x9F
|
||||
|
||||
void W25QXX_Init(void);
|
||||
u16 W25QXX_ReadID(void); // 读取FLASH ID
|
||||
u8 W25QXX_ReadSR(void); // 读取状态寄存器
|
||||
void W25QXX_Write_SR(u8 sr); // 写状态寄存器
|
||||
void W25QXX_Write_Enable(void); // 写使能
|
||||
void W25QXX_Write_Disable(void); // 写保护
|
||||
void W25QXX_Write_NoCheck(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite);
|
||||
void W25QXX_Read(u8 *pBuffer, u32 ReadAddr, u16 NumByteToRead); // 读取flash
|
||||
void W25QXX_Write_Page(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite);
|
||||
void W25QXX_Write(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite); // 写入flash
|
||||
void W25QXX_Erase_Chip(void); // 整片擦除
|
||||
void W25QXX_Erase_Sector(u32 Dst_Addr); // 扇区擦除
|
||||
void W25QXX_Wait_Busy(void); // 等待空闲
|
||||
void W25QXX_PowerDown(void); // 进入掉电模式
|
||||
void W25QXX_WAKEUP(void); // 唤醒
|
||||
Reference in New Issue
Block a user