⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flash.c

📁 基于LPC2478硬件平台的IAP和远程WEB应用。 系统共分为三个部分
💻 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 + -