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,
我觉得你的问题,出在时序关系的问题上的几率较大