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

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Запись в Serial EEprom.
Jenya7
сообщение Apr 11 2016, 13:01
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



Записывая в память нужно следить чтобы не перейти страницу.
Код
#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

то есть первый адресс следующей страницы не прописывается. целый день бьюсь над проблемой не могу понять в чем дело.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 11 2016, 20:26
Сообщение #2


Гуру
******

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



Какой-то ужас, если честно.
Код
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;
    }
}
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Apr 12 2016, 07:03
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



я извиняюсь немного непонятно это
Код
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
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 12 2016, 07:07
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(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 или что-то в этом роде).
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 12 2016, 07:09
Сообщение #5


Гуру
******

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



Цитата(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;
       }
    }
}
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Apr 12 2016, 07:25
Сообщение #6


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



большое спасибо так работает. sm.gif
причем тестировать флаг не помогает
Код
while(SPIEEPROM_ReadStatus() & SPIEEPROM_STATUS_WIP)
{
    if(!--timer)
          break;
}

нужно вставлять задержку 5мс, что очень не кстати. sad.gif
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 12 2016, 07:53
Сообщение #7


Гуру
******

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



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

Может, LOGGER_DELAY маловата?
Go to the top of the page
 
+Quote Post
esaulenka
сообщение Apr 12 2016, 08:05
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877



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


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

И название микросхемы хорошо б сразу указывать. Тут, конечно, у многих навыки телепатии неплохие, но некрасиво это.


--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 12 2016, 08:16
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(aaarrr @ Apr 12 2016, 13:53) *
Может, LOGGER_DELAY маловата?

А зачем там вообще какая-то delay? Надо читать статус до тех пор пока не будет снят статус "занято". И делать это лучше не после, а перед операцией записи/стирания.
Опять-же не выдерживается мин. время неактивности CS (ТС не читал даташит).
Опять-же - не понятно как внутри устроена SPI_SendByte() у ТС, но очевидно что криво. Ибо, если она завершается сразу после записи байта данных в буферный регистр передатчика, то сразу после неё нельзя делать SPI_CShigh(); если же она завершается после опустошения сдвигового регистра передатчика, то это неоптимально (так как нет необходимости этого ждать внутри пакета байт команды).
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 12 2016, 08:26
Сообщение #10


Гуру
******

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



Цитата(jcxz @ Apr 12 2016, 11:16) *
А зачем там вообще какая-то delay? Надо читать статус до тех пор пока не будет снят статус "занято".

Выход по тайм-ауту в таких случаях желательно все же иметь. Но при аварии надо ошибку вернуть, конечно, а не просто вывалиться.
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Apr 12 2016, 08:27
Сообщение #11


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



таймаут нужен чтоб не застрять навсегда в цикле. у меня все циклы имееют таймаут.
функции такие
Код
// 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

Сообщение отредактировал Jenya7 - Apr 12 2016, 08:33
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 12 2016, 08:39
Сообщение #12


Гуру
******

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



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

Вот для циклов, работающих с внутренней простой периферией типа SPI, тайм-ауты как раз излишни.
Go to the top of the page
 
+Quote Post
Jenya7
сообщение Apr 12 2016, 08:48
Сообщение #13


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



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

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

только не говорите мне про атомарное обращение. не везде это приемлимо.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 12 2016, 08:51
Сообщение #14


Гуру
******

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



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

А смысл? Экономия ведь нулевая.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 12 2016, 08:59
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



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

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

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

Хорошо, вот наступил этот таймаут. Ваши действия? Что после этого делать-то?
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 - 17:55
Рейтинг@Mail.ru


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