LINUX.ORG.RU

Рандомная запись в NAND Macronix

 , , , ,


0

2

Пытаюсь осуществить случайные чтение и запись в NAND. Делаю все по AC waveform указанной в даташите

    struct IORequest_t {
        void*    buffer;
        uint16_t ofst;
        uint16_t size;
    };    

    ResultCode_t
    NandBase::Write(uint32_t addr, IORequest_t *requests, uint32_t cnt) {
        /// Вычисляем адрес страницы в микроосхеме
        uint32_t pageNumber = addr / NAND_PAGE_SIZE;
        addr = pageNumber << 16;
    
        /// Ждем готовности микросхемы
        if(WaitReady() != RESULT_SUCCESS) {
            return RESULT_TIMEOUT;
        }
    
        /// Отправляем команду записи
        *(uint8_t* )(MapAddress | COMMAND_SECTION) = 0x80;//CMD_PAGE_WRITE;   
    
        /// Отправляем адрес
        *(uint32_t* )(MapAddress | ADDRESS_SECTION) = addr;
        
    
        /// Записываем данные
        for(uint32_t i = 0; i < cnt; i++) {
            const uint8_t* src  = (const uint8_t*) requests[i].buffer;
            uint16_t ofst = requests[i].ofst;
            uint16_t size = requests[i].size;
        
            /// Проверяем не выйдет ли запись за предел страницы
            if(ofst+size > NAND_PAGE_SIZE) {
                return RESULT_INVALID_PARAMS;
            }
        
            /// Отправляем команду произвольного доступа
            *(uint8_t* )(MapAddress | COMMAND_SECTION) = 0x85;//CMD_PAGE_WRITE;
        
            /// Отправляем смещение
            *(uint16_t*)(MapAddress | ADDRESS_SECTION) = ofst;
        
            /// Пишем данные
            for(const uint8_t* data = src; size; size--) {
                *(uint8_t*)(MapAddress | DATA_SECTION) = *data++;
            }
       
        }
    
        /// Отправляем команду подтверждения записи
        *(uint8_t* )(MapAddress | COMMAND_SECTION) = 0x10;//CMD_WRITE_CONFIRM;
    
        /// Ждем готовности микросхемы
        if(WaitReady() != RESULT_SUCCESS) {
            return RESULT_TIMEOUT;
        }
    
        /// Проверяем результат записи
        uint8_t status;
        ReadStatus(&status);
        if(status & 1) {
            return RESULT_PROGRAM_FAILED;
        }
    
        /// Отправляем коману чтения
        *(uint8_t* )(MapAddress | COMMAND_SECTION) = 0x00;//CMD_PAGE_READ;
    
        /// Отправляем адрес
        *(uint32_t* )(MapAddress | ADDRESS_SECTION) = addr;
    
        /// Отправляем команду подтверждения
        *(uint8_t* )(MapAddress | COMMAND_SECTION) = 0x30;///CMD_READ_CONFIRM;
    
        /// Ждем готовности микросхемы
        if(WaitReady() != RESULT_SUCCESS) {
            return RESULT_TIMEOUT;
        }
 
        /// Чтение каждого блока данных
        for(uint32_t i = 0; i < cnt; i++) {
            const uint8_t* src  = (const uint8_t*) requests[i].buffer;
            uint16_t ofst = requests[i].ofst;
            uint16_t size = requests[i].size;
        
            /// Отправляем команду рандомного доступа
            *(uint8_t*)(MapAddress | COMMAND_SECTION) = 0x05;//CMD_RANDOM_DATA_OUTPUT;
        
            /// Отправляем смещение
            *(uint16_t*)(MapAddress | ADDRESS_SECTION) = ofst;
        
            /// Отправляем команду подтверждения рандомного чтения
            *(uint8_t*) (MapAddress | COMMAND_SECTION) = 0xE0;//CMD_RANDOM_DATA_OUTPUT_CONFIRM;
        
            /// Сравниваем исходные и записанные данные
            for(const uint8_t* data = src; size; size--) {
                if(*data++ != *(uint8_t* )(MapAddress | DATA_SECTION)) {
                    return RESULT_PROGRAM_FAILED;
                }
            }
        }
    
        return RESULT_SUCCESS;
    }
Пишу в предварительно стертый блок, проверка чтением всегда проваливается: читаются единицы. Что я делаю не так?

★★★★★

Последнее исправление: mersinvald (всего исправлений: 1)

        uint32_t pageNumber = addr / NAND_PAGE_SIZE;
        addr = pageNumber << 16;

Вот эта строчка выглядит подозрительно. Вы совсем потеряли младшие биты адреса. Возможно, надо что-то типа

        addr %= NAND_PAGE_SIZE;

Beewek ★★
()
Ответ на: комментарий от Beewek

Заметьте: шифтится номер страницы.
По даташиту он должен быть в старших 2х байтах, а в младших смещение в странице, тут все верно.

mersinvald ★★★★★
() автор топика
Ответ на: комментарий от Beewek

Проблема оказалась хардварная — была подключена не та плата... *facepalm*

mersinvald ★★★★★
() автор топика
Ответ на: комментарий от mersinvald

По даташиту он должен быть в старших 2х байтах, а в младших смещение в странице, тут все верно.

Так у вас смещения не остаётся! Вы же переменную addr перезаписываете сдвинутым номером страницы. Смещение будет всегда нулевым. Вы, видимо, в процессе тестирования всегда писали страницы целиком, поэтому смещение всегда было нулевым, вот и не заметили ошибки.

Beewek ★★
()
Ответ на: комментарий от Beewek

Чего-й то?
16-битный номер страницы в старших байтах (не адрес) и 16-битное смещение в младших.
Тут by design любое смещение обнуляется, если оно есть (а если оно есть - это баг), так как смещения идут в структурке для рандомной записи.

mersinvald ★★★★★
() автор топика
Последнее исправление: mersinvald (всего исправлений: 1)
Ответ на: комментарий от mersinvald

Давайте на примере покажу. Допустим, функция вызывается с параметром addr = 0x123456. Размера страницы я не знаю, пусть будет 0x1000. Тогда pageNumber = addr/0x1000 - получится 0x123, соответственно, смещение должно быть 0x456. А у вас addr = pageNumber << 16, это будет 0x1230000. Смещение (0x456) потеряли.

Вместо 0x1230456 получили 0x1230000. Теперь-то, надеюсь, понятно?

Beewek ★★
()
Ответ на: комментарий от Beewek

А если вы прочитаете мое предыдущее сообщение и код, то вы увидите, что смещение хранится и скармливается контроллеру микросхемы отдельно.

mersinvald ★★★★★
() автор топика
Ответ на: комментарий от mersinvald

А-а-а, теперь понял. Надо было назвать параметр не addr, а pageAddr, а ещё лучше передавать сразу pageNumber. Тогда код был бы яснее.

И ещё одно.

        *(uint8_t* )(MapAddress | COMMAND_SECTION) = 0x80;//CMD_PAGE_WRITE;   
...

        *(uint8_t* )(MapAddress | COMMAND_SECTION) = 0x85;//CMD_PAGE_WRITE;
Обратите внимание на комментарии. Какой-то из них явно не соответствует действительности. Поэтому правильнее и надёжнее объявлять эти CMD_PAGE_WRITE в виде enum-а, а не вставлять в код магические числа с комментариями.

Beewek ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.