首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > VxWorks >

NAND FLASH 设备ID读取异常

2012-03-08 
NAND FLASH 设备ID读取错误个问题调了好几天了,实在不知道哪出问题,跪求各位大侠帮小弟看看。CPU是AT91RM92

NAND FLASH 设备ID读取错误
个问题调了好几天了,实在不知道哪出问题,跪求各位大侠帮小弟看看。

  CPU是AT91RM9200 ,FLASH是三星的K9F1G08U0M,出现的问题是FLASH id老是读不正确,有的时候是0x0,有的时候是一串没规律的数字,ReadStatus()放在ReadID()之前的时候,得到的值是0xe0,放在ReadID()的时候得到的值是0x60。

源码:
#include "cpuRegs.h"
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef unsigned char UINT8;
typedef unsigned int UINT32;
  
#define REG32(addr) *((volatile unsigned long * const) (addr))
#define REG08(addr) *((volatile unsigned char * const) (addr))
  
/* Flash commands:*/
#define SERIAL_DATA_INPUT 0x80
#define READ_MODE 0x00
#define RESET_FLASH 0xff
#define SETUP_WRITE 0x10
#define SETUP_ERASE 0x60
#define CONFIRM_ERASE 0xd0
#define READ_STATUS 0x70
#define READ_ID (0x90)
#define SUSPEND_ERASE 0xb0
#define REGISTER_READ 0xe0 
#define READ_END 0x30


#define NAND_ADDR_DATA 0x40000000
#define NAND_ADDR_COMM 0x40200000
#define NAND_ADDR_ADDR 0x40400000
//#define GET_NAND_R_B ((AT91_PIOC_PDSR & (1<<5)) ? 1 : 0)
/**
  * @brief CPU输出管脚控制
  * @param port 端口编号(参考bsp.h)
  * @param no 管脚编号
  * @param value 0,置低; 非0,置高
  * @retval 无
  */
void bspPinOut(char port, BYTE no, BYTE value) 
{
DWORD temp = (1<<no);
if(port=='A'){
  if(value)
  REG32(AT91C_PIOA_SODR) = temp;
  else
  REG32(AT91C_PIOA_CODR) = temp;
}
else if(port=='B'){
  if(value)
  REG32(AT91C_PIOB_SODR) = temp;
  else
  REG32(AT91C_PIOB_CODR) = temp;
}
else if(port == 'C'){
  if(value)
  REG32(AT91C_PIOC_SODR) = temp;
  else
  REG32(AT91C_PIOC_CODR) = temp;
}
  else if(port=='D'){
  if(value)
  REG32(AT91C_PIOD_SODR) = temp;
  else
  REG32(AT91C_PIOD_CODR) = temp;
  }
}
/**
  * @brief CPU输出管脚初始化
  * @param port 端口编号(参考bsp.h)
  * @param no 管脚编号
  * @param value 初始化值; 0,置低; 非0,置高
  * @retval 无
  */
void bspPinOutInit(char port, BYTE no, BYTE value)
{
DWORD temp = (1<<no);
if(port == 'A'){
  REG32(AT91C_PIOA_PER) = temp;
  REG32(AT91C_PIOA_OER) = temp;
}
else if(port == 'B'){
  REG32(AT91C_PIOB_PER) = temp;
  REG32(AT91C_PIOB_OER) = temp;
}
else if(port == 'C'){
  REG32(AT91C_PIOC_PER) = temp;
  REG32(AT91C_PIOC_OER) = temp;
}
  else if(port == 'D'){
  REG32(AT91C_PIOD_PER) = temp;
  REG32(AT91C_PIOD_OER) = temp;
}
bspPinOut(port, no, value);
}
/**
  * @brief CPU外设管脚初始化
  * @param port 端口编号(参考bsp.h)
  * @param no 管脚编号
  * @param value 初始化值; 0,置低; 非0,置高
  * @param ab A:选择A复用,B:选择B复用
  * @retval 无
  */
void bspPinPeriInit(char port,BYTE no,char ab)
{
  DWORD temp=(1<<no);
  if(port == 'A'){
  REG32(AT91C_PIOA_PDR) = temp;
  if(ab=='A')
  REG32(AT91C_PIOA_ASR) = temp;
  else if (ab=='B')
  REG32(AT91C_PIOA_BSR) = temp;
}
else if(port == 'B'){
  REG32(AT91C_PIOB_PDR) = temp;
  if(ab=='A')
  REG32(AT91C_PIOB_ASR) = temp;
  else if (ab=='B')
  REG32(AT91C_PIOB_BSR) = temp;
}
else if(port == 'C'){
  REG32(AT91C_PIOC_PDR) = temp;
  if(ab=='A')
  REG32(AT91C_PIOC_ASR) = temp;


  else if (ab=='B')
  REG32(AT91C_PIOC_BSR) = temp;
}
  else if(port == 'D'){
  REG32(AT91C_PIOD_PDR) = temp;
  if(ab=='A')
  REG32(AT91C_PIOD_ASR) = temp;
  else if (ab=='B')
  REG32(AT91C_PIOD_BSR) = temp;
}
  // bspPinOut(port, no, value);
}
/**
  * @brief CPU输入管脚初始化
  * @param port 端口编号(参考bsp.h)
  * @param no 管脚编号
  * @retval 无
  */
