Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: замена AT45DB161B-RI на AT45DB161D-SU
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
plombir
Доброго дня, Господа!

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

Если кто сталкивался с программным опросом м/с flash AT45 через регистр, подскажите пожалуйста последовательность действий при ожидании занятости.
prottoss
Цитата(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);
}
VDG
Цитата(plombir @ Nov 17 2006, 15:33) *
Если кто сталкивался с программным опросом м/с flash AT45 через регистр, подскажите пожалуйста последовательность действий при ожидании занятости.

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

Два лучше, чем один :-) сразу "в лоб" - асинхронные запись и чтение. И вообще по необходимости.
У меня, например, во втором FAT-ик лежит и места не занимает в основной памяти и записать
быстренько можно в случае чего и лишний раз не писать-читать.....
rezident
Цитата(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
Думаю все понятно станет.
prottoss
Цитата(rezident @ Nov 18 2006, 03:23) *
На гав.ру почитайте статейки про DataFlash. http://www.gaw.ru/html.cgi/txt/ic/Atmel/me.../at45/index.htm
Думаю все понятно станет.
Спасибо! Не много, но толково. В принципе, все понятно
Ykidia
Цитата
Ничего сложного там нет. Читаете даташит и строго повторяете "эпюры". В даташите кстати есть и полный рисунок всех эпюр для опроса регистра состояния.

Все так, родной, да вот незадача - на некоторых экземплярах 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, 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;
}
Ykidia
Спасибо за ответ. У меня примерно такой же код (собственно там сложно сделать принципиально по-другому smile.gif ). Но работает не везде. На осцилле вижу обмен (например, когда висит в бесконечном ожидании занятости), все как надо. Конечно, у нас нет такого обширного опыта работы с различными изделиями Atmel, как у Вас, однако к AT45DB161B нареканий нет - там действительно как написано, так и работает. Но вот что делать с 'D'...
add
Работал с AT45DB041 в soic8 корпусе. Там нет ножки на RDY/BUSY . Опрашивал програмно. CS вниз, потом 0x57, читаю байт ипроверяю седьмой бит. Если "1" то CS вверх и работаю дальше.Если "0" читаю еще один байт, пока не получу "1" в седьмом бите.
Проблем с этим небыло.
Сергей Борщ
Цитата(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 сразу после передачи команды? Тогда там может быть все, что угодно, впоть до копии посланных данных, ведь во время приема команды состояние выходной линии памяти неопределено.
Ykidia
Да, фиктивную передачу делаю, иначе просто бит окончания приема/передачи никогда не установится (потому что передача не будет запущена, клоки не пойдут и т.д. 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 );
}

Однако теперь никакие передергивания не спасают... Что-то не так делаю...
Itch
Насколько я понял из даташита, читать весь статусный байт не обязательно, можно послать команду чтения статус-байта, потом ещё один раз дернуть клок и остановиться. При этом вывод MISO будет индикатором завершения записи.
Artem_Petrik
Цитата
do {
DF_ChipSelect_Start();
SPI_WriteByte( DF_CMD_STATUS_READ_SPI03 );
bLastStatus = SPI_ReadByte();
DF_ChipSelect_Stop();
} while( (bLastStatus & 0x80) == 0 );


Здесь при неготовности микросхемы после деселекта микросхемы сразу идет опять выбор. Достаточно ли времени ChipSelect находится в неактивном состоянии, чтобы DataFlash его заметила? Ато проц нереально шустрый, может она не успевает? У меня с другими микрухами из-за этого както раз были проблемы, пришлось вставлять задержку. Так у меня AVR-ка была, а тут проц побыстрее.
Сергей Борщ
Цитата(Ykidia @ Mar 28 2007, 13:38) *
Да, фиктивную передачу делаю, иначе просто бит окончания приема/передачи никогда не установится
А покажите настройку SPI и текст SPI_WriteByte(), SPI_ReadByte()
Ykidia
Вот они:

Код
#define SPI_MODE                0x38    // MSTR CPOL CPHA = 111
#define SPI_RATE                0x08

// SPI Initialization
void SPI_Init( void )
{
    S0SPSR;
    S0SPINT         = 0x01;
    S0SPCCR         = SPI_RATE;
    S0SPCR          = SPI_MODE;
    S0SPDR;
    S0SPSR;
}

// SPI Read byte
unsigned char SPI_ReadByte( void )
{
    unsigned char bTmp;

    S0SPSR;
    S0SPCCR         = SPI_RATE;
    S0SPCR          = SPI_MODE;
    S0SPDR          = 0;
    do {
        bTmp = S0SPSR;
        if( (bTmp & 0x10) != 0 )
            // if MODF = 1
            S0SPCR = SPI_MODE;
        if( (bTmp & 0x40) != 0 )
            // if WCOL = 1
            S0SPDR;
    } while( (bTmp & 0x80) == 0 );

    return( S0SPDR );
}

// SPI Write byte
void SPI_WriteByte( unsigned char bData )
{
    unsigned char bTmp;

    S0SPSR;
    S0SPCCR         = SPI_RATE;
    S0SPCR          = SPI_MODE;
    S0SPDR          = bData;
    do {
        bTmp = S0SPSR;
        if( (bTmp & 0x10) != 0 )
            // if MODF = 1
            S0SPCR = SPI_MODE;
        if( (bTmp & 0x40) != 0 )
            // if WCOL = 1
            S0SPDR;
    } while( (bTmp & 0x80) == 0 );
}


Раньше на чтение/запись по SPI была одна функция, но когда начались непонятные пляски, пришлось разделить на всякий случай.
Сергей Борщ
Цитата(Ykidia @ Mar 30 2007, 09:17) *
Вот они:
Ха! Батенька!
#define SPI_MODE 0x38
Цитата
6 LSBF LSB First controls which direction each byte is shifted when transferred. When 1, SPI data is transferred LSB (bit 0) first. When 0, SPI data is transferred MSB (bit 7) first.
Вы же данные не тем концом суете.
Цитата
All instructions, addresses, and data are transferred with the most significant bit (MSB) first.

Код
{
    __spcr_bits Tmp;
    Tmp.CPHA = 1;
    Tmp.CPOL = 1;
    Tmp.MSTR = 1;
    Tmp.LSBF = 0;
    Tmp.SPIE = 0;
    S0SPCR_bit = Tmp;
}
В остальном не вижу криминала. Единственное, у меня IAR строчки вида S0SPSR; просто выкидывает. Хотя это явная ошибка, по стандарту должно быть чтение. Поэтому я делаю { volatile uint8_t tmp = S0SPSR; }. Не смотрели листинг, может то же самое?
sensor_ua
Цитата
Единственное, у меня IAR строчки вида S0SPSR; просто выкидывает. Хотя это явная ошибка

Вспоминается, что если S0SPSR объявлен как volatile, то не должон. Если объявлен не так, то компилер имеет полное право. В iomacro.h написано, что
SFR_B разворачивается в __io union, а в мануале пишут
The __io memory attribute implies that objects are __no_init and volatile.
Если правда игнорит, то действительно невесело.
Сергей Борщ
Цитата(sensor_ua @ Mar 31 2007, 09:00) *
Вспоминается, что если S0SPSR объявлен как volatile, то не должон. Если правда игнорит, то действительно невесело.
В том то и дело:
Код
#define __IO_REG32_BIT(NAME, ADDRESS, ATTRIBUTE, BIT_STRUCT)\
                        volatile __no_init ATTRIBUTE union \
                         {                                 \
                           unsigned long NAME;             \
                           BIT_STRUCT NAME ## _bit;      \
                         } @ ADDRESS
__IO_REG32_BIT(S0SPSR, 0xE0020004,__READ,__spsr_bits);
//-----------------------------------
    S0SPSR = 0;
    S0SPSR;          // Warning[Pe174]: expression has no effect
    S0SPSR = 0;
//-----------------------------------
    379              S0SPSR = 0;
   \   000001BC   041082E5           STR         R1,[R2, #+0x4]
    380              S0SPSR;
    381              S0SPSR = 0;
   \   000001C0   041082E5           STR         R1,[R2, #+0x4]
Я помню, ReAl когда-то писал, что подобные выражения оформляет как (void)S0SPSR; чтобы самому себе напомнить, что это не описка а чтение. Но, увы, IAR тут делает большой промах. Хотя по доке вроде все нормально:
Цитата
Descriptions of implementation-defined behavior
Access to volatile objects (6.5.3)
Any reference to an object with volatile qualified type is an access.
Смущает только упоминание implementation-defined behavior. Надо будет на работе в стандарт глянуть - что там об этом случае сказано.

P.S. Ветка как-то плавно уползла от AVR к ARM, но описанная проблема относится ко всем IAR, с которыми работал.
zltigo
Цитата(Сергей Борщ @ Mar 31 2007, 12:24) *
P.S. Ветка как-то плавно уползла от AVR к ARM, но описанная проблема относится ко всем IAR, с которыми работал.

Да нету проблемы. Использую постоянно. Ниже первый попавшийся кусок, где дважды используется пустышка. Командная строка и листинг прилагаются.

Код
//////////////////////////////////////////////////////////////////////////////
//                                                                           /
// IAR ARM ANSI C/C++ Compiler V4.41A/W32   27/Mar/2007  19:41:57 /
// Copyright 1999-2005 IAR Systems. All rights reserved.                     /
//                                                                           /
//    Cpu mode        =  arm                                                 /
//    Endian          =  little                                              /
//    Stack alignment =  4                                                   /
//    Source file     =  D:\ARM_WORK\pcmu\MAIN\SPI.C                         /
//    Command line    =  D:\ARM_WORK\pcmu\MAIN\SPI.C -D LPC2000_IAR -lC      /
//                       D:\ARM_WORK\pcmu\Works\List\ -lA                    /
//                       D:\ARM_WORK\pcmu\Works\List\ --remarks -o           /
//                       D:\ARM_WORK\pcmu\Works\Obj\ -s9 --debug --cpu_mode  /
//                       arm --endian little --cpu ARM7TDMI-S --stack_align  /
//                       4 --warnings_affect_exit_code                       /
//                       --no_path_in_file_macros -e --require_prototypes    /
//                       --fpu None --dlib_config "D:\IAR\Embedded           /
//                       Workbench\arm\LIB\dl4tpannl8n.h" -I                 /
//                       D:\ARM_WORK\pcmu\..\COMMON\RTOS\portable\IAR\LPC200 /
//                       0\ -I D:\ARM_WORK\pcmu\..\COMMON\RTOS\include\ -I   /
//                       D:\ARM_WORK\pcmu\..\COMMON\include\ -I              /
//                       D:\ARM_WORK\pcmu\MAIN\include\ -I "D:\IAR\Embedded  /
//                       Workbench\arm\INC\" --inline_threshold=2            /
//    List file       =  D:\ARM_WORK\pcmu\Works\List\SPI.s79                 /
//                                                                           /
//                                                                           /
//////////////////////////////////////////////////////////////////////////////

....

        RSEG CODE:CODE:NOROOT(2)
        CFI Block cfiBlock7 Using cfiCommon0
        CFI Function fpga_switch
        ARM
//  int fpga_switch( WORD data, WORD addr )
//  {
//  ulong value = ( 0x9C0000>>(8+2) );
//  int ret_data;
//  value |= (addr>>8)|((addr&0x1F)<<3);      
//  value <<= 8;
//  value |= (data>>8)|((data&0x1F)<<3);      
//  value <<= 2;
fpga_switch:
        LSR      R2,R1,#+8
        AND      R1,R1,#0x1F
        ORR      R1,R2,R1, LSL #+3
        ORR      R1,R1,#0x2700
        LSR      R2,R0,#+8
        AND      R0,R0,#0x1F
        ORR      R0,R2,R0, LSL #+3
        ORR      R0,R0,R1, LSL #+8
        LSL      R1,R0,#+2
//  IO0CLR = P0B_SEL_FPGA;    // Select(soft)
        MOV      R0,#-536870908
        ORR      R0,R0,#0x28000
        MOV      R2,#+268435456
        ORR      R2,R2,#0x1000
        STR      R2,[R0, #+8]
//  SSPDR  = value>>16;
        MOV      R3,#-536870904
        ORR      R3,R3,#0x68000
        LSR      R12,R1,#+16
        STR      R12,[R3, #+0]
//  IO0SET = P0B_SEL_FPGA;    // Unselect
        STR      R2,[R0, #+0]
//  while( !(SSPSR & SSPSR_RNE) );
??fpga_switch_0:
        LDR      R0,[R3, #+4]
        TST      R0,#0x4
        BEQ      ??fpga_switch_0
//  ret_data = SSPDR;
        LDR      R0,[R3, #+0]
//  SSPDR = value>>8;
        LSR      R2,R1,#+8
        STR      R2,[R3, #+0]
//  while( !(SSPSR & SSPSR_RNE) );
??fpga_switch_1:
        LDR      R2,[R3, #+4]
        TST      R2,#0x4
        BEQ      ??fpga_switch_1
//  SSPDR;
        LDR      R2,[R3, #+0]
//  SSPDR = value;
        STR      R1,[R3, #+0]
//  while( !(SSPSR & SSPSR_RNE) );
??fpga_switch_2:
        LDR      R1,[R3, #+4]
        TST      R1,#0x4
        BEQ      ??fpga_switch_2
//  SSPDR;
        LDR      R1,[R3, #+0]
//  return( ret_data );
        MOV      PC,LR           ;; return
        CFI EndBlock cfiBlock7
//  }
Сергей Борщ
Цитата(zltigo @ Mar 31 2007, 15:32) *
Да нету проблемы.
Конечно! А я, значит, листинг и варнинг компилятора сам сочинил?
zltigo
Цитата(Сергей Борщ @ Mar 31 2007, 15:45) *
Конечно! А я, значит, листинг и варнинг компилятора сам сочинил?

А я smile.gif ? Только я еще и командную строку, и версию компилятора привел, однако.
Могу еще добавить, для другого регистра и других условий:
Код
//  __fiq __arm void FIQ_ISR_handler(void)
//  {
FIQ_ISR_handler:
        SUB      LR,LR,#+4
        CFI ?RET R14
        PUSH     {R0-R4,LR}
        CFI ?RET Frame(CFA, -4)
        CFI R4 Frame(CFA, -8)
        CFI R3 Frame(CFA, -12)
        CFI R2 Frame(CFA, -16)
        CFI R1 Frame(CFA, -20)
        CFI R0 Frame(CFA, -24)
        CFI CFA R13+24
        SUB      SP,SP,#+16
        CFI CFA R13+40
//  ulong data;    
//  // Need for Request clear:(    
// S0SPSR;
        MOV      R8,#-536870908
        ORR      R8,R8,#0x20000
        LDR      R0,[R8, #+0]
// // Clear Interrupt
// S0SPINT = SPINT_SPIIF;
        MOV      R0,#+1
        STR      R0,[R8, #+24]
//  Read Data
//  data = S0SPDR;
        LDR      R9,[R8, #+4]
......
Ykidia
Цитата
Вы же данные не тем концом суете.

Вообще-то 2 варианта. Если вдруг Вы правы, тогда у меня бы все читалось наоборот, и в статусе было бы что-то вроде 0x35 вместо 0xAC или 0x37 вместо 0xEC. Но такого нет и рядом, читается 0x00 (либо 0xFF, который я раньше выдавал в линию для старта передачи), а в большинстве "рабочих" экземпляров читается что надо.
Ну а второй вариант - просто посмотрите внимательно на мой дефайн:
Цитата
#define SPI_MODE 0x38

Бит 6 = 0, отсюда
Цитата
When 0, SPI data is transferred MSB (bit 7) first.

что вполне совпадает с требованиями:
Цитата
All instructions, addresses, and data are transferred with the most significant bit (MSB) first.


Цитата
Единственное, у меня IAR строчки вида S0SPSR; просто выкидывает. Хотя это явная ошибка, по стандарту должно быть чтение. Поэтому я делаю { volatile uint8_t tmp = S0SPSR; }. Не смотрели листинг, может то же самое?

У меня не выкидывает. Смотрел по листингу для 2214 - чтение на месте. Для 2138 при компиляции почему-то сообщает, что выражение не имеет эффекта, но по листингу все равно чтение остается.
Сергей Борщ
Цитата(Ykidia @ Mar 31 2007, 19:59) *
Ну а второй вариант - просто посмотрите внимательно на мой дефайн:
Бит 6 = 0
Мда, сглупил. Извиняюсь. Сообщите, если найдете причину. Альтернатив-то команде чтения статуса нет, а на нее все остальные завязаны. Маловероятно, чтобы такую плюху пропустили.
Еще меня несколько смущает, что вы каждый раз делаете переинициализацию SPI. Может в результате этого происходит какое-то лишнее шевеление ногой CLK? Я бы попробовал с таким максимально простым кодом:
Код
unsigned char SPI_ReadByte( void )
{
    S0SPDR          = 0;
    while( !(S0SPSR & 0x80) );
    return( S0SPDR );
}

void SPI_WriteByte( unsigned char bData )
{
    S0SPDR          = bData;
    while( !(S0SPSR & 0x80) );
}
defunct
Цитата(Ykidia @ Mar 31 2007, 19:59) *
Вообще-то 2 варианта. Если вдруг Вы правы, тогда у меня бы все читалось наоборот...

Вообще-то был бы только 1 вариант - писалось бы наоборот тоже. Тобиш вместо опкода 0x57 посылался бы 0xEA.. На такой опкод вполне реально получить в ответ 0x0 или 0xFF.
Но это к проблеме не относится.. а так просто чтобы обратить внимание на причинно следственную связь.

А по проблеме, думаю банально накосячили с сигналами либо заняли чем-то SSEL..
Если программно клокать, работает?

Цитата
S0SPSR;

Я бы так ни в жизнь не написал.

Код
    V32 dummy = S0SPSR; // dummy read of SPIF

куда понятнее смотрится и безопастнее.
sensor_ua
Цитата
Я бы так ни в жизнь не написал

А меня задолбали варнинги на неиспользуемые dummy и стал писать только такwink.gif
zltigo
Цитата(defunct @ Apr 1 2007, 03:56) *
Я бы так ни в жизнь не написал.

Жизнь она такая штука smile.gif - меняется smile.gif. Чем, например, такое написание хуже и непонятнее вызова функции без аргументов с игнорированием возвращаемого ей значения?
Это нормально?
status();
Или так надо smile.gif?
V32 dummy = status();
Ykidia
Цитата
Я бы попробовал с таким максимально простым кодом

Да у меня и было максимально просто, а как пошли глюки, так я постарался сделать точно так, как написано в даташите на LPC2214 в разделе SPI:

The following sequence describes how one should process a data transfer with the SPI block when it is set up to be the master.
This process assumes that any prior data transfer has already completed.
1. Set the SPI clock counter register to the desired clock rate.
2. Set the SPI control register to the desired settings.
3. Write the data to transmitted to the SPI data register. This write starts the SPI data transfer.
4. Wait for the SPIF bit in the SPI status register to be set to 1. The SPIF bit will be set after the last cycle of the SPI data
transfer.
5. Read the SPI status register.
6. Read the received data from the SPI data register (optional).
7. Go to step 3 if more data is required to transmit.

Ну и т.д. wink.gif
Цитата
просто чтобы обратить внимание на причинно следственную связь.

Это да, но про варианты я сказал не особо серьезно, так как внимание уже было обращено на тот факт, что почти везде работает как надо, т.е. пишет, читает то, что писалось, читается статус - занятость, результат сравнения и т.д.
Цитата
Я бы так ни в жизнь не написал.

Никогда не говорите никогда.
Плохо кончится, родной © Кин-дза-дза
wink.gif
Однако я так пишу потому что
Цитата
А меня задолбали варнинги на неиспользуемые dummy и стал писать только так
полностью согласен smile.gif. Более того - Вы смотрели листинг с использованием этих dummy? Я решил проверить. почему выходит варнинг, и оказалось, что для таких случаев строки типа
Цитата
V32 dummy = S0SPSR; // dummy read of SPIF
просто выкинуты и отсутствуют в ассемблерном коде.
defunct
Цитата(Ykidia @ Apr 1 2007, 22:48) *
и оказалось, что для таких случаев строки типа
Цитата

V32 dummy = S0SPSR; // dummy read of SPIF

просто выкинуты и отсутствуют в ассемблерном коде.

Приводите в пример конкретные строки, которые у вас выкидываются или те на которых у вас выскакивают варнинги.

V32 это есть
typedef volatile unsinged long V32
и на приведенной строчке варнинга не может быть впринципе.

Цитата(zltigo @ Apr 1 2007, 08:18) *
Жизнь она такая штука smile.gif - меняется smile.gif.

;>
Цитата
Чем, например, такое написание хуже и непонятнее вызова функции без аргументов с игнорированием возвращаемого ей значения?

Оно неестественно выглядит.. То ли это вызов макроса, но тогда почему бы не добавить (), то ли просто переменная воткнута. Дело привычки и стиля.
такое тоже смотрится неестественно:

if (condition)

// la la
// bla bla

do_sth();

тем не менее компилироваться и работать будет..
Ykidia
Доброе утро! wink.gif
Цитата
V32 это естьtypedef volatile unsinged long V32и на приведенной строчке варнинга не может быть впринципе.

Извиняюсь, был неправ, надо было самому уточнить, что такое V32.
Цитата
Вы же согласны что такое смотрится неестественно:
if (condition)

// la la
// bla bla

do_sth();

а компилироваться и работать будет..

Согласен. Вашу точку зрения понимаю wink.gif
Ykidia
Господа! Прошу простить меня за беспокойство! Проблема локализована (вроде): причиной всей заварухи был плохая пропайка. В отчаянии нажал пальцем на корпус микросхемы, и она стала давать ответы. Хотя раньше осциллом проверял - все сигналы типа доходят. Но удивительно другое. Если была плохая связь по SPI в результате недостаточного контакта или еще чего-то, то почему не работало лишь частично, а именно - из использующихся команд не работала только команда чтения статуса? Как такое может быть?
На других экземплярах причина оказалась именно в неправильном режиме SPI, который подходил для 'B', но не подходит для 'D'.
Просто так получилось по иронии судьбы, что я, для экспериментов и исследования взяв, на свой взгляд, плату с самым стабильным повторением эффекта (казалось бы, того же самого), долго мучился с ней по совсем другой причине - плохие контакты...
Итак, Atmel оказался ни при чем (по крайней мере, криминала нет), это я ступил. Поэтому сам отвечаю на свои же вопросы:
Цитата
Как бы гарантированно читать регистр статуса? Сигнал RDY/BUSY на внешней ноге - это хорошо, а результат сравнения откуда тогда брать?

1. Правильно настроить SPI: CPOL = 1, CPHA = 1 (при CPHA = 0 также работает, но при CPOL = 0 не работает никак), такую конфигурацию называют обычно SPI Mode 3.
2. Использовать команду чтения статуса 0xD7, про устаревший ("legacy") код команды 0x57 - забыть.
3. Убедиться в том, что все хорошо пропаяно, сигналы соответствуют нормам и т.д. и т.п.

Цитата
а какие еще команды "могут не работать" в этих флэшках?
Никакие. Все, по крайней мере из обычно используемых, работают. Однако с плохими контактами может быть всякое - что-то может работать, а что-то нет. Здесь Atmel, ясное дело, не при чем, все вопросы к монтажникам/разводчикам/электронщикам.
Ykidia
Забыл сказать всем ответившим - большое спасибо за помощь и понимание!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.