📄 flash.c
字号:
/****************************************Copyright (c)****************************************************
** ZhangZhou KENENG electronics Co.,LTD.
**
**
**
**--------------File Info---------------------------------------------------------------------------------
** File name: flash.c
** Last modified Date: 2009-03-11
** Last Version: 1.0
** Descriptions: 提供操作片外NOR FLASH的接口,当前主要用到初始化函数
同时提供其他操作,以备将来BOOTLOADER功能扩展需要。
** 此驱动专针对SST39VF1601芯片,它是1Mx16宽的芯片。
** (此驱动在之前的bootloader代码中完成,但是没考虑软件环境,
** 现在将其移植到uc/os-II的操作系统中,需要考虑uc/os-II操作系统
** 运行环境的一些因素,因此做了一些调整。大体框架不变)
**--------------------------------------------------------------------------------------------------------
** Created by: heshusheng
** Created date: 2009-03-11
** Version: 1.0
** Descriptions: The original version
**
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
**
*********************************************************************************************************/
//#include "flash.h"
#include "config.h"
#include "flash.h"
/********************************************************************************************************
**存储flash信息;
*********************************************************************************************************/
static flash_info_type flash_info;
/********************************************************************************************************
* 转换地址。将要发送给SST39VF1601的地址值进行转换,以便于LPC2210输出。
* 由于SST39VF1601的A0是与LPC2470的A1相连,所以addr要左移1位。
*********************************************************************************************************/
#define GetAddr(addr) (volatile uint16 *)(flash_info.base_addr|(addr<<1))
/********************************************************************************************************
*将16位的前后两个字节进行颠倒处理
*
*********************************************************************************************************/
#define SWAP_16(x) ((uint16)( \
(((uint16)(x) & (uint16)0x00ffU) << 8) | \
(((uint16)(x) & (uint16)0xff00U) >> 8) ))
/********************************************************************************************************
*定义最大地址
*
*********************************************************************************************************/
#define MAX_ADDR() (flash_info.base_addr + flash_info.size)
/*********************************************************************************************************
* 名 称:WordProgram()
* 功 能:半字(16位)数据编程。
* 入口参数:Addr 编程地址(SST39VF1601内部地址)
* Data 编程数据
* 出口参数:返回TRUE表示操作成功,返回FALSE表示操作失败
**********************************************************************************************************/
uint8 WordProgram(uint32 iAddr, uint16 iData)
{
volatile uint16 *ipTmp;
uint16 itemp1,itemp2;
OS_ENTER_CRITICAL( );
ipTmp = GetAddr(0x5555); /* 转换地址0x5555 */
ipTmp[0] = 0xaaaa; /* 第一个周期,地址0x5555,数据0xAA*/
ipTmp = GetAddr(0x2aaa);
ipTmp[0] = 0x5555; /* 第二个周期,地址0x2aaa,数据0x55*/
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0xa0a0; /* 第三个周期,地址0x5555,数据0xA0*/
ipTmp = (volatile uint16 *)iAddr;
*ipTmp = iData; /* 第四个周期,地址Addr,数据Data */
OS_EXIT_CRITICAL( );
/*
* 等待操作完成 (若编程操作没有完成,每次读操作DQ6会跳变)
*/
while (1)
{
itemp1 = *ipTmp;
itemp2 = *ipTmp;
if (itemp1 == itemp2)
{
itemp1 = *ipTmp;
itemp2 = *ipTmp;
if (itemp1 != iData)
return(FALSE);
return(TRUE);
}
}
}
/*********************************************************************************************************
* 名 称:flash_erase_sector
* 功 能:擦除指定的扇区 4Kbyte
* 入口参数:Addr 编程地址
* no 扇区数目
* 出口参数:返回TRUE表示操作成功,返回FALSE表示操作失败
**********************************************************************************************************/
int flash_erase_sector(long addr, int no)
{
volatile uint16 *ipTmp;
uint16 itemp1,itemp2;
int i;
for (i = 0; i < no; i++)
{
if (addr <= MAX_ADDR())
{
OS_ENTER_CRITICAL( );
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0xaaaa;
ipTmp = GetAddr(0x2aaa);
ipTmp[0] = 0x5555;
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0x8080;
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0xaaaa;
ipTmp = GetAddr(0x2aaa);
ipTmp[0] = 0x5555;
ipTmp = (volatile uint16 *)addr;
*ipTmp = 0x3030;
OS_EXIT_CRITICAL( );
/*
* 等待操作完成 (若编程操作没有完成,每次读操作DQ6会跳变)
*/
while (1)
{
itemp1 = *ipTmp;
itemp2 = *ipTmp;
if (itemp1 == itemp2)
if (itemp1 != 0xffff)
return 0;
else
break;
}
addr += flash_info.sector_size;
}
else
return 1;
}
return 1;
}
/*********************************************************************************************************
* 名 称:flash_erase_block
* 功 能:擦除指定的块64Kbyte
* 入口参数:Addr 编程地址
* no 块数目
* 出口参数:返回TRUE表示操作成功,返回FALSE表示操作失败
**********************************************************************************************************/
int flash_erase_block(long addr, int no)
{
volatile uint16 *ipTmp;
uint16 itemp1,itemp2;
int i;
for (i = 0; i < no; i++)
{
if (addr <= MAX_ADDR())
{
OS_ENTER_CRITICAL( );
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0xaaaa;
ipTmp = GetAddr(0x2aaa);
ipTmp[0] = 0x5555;
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0x8080;
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0xaaaa;
ipTmp = GetAddr(0x2aaa);
ipTmp[0] = 0x5555;
ipTmp = (volatile uint16 *)addr;
*ipTmp = 0x5050;
OS_EXIT_CRITICAL( );
/*
* 等待操作完成 (若编程操作没有完成,每次读操作DQ6会跳变)
*/
while (1)
{
itemp1 = *ipTmp;
itemp2 = *ipTmp;
if (itemp1 == itemp2)
if (itemp1 != 0xffff)
return 0;
else
break;
}
addr += flash_info.block_size;
}
else
return 1;
}
return 1;
}
/*********************************************************************************************************
* 名 称:flash_erase_chip()
* 功 能:提供接口供给外部调用,擦除全片数据
* 入口参数:
* 出口参数:返回TRUE表示操作成功,返回FALSE表示操作失败
**********************************************************************************************************/
int flash_erase_chip( void )
{
volatile uint16 *ipTmp;
uint16 itemp1,itemp2;
OS_ENTER_CRITICAL( );
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0xaaaa; /* 第一个周期,地址0x5555,数据0xAA*/
ipTmp = GetAddr(0x2aaa);
ipTmp[0] = 0x5555; /* 第二个周期,地址0x2aaa,数据0x55*/
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0x8080; /* 第三个周期,地址0x5555,数据0x80*/
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0xaaaa; /* 第四个周期,地址0x5555,数据0xAA*/
ipTmp = GetAddr(0x2aaa);
ipTmp[0] = 0x5555; /* 第五个周期,地址0x2aaa,数据0x55*/
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0x1010; /* 第六个周期,地址0x5555,数据0x10*/
OS_EXIT_CRITICAL( );
/*
* 等待操作完成 (若擦除操作没有完成,每次读操作DQ6会跳变)
*/
while (1)
{
itemp1 = *ipTmp;
itemp2 = *ipTmp;
if (itemp1 == itemp2)
{
if (itemp1 != 0xffff)
return(FALSE);
return(TRUE);
}
}
}
/*********************************************************************************************************
* 名 称:flash_write()
* 功 能:提供接口供给外部调用,按字节进行编程。
* 入口参数:src 写入的数据缓存
* addr : 写入的地址,使用0x81******开头的地址
* cnt :写入的数据长度
* 出口参数:返回TRUE表示操作成功,返回FALSE表示操作失败
**********************************************************************************************************/
int flash_write(char *src,long addr,long cnt)
{
long cp, wp;
uint16 data;
int count, i, l, rc, port_width;
if ( (addr + cnt) > MAX_ADDR())
return FALSE;
wp = (addr & ~1);
port_width = 2;
/*处理非16位对齐的起始地址*/
if ((l = addr - wp) != 0) {
data = 0;
for (i = 0, cp = wp; i < l; ++i, ++cp) {
data = (data << 8) | (*(char *) cp);
}
for (; i < port_width && cnt > 0; ++i) {
data = (data << 8) | *src++;
--cnt;
++cp;
}
for (; cnt == 0 && i < port_width; ++i, ++cp) {
data = (data << 8) | (*(char *) cp);
}
if ((rc = WordProgram( wp, SWAP_16 (data))) == 0) {
return (rc);
}
wp += port_width;
}
/*处理对齐后的数据部分*/
count = 0;
while (cnt >= port_width) {
data = 0;
for (i = 0; i < port_width; ++i) {
data = (data << 8) | *src++;
}
if ((rc = WordProgram( wp, SWAP_16 (data))) == 0) {
return (rc);
}
wp += port_width;
cnt -= port_width;
if (count++ > 0x800) {
count = 0;
}
}
if (cnt == 0) {
return (1);
}
/*处理非16位对齐的结尾地址*/
data = 0;
for (i = 0, cp = wp; i < port_width && cnt > 0; ++i, ++cp) {
data = (data << 8) | *src++;
--cnt;
}
for (; i < port_width; ++i, ++cp) {
data = (data << 8) | (*(char *) cp);
}
return (WordProgram ( wp, SWAP_16 (data)));
}
/*********************************************************************************************************
* 名 称:flash_get_id()
* 功 能:获取flash id.用于判断当前EMC外接的NOR FLASH的类型
* 入口参数:无
* 出口参数:16位flash id.
**********************************************************************************************************/
static uint16 flash_get_id( void )
{
volatile uint16 *ipTmp;
uint16 itemp;
//enter cfi read mode.
OS_ENTER_CRITICAL( );
ipTmp = GetAddr(0x5555); /* 转换地址0x5555 */
ipTmp[0] = 0xaaaa; /* 第一个周期,地址0x5555,数据0xAA*/
ipTmp = GetAddr(0x2aaa);
ipTmp[0] = 0x5555; /* 第二个周期,地址0x2aaa,数据0x55*/
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0x9898; /* 第三个周期,地址0x5555,数据0x98*/
OS_EXIT_CRITICAL( );
//SST flash
ipTmp = GetAddr(0x0000);
itemp = *ipTmp;
if ( itemp != 0xbf)
return FALSE;
//read id.
ipTmp = GetAddr(0x0001);
itemp = *ipTmp;
//exit cfi read mode.
OS_ENTER_CRITICAL( );
ipTmp = GetAddr(0x5555); /* 转换地址0x5555 */
ipTmp[0] = 0xaaaa; /* 第一个周期,地址0x5555,数据0xAA*/
ipTmp = GetAddr(0x2aaa);
ipTmp[0] = 0x5555; /* 第二个周期,地址0x2aaa,数据0x55*/
ipTmp = GetAddr(0x5555);
ipTmp[0] = 0xf0f0; /* 第三个周期,地址0x5555,数据0xf0*/
OS_EXIT_CRITICAL( );
return itemp;
}
/*********************************************************************************************************
* 名 称:flash_init()
* 功 能:提供接口供给外部调用,NORFLASH 初始化函数
* 入口参数:无
* 出口参数:无
**********************************************************************************************************/
void flash_init( void )
{
uint16 id;
//硬件初始化
PINSEL6 = 0x55555555;
PINSEL8 = 0x55555555;
PINSEL9 |= 0x40050155;
EMCControl = 0x01;
EMCStaticConfig1 = 0x00000081;
EMCStaticWaitRd1 = 0x04;
EMCStaticWaitOen1 = 0x01;
EMCStaticWaitWen1 = 0x00;
EMCStaticWaitWr1 = 0x02;
//读取flash物理设备的ID。
flash_info.base_addr = 0x81000000;
id = flash_get_id( );
switch(id)
{
//39vf1601
case 0x234b:
flash_info.size = 0x200000;
flash_info.sector_size = 0x1000;
flash_info.block_size = 0x10000;
break;
//add other types of flash.
default:
break;
}
}
/*--------------------------------------------------------------------------------------------------------------------------------
** END OF FILE
----------------------------------------------------------------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -