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

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> замена AT45DB161B-RI на AT45DB161D-SU, проблема с отсутствием ноги RDY/~BUSY
plombir
сообщение Nov 17 2006, 12:33
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 99
Регистрация: 14-12-05
Пользователь №: 12 191



Доброго дня, Господа!

Так как м/с flash AT45DB161B-RI (28 ног) снята с производства, решено заменить её на 8-и ножечную. Так, вот, проблема возникла при написании кода определения занятости м/с. Если раньше сигнал проверялся на ноге RDY/~BUSY и проблем не было, то здесь она отсутствует и приходится проверять через "Регистр Статуса" 7-ой бит. Что то не получается... Перепробовал по разному и по всякому. Начинает работать если ставится задержка из цикла NOP-ов вместо ожидания.

Если кто сталкивался с программным опросом м/с flash AT45 через регистр, подскажите пожалуйста последовательность действий при ожидании занятости.
Go to the top of the page
 
+Quote Post
prottoss
сообщение Nov 17 2006, 12:41
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(plombir @ Nov 17 2006, 19:33) *
Доброго дня, Господа! ...
... Если кто сталкивался с программным опросом м/с flash AT45 через регистр, подскажите пожалуйста последовательность действий при ожидании занятости.
Буквально на днях нацарапал вот такую подпрограммку - работает)

Код
/*****************************************************************************
Биты регистра состояния
******************************************************************************/

/* Bit 7 = "1" (RDY) indicates the device is ready.
Bit 7 = "0" indicates the write cycle is in progress. */
#define AT45_SREG_RDY  7



/* Bit 6 = "0" data in the main memory page matches the data in the buffer.
Bit 6 = "1" at least one bit of the data in the main memory page not match
the data in the buffer. */
#define AT45_SREG_COMP  6



/* маска идентификатора чипа, сдвинутая в право на два бита */
#define AT45_DEVICE_ID_MASK (0x0F << 2)



/*****************************************************************************
Инициализация SPI драйвера и тестирование МС памяти
Возвращает TRUE, если нет ошибок памяти, иначе FALSE
******************************************************************************/
BOOL SPIMEM_Init(void)
{
   SPI_Init(); /* инициализируем порт SPI */

    

/* ждем установки памяти в рабочее состояние */
ULONG start = g_SysTIME_ms;
    while(AT45_STARTUP_TIME > (g_SysTIME_ms - start));

    

/* читаем регистр статуса МС */
    UCHAR status = SPIMEM_GetStatus();
    if(AT45_DEVICE_ID != (status  & AT45_DEVICE_ID_MASK))
       return FALSE; /* ошибка! не совпал ID установленной МС */

    

/* тестируем внутренние буферы МС */
UCHAR test = 0x55; /* тест-байт */
    for(UCHAR j = 0; j < 2; j++)
    {
     for(UINT i = 0; i < AT45_PAGE_SIZE; i++)
     {
           /* пишем тест-байт в оба буфера */
           SPIMEM_BufWrite(AT45_BUFFER1_WRITE, i, 1, &test);
         SPIMEM_BufWrite(AT45_BUFFER2_WRITE, i, 1, &test);
      
            /* проверяем прочитанный байт на равенство тест-байту */
        SPIMEM_BufRead(AT45_BUFFER1_READ, i, 1, &status);
         if(test != status)
                return FALSE;
            SPIMEM_BufRead(AT45_BUFFER2_READ, i, 1, &status);
         if(test != status)
              return FALSE;
        }
        test = 0xAA; /* инвертируем тест-байт */
    }

    /* OK */
    return TRUE;
}



/*****************************************************************************
Чтение регистра статуса
AT45_STATUS_READ
******************************************************************************/
UCHAR SPIMEM_GetStatus(void)
{
   SPI_SlaveSelect(); /* выбираем чип */
    SPI_Write(AT45_STATUS_READ); /* посылаем команду */
    UCHAR status = SPI_Read(); /* читаем статус */
    SPI_SlaveDeselect(); /* освобождаем чип */
    return status;
}


