Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Запись в Serial EEprom.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Jenya7
Записывая в память нужно следить чтобы не перейти страницу.
Код
#define USE_STATUS_REG 0   //doesn't help any way

void LOGGER_PageWrite(uint32_t address, uint32_t length, uint8_t *buffer)
{
    #if USE_STATUS_REG
    uint32_t timer;
    #endif
    volatile uint32_t page_limit=0;
    volatile uint32_t bytes_to_fit=0;
    volatile uint32_t bytes_to_write=0;

    //find a page limit for the address
    while (address > page_limit)
    {
        page_limit += 64;
    }
    //actual page limit
    page_limit--;

    bytes_to_fit = page_limit - address;
    bytes_to_write = bytes_to_fit;

    // Note!!!Every write operation demands a write enable!!!
    SPI_CSlow();
    SPI_SendByte(SPIEEPROM_CMD_WREN);
    SPI_CShigh();

    // start write
    SPI_CSlow();
    // send write command
    SPI_SendByte(SPIEEPROM_CMD_WRITE);
    // send address
    SPI_SendByte(address>>8);
    SPI_SendByte(address&0x00FF);
    while(bytes_to_write--)
    {
        // send data to be written
         SPI_SendByte(*buffer++);
    }
    // stop write
    SPI_CShigh();

    #if USE_STATUS_REG
    timer = LOGGER_DELAY;
    //wait for write operation to complete
    while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP)
    {
        if(!--timer)
           break;
    }
    #else
    //needs 5ms for page write
    Delay_us_sys(5000);
    #endif

    if (bytes_to_fit <= length)
    {
        address += bytes_to_fit+1;
        bytes_to_write = length - bytes_to_fit;

         // Note!!!Every write operation demands a write enable!!!
        SPI_CSlow();
        SPI_SendByte(SPIEEPROM_CMD_WREN);
        SPI_CShigh();

        // start write
        SPI_CSlow();
        // send write command
        SPI_SendByte(SPIEEPROM_CMD_WRITE);
        // send address
        SPI_SendByte(address>>8);
        SPI_SendByte(address&0xFF);
        while(bytes_to_write--)
        {
            // send data to be written
            SPI_SendByte(*buffer++);
        }
        // stop write
        SPI_CShigh();

        #if USE_STATUS_REG
        timer = LOGGER_DELAY;
        //wait for write operation to complete
        while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP)
        {
            if(!--timer)
                break;
        }
        #else
        //needs 5ms for page write
        Delay_us_sys(5000);
        #endif
    }
}

проверяю. пишу по середине большое количество байт чтоб перейти на другую страницу.
Код
uint8_t rxbuffer[50];
for (int i=0; i < 50; i++)
{
    rxbuffer[i] = i+1;
}
LOGGER_PageWrite(80, 50, rxbuffer);

и потом считываю.
Код
uint8_t txbuffer[50];
LOGGER_Read(80, 50,txbuffer);

результаты такие:
в адрессе 80-127 я вижу данные 1-47 и это правильно
в адрессе 128-130 я вижу /0, 48, 49

то есть первый адресс следующей страницы не прописывается. целый день бьюсь над проблемой не могу понять в чем дело.
aaarrr
Какой-то ужас, если честно.
Код
void eep_write(uint32_t addr, uint32_t len, uint8_t *data)
{
    uint32_t bytes_to_write;

    while(len)
    {
        if(((addr & (EEPROM_PAGE_SIZE - 1)) + len) >= EEPROM_PAGE_SIZE)
            bytes_to_write = EEPROM_PAGE_SIZE - (addr & (EEPROM_PAGE_SIZE - 1));
        else
            bytes_to_write = len;

        // тут пишем (addr, bytes_to_write, data);

        data += a;
        addr += a;
        len -= a;
    }
}
Jenya7
я извиняюсь немного непонятно это
Код
data += a;
addr += a;
len -= a;

'а' это bytes_to_write?


