Все оказалось гораздо проще. Выбранная микросхема Micron MT29F4G08AAAWP ET D, в отличие от своих аналогов более ранних версий таких как Micron MT29F4G08AAAWP ET A (B, C), выполнена по новому стандарту ONFI. Даташит на нее вышел только 9 апреля 2009 года. На официальном сайте упоминаний, что данная серия будет переведена на новый стандарт опубликовано не было.
Основное отличие заключается в расширенной структуре команд, а также распиновки шины данных (см рис).
По рисункам видно, что младшие адреса шины данных у новых 16-ти и 8-ми разрядных Nand Flash одинаковые, а в более ранних версиях микросхем они разные. Таким образом для микросхем памяти типа NAND, перешедших на новый стандарт, требуется другая трассировка платы. Если же это сделать нельзя (перетрассировать плату), то можно поступить иначе (использовать «программные заплатки»). Т.к. новый стандарт не отличается по алгоритмам чтения, записи или очистки блока, то необходимо перекодировать команды, чтобы на всех линиях шины данных были необходимые состояния. Для этого нужно использовать следующие процедурки:
Код
// MOVEBIT macro
#define MOVEBIT(x,s,d) ((((x)>>(s)) & 0x1) << (d))
// test functions
// nand_Forward
unsigned nand_Forward(unsigned x)
{
// form and return result return
MOVEBIT(x, 0, 9) | MOVEBIT(x, 1, 2) | MOVEBIT(x, 2, 10) | MOVEBIT(x, 3, 3) |
MOVEBIT(x, 4, 12) | MOVEBIT(x, 5, 5) | MOVEBIT(x, 6, 13) | MOVEBIT(x, 7, 6);
}
// nand_Backward
unsigned nand_Backward(unsigned x)
{
// form and return result return
MOVEBIT(x, 9, 0) | MOVEBIT(x, 2, 1) | MOVEBIT(x, 10, 2) | MOVEBIT(x, 3, 3) |
MOVEBIT(x, 12, 4) | MOVEBIT(x, 5, 5) | MOVEBIT(x, 13, 6) | MOVEBIT(x, 6, 7);
}
Пример использования макросов. Процедура чтения id.
Код
#define read_data() (*(volatile unsigned short*)0x40000000)
#define write_data(x) *((volatile unsigned short*)0x40000000) = (unsigned short)(x)
#define write_command(x) *((volatile unsigned short*)0x40080000) = (unsigned short)(x)
#define write_address(x) *((volatile unsigned short*)0x40100000) = (unsigned short)(x)
void NAND_READ_ID(void)
{
unsigned short status;
unsigned short shifr_value = 0x0;
sys_DoDelay(1);
write_command( nand_Forward(0xFF) );
sys_DoDelay(100);
//write_command( nand_Forward(0x90) );
write_command( 0x0090);
write_address(0x0000);
status = read_data ();
status = nand_Backward(status);
printf("NAND status = [%.4x] ", (unsigned)status);
status = read_data ();
status = nand_Backward(status);
printf(" [%.4x] ", (unsigned)status);
status = read_data ();
status = nand_Backward(status);
printf(" [%.4x] ", (unsigned)status);
status = read_data ();
status = nand_Backward(status);
printf(" [%.4x]\n", (unsigned)status);
}
Забыл упомянуть, перед началом работы с NAND микросхему необходимо софтверно перезагрузить, путем подачи команды 0xFF.
Т.к. команды управления м/c жестко определены, то для экономии ресурсов системы их можно объявить статическ define, предварительно изменив режим компиляции.
например
Код
#define NAND_CMD_READ0 ( nand_Forward(0))
#define NAND_CMD_READ1 ( nand_Forward(1))
#define NAND_CMD_READ_CONFIRM ( nand_Forward(0x30))
#define NAND_CMD_PAGEPROG ( nand_Forward(0x10))
#define NAND_CMD_READOOB ( nand_Forward(0x50))
#define NAND_CMD_ERASE1 ( nand_Forward(0x60))
#define NAND_CMD_STATUS ( nand_Forward(0x70))
#define NAND_CMD_SEQIN ( nand_Forward(0x80))
#define NAND_CMD_READID ( nand_Forward(0x90))
#define NAND_CMD_ERASE2 ( nand_Forward(0xd0))
#define NAND_CMD_RESET ( nand_Forward(0xff))
В результате выше указанные макросы нужно будет использовать только в случае записи адреса или получения статуса.
Можно долго посыпать себе голову пеплом и кричать, что нужно вначале читать даташит, а потом трассировать плату, однако вовремя получить даташит с сайта MIRCON мне не удалось. Это вызвано усложненной системой скачиваания документации по письменному запросу.
Надеюсь эта статья поможет сохранить ваши нервы, в случае использования таких версий микросхем.
После написания базовых функций записи, чтения и очистки блока. Была поставлена файловая система yaffs. Полет нормальный! Ниже привожу код функций direct интерфеса, необходимого для запуска yaffs. Код сырой!
Код
void nand_read_page ( int page, unsigned char *buffer, unsigned char *tags )
{
unsigned int block_num;
unsigned int page_num;
unsigned int i = 0x0;
unsigned short temp_read;
page_num = page / NAND_PAGE_MAX;
block_num = page % NAND_PAGE_MAX;
write_command(0x0);
write_address(0x0);
write_address(0x0);
write_address( nand_Forward(page_num | ((block_num & 3) <<6) ));
write_address(nand_Forward((block_num >> 2) & 0xFF ));
write_address(nand_Forward((block_num >>10) & 0x01 ));
write_command(nand_Forward(0x30));
for (i = 0; i < NAND_COUNT_DATA; i+=2)
{
if(buffer)
{
// temp_read = read_data();
// buffer[i] = (char)(temp_read & 0x00FF);
temp_read = read_data();
buffer[i] = (char)(temp_read & 0x00FF);
if ((i + 1) < NAND_COUNT_TAGS )
buffer[i+1] = (char)((temp_read & 0xFF00) >> 8);
}
else read_data();
}
if (tags)
{
for ( i = 0; i < NAND_COUNT_TAGS; i+=2 )
{
// temp_read = read_data();
// tags[i] = (char)(temp_read & 0x00FF);
temp_read = read_data();
tags[i] = (char)(temp_read & 0x00FF);
if ((i + 1) < NAND_COUNT_TAGS )
tags[i] = (char)((temp_read & 0xFF00) >> 8 );
}
}
}
void nand_write_page ( int page, unsigned char *buffer, unsigned char *tags )
{
unsigned int i;
unsigned short status_data = 0x0;
unsigned int block_num;
unsigned int page_num;
unsigned short temp_read;
page_num = page / NAND_PAGE_MAX;
block_num = page % NAND_PAGE_MAX;
write_command( nand_Forward( 0x80 ) );
write_address(0x0);
write_address(0x0);
write_address( nand_Forward(page_num | ((block_num & 3) <<6) ));
write_address( nand_Forward((block_num >> 2) & 0xFF ));
write_address( nand_Forward((block_num >>10) & 0x01 ));
for( i = 0; i < NAND_COUNT_DATA; i=+2 )
{
temp_read = 0x0;
// temp_read = (temp_read | buffer[i]);
if ((i+1) < NAND_COUNT_DATA)
temp_read = ((buffer[i+1] << 8) | buffer[i]);
else temp_read = (temp_read | buffer[i]);
write_data( temp_read );
}
if ( tags )
{
for(i = 0; i < NAND_COUNT_TAGS; i+=2)
{
temp_read = 0x0;
// temp_read = (temp_read | buffer[i]);
if ((i+1) < NAND_COUNT_DATA)
temp_read = ((tags[i+1] << 8) | tags[i]);
else temp_read = (temp_read | tags[i]);
write_data( temp_read );
}
}
write_command(nand_Forward(0x10));
// rtems_task_wake_after(50);
write_command(nand_Forward(0x70));
// status chec
while (1)
{
status_data = read_data();
status_data = nand_Backward(status_data);
printf("[%x]\n",status_data);
if (status_data == 0x60) break;
if (status_data == 0xE0) break;
}
//printf("write page done\n");
}
void nand_block_erase ( int block_num )
{
if ( block_num >= NAND_MAX_BLOCK_NUM )
return;
write_command( nand_Forward(0x60) );
// rtems_task_wake_after(3);
// page_num |
write_address( nand_Forward( ((block_num & 3) <<6) ));
write_address( nand_Forward(( block_num >> 2 ) & 0xFF) );
write_address( nand_Forward(( block_num >> 10 ) & 0x01) );
// rtems_task_wake_after(3);
write_command( nand_Forward(0xD0) );
rtems_task_wake_after(3);
}
/****************************/
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
{
nand_block_erase(blockNumber);
return YAFFS_OK;
}
static int yaffs_CheckAllFF(unsigned char *ptr, int n)
{
while(n)
{
n--;
if(*ptr!=0xFF) return 0;
ptr++;
}
return 1;
}
int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
{
nand_read_page(chunkInNAND, data, (unsigned char *)tags);
if (yaffs_CheckAllFF((unsigned char *)tags, sizeof(yaffs_ExtendedTags)))
yaffs_InitialiseTags(tags);
else
tags->chunkUsed = 1;
return YAFFS_OK;
}
int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
{
nand_write_page(chunkInNAND, data, (unsigned char *)tags);
return YAFFS_OK;
}
int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
{
yaffs_ExtendedTags tags;
int chunkNo;
*sequenceNumber = 0;
chunkNo = blockNo * dev->nChunksPerBlock;
yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
if(tags.blockBad)
{
*state = YAFFS_BLOCK_STATE_DEAD;
}
else if(!tags.chunkUsed)
{
*state = YAFFS_BLOCK_STATE_EMPTY;
}
else if(tags.chunkUsed)
{
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
*sequenceNumber = tags.sequenceNumber;
}
return YAFFS_OK;
}
int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
printf("!!!!!!! MarkNANDBlockBad!!!!! %d\n", blockNo);
return YAFFS_OK;
}
int yflash_InitialiseNAND(yaffs_Device *dev)
{
return YAFFS_OK;
}
void nand_all_blocks_erase ( void )
{
int block;
puts("Erasing all blocks...");
for (block = 0; block < NAND_MAX_BLOCK_NUM; block++)
{
nand_block_erase(block);
}
puts("Done.");
}
/****************************/
Сообщение отредактировал primus - Jul 21 2009, 18:01