/*****************************************************************************
Чтение порта SPI
******************************************************************************/
UCHAR SPI_Read(void)
{
   SPDR = 0xff; /* загружаем SPI данными */
    while(!(SPSR & (1<<SPIF))); /* ждем окончания передачи */
    return SPDR; /* возвращаем принятые данные */
}

/*****************************************************************************
Запись в порт SPI
******************************************************************************/
void SPI_Write(UCHAR data)
{
   SPDR = data; /* загружаем SPI данными */
    while(!(SPSR & (1<<SPIF))); /* ждем окончания передачи */
}



/*****************************************************************************
Чтение буфера
AT45_BUFFER1(2)_READ = 0x54(0x56)
Вход:
command - команда чтения буфера №1 или №2
buf_pos - адрес начала читаемого блока в буфере
size  - размер блока
trg  - буфер для записи
******************************************************************************/
void SPIMEM_BufRead(UCHAR command, UINT buf_pos, UINT size, UCHAR *trg)
{
   /* сылаем команду */
   SPIMEM_Tx5(command, 0, buf_pos);

    /* читаем массив */
    while(size--)
     *trg++ = SPI_Read();

    /* освобождаем чип */
    SPI_SlaveDeselect();
}

/*****************************************************************************
Запись в буфер
AT45_BUFFER1(2)_WRITE = 0x84(0x87)
Вход:
command - команда записи в буфер №1 или №2
buf_pos - адрес начала читаемого блока в буфере
size  - размер блока
src  - буфер для чтения
******************************************************************************/
void SPIMEM_BufWrite(UCHAR command, UINT buf_pos, UINT size, UCHAR *src)
{
   /* посылаем команду */
   SPIMEM_Tx4(command, 0, buf_pos);

    /* пишем массив */
    while(size--)
     SPI_Write(*src++);

    /* освобождаем чип */
    SPI_SlaveDeselect();
}



/*****************************************************************************
4-х байтная посылка:
Вход:
command  - команда
page_addr - адрес страницы
buf_pos  - позиция в буфере

!!! Кроме этого производит выборку кристалла МС !!!
******************************************************************************/
void SPIMEM_Tx4(UCHAR command, UINT page_addr, UINT buf_pos)
{
   SPI_SlaveSelect();
   page_addr <<= 1;
    SPI_Write(command);
   SPI_Write(HIBYTE(page_addr));
    SPI_Write(LOBYTE(page_addr) | HIBYTE(buf_pos));
    SPI_Write(LOBYTE(buf_pos));
}

/*****************************************************************************
5-и байтная посылка:
Установка адреса дополняется посылкой 1-го пустого байта

!!! Кроме этого производит выборку кристалла МС !!!
******************************************************************************/
void SPIMEM_Tx5(UCHAR command, UINT page_addr, UINT buf_pos)
{
   SPIMEM_Tx4(command, page_addr, buf_pos);
    SPI_Write(0);
}


--------------------
Go to the top of the page
 
+Quote Post
VDG
сообщение Nov 17 2006, 12:42
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 845
Регистрация: 10-02-06
Пользователь №: 14 193



Цитата(plombir @ Nov 17 2006, 15:33) *
Если кто сталкивался с программным опросом м/с flash AT45 через регистр, подскажите пожалуйста последовательность действий при ожидании занятости.

Ничего сложного там нет. Читаете даташит и строго повторяете "эпюры". В даташите кстати есть и полный рисунок всех эпюр для опроса регистра состояния.


--------------------
Go to the top of the page
 
+Quote Post
prottoss
сообщение Nov 17 2006, 15:14
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Раз уж создана тема про ДатаФлэш, хотелось бы спросить: От чего в некоторых МС АТ45ххх сделано два буфера? В чем скрытый смысл, мне не известный? Просвятите, плиз...
Вроде бы в даташите по использованию данной серии http://www.atmel.com/dyn/resources/prod_do...nts/doc0842.pdf приведены алгоритмы работы с одним буфером...


--------------------
Go to the top of the page
 
+Quote Post
vesago
сообщение Nov 17 2006, 19:29
Сообщение #5


Тутэйшы
****

Группа: Свой
Сообщений: 708
Регистрация: 30-11-04
Пользователь №: 1 263



Я из экономии ног и 28 ноговую db161 опрашивал через статусный регистр. Работает хорошо. Второй буфер я пользовал как промежуточный буфер. Я во флеш писал журнал. Накапливал сначала в первом буфере и как заполнял - скидывал в основную память. Когда производил выборку, дабы не вносить изменений, временно вновь поступающие данные кидал во второй буфер. После завершения выборки, копировал в первый буфер. Вообще лишняя рама в системе никогда не повредит.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Nov 17 2006, 19:36
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(prottoss @ Nov 17 2006, 17:14) *
Раз уж создана тема про ДатаФлэш, хотелось бы спросить: От чего в некоторых МС АТ45ххх сделано два буфера?

Два лучше, чем один :-) сразу "в лоб" - асинхронные запись и чтение. И вообще по необходимости.
У меня, например, во втором FAT-ик лежит и места не занимает в основной памяти и записать
быстренько можно в случае чего и лишний раз не писать-читать.....


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
rezident
сообщение Nov 17 2006, 20:23
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(prottoss @ Nov 17 2006, 20:14) *
Раз уж создана тема про ДатаФлэш, хотелось бы спросить: От чего в некоторых МС АТ45ххх сделано два буфера? В чем скрытый смысл, мне не известный? Просвятите, плиз...
Вроде бы в даташите по использованию данной серии http://www.atmel.com/dyn/resources/prod_do...nts/doc0842.pdf приведены алгоритмы работы с одним буфером...

На гав.ру почитайте статейки про DataFlash. http://www.gaw.ru/html.cgi/txt/ic/Atmel/me.../at45/index.htm
Думаю все понятно станет.
Go to the top of the page
 
+Quote Post
prottoss
сообщение Nov 18 2006, 16:17
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(rezident @ Nov 18 2006, 03:23) *
На гав.ру почитайте статейки про DataFlash. http://www.gaw.ru/html.cgi/txt/ic/Atmel/me.../at45/index.htm
Думаю все понятно станет.
Спасибо! Не много, но толково. В принципе, все понятно


--------------------
Go to the top of the page
 
+Quote Post
Ykidia
сообщение Mar 28 2007, 12:41
Сообщение #9


Частый гость
**

Группа: Свой
Сообщений: 80
Регистрация: 3-08-06
Пользователь №: 19 287



Цитата
Ничего сложного там нет. Читаете даташит и строго повторяете "эпюры". В даташите кстати есть и полный рисунок всех эпюр для опроса регистра состояния.

Все так, родной, да вот незадача - на некоторых экземплярах AT45DB161D команда чтения регистра статуса не работает.
Причем в горячо любимом даташите написано, чтобы не пользовали устаревшие коды команд для режимов SPI, которые не будут поддерживаться. Т.е. для чтения статуса надо пользовать код 0xD7 в соотв. режиме (SPI Mode 0 или 3, я использую Mode 3 - CPOL = 1 и CPHA = 1), а про 0x57 - забыть.
Причем сказано, что код 0x57 все-таки поддерживается, но в микросхемах выпуска 0636 и позже.
На деле получается такая "особенность": у меня сейчас партия плат с уже впаянными датафлэшами выпуска 0647, т.е. вроде все должно быть пучком. Но нет - на некоторых экземплярах не работает ни один из вышеприведенных кодов команды чтения регистра статуса. Я даже вставлял задержки разные между посылом кода команды и чтения данных с шины - результата никакого: датафлэш отвечает либо то, что я выдаю в регистр данных в момент запуска передачи по SPI (микроконтроллер LPC2214, регистр S0SPDR), либо 0. То же самое происходит, если подать код несуществующей команды.

Так что хотелось бы снова поднять данный вопрос. Как бы гарантированно читать регистр статуса? Сигнал RDY/BUSY на внешней ноге - это хорошо, а результат сравнения откуда тогда брать?
И вообще. Коли пошла такая пьянка - а какие еще команды "могут не работать" в этих флэшках?

Сообщение отредактировал Ykidia - Mar 28 2007, 12:44
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 28 2007, 13:05
Сообщение #10


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Ykidia @ Mar 28 2007, 11:41) *
Так что хотелось бы снова поднять данный вопрос. Как бы гарантированно читать регистр статуса? Сигнал RDY/BUSY на внешней ноге - это хорошо, а результат сравнения откуда тогда брать?И вообще. Коли пошла такая пьянка - а какие еще команды "могут не работать" в этих флэшках?
У меня AT45DB321С ("D" заложена в разводку но пока у наших поставщиков стоит дороже). В процессе путешествия от AT45DB081 через D161,DB161, DB321, DB321B, DB321C ни разу не было чтобы описанная в даташите команда не работала. Вот мой код (к сожалению стандартно лопухнулся с SSEL поэтому приходится шевелить ногами вручную):
Код
uint8_t spi_t::exchange(uint8_t out)
{
    uint8_t Data = out;
    for(uint8_t i = 0; i < 8; i++)
    {
        if(Data & (1 << 7))
            on(SPI_MOSI);
        else
            off(SPI_MOSI);

        on(SPI_SCLK);

        Data <<= 1;

        if(signal(SPI_MISO))
            Data |= (1<<0);
        off(SPI_SCLK);
    }
    return Data;
}
inline void spi_t::wait_done()
{
}
#define STATUS_READ                     0xD7

uint8_t at45_t::ReadStatus( void )
{
    Enable();
    spi_t::exchange(STATUS_READ);
    spi_t::wait_done();
    status_t Result = (status_t)spi_t::exchange();              //send dummy data and receive Status
    spi_t::wait_done();
    Disable();
    return Result;
}


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Ykidia
сообщение Mar 28 2007, 13:25
Сообщение #11


Частый гость
**

Группа: Свой
Сообщений: 80
Регистрация: 3-08-06
Пользователь №: 19 287



Спасибо за ответ. У меня примерно такой же код (собственно там сложно сделать принципиально по-другому smile.gif ). Но работает не везде. На осцилле вижу обмен (например, когда висит в бесконечном ожидании занятости), все как надо. Конечно, у нас нет такого обширного опыта работы с различными изделиями Atmel, как у Вас, однако к AT45DB161B нареканий нет - там действительно как написано, так и работает. Но вот что делать с 'D'...
Go to the top of the page
 
+Quote Post
add
сообщение Mar 28 2007, 13:35
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 345
Регистрация: 10-10-05
Пользователь №: 9 459



Работал с AT45DB041 в soic8 корпусе. Там нет ножки на RDY/BUSY . Опрашивал програмно. CS вниз, потом 0x57, читаю байт ипроверяю седьмой бит. Если "1" то CS вверх и работаю дальше.Если "0" читаю еще один байт, пока не получу "1" в седьмом бите.
Проблем с этим небыло.


--------------------
Если задачу можно решить, то не надо тревожиться. А если нельзя решить, то тревожиться бесполезно.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 28 2007, 13:47
Сообщение #13


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Ykidia @ Mar 28 2007, 12:25) *
однако к AT45DB161B нареканий нет - там действительно как написано, так и работает. Но вот что делать с 'D'...
Хм. может я и погорячился. А пробовали ноги вручную дергать? Вот мой код ожидания готовности, там действительно ошибиться негде:
Код
#if     defined( AT45DB041 )
    #define FLASH_ID_MASK           0x38
    #define FLASH_ID                0x18
#elif   defined( AT45DB161 )
    #define FLASH_ID_MASK           0x3C
    #define FLASH_ID                0x2C
#elif   defined( AT45DB321 )
    #define FLASH_ID_MASK           0x3C
    #define FLASH_ID                0x34
#else
    #error  "No External flash type specified"
#endif
#define COMPARE_MISMATCH_BIT            (1<<6)
#define FLASH_READY_BIT                 (1<<7)

uint8_t at45_t::WaitReady(void)
{
    uint8_t Result;
    do
        Result = ReadStatus();
    while( (Result & (FLASH_ID_MASK | FLASH_READY_BIT)) != (FLASH_ID | FLASH_READY_BIT));
    return Result;
}
Кстати, вот подумалось - а вы при чтении статуса делаете фиктивную передачу или забираете из SPDR сразу после передачи команды? Тогда там может быть все, что угодно, впоть до копии посланных данных, ведь во время приема команды состояние выходной линии памяти неопределено.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Ykidia
сообщение Mar 28 2007, 14:38
Сообщение #14


Частый гость
**

Группа: Свой
Сообщений: 80
Регистрация: 3-08-06
Пользователь №: 19 287



Да, фиктивную передачу делаю, иначе просто бит окончания приема/передачи никогда не установится (потому что передача не будет запущена, клоки не пойдут и т.д. smile.gif ) и проблема в работе SPI тут же обнаружится. Причем какие данные загружаю при фиктивной передаче, такие и получаю на входе в качестве значения регистра статуса. Либо 0x00.
Проблема в том, что у нас несколько вариантов плат. Так получилось, что где-то RDY/BUSY заведен на одну ногу LPC2214/2138, а где-то - на другую. А у меня бутлоадер раньше был под все платы, с определением конкретного микроконтроллера, размера его секторов, доступной памяти и т.д. - всех необходимых данных, чтобы корректно перепрошить контроллер данными из этой DataFlash, если нужно. Теперь же получается, что я должен 1) делать программное сравнение вместо внутреннего аппаратного и 2) делать разные варианты бутлоадера для разных плат. Бред. Неужели это тупик? Так и свихнуться можно...

У меня чтение регистра состояния было реализовано по-разному. Сначала так:
Код
#define DF_CMD_STATUS_READ_SPI03            0xD7
unsigned char bLastStatus;

// *
// * additionally deactivates Chip Select signal before actual waiting,
// * places last status register value in bLastStatus
// *
void DF_Wait_Busy( void )
{
    DF_ChipSelect_Stop();
    bLastStatus = 0;
    DF_ChipSelect_Start();
    SPI_WriteByte( DF_CMD_STATUS_READ_SPI03 );
    do {
        bLastStatus = SPI_ReadByte();
    } while( (bLastStatus & 0x80) == 0 );
    DF_ChipSelect_Stop();
}

Потом, кстати, были ситуации, когда вышеописанная проблема возникала, но устранялась дополнительным "передергиванием" линии _CS. Поэтому я сделал так:
Код
void DF_Wait_Busy( void )
{
    DF_ChipSelect_Stop();
    bLastStatus = 0;
    do {
        DF_ChipSelect_Start();
        SPI_WriteByte( DF_CMD_STATUS_READ_SPI03 );
        bLastStatus = SPI_ReadByte();
        DF_ChipSelect_Stop();
    } while( (bLastStatus & 0x80) == 0 );
}

Однако теперь никакие передергивания не спасают... Что-то не так делаю...
Go to the top of the page
 
+Quote Post
Itch
сообщение Mar 28 2007, 21:42
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 358
Регистрация: 27-06-06
Из: Новосибирск
Пользователь №: 18 410



Насколько я понял из даташита, читать весь статусный байт не обязательно, можно послать команду чтения статус-байта, потом ещё один раз дернуть клок и остановиться. При этом вывод MISO будет индикатором завершения записи.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 18th July 2025 - 08:57
Рейтинг@Mail.ru


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