void bspPinInInit(BYTE port, BYTE no)
{
DWORD temp = (1<<no);
if(port == 1){
  REG32(AT91C_PIOA_PER) = temp;
  REG32(AT91C_PIOA_ODR) = temp;
}
else if(port == 2){
  REG32(AT91C_PIOB_PER) = temp;
  REG32(AT91C_PIOB_ODR) = temp;
}
else if(port == 3){
  REG32(AT91C_PIOC_PER) = temp;
  REG32(AT91C_PIOC_ODR) = temp;
}
}

/**
  * @brief CPU输入管脚状态
  * @param port 端口编号(参考bsp.h)
  * @param no 管脚编号
  * @retval 管脚状态: 0,低; 1,高
  */
BYTE bspPinInState(BYTE port, BYTE no)
{
DWORD temp = (1<<no);
if(port == 1){
  if(REG32(AT91C_PIOA_PDSR) & temp) return 1;
}
else if(port == 2){
  if(REG32(AT91C_PIOB_PDSR) & temp) return 1;
}
else if(port == 3){
  if(REG32(AT91C_PIOC_PDSR) & temp) return 1;
}
return 0;
}
void EnableCE()
{
  bspPinOut('C',4, 0);
}
void DisableCE()
{
bspPinOut('C',4, 1);  
}
void Reset(void)
{
  int i;
  EnableCE(); 
  REG08(NAND_ADDR_COMM) = RESET_FLASH;
// taskDelay(10);
  for(i=0; i<100000; i++) 
  if(bspPinInState(3,5)) break; // If Flash is ready
  DisableCE();
}
unsigned char ReadStatus(void)
{
  unsigned char chipStatus;
  EnableCE();
  REG08(NAND_ADDR_COMM) = READ_STATUS;
  chipStatus = REG08(NAND_ADDR_DATA);
  DisableCE(); 
  return chipStatus;
}
DWORD ReadID(void)
{
  BYTE v[4];  
  DWORD ret; int i,j;
  EnableCE();
// 
  REG08(NAND_ADDR_COMM) = (UINT8)READ_ID;
  REG08(NAND_ADDR_ADDR) = (UINT8)0x00;
   
  ret = ReadStatus();
  printf("i=0x%x\n", ret);
   
   
  taskDelay(10);
  v[0] = REG08(NAND_ADDR_DATA);
  v[1] = REG08(NAND_ADDR_DATA);
  v[2] = REG08(NAND_ADDR_DATA);
  v[3] = REG08(NAND_ADDR_DATA);

  DisableCE();
  ret = (v[3]<<24)|(v[2]<<16)|(v[1]<<8)|v[0];
  // ret = ((v[0]<<24)|(v[1]<<16)|(v[2]<<8)|v[3]);
  //ret = v[0];
  return ret;
}
/* set the bus interface characteristics based on
  tDS Data Set up Time 30 - ns
  tDH Data Hold Time 20 - ns
  tALS ALE Set up Time 20 - ns
  16ns at 60 MHz ~= 3 */
/*memory mapping structures */
#define SM_ID_RWH (5 << 28)
#define SM_RWH (1 << 28)
#define SM_RWS (0 << 24)
#define SM_TDF (1 << 8)
#define SM_NWS (3)
#define AT91C_SMC2_ACSS_STANDARD 0
#define AT91C_SMC2_DBW_8 ((unsigned int) 0x2 << 13)
#define AT91C_SMC2_WSEN ((unsigned int) 0x1 << 7)
void test(void)
{
  DWORD ret;
  int i;
  bspPinOutInit('C', 4, 1);//set the pc4 in I/O state
  bspPinPeriInit('C',1,'A');
  bspPinPeriInit('C',3,'A');
  bspPinInInit(3, 5);
  /*PC4,PC5*/
  // REG32(AT91C_PIOC_PPUER) = (1<<5)|(1<<4);



  REG32(AT91C_EBI_CSA) = 0x0000000A;
  REG32(AT91C_SMC_CSR3) = 0x11005281;
   
  /*REG32(AT91C_SMC_CSR3) = (SM_RWH | SM_RWS |
  AT91C_SMC2_ACSS_STANDARD | AT91C_SMC2_DBW_8 |
  SM_TDF | AT91C_SMC2_WSEN | SM_NWS);*/

  Reset();
  for(i=0; i<100000; i++) 
  if(bspPinInState(3,5)) break; // If Flash is ready
  ret = ReadStatus();
  printf("ReadStatus=0x%x\n",ret);
  ret = ReadID();
  printf("ReadID=0x%x\n",ret);
}

[解决办法]
1. 不要频繁的 chip selection 使能 关闭, 你的代码中 EnableCE, DisableCE的地方很多
使能后,可以保存下来,下次要使能之前,判断一下是否已经使能了,是的话,不必再使能
关闭后,保存下来这个状态,下次要关闭前,判断一下是否关闭了,是的话,不必再关闭

2. EnableCE 之后,是否考虑,加一个小延时,如果片选的状态没那么快恢复,你就放命令字和地址,我不知道这样是否可以

3. 是否可以尝试,在发送 READ_ID命令字之前,先reset一下芯片,把芯片放在一个确定的状态,然后,再去READ_ID, 

我觉得你的问题,出在时序关系的问题上的几率较大

热点排行