[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*
* 模块名称 : SPI接口串行FLASH 读写模块
* 文件名称 : bsp_spi_flash.c
* 版 本 : V1.0
* 说 明 : 支持 SST25VF016B、MX25L1606E 和 W25Q64BVSSIG
* SST25VF016B 的写操作采用AAI指令,可以提高写入效率。
*
* 缺省使用STM32F4的硬件SPI1接口,时钟频率最高为 42MHz (超频使用)
*
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 2013-02-01 armfly 正式发布
*
* Copyright (C), 2013-2014, 安富莱电子 [url]www.armfly.com[/url]
*
*********************************************************************************************************
*/
#include "bsp.h"
/* 串行Flsh的片选GPIO端口, PD13 */
#define SF_CS_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define SF_CS_GPIO GPIOD
#define SF_CS_PIN GPIO_PIN_13
#define SF_CS_0() SF_CS_GPIO->BSRRH = SF_CS_PIN
#define SF_CS_1() SF_CS_GPIO->BSRRL = SF_CS_PIN
#define CMD_AAI 0xAD /* AAI 连续编程指令(FOR SST25VF016B) */
#define CMD_DISWR 0x04 /* 禁止写, 退出AAI状态 */
#define CMD_EWRSR 0x50 /* 允许写状态寄存器的命令 */
#define CMD_WRSR 0x01 /* 写状态寄存器命令 */
#define CMD_WREN 0x06 /* 写使能命令 */
#define CMD_READ 0x03 /* 读数据区命令 */
#define CMD_RDSR 0x05 /* 读状态寄存器命令 */
#define CMD_RDID 0x9F /* 读器件ID命令 */
#define CMD_SE 0x20 /* 擦除扇区命令 */
#define CMD_BE 0xC7 /* 批量擦除命令 */
#define DUMMY_BYTE 0xA5 /* 哑命令,可以为任意值,用于读操作 */
#define WIP_FLAG 0x01 /* 状态寄存器中的正在编程标志(WIP) */
SFLASH_T g_tSF;
#if 0
static void sf_WriteStatus(uint8_t _ucValue);
#endif
static void sf_WriteEnable(void);
static void sf_WaitForWriteEnd(void);
static uint8_t sf_NeedErase(uint8_t * _ucpOldBuf, uint8_t *_ucpNewBuf, uint16_t _uiLen);
static uint8_t sf_CmpData(uint32_t _uiSrcAddr, uint8_t *_ucpTar, uint32_t _uiSize);
static uint8_t sf_AutoWritePage(uint8_t *_ucpSrc, uint32_t _uiWrAddr, uint16_t _usWrLen);
static uint8_t s_spiBuf[4*1024]; /* 用于写函数,先读出整个page,修改缓冲区后,再整个page回写 */
/*
*********************************************************************************************************
* 函 数 名: bsp_InitSFlash
* 功能说明: 串行falsh硬件初始化。 配置CS GPIO, 读取ID。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitSFlash(void)
{
/* 配置CS GPIO */
{
GPIO_InitTypeDef gpio_init;
/* 打开GPIO时钟 */
SF_CS_CLK_ENABLE();
gpio_init.Mode = GPIO_MODE_OUTPUT_PP; /* 设置推挽输出 */
gpio_init.Pull = GPIO_NOPULL; /* 上下拉电阻不使能 */
gpio_init.Speed = GPIO_SPEED_FREQ_HIGH; /* GPIO速度等级 */
gpio_init.Pin = SF_CS_PIN;
HAL_GPIO_Init(SF_CS_GPIO, &gpio_init);
}
/* 读取芯片ID, 自动识别芯片型号 */
sf_ReadInfo();
}
/*
*********************************************************************************************************
* 函 数 名: sf_SetCS
* 功能说明: 串行FALSH片选控制函数
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void sf_SetCS(uint8_t _Level)
{
if (_Level == 0)
{
bsp_SpiBusEnter();
bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_8, SPI_PHASE_1EDGE, SPI_POLARITY_LOW);
SF_CS_0();
}
else
{
SF_CS_1();
bsp_SpiBusExit();
}
}
/*
*********************************************************************************************************
* 函 数 名: sf_EraseSector
* 功能说明: 擦除指定的扇区
* 形 参: _uiSectorAddr : 扇区地址
* 返 回 值: 无
*********************************************************************************************************
*/
void sf_EraseSector(uint32_t _uiSectorAddr)
{
sf_WriteEnable(); /* 发送写使能命令 */
/* 擦除扇区操作 */
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = CMD_SE; /* 发送擦除命令 */
g_spiTxBuf[g_spiLen++] = ((_uiSectorAddr & 0xFF0000) >> 16); /* 发送扇区地址的高8bit */
g_spiTxBuf[g_spiLen++] = ((_uiSectorAddr & 0xFF00) >> 8); /* 发送扇区地址中间8bit */
g_spiTxBuf[g_spiLen++] = (_uiSectorAddr & 0xFF); /* 发送扇区地址低8bit */
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
sf_WaitForWriteEnd(); /* 等待串行Flash内部写操作完成 */
}
/*
*********************************************************************************************************
* 函 数 名: sf_EraseChip
* 功能说明: 擦除整个芯片
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void sf_EraseChip(void)
{
sf_WriteEnable(); /* 发送写使能命令 */
/* 擦除扇区操作 */
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = CMD_BE; /* 发送整片擦除命令 */
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
sf_WaitForWriteEnd(); /* 等待串行Flash内部写操作完成 */
}
/*
*********************************************************************************************************
* 函 数 名: sf_PageWrite
* 功能说明: 向一个page内写入若干字节。字节个数不能超出页面大小(4K)
* 形 参: _pBuf : 数据源缓冲区;
* _uiWriteAddr :目标区域首地址
* _usSize :数据个数,不能超过页面大小
* 返 回 值: 无
*********************************************************************************************************
*/
void sf_PageWrite(uint8_t * _pBuf, uint32_t _uiWriteAddr, uint16_t _usSize)
{
uint32_t i, j;
if (g_tSF.ChipID == SST25VF016B_ID)
{
/* AAI指令要求传入的数据个数是偶数 */
if ((_usSize < 2) && (_usSize % 2))
{
return ;
}
sf_WriteEnable(); /* 发送写使能命令 */
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = CMD_AAI; /* 发送AAI命令(地址自动增加编程) */
g_spiTxBuf[g_spiLen++] = ((_uiWriteAddr & 0xFF0000) >> 16); /* 发送扇区地址的高8bit */
g_spiTxBuf[g_spiLen++] = ((_uiWriteAddr & 0xFF00) >> 8); /* 发送扇区地址中间8bit */
g_spiTxBuf[g_spiLen++] = (_uiWriteAddr & 0xFF); /* 发送扇区地址低8bit */
g_spiTxBuf[g_spiLen++] = (*_pBuf++); /* 发送第1个数据 */
g_spiTxBuf[g_spiLen++] = (*_pBuf++); /* 发送第2个数据 */
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
sf_WaitForWriteEnd(); /* 等待串行Flash内部写操作完成 */
_usSize -= 2; /* 计算剩余字节数 */
for (i = 0; i < _usSize / 2; i++)
{
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (CMD_AAI); /* 发送AAI命令(地址自动增加编程) */
g_spiTxBuf[g_spiLen++] = (*_pBuf++); /* 发送数据 */
g_spiTxBuf[g_spiLen++] = (*_pBuf++); /* 发送数据 */
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
sf_WaitForWriteEnd(); /* 等待串行Flash内部写操作完成 */
}
/* 进入写保护状态 */
sf_SetCS(0);
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (CMD_DISWR);
bsp_spiTransfer();
sf_SetCS(1);
sf_WaitForWriteEnd(); /* 等待串行Flash内部写操作完成 */
}
else /* for MX25L1606E 、 W25Q64BV */
{
for (j = 0; j < _usSize / 256; j++)
{
sf_WriteEnable(); /* 发送写使能命令 */
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (0x02); /* 发送AAI命令(地址自动增加编程) */
g_spiTxBuf[g_spiLen++] = ((_uiWriteAddr & 0xFF0000) >> 16); /* 发送扇区地址的高8bit */
g_spiTxBuf[g_spiLen++] = ((_uiWriteAddr & 0xFF00) >> 8); /* 发送扇区地址中间8bit */
g_spiTxBuf[g_spiLen++] = (_uiWriteAddr & 0xFF); /* 发送扇区地址低8bit */
for (i = 0; i < 256; i++)
{
g_spiTxBuf[g_spiLen++] = (*_pBuf++); /* 发送数据 */
}
bsp_spiTransfer();
sf_SetCS(1); /* 禁止片选 */
sf_WaitForWriteEnd(); /* 等待串行Flash内部写操作完成 */
_uiWriteAddr += 256;
}
/* 进入写保护状态 */
sf_SetCS(0);
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (CMD_DISWR);
bsp_spiTransfer();
sf_SetCS(1);
sf_WaitForWriteEnd(); /* 等待串行Flash内部写操作完成 */
}
}
/*
*********************************************************************************************************
* 函 数 名: sf_ReadBuffer
* 功能说明: 连续读取若干字节。字节个数不能超出芯片容量。
* 形 参: _pBuf : 数据源缓冲区;
* _uiReadAddr :首地址
* _usSize :数据个数, 可以大于PAGE_SIZE,但是不能超出芯片总容量
* 返 回 值: 无
*********************************************************************************************************
*/
void sf_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
{
uint16_t rem;
uint16_t i;
/* 如果读取的数据长度为0或者超出串行Flash地址空间,则直接返回 */
if ((_uiSize == 0) ||(_uiReadAddr + _uiSize) > g_tSF.TotalSize)
{
return;
}
/* 擦除扇区操作 */
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (CMD_READ); /* 发送读命令 */
g_spiTxBuf[g_spiLen++] = ((_uiReadAddr & 0xFF0000) >> 16); /* 发送扇区地址的高8bit */
g_spiTxBuf[g_spiLen++] = ((_uiReadAddr & 0xFF00) >> 8); /* 发送扇区地址中间8bit */
g_spiTxBuf[g_spiLen++] = (_uiReadAddr & 0xFF); /* 发送扇区地址低8bit */
bsp_spiTransfer();
/* 开始读数据,疑问底层DMA缓冲区有限,必须分包读 */
for (i = 0; i < _uiSize / SPI_BUFFER_SIZE; i++)
{
g_spiLen = SPI_BUFFER_SIZE;
bsp_spiTransfer();
memcpy(_pBuf, g_spiRxBuf, SPI_BUFFER_SIZE);
_pBuf += SPI_BUFFER_SIZE;
}
rem = _uiSize % SPI_BUFFER_SIZE; /* 剩余字节 */
if (rem > 0)
{
g_spiLen = rem;
bsp_spiTransfer();
memcpy(_pBuf, g_spiRxBuf, rem);
}
sf_SetCS(1); /* 禁能片选 */
}
/*
*********************************************************************************************************
* 函 数 名: sf_CmpData
* 功能说明: 比较Flash的数据.
* 形 参: _ucpTar : 数据缓冲区
* _uiSrcAddr :Flash地址
* _uiSize :数据个数, 可以大于PAGE_SIZE,但是不能超出芯片总容量
* 返 回 值: 0 = 相等, 1 = 不等
*********************************************************************************************************
*/
static uint8_t sf_CmpData(uint32_t _uiSrcAddr, uint8_t *_ucpTar, uint32_t _uiSize)
{
uint16_t i, j;
uint16_t rem;
/* 如果读取的数据长度为0或者超出串行Flash地址空间,则直接返回 */
if ((_uiSrcAddr + _uiSize) > g_tSF.TotalSize)
{
return 1;
}
if (_uiSize == 0)
{
return 0;
}
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (CMD_READ); /* 发送读命令 */
g_spiTxBuf[g_spiLen++] = ((_uiSrcAddr & 0xFF0000) >> 16); /* 发送扇区地址的高8bit */
g_spiTxBuf[g_spiLen++] = ((_uiSrcAddr & 0xFF00) >> 8); /* 发送扇区地址中间8bit */
g_spiTxBuf[g_spiLen++] = (_uiSrcAddr & 0xFF); /* 发送扇区地址低8bit */
bsp_spiTransfer();
/* 开始读数据,因为底层DMA缓冲区有限,必须分包读 */
for (i = 0; i < _uiSize / SPI_BUFFER_SIZE; i++)
{
g_spiLen = SPI_BUFFER_SIZE;
bsp_spiTransfer();
for (j = 0; j < SPI_BUFFER_SIZE; j++)
{
if (g_spiRxBuf[j] != *_ucpTar++)
{
goto NOTEQ; /* 不相等 */
}
}
}
rem = _uiSize % SPI_BUFFER_SIZE; /* 剩余字节 */
if (rem > 0)
{
g_spiLen = rem;
bsp_spiTransfer();
for (j = 0; j < rem; j++)
{
if (g_spiRxBuf[j] != *_ucpTar++)
{
goto NOTEQ; /* 不相等 */
}
}
}
sf_SetCS(1);
return 0; /* 相等 */
NOTEQ:
sf_SetCS(1); /* 不相等 */
return 1;
}
/*
*********************************************************************************************************
* 函 数 名: sf_NeedErase
* 功能说明: 判断写PAGE前是否需要先擦除。
* 形 参: _ucpOldBuf : 旧数据
* _ucpNewBuf : 新数据
* _uiLen :数据个数,不能超过页面大小
* 返 回 值: 0 : 不需要擦除, 1 :需要擦除
*********************************************************************************************************
*/
static uint8_t sf_NeedErase(uint8_t * _ucpOldBuf, uint8_t *_ucpNewBuf, uint16_t _usLen)
{
uint16_t i;
uint8_t ucOld;
/*
算法第1步:old 求反, new 不变
old new
1101 0101
~ 1111
= 0010 0101
算法第2步: old 求反的结果与 new 位与
0010 old
& 0101 new
=0000
算法第3步: 结果为0,则表示无需擦除. 否则表示需要擦除
*/
for (i = 0; i < _usLen; i++)
{
ucOld = *_ucpOldBuf++;
ucOld = ~ucOld;
/* 注意错误的写法: if (ucOld & (*_ucpNewBuf++) != 0) */
if ((ucOld & (*_ucpNewBuf++)) != 0)
{
return 1;
}
}
return 0;
}
/*
*********************************************************************************************************
* 函 数 名: sf_AutoWritePage
* 功能说明: 写1个PAGE并校验,如果不正确则再重写两次。本函数自动完成擦除操作。
* 形 参: _pBuf : 数据源缓冲区;
* _uiWriteAddr :目标区域首地址
* _usSize :数据个数,不能超过页面大小
* 返 回 值: 0 : 错误, 1 : 成功
*********************************************************************************************************
*/
static uint8_t sf_AutoWritePage(uint8_t *_ucpSrc, uint32_t _uiWrAddr, uint16_t _usWrLen)
{
uint16_t i;
uint16_t j; /* 用于延时 */
uint32_t uiFirstAddr; /* 扇区首址 */
uint8_t ucNeedErase; /* 1表示需要擦除 */
uint8_t cRet;
/* 长度为0时不继续操作,直接认为成功 */
if (_usWrLen == 0)
{
return 1;
}
/* 如果偏移地址超过芯片容量则退出 */
if (_uiWrAddr >= g_tSF.TotalSize)
{
return 0;
}
/* 如果数据长度大于扇区容量,则退出 */
if (_usWrLen > g_tSF.PageSize)
{
return 0;
}
/* 如果FLASH中的数据没有变化,则不写FLASH */
sf_ReadBuffer(s_spiBuf, _uiWrAddr, _usWrLen);
if (memcmp(s_spiBuf, _ucpSrc, _usWrLen) == 0)
{
return 1;
}
/* 判断是否需要先擦除扇区 */
/* 如果旧数据修改为新数据,所有位均是 1->0 或者 0->0, 则无需擦除,提高Flash寿命 */
ucNeedErase = 0;
if (sf_NeedErase(s_spiBuf, _ucpSrc, _usWrLen))
{
ucNeedErase = 1;
}
uiFirstAddr = _uiWrAddr & (~(g_tSF.PageSize - 1));
if (_usWrLen == g_tSF.PageSize) /* 整个扇区都改写 */
{
for (i = 0; i < g_tSF.PageSize; i++)
{
s_spiBuf[i] = _ucpSrc[i];
}
}
else /* 改写部分数据 */
{
/* 先将整个扇区的数据读出 */
sf_ReadBuffer(s_spiBuf, uiFirstAddr, g_tSF.PageSize);
/* 再用新数据覆盖 */
i = _uiWrAddr & (g_tSF.PageSize - 1);
memcpy(&s_spiBuf[i], _ucpSrc, _usWrLen);
}
/* 写完之后进行校验,如果不正确则重写,最多3次 */
cRet = 0;
for (i = 0; i < 3; i++)
{
/* 如果旧数据修改为新数据,所有位均是 1->0 或者 0->0, 则无需擦除,提高Flash寿命 */
if (ucNeedErase == 1)
{
sf_EraseSector(uiFirstAddr); /* 擦除1个扇区 */
}
/* 编程一个PAGE */
sf_PageWrite(s_spiBuf, uiFirstAddr, g_tSF.PageSize);
if (sf_CmpData(_uiWrAddr, _ucpSrc, _usWrLen) == 0)
{
cRet = 1;
break;
}
else
{
if (sf_CmpData(_uiWrAddr, _ucpSrc, _usWrLen) == 0)
{
cRet = 1;
break;
}
/* 失败后延迟一段时间再重试 */
for (j = 0; j < 10000; j++);
}
}
return cRet;
}
/*
*********************************************************************************************************
* 函 数 名: sf_WriteBuffer
* 功能说明: 写1个扇区并校验,如果不正确则再重写两次。本函数自动完成擦除操作。
* 形 参: _pBuf : 数据源缓冲区;
* _uiWrAddr :目标区域首地址
* _usSize :数据个数,不能超过页面大小
* 返 回 值: 1 : 成功, 0 : 失败
*********************************************************************************************************
*/
uint8_t sf_WriteBuffer(uint8_t* _pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
{
uint16_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = _uiWriteAddr % g_tSF.PageSize;
count = g_tSF.PageSize - Addr;
NumOfPage = _usWriteSize / g_tSF.PageSize;
NumOfSingle = _usWriteSize % g_tSF.PageSize;
if (Addr == 0) /* 起始地址是页面首地址 */
{
if (NumOfPage == 0) /* 数据长度小于页面大小 */
{
if (sf_AutoWritePage(_pBuf, _uiWriteAddr, _usWriteSize) == 0)
{
return 0;
}
}
else /* 数据长度大于等于页面大小 */
{
while (NumOfPage--)
{
if (sf_AutoWritePage(_pBuf, _uiWriteAddr, g_tSF.PageSize) == 0)
{
return 0;
}
_uiWriteAddr += g_tSF.PageSize;
_pBuf += g_tSF.PageSize;
}
if (sf_AutoWritePage(_pBuf, _uiWriteAddr, NumOfSingle) == 0)
{
return 0;
}
}
}
else /* 起始地址不是页面首地址 */
{
if (NumOfPage == 0) /* 数据长度小于页面大小 */
{
if (NumOfSingle > count) /* (_usWriteSize + _uiWriteAddr) > SPI_FLASH_PAGESIZE */
{
temp = NumOfSingle - count;
if (sf_AutoWritePage(_pBuf, _uiWriteAddr, count) == 0)
{
return 0;
}
_uiWriteAddr += count;
_pBuf += count;
if (sf_AutoWritePage(_pBuf, _uiWriteAddr, temp) == 0)
{
return 0;
}
}
else
{
if (sf_AutoWritePage(_pBuf, _uiWriteAddr, _usWriteSize) == 0)
{
return 0;
}
}
}
else /* 数据长度大于等于页面大小 */
{
_usWriteSize -= count;
NumOfPage = _usWriteSize / g_tSF.PageSize;
NumOfSingle = _usWriteSize % g_tSF.PageSize;
if (sf_AutoWritePage(_pBuf, _uiWriteAddr, count) == 0)
{
return 0;
}
_uiWriteAddr += count;
_pBuf += count;
while (NumOfPage--)
{
if (sf_AutoWritePage(_pBuf, _uiWriteAddr, g_tSF.PageSize) == 0)
{
return 0;
}
_uiWriteAddr += g_tSF.PageSize;
_pBuf += g_tSF.PageSize;
}
if (NumOfSingle != 0)
{
if (sf_AutoWritePage(_pBuf, _uiWriteAddr, NumOfSingle) == 0)
{
return 0;
}
}
}
}
return 1; /* 成功 */
}
/*
*********************************************************************************************************
* 函 数 名: sf_ReadID
* 功能说明: 读取器件ID
* 形 参: 无
* 返 回 值: 32bit的器件ID (最高8bit填0,有效ID位数为24bit)
*********************************************************************************************************
*/
uint32_t sf_ReadID(void)
{
uint32_t uiID;
uint8_t id1, id2, id3;
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[0] = (CMD_RDID); /* 发送读ID命令 */
g_spiLen = 4;
bsp_spiTransfer();
id1 = g_spiRxBuf[1]; /* 读ID的第1个字节 */
id2 = g_spiRxBuf[2]; /* 读ID的第2个字节 */
id3 = g_spiRxBuf[3]; /* 读ID的第3个字节 */
sf_SetCS(1); /* 禁能片选 */
uiID = ((uint32_t)id1 << 16) | ((uint32_t)id2 << 8) | id3;
return uiID;
}
/*
*********************************************************************************************************
* 函 数 名: sf_ReadInfo
* 功能说明: 读取器件ID,并填充器件参数
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void sf_ReadInfo(void)
{
/* 自动识别串行Flash型号 */
{
g_tSF.ChipID = sf_ReadID(); /* 芯片ID */
switch (g_tSF.ChipID)
{
case SST25VF016B_ID:
strcpy(g_tSF.ChipName, "SST25VF016B");
g_tSF.TotalSize = 2 * 1024 * 1024; /* 总容量 = 2M */
g_tSF.PageSize = 4 * 1024; /* 页面大小 = 4K */
break;
case MX25L1606E_ID:
strcpy(g_tSF.ChipName, "MX25L1606E");
g_tSF.TotalSize = 2 * 1024 * 1024; /* 总容量 = 2M */
g_tSF.PageSize = 4 * 1024; /* 页面大小 = 4K */
break;
case W25Q64BV_ID:
strcpy(g_tSF.ChipName, "W25Q64");
g_tSF.TotalSize = 8 * 1024 * 1024; /* 总容量 = 8M */
g_tSF.PageSize = 4 * 1024; /* 页面大小 = 4K */
break;
case W25Q128_ID:
strcpy(g_tSF.ChipName, "W25Q128");
g_tSF.TotalSize = 16 * 1024 * 1024; /* 总容量 = 8M */
g_tSF.PageSize = 4 * 1024; /* 页面大小 = 4K */
break;
default:
strcpy(g_tSF.ChipName, "Unknow Flash");
g_tSF.TotalSize = 2 * 1024 * 1024;
g_tSF.PageSize = 4 * 1024;
break;
}
}
}
/*
*********************************************************************************************************
* 函 数 名: sf_WriteEnable
* 功能说明: 向器件发送写使能命令
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void sf_WriteEnable(void)
{
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (CMD_WREN); /* 发送命令 */
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
}
#if 0
/*
*********************************************************************************************************
* 函 数 名: sf_WriteStatus
* 功能说明: 写状态寄存器
* 形 参: _ucValue : 状态寄存器的值
* 返 回 值: 无
*********************************************************************************************************
*/
static void sf_WriteStatus(uint8_t _ucValue)
{
if (g_tSF.ChipID == SST25VF016B_ID)
{
/* 第1步:先使能写状态寄存器 */
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (CMD_EWRSR); /* 发送命令, 允许写状态寄存器 */
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
/* 第2步:再写状态寄存器 */
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (CMD_WRSR); /* 发送命令, 写状态寄存器 */
g_spiTxBuf[g_spiLen++] = (_ucValue); /* 发送数据:状态寄存器的值 */
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
}
else
{
sf_SetCS(0); /* 使能片选 */
g_spiLen = 0;
g_spiTxBuf[g_spiLen++] = (CMD_WRSR); /* 发送命令, 写状态寄存器 */
g_spiTxBuf[g_spiLen++] = (_ucValue); /* 发送数据:状态寄存器的值 */
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
}
}
#endif
/*
*********************************************************************************************************
* 函 数 名: sf_WaitForWriteEnd
* 功能说明: 采用循环查询的方式等待器件内部写操作完成
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void sf_WaitForWriteEnd(void)
{
sf_SetCS(0); /* 使能片选 */
g_spiTxBuf[0] = (CMD_RDSR); /* 发送命令, 读状态寄存器 */
g_spiLen = 2;
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
while(1)
{
sf_SetCS(0); /* 使能片选 */
g_spiTxBuf[0] = (CMD_RDSR); /* 发送命令, 读状态寄存器 */
g_spiTxBuf[1] = 0; /* 无关数据 */
g_spiLen = 2;
bsp_spiTransfer();
sf_SetCS(1); /* 禁能片选 */
if ((g_spiRxBuf[1] & WIP_FLAG) != SET) /* 判断状态寄存器的忙标志位 */
{
break;
}
}
}
/***************************** 安富莱电子 [url]www.armfly.com[/url] (END OF FILE) *********************************/