реклама на сайте
подробности

 
 
> 16xNAND и AT91RM9200, подключение 16 битной NAND flash и драйвер для работы с ней
primus
сообщение Jul 3 2009, 09:09
Сообщение #1





Группа: Участник
Сообщений: 11
Регистрация: 9-04-07
Из: Санкт-Петербург
Пользователь №: 26 884



Доброго времени суток, ALL!

Надеюсь на вашу помошь, т.к. собственных сил уже не хватает.

Subj, заключается в следующем.

Появилась необходимость повышения производительности в работе с NAND flash, поэтому заменил ранее использовавшуюся 8-ми битную NAND Micron MT29F4G08AAAWP ET
на аналогичную ей 16-ти битную Micron MT29F2G16AAD ET D. Возникла проблема - не могу считать ID c 16 битной NAND, когда на 8-ми битной все работает.

Подкорректировал схему включения микросхемы, но структорно она осталась прежней:

AT91RM9200 MICRON

NSC3| ------------->| !CE
A19| ------------->| CLE
A20| ------------->| ALE
NANDOE| ------------->| !RE
NANDWE| ------------->| !WE
PC8|<-------------- | !R/b
16x I/0|--< шина >--| 16x I/0


где !СE - инвертированный вход, аналогично как и RE, WE

Сигналы все проходят (проверил осциллогорафом).

Схемотехнически, imho, все выполненно правильно. В цепи питания видимых ошибок не обнаруженно.
(да и ошибиться-то там негде)
написал маленький дравер для работы с NAND (первичный загрузчик отлажен и проверен (100% работает!)):

//listing...

CODE

//чтение данных
#define read_data() (*(volatile unsigned short*)0x40000000)

//запись данных
#define write_data(x) *((volatile unsigned short*)0x40000000) = (unsigned short)(x)
//запись команды - поднимается CS и адресс A19 (CLE)
#define write_command(x) *((volatile unsigned short*)0x40080000) = (unsigned short)(x)
//запись адреса - поднимается CS и адресс A20 (ALE)
#define write_address(x) *((volatile unsigned short*)0x40100000) = (unsigned short)(x)

// инициализация NAND
void nand_init(void)
{

// Конфигурирование EBI - CS3 настраивается для работы с NAND (CS - !CE)
SET(MCU_MC|EBI_CSA, 0x00000008);

/*
настройка регистра SMC Chip Select Register 3
( Byte Access Type = 16 бит;
Data Bus Width = 16 бит;
Wait State Enable = 1;
Number of Wait States = 127;
перепробовал все варианты, с учетом всех задержек и временных диаграмм
)
*/
SET(MCU_MC|SMC_CSR3, 0x000030FF);

// настройка PIO - здесь все просто
SET(MCU_PIOC|PIO_ASR, 0x0000000a);
//SET(MCU_PIOC|PIO_MDDR, 0x0000000a);
SET(MCU_PIOC|PIO_PUER, 0x0000000a);
SET(MCU_PIOC|PIO_PDR, 0x0000000a);
}

// чтение ID
void NAND_READ_ID(void)
{

unsigned short status;

write_command(0x0090); // в старших адресах 0x00
write_address(0x0000);

status = read_data();
printf("NAND status = %.4x\n", (unsigned)status);

status = read_data();
printf("NAND status = %.4x\n", (unsigned)status);

status = read_data();
printf("NAND status = %.4x\n", (unsigned)status);

status = read_data();
printf("NAND status = %.4x\n", (unsigned)status);
}



На выходе получаю FFFF. Шина данных подтянута. Такое ощущение, что nand просто не работает.
Но! При подаче управляющего сигнала переазгрузки (write_command(0x00FF); ) сигнал R/B генерируется и прерыване возбуждается. Что говорит о том что NAND срабатывает. Ошибки в передаче по сигнальным линиям быть не может.
Очень часто данная команда "не проходит", но всегда прохоит команда (write_command(0xFFFF)!!! С чем это связанно я не знаю.
Аналогичный алгоритм работает при использовани 8 битной NAND.

При использовании другого значения для SMC Chip Select Register 3 ( SET(MCU_MC|SMC_CSR3, 0x77033F80)) в соответствии с даташитом.
Получаю на выходе 0x1111.

Может кроме EBI и SMC нужно что-то еще настраивать?
Мог накосячить в разыменовании указателя типа short, но в листинге (см. выше) ошибок не нашел.
Думаю косяк в програмной части, но где найти не могу.
Подскажите! Собственных сил уже не осталось, все волосы с задницы вырвал.
Расчитываю на вашу помощь!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
primus
сообщение Jul 21 2009, 17:51
Сообщение #2





Группа: Участник
Сообщений: 11
Регистрация: 9-04-07
Из: Санкт-Петербург
Пользователь №: 26 884



Все оказалось гораздо проще. Выбранная микросхема 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
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 31st July 2025 - 20:23
Рейтинг@Mail.ru


Страница сгенерированна за 0.01403 секунд с 7
ELECTRONIX ©2004-2016