переписал так
Код
void LOGGER_Write(uint32_t address, uint32_t lenght, uint8_t *data)
{
        uint32_t timer;
    uint32_t bytes_to_write=0;

    while(lenght)
    {
       if(((address & (PAGE_SIZE - 1)) + lenght) >= PAGE_SIZE)
           bytes_to_write = PAGE_SIZE - (address & (PAGE_SIZE - 1));
       else
          bytes_to_write = lenght;

       // Every write operation demands a write enable!!!
          SPI_CSlow();
          SPI_SendByte(SPIEEPROM_CMD_WREN);
          SPI_CShigh();

          // start write
          SPI_CSlow();
          // send write command
          SPI_SendByte(SPIEEPROM_CMD_WRITE);
          // send address
          SPI_SendByte(address>>8);
          SPI_SendByte(address&0x00FF);

          while(lenght--)
          {
              // send data to be written
               SPI_SendByte(*data++);
          }
          // stop write
          SPI_CShigh();

          timer = LOGGER_DELAY;
          //wait for write operation to complete
          while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP)
          {
              if(!--timer)
                  break;
          }
      
       data += bytes_to_write;
       address += bytes_to_write;
       lenght -= bytes_to_write;
    }
}

заходит в функцию но на выходе попадает в эксепшен.
Код
Default_Handler:
  b  Default_Handler

  .size  Default_Handler, .-Default_Handler
jcxz
Цитата(aaarrr @ Apr 12 2016, 02:26) *
Какой-то ужас, если честно.

Полностью с Вами согласен! Сочувствую работодателю топикстартера.
И так чуть оптимальнее:
Код
void eep_write(uint32_t addr, uint32_t len, uint8_t *data)
{
  uint32_t i;
  while (len) {
    i = EEPROM_PAGE_SIZE - (addr & EEPROM_PAGE_SIZE - 1);
    if (i > len) i = len;
    //тут проверяем статус EEPROM, посылаем WREN и пишем (addr, i, data);
    data += i;
    addr += i;
    len -= i;
  }
}

И между SPI_CShigh() и SPI_CSlow() которые между каждыми двумя соседними командами, нужна хотя-бы минимальная задержка, чтобы микросхема успела почувствовать CS high. А точнее - задержка в соответствии с даташитом на микросхему (CS high минимум time или что-то в этом роде).
aaarrr
Цитата(Jenya7 @ Apr 12 2016, 10:03) *
я извиняюсь немного непонятно это
Код
data += a;
  addr += a;
  len -= a;

'а' это bytes_to_write?

Да, забыл отредактировать.

Цитата(Jenya7 @ Apr 12 2016, 10:03) *
переписал так

Должно быть так:
Код
void LOGGER_Write(uint32_t address, uint32_t lenght, uint8_t *data)
{
    uint32_t timer;
    uint32_t bytes_to_write=0;

    while(lenght)
    {
       if(((address & (PAGE_SIZE - 1)) + lenght) >= PAGE_SIZE)
          bytes_to_write = PAGE_SIZE - (address & (PAGE_SIZE - 1));
       else
          bytes_to_write = lenght;

       // Every write operation demands a write enable!!!
       SPI_CSlow();
       SPI_SendByte(SPIEEPROM_CMD_WREN);
       SPI_CShigh();

       // start write
       SPI_CSlow();
       // send write command
       SPI_SendByte(SPIEEPROM_CMD_WRITE);
       // send address
       SPI_SendByte(address>>8);
       SPI_SendByte(address&0x00FF);

       address += bytes_to_write;
       lenght -= bytes_to_write;

       while(bytes_to_write--)
       {
           // send data to be written
            SPI_SendByte(*data++);
       }
       // stop write
       SPI_CShigh();

       timer = LOGGER_DELAY;
       //wait for write operation to complete
       while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP)
       {
           if(!--timer)
               break;
       }
    }
}
Jenya7
большое спасибо так работает. sm.gif
причем тестировать флаг не помогает
Код
while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP)
{
    if(!--timer)
          break;
}

нужно вставлять задержку 5мс, что очень не кстати. sad.gif
aaarrr
Цитата(Jenya7 @ Apr 12 2016, 10:25) *
нужно вставлять задержку 5мс, что очень не кстати. sad.gif

Может, LOGGER_DELAY маловата?
esaulenka
Цитата
Суд. Бракоразводный процесс. Судья спрашивает жену:
- По какой причине вы хотите развестись с мужем?
- Он меня как мужчина не удовлетворяет!
Женский голос из зала:
- Всех удовлетворяет, а её нет!
Мужской голос из зала:
- А её никто не удовлетворяет!


Извините за флуд, но проверка регистра статуса - это рабочее решение (собственно, для того он там и есть).
Ищите ошибку, кто такие LOGGER_DELAY, SPIEEPROM_ReadStatus() и SPIEEPROM_STATUS_WIP нам неведомо.

И название микросхемы хорошо б сразу указывать. Тут, конечно, у многих навыки телепатии неплохие, но некрасиво это.
jcxz
Цитата(aaarrr @ Apr 12 2016, 13:53) *
Может, LOGGER_DELAY маловата?

А зачем там вообще какая-то delay? Надо читать статус до тех пор пока не будет снят статус "занято". И делать это лучше не после, а перед операцией записи/стирания.
Опять-же не выдерживается мин. время неактивности CS (ТС не читал даташит).
Опять-же - не понятно как внутри устроена SPI_SendByte() у ТС, но очевидно что криво. Ибо, если она завершается сразу после записи байта данных в буферный регистр передатчика, то сразу после неё нельзя делать SPI_CShigh(); если же она завершается после опустошения сдвигового регистра передатчика, то это неоптимально (так как нет необходимости этого ждать внутри пакета байт команды).
aaarrr
Цитата(jcxz @ Apr 12 2016, 11:16) *
А зачем там вообще какая-то delay? Надо читать статус до тех пор пока не будет снят статус "занято".

Выход по тайм-ауту в таких случаях желательно все же иметь. Но при аварии надо ошибку вернуть, конечно, а не просто вывалиться.
Jenya7
таймаут нужен чтоб не застрять навсегда в цикле. у меня все циклы имееют таймаут.
функции такие
Код
// commands
#define SPIEEPROM_CMD_READ        0x03    // Read byte(s)
#define SPIEEPROM_CMD_WRITE        0x02    // Write byte(s)
#define SPIEEPROM_CMD_WREN        0x06    // Write Enable
#define SPIEEPROM_CMD_WRDI        0x04    // Write Disable
#define SPIEEPROM_CMD_RDSR        0x05    // Read Status Register
#define SPIEEPROM_CMD_WRSR        0x01    // Write Status Register

// status register bit defines
#define SPIEEPROM_STATUS_WIP    0x01    // Write in progress
#define SPIEEPROM_STATUS_WEL    0x02    // Write enable
#define SPIEEPROM_STATUS_BP0    0x04    // Block Protection 0
#define SPIEEPROM_STATUS_BP1    0x08    // Block Protection 1
#define SPIEEPROM_STATUS_WPEN    0x80    // Write Protect Enable

uint32_t SPI_TransferByte(uint32_t sendbyte)
{
    uint32_t timeout = SPI_DELAY;
    /* Check that transmit buffer is empty */
    while (!(SPI_USART->STATUS & USART_STATUS_TXBL))
    {
        if(!--timeout)
            break;
    }
    SPI_USART->TXDATA = (uint32_t)sendbyte;
    /* Wait for transmitting to finished */
    timeout = SPI_DELAY;
    while (!(SPI_USART->STATUS & USART_STATUS_TXC))
    {
        if(!--timeout)
            break;
    }
    //return data;
    return majority32const(&SPI_USART->RXDATA);
}

void SPI_SendByte(uint8_t sendbyte)
{
    uint32_t timeout = SPI_DELAY;

    USART_Tx(SPI_USART,sendbyte);

    /* Wait for transmitting to finished */
    while (!(SPI_USART->STATUS & USART_STATUS_TXC))
    {
      if(!--timeout)
          break;
    }
}

uint8_t SPIEEPROM_ReadStatus(void)
{
    uint8_t status;
    SPI_CSlow();
    // send read status register command
    SPI_SendByte(SPIEEPROM_CMD_RDSR);
    // get status register value
    status = SPI_TransferByte(0xFF);
    SPI_CShigh();
    return status;
}


память CAT25256
aaarrr
Цитата(Jenya7 @ Apr 12 2016, 11:27) *
таймаут нужен чтоб не застрять навсегда в цикле. у меня все циклы имееют таймаут.

Вот для циклов, работающих с внутренней простой периферией типа SPI, тайм-ауты как раз излишни.
Jenya7
Цитата(aaarrr @ Apr 12 2016, 14:39) *
Вот для циклов, работающих с внутренней простой периферией типа SPI, тайм-ауты как раз излишни.

у меня SPI не тактируется постоянно. включил клок - переслал - выключил. кроме того на том же SPI кроме памяти сидит еще один модуль. кроме того куча прерываний. я не могу предвидеть все ситуации. но если возникнет ситуация обращения к SPI при выключенном клоке - без таймаута я зависну намертво.

только не говорите мне про атомарное обращение. не везде это приемлимо.
aaarrr
Цитата(Jenya7 @ Apr 12 2016, 11:48) *
у меня SPI не тактируется постоянно. включил клок - переслал - выключил.

А смысл? Экономия ведь нулевая.
jcxz
Цитата(aaarrr @ Apr 12 2016, 14:26) *
Выход по тайм-ауту в таких случаях желательно все же иметь. Но при аварии надо ошибку вернуть, конечно, а не просто вывалиться.

Да, а потом ещё не забыть сделать обработку этих возвращаемых статусов ошибок во всех точках вызова (что обычно обязательно забывают где-нить сделать).
Или вернуть этот статус выше и там обработать. В любом случае с этой ошибкой (таймаут неготовности) надо что-то делать.
А что делать? Ведь если превышен таймаут (который выставлен правильно в соответствии с даташитом), то значит микросхема не функционирует.
Вы все характеристики всех элементов в схеме проверяете на их соответствие заявленным в даташите, или всё же предполагаете, что она должна функционировать как обещал производитель?
Я обычно тоже делаю контроль таймаута в таких случаях, но при возникновении события таймаута (превышения времени заявленного в даташите) не возвращаю какой-то статус, а вызываю событие "критическая ошибка" (так как это явно отказ аппаратуры). Обработчик такого события или просто выполняет аппаратный сброс или например входит в состояние "критическая ошибка" с индикацией этого состояния (в режиме отладки).

Цитата(Jenya7 @ Apr 12 2016, 14:27) *
таймаут нужен чтоб не застрять навсегда в цикле. у меня все циклы имееют таймаут.

Хорошо, вот наступил этот таймаут. Ваши действия? Что после этого делать-то?
Jenya7
Цитата(aaarrr @ Apr 12 2016, 14:51) *
А смысл? Экономия ведь нулевая.

ничего себе нулевая. Вы бы посмотрели на токовый профиль - каждый клок увеличивает ток. причем значительно. опять таки - у меня все питается от батарейки. иначе половина моих вопросов на форуме была бы не актуальна.
jcxz
Цитата(Jenya7 @ Apr 12 2016, 14:48) *
но если возникнет ситуация обращения к SPI при выключенном клоке - без таймаута я зависну намертво.

А как такое может быть - "обращения к SPI при выключенном клоке"??? Ведь этим клоком должен управлять этот-же код, который управляет обменом по SPI. Значит он сам его и выключил?
Если так - то это ошибка в коде, её надо искать и исправлять, а не ваять костыли всякие типа таймаутов, которые её "замажут" в некоторых случаях и приведут к непредсказуемому поведению ПО.
Jenya7
Цитата(jcxz @ Apr 12 2016, 14:59) *
Да, а потом ещё не забыть сделать обработку этих возвращаемых статусов ошибок во всех точках вызова (что обычно обязательно забывают где-нить сделать).
Или вернуть этот статус выше и там обработать. В любом случае с этой ошибкой (таймаут неготовности) надо что-то делать.
А что делать? Ведь если превышен таймаут (который выставлен правильно в соответствии с даташитом), то значит микросхема не функционирует.
Вы все характеристики всех элементов в схеме проверяете на их соответствие заявленным в даташите, или всё же предполагаете, что она должна функционировать как обещал производитель?
Я обычно тоже делаю контроль таймаута в таких случаях, но при возникновении события таймаута (превышения времени заявленного в даташите) не возвращаю какой-то статус, а вызываю событие "критическая ошибка" (так как это явно отказ аппаратуры). Обработчик такого события или просто выполняет аппаратный сброс или например входит в состояние "критическая ошибка" с индикацией этого состояния (в режиме отладки).


Хорошо, вот наступил этот таймаут. Ваши действия? Что после этого делать-то?

это уже следующий этап. сейчас мне важно чтоб система не зависла. в принцине у меня есть переменная которая содержит флаги ошибок которые я периодически тестирю в коде.

Цитата(jcxz @ Apr 12 2016, 15:03) *
А как такое может быть - "обращения к SPI при выключенном клоке"??? Ведь этим клоком должен управлять этот-же код, который управляет обменом по SPI. Значит он сам его и выключил?

это маловероятно - но на этот случай есть таймаут.
jcxz
Цитата(Jenya7 @ Apr 12 2016, 15:05) *
это уже следующий этап. сейчас мне важно чтоб система не зависла. в принцине у меня есть переменная которая содержит флаги ошибок которые я периодически тестирю в коде.

Так а как Вы вообще отлаживаете? Что значит "не важно"?
Вот у Вас скажем одно из обращений к EEPROM закончилось таймаутом, выставился где-то какой-то флаг и поехало дальше выполнение. Дальше опять вызывается транзакция с этой EEPROM, а у Вас при старте транзакции не проверятся что предыдущая завершилась (а предыдущая завершилась таймаутом и EEPROM всё ещё busy) и Вы начинаете гнать туда какие-то байты, считая что идёт запись.
В это время EEPROM по середине этих данных наконец снимает статус busy и воспринимает очередной байт данных как некую команду (например стирания или записи или перевода в сон и т.п.).
И что будет после этого в Вашем ПО и EEPROM? Каша!

Вот именно поэтому и могут происходить такие проблемы как Вы писали в первом посте.
Ну а если вообще также халтурно подходить к написанию ПО, то вообще где угодно могут быть проблемы.

Цитата(Jenya7 @ Apr 12 2016, 15:08) *
это маловероятно - но на этот случай есть таймаут.

Пипец просто! Вы читаете что Вам пишут? Ваш таймаут - это костыль на Ваши же баги.
Таймаут вообще не для этого нужен. Он нужен чтобы отследить сбои в работе вызванные внешними причинами (неисправностью внешней микросхемы), а не проблемами в Вашем коде.
Jenya7
Цитата(jcxz @ Apr 12 2016, 15:16) *
Так а как Вы вообще отлаживаете? Что значит "не важно"?
Вот у Вас скажем одно из обращений к EEPROM закончилось таймаутом, выставился где-то какой-то флаг и поехало дальше выполнение. Дальше опять вызывается транзакция с этой EEPROM, а у Вас при старте транзакции не проверятся что предыдущая завершилась (а предыдущая завершилась таймаутом и EEPROM всё ещё busy) и Вы начинаете гнать туда какие-то байты, считая что идёт запись.
В это время EEPROM по середине этих данных наконец снимает статус busy и воспринимает очередной байт данных как некую команду (например стирания или записи или перевода в сон и т.п.).
И что будет после этого в Вашем ПО и EEPROM? Каша!

Вот именно поэтому и могут происходить такие проблемы как Вы писали в первом посте.
Ну а если вообще также халтурно подходить к написанию ПО, то вообще где угодно могут быть проблемы.


Пипец просто! Вы читаете что Вам пишут? Ваш таймаут - это костыль на Ваши же баги.
Таймаут вообще не для этого нужен. Он нужен чтобы отследить сбои в работе вызванные внешними причинами (неисправностью внешней микросхемы), а не проблемами в Вашем коде.

Вы знаете мне бы хотелось для начала отладить запись в EEPROM а потом уже решать остальные проблемы.
и если рассуждать логически - если заменив это
Код
while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP)
{
  //NO TIMEOUT
}

на это
Код
Delay_us(5000);

все успевает прописаться то очевидно предыдущий код не содержит смертных грехов.
aaarrr
Цитата(Jenya7 @ Apr 12 2016, 12:00) *
ничего себе нулевая. Вы бы посмотрели на токовый профиль - каждый клок увеличивает ток.

Взял первую попавшуюся цифру для SPI - 3uA/MHz. Но не надо забывать, что это цифра для работающей периферии, а не простаивающей с включенным клоком. Реальное значение лучше замерить, и сомневаюсь, что Вы найдете сколько-нибудь значительную разницу.
jcxz
Цитата(aaarrr @ Apr 12 2016, 15:50) *
Взял первую попавшуюся цифру для SPI - 3uA/MHz. Но не надо забывать, что это цифра для работающей периферии, а не простаивающей с включенным клоком. Реальное значение лучше замерить, и сомневаюсь, что Вы найдете сколько-нибудь значительную разницу.

Скорей всего наибольшую экономию даёт именно отключение тактирования всего SPI-порта. А передаёт в данный момент он или простаивает с включённым клоком - скорей всего крохи разницы.
Оптимизировал когда-то потребление устройства на LPC1758 - только отключение тактирования каждого периферийного узла давало экономию, заметную на микроамперметре. Исключая конечно токи нагрузки пинов.
Jenya7
Цитата(aaarrr @ Apr 12 2016, 15:50) *
Взял первую попавшуюся цифру для SPI - 3uA/MHz. Но не надо забывать, что это цифра для работающей периферии, а не простаивающей с включенным клоком. Реальное значение лучше замерить, и сомневаюсь, что Вы найдете сколько-нибудь значительную разницу.

моя система потребляет 6 микро в ожидающем режиме. много-мало это беспредметный спор - все зависит от требований. вот почему статус бит не тестируется - вот это вопрос.

желательно разрешить проблему пока предупреждения не досигли 100%. Товарищ Herz не дремлет, спасибо ему. sm.gif

в даташит написано
Код
tWC (Note 13)   Write Cycle Time    5 ms .

13.tWC is the time from the rising edge of CS after a valid write sequence to the end of the internal write cycle.

получается как ни крути а 5мс нужно ждать?
aaarrr
Цитата(Jenya7 @ Apr 12 2016, 13:02) *
моя система потребляет 6 микро в ожидающем режиме.

Верю. Но тут вопрос сколько она потребляет в активном режиме, и сколько на этом фоне занимает SPI.

Цитата(Jenya7 @ Apr 12 2016, 13:02) *
получается как ни крути а 5мс нужно ждать?

Почему? 5мс - максимальное время записи, опрашивать статусный регистр можно и нужно.
Jenya7
чобы было легче дебагировать я немного переделал опрос регистра статуса.
Код
busy = 1;
//wait for write operation to complete
while(busy)
{
    busy = (SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP);
}

когда то бит обнуляется. в режиме отладчика реальное время трудно замерять. но подозреваю что бит не отражает реальное положение вещей.
jcxz
Цитата(Jenya7 @ Apr 12 2016, 16:02) *
получается как ни крути а 5мс нужно ждать?

Нет. Нужно правильно написать чтение статуса.

Цитата(Jenya7 @ Apr 12 2016, 19:36) *
когда то бит обнуляется. в режиме отладчика реальное время трудно замерять. но подозреваю что бит не отражает реальное положение вещей.

Отражает. Ищите баги у себя.
Jenya7
ввел задержку.
Код
busy = 1;
//wait for write operation to complete
while(busy)
{
    busy = (SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP);
    Delay_us(1);
}

теперь все прописывается корректно. очевидно нога слейв селект не успевала отработать в цикле.
спасибо за помощь.

что интересно - во всех примерах статус регистр опрашивается в цикле без задержки. или это я такой особенный или ребята выдают код с багами.

вобщем я оптимизировал чтение статус регистра.
функцию чтения нужно переписать так
Код
uint8_t SPIEEPROM_ReadStatus(void)
{
    uint8_t status;
    //SPI_CSlow();  //outside

    // send read status register command
    //SPI_SendByte(SPIEEPROM_CMD_RDSR);  //transfer - not send
    SPI_TransferByte(SPIEEPROM_CMD_RDSR);

    // get status register value
    status = SPI_TransferByte(0xFF);

    //SPI_CShigh();  //outside

    return status;
}

а управление слейв селект вынести вне цикла.
Код
busy = 1;
//wait for write operation to complete
SPI_CSlow();
while(busy)
{
    busy = (SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP);
}
SPI_CShigh();
aaarrr
Цитата(Jenya7 @ Apr 12 2016, 17:18) *
что интересно - во всех примерах статус регистр опрашивается в цикле без задержки. или это я такой особенный или ребята выдают код с багами.

Так длительность опроса то тайм-аута без задержки Вы измеряли, или нет? Может, там и 1мс не было.
jcxz
Цитата(Jenya7 @ Apr 12 2016, 20:18) *
ввел задержку.
Delay_us(1);
теперь все прописывается корректно. очевидно нога слейв селект не успевала отработать в цикле.

Я Вам несколько раз писал, что у Вас между CShigh и следующим CSlow нет никакого интервала времени.

Цитата(Jenya7 @ Apr 12 2016, 20:18) *
а управление слейв селект вынести вне цикла.
...

Лучше каждую новую команду к EEPROM начинать с нового спада импульса на CS. Каждый спад CS должен сбрасывать автомат состояний внутри микросхемы (перезапускать битовые и прочие счётчики).
Бит занятости в слове статуса - 0-й бит? Если да - можно ещё попробовать просто выдать команду чтения статуса и дальше просто держать CS и смотреть на состояние линии MISO: некоторые микросхемы SPI-flash, в которых в статусном регистре бит занятости 0й, могут выдавать в этом случае на линию MISO текущее состояние бита. Т.е. - просто ждёте пока линия не перейдёт в состояние свободно - операция записи закончилась. Если Ваша EEPROM так умеет, тогда не нужно периодически выдавать команду чтения статуса - достаточно её передать один раз.
Jenya7
Цитата(jcxz @ Apr 13 2016, 11:46) *
Я Вам несколько раз писал, что у Вас между CShigh и следующим CSlow нет никакого интервала времени.


Лучше каждую новую команду к EEPROM начинать с нового спада импульса на CS. Каждый спад CS должен сбрасывать автомат состояний внутри микросхемы (перезапускать битовые и прочие счётчики).
Бит занятости в слове статуса - 0-й бит? Если да - можно ещё попробовать просто выдать команду чтения статуса и дальше просто держать CS и смотреть на состояние линии MISO: некоторые микросхемы SPI-flash, в которых в статусном регистре бит занятости 0й, могут выдавать в этом случае на линию MISO текущее состояние бита. Т.е. - просто ждёте пока линия не перейдёт в состояние свободно - операция записи закончилась. Если Ваша EEPROM так умеет, тогда не нужно периодически выдавать команду чтения статуса - достаточно её передать один раз.

бит 0-й но насколько я понял чтобы получить статус регистор надо каждый раз передавать команду. если передергивать слейв селект надо вводить задержку. не знаю насколько это хорошо.
jcxz
Цитата(Jenya7 @ Apr 13 2016, 12:29) *
бит 0-й но насколько я понял чтобы получить статус регистор надо каждый раз передавать команду. если передергивать слейв селект надо вводить задержку.

Откройте диаграмму чтения слова состояния в даташите. Там обычно рисуют что после последнего клока остаётся состояние последнего выдвинутого бита сколько угодно долго. Вопрос только в том - выводится ли там текущее состояние бита занятости или защёлкнутое в момент перепада SCLK.
Jenya7
Цитата(jcxz @ Apr 13 2016, 12:33) *
Откройте диаграмму чтения слова состояния в даташите. Там обычно рисуют что после последнего клока остаётся состояние последнего выдвинутого бита сколько угодно долго. Вопрос только в том - выводится ли там текущее состояние бита занятости или защёлкнутое в момент перепада SCLK.

там написано так.
Цитата
To read the status register, the host simply sends a RDSR command. After receiving the last bit of the command, the CAT25256 will shift out the contents of the status register on the SO pin (Figure 10). The status register may be read at any time, including during an internal write cycle. While the internal write cycle is in progress, the RDSR command will
output the full content of the status register (New product, Rev. E) or the RDY (Ready) bit only (i.e., data out = FFh) for previous product revisions C, D (Mature product). For easy detection of the internal write cycle completion, both during writing to the memory array and to the status register, we
recommend sampling the RDY bit only through the polling routine. After detecting the RDY bit “0”, the next RDSR instruction will always output the expected content of the status register.

они рекомендуют поллинг то есть обращение к регистру в цикле. непонятно только что делать с ногой слейв селект.
aaarrr
Цитата(Jenya7 @ Apr 13 2016, 09:50) *
непонятно только что делать с ногой слейв селект.

Цитата

Every communication session between host and CAT25256 must be preceded by a
high to low transition and concluded with a low to high transition of the CS input.
jcxz
Автор совершенно не желает читать даташит..... sad.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.