Перейти к содержанию
    

STM32L433 EEPROM EMULATION

Всем привет! Возникла необходимость хранить некоторые параметры в энергонезависимой памяти. На борту у STM32L433 ее нет, как и у всей линейки L4, но зато есть мануал от STM https://www.st.com/content/ccc/resource/technical/document/application_note/group0/b2/94/a6/62/18/c0/4f/e6/DM00311483/files/DM00311483.pdf/jcr:content/translations/en.DM00311483.pdf и либа https://www.st.com/en/embedded-software/x-cube-eeprom.htmlПроблема следующего характера есть готовая функция EEInit код под споилером. И после первой прошивки микроконтроллера, данная инициализация возвращает мне всегда EE_ERASE_ERROR . 
Далее уже инициализация, запись и считывание происходит без проблем.  Пробовал инициализировать и через EE_FORCED_ERASE и через EE_CONDITIONAL_ERASE , но всегда после первой прошивки возвращает ERASE_ERROR. Как подлечить , куда глядеть ?

Spoiler




/**
  * @brief  Restore the pages to a known good state in case of power loss.
  *         If a page is in RECEIVE state, resume transfer.
  *         Then if some pages are ERASING state, erase these pages.
  * @param  VirtAddTab Table of virtual addresses defined by user.
  *           0xFFFF value is prohibited as virtual address.
  * @param  EraseType: Type of erase to apply on page requiring to be erased.
  *         This parameter can be one of the following values:
  *          @arg @ref EE_FORCED_ERASE      pages to erase are erased unconditionnally
  *          @arg @ref EE_CONDITIONAL_ERASE pages to erase are erased only if not fully erased
  * @retval EE_Status
  *           - EE_OK in case of success
  *           - EE error code in case of error
  */
EE_Status EE_Init(uint16_t* VirtAddTab, EE_Erase_type EraseType)
{
  EE_State_type pagestatus = STATE_PAGE_INVALID;
  uint32_t page = 0U, pageaddress = 0U, varidx = 0U,
           nbactivepage = 0U, nbactivereceivepage = 0U, nbvalidpage = 0U,
           lastvalidpage = 0U, firstvalidpage = 0U,
           recoverytransfer = 0U;
  EE_ELEMENT_TYPE addressvalue = 0U;
  EE_State_Reliability pagestate = STATE_RELIABLE;
  EE_Status status = EE_OK;

  /* Check if the configuration is 128-bits bank or 2*64-bits bank */
  if (CheckBankConfig() != EE_OK)
  {
    return EE_INVALID_BANK_CFG;
  }

  /***************************************************************************/
  /* Step 0: Check parameters validity and perform initial configuration     */
  /***************************************************************************/
  /* Configure CRC peripheral for eeprom emulation usage */
  ConfigureCrc();

  /* Check validity of Table of Virtual addresses */
  if (VirtAddTab == NULL)
  {
    return EE_INVALID_VIRTUALADDRESS;
  }

  /* Store Table of Virtual addressess */
  puhVirtAdd = VirtAddTab;

  /* Check the variables definitions: 0x0000 and 0xFFFF value are prohibited */
  for (varidx = 0U; varidx < NB_OF_VARIABLES; varidx++)
  {
    if ((puhVirtAdd[varidx] == 0x0000U) || (puhVirtAdd[varidx] == 0xFFFFU))
    {
      return EE_INVALID_VIRTUALADDRESS;
    }
  }

  /***************************************************************************/
  /* Step 1: Read all lines of the flash pages of eeprom emulation to        */
  /*         delete corrupted lines detectable through NMI                   */
  /***************************************************************************/
  for (page = START_PAGE; page < (START_PAGE + PAGES_NUMBER); page++)
  {
    pageaddress = PAGE_ADDRESS(page);
    for (varidx = 0U; varidx < PAGE_SIZE; varidx += EE_ELEMENT_SIZE)
    {
      addressvalue = (*(__IO EE_ELEMENT_TYPE*)(pageaddress + varidx));
    }
  }

  /***************************************************************************/
  /* Step 2: Handle case of reset during transfer with no receive page       */
  /*         present, by setting missing receive page state                  */
  /***************************************************************************/
  /* Check if no active page and no receive page present */
  /* Browse all pages */
  for (page = START_PAGE; page < (START_PAGE + PAGES_NUMBER); page++)
  {
    pageaddress = PAGE_ADDRESS(page);
    pagestatus = GetPageState(pageaddress);

    /* Search for active and receive page */
    if ((pagestatus == STATE_PAGE_ACTIVE) || (pagestatus == STATE_PAGE_RECEIVE))
    {
      nbactivereceivepage++;
    }
    /* Keep index of first valid page, and last valid page */
    else if (pagestatus == STATE_PAGE_VALID)
    {
      if (nbvalidpage == 0U)
      {
        firstvalidpage = page;
      }
      lastvalidpage = page;
      nbvalidpage++;
    }
  }

  /* Check if no active and no receive page have been detected */
  if (nbactivereceivepage == 0U)
  {
    /* Check if valid pages have been detected */
    if (nbvalidpage > 0U)
    {
      /* Check state of page just before first valid page.
      If it is erasing page, then page after last valid page shall be set
      to receiving state */
      if (GetPageState(PAGE_ADDRESS(PREVIOUS_PAGE(firstvalidpage))) == STATE_PAGE_ERASING)
      {
        if (SetPageState(FOLLOWING_PAGE(lastvalidpage), STATE_PAGE_RECEIVE) != EE_OK)
        {
          return EE_WRITE_ERROR;
        }
      }
    }
    /* Format flash pages used for eeprom emulation in case no active, no receive, no valid pages are found */
    else
    {
      return EE_Format(EE_FORCED_ERASE);
    }
  }

  /*********************************************************************/
  /* Step 3: Handle case of reset during transfer, by performing       */
  /*         transfer recovery                                         */
  /*********************************************************************/
  /* Browse all pages */
  for (page = START_PAGE; page < (START_PAGE + PAGES_NUMBER); page++)
  {
    pageaddress = PAGE_ADDRESS(page);
    pagestatus = GetPageState(pageaddress);

    /* Check if there is receive page, meaning transfer has been interrupted */
    if (pagestatus == STATE_PAGE_RECEIVE)
    {
      /* Verify that receive page is a true one, not a corrupted page state */
      /* Check if page is not the first page of a bloc */
      if ((page != START_PAGE) && (page != (uint32_t)(START_PAGE + (PAGES_NUMBER / 2U))))
      {
        /* Check that previous page is valid state */
        if (GetPageState(PAGE_ADDRESS(PREVIOUS_PAGE(page))) == STATE_PAGE_VALID)
        {
          /* The receive page is a true receive page */
          pagestate = STATE_RELIABLE;
        }
        else /* Previous page is not valid state */
        {
          /* The receive page is false receive page due to header corruption */
          pagestate = STATE_CORRUPTED;
        }
      }
      else /* The receive page is the first page of a bloc */
      {
        /* Check that following page is erased state */
        if (GetPageState(PAGE_ADDRESS(FOLLOWING_PAGE(page))) == STATE_PAGE_ERASED)
        {
          /* The receive page is a true receive page */
          pagestate = STATE_RELIABLE;
        }
        else /* Following page is not erased state */
        {
          /* The receive page is false receive page due to header corruption */
          pagestate = STATE_CORRUPTED;
        }
      }

      /* If the receive page is a true receive page, resume pages transfer */
      if (pagestate == STATE_RELIABLE)
      {
        /* Initialize current active page */
        ubCurrentActivePage = page;

        /* Resume the interrupted page transfer, using dummy new data */
        if (PagesTransfer(0U, 0U, EE_TRANSFER_RECOVER) != EE_CLEANUP_REQUIRED)
        {
          return EE_TRANSFER_ERROR;
        }

        /* Memorize transfer recovery occured */
        recoverytransfer = 1U;

        /* transfer recovery is done, then stop searching receive page */
        break;
      }
    }
  }

  /*********************************************************************/
  /* Step 4: Verify presence of one unique active page                 */
  /*         If more than one active page, raise error                 */
  /*         If no active page present, set missing active page        */
  /*********************************************************************/
  /* Browse all pages to search for active pages */
  nbactivepage = 0U;
  for (page = START_PAGE; page < (START_PAGE + PAGES_NUMBER); page++)
  {
    pageaddress = PAGE_ADDRESS(page);
    pagestatus = GetPageState(pageaddress);

    /* Search for active page */
    if (pagestatus == STATE_PAGE_ACTIVE)
    {
      /* Verify that active page is a true one, not a corrupted page state */
      /* Check if page is not the first page of a bloc */
      if ((page != START_PAGE) && (page != (uint32_t)(START_PAGE + (PAGES_NUMBER / 2U))))
      {
        /* Check that previous page is valid state */
        if (GetPageState(PAGE_ADDRESS(PREVIOUS_PAGE(page))) == STATE_PAGE_VALID)
        {
          /* The active page is a true active page */
          pagestate = STATE_RELIABLE;
        }
        else /* Previous page is not valid state */
        {
          /* The active page is false active page due to header corruption */
          pagestate = STATE_CORRUPTED;
        }
      }
      else /* The active page is the first page of a bloc */
      {
        /* Check that following page is erased state */
        if (GetPageState(PAGE_ADDRESS(FOLLOWING_PAGE(page))) == STATE_PAGE_ERASED)
        {
          /* The active page is a true active page */
          pagestate = STATE_RELIABLE;
        }
        else /* Following page is not erased state */
        {
          /* The active page is false active page due to header corruption */
          pagestate = STATE_CORRUPTED;
        }
      }

      /* If the active page is a true active page, initialize global variables */
      if (pagestate == STATE_RELIABLE)
      {
        if (nbactivepage == 0U)
        {
          ubCurrentActivePage = page;
          nbactivepage++;
        }
        else
        {
          /* Error: More than one reliable active page is present */
          return EE_INVALID_PAGE_SEQUENCE;
        }
      }
    }
    /* Keep index of last valid page, will be required in case no active page is found */
    else if (pagestatus == STATE_PAGE_VALID)
    {
      lastvalidpage = page;
    }
  }

  /* In case no active page is found, set page after last valid page to active state */
  if (nbactivepage == 0U)
  {
    ubCurrentActivePage = FOLLOWING_PAGE(lastvalidpage);
    if (SetPageState(ubCurrentActivePage, STATE_PAGE_ACTIVE) != EE_OK)
    {
      return EE_WRITE_ERROR;
    }
  }

  /*********************************************************************/
  /* Step 5: Initialize eeprom emulation global variables relative     */
  /*         to active page                                            */
  /*********************************************************************/
  /* Initialize global variables, with elements detected in active page */
  uhNbWrittenElements = 0U;
  uwAddressNextWrite = PAGE_HEADER_SIZE;

  for (varidx = PAGE_HEADER_SIZE; varidx < PAGE_SIZE; varidx += EE_ELEMENT_SIZE)
  {
    /* Check elements present in active page */
    addressvalue = (*(__IO EE_ELEMENT_TYPE*)(PAGE_ADDRESS(ubCurrentActivePage) + varidx));
    if (addressvalue != EE_MASK_FULL)
    {
      /* Then increment uhNbWrittenElements and uwAddressNextWrite */
      uhNbWrittenElements++;
      uwAddressNextWrite += EE_ELEMENT_SIZE;
    }
    else /* no more element in the page */
    {
      break;
    }
  }

  /*********************************************************************/
  /* Step 6: Finalize eeprom emulation global variables relative       */
  /*         to valid pages, and check consistency of pages sequence   */
  /*********************************************************************/
  /* Check consistency of pages sequence: one active page, optionnally some valid pages before */
  /* Update global variable uhNbWrittenElements if valid pages are found */
  page = ubCurrentActivePage;
  firstvalidpage = ubCurrentActivePage;
  while ((page != START_PAGE) && (page != (uint32_t)(START_PAGE + (PAGES_NUMBER / 2U))))
  {
    /* Decrement page index among circular pages list */
    page = PREVIOUS_PAGE(page);
    pagestatus = GetPageState(PAGE_ADDRESS(page));

    /* Check if page is valid state */
    if (pagestatus == STATE_PAGE_VALID)
    {
      /* Update uhNbWrittenElements with number of elements in full page */
      uhNbWrittenElements += NB_MAX_ELEMENTS_BY_PAGE;

      /* Keep index of first valid page */
      firstvalidpage = page;
    }
    else
    {
      /* Error: Pages sequence is not consistent */
      return EE_INVALID_PAGE_SEQUENCE;
    }
  }

  /*********************************************************************/
  /* Step 7: Ensure empty pages are erased                             */
  /*********************************************************************/
  /* Ensure all pages after active page, until first valid page, are erased */
  page = FOLLOWING_PAGE(ubCurrentActivePage);
  pageaddress = PAGE_ADDRESS(page);

  while (page != firstvalidpage)
  {
    /* Check if page erase has to be forced unconditionally (default case) */
    if (EraseType == EE_FORCED_ERASE)
    {
      /* Force page erase independently of its content */
      if (PageErase(page, 1U) != EE_OK)
      {
        return EE_ERASE_ERROR;
      }
    }
    else /* EraseType == EE_CONDITIONAL_ERASE */
    {
      /* Check if page is fully erased */
      if (VerifyPageFullyErased(pageaddress, PAGE_SIZE) == EE_PAGE_NOTERASED)
      {
        /* Erase pages if not fully erased */
        if (PageErase(page, 1U) != EE_OK)
        {
          return EE_ERASE_ERROR;
        }
      }
    }

    /* Increment page index among circular pages list, to get first page to erased */
    page = FOLLOWING_PAGE(page);
    pageaddress = PAGE_ADDRESS(page);
  }

  /*********************************************************************/
  /* Step 8: Perform dummy write '0' to get rid of potential           */
  /*         instability of line value 0xFFFFFFFF consecutive to a     */
  /*         reset during write here                                   */
  /*         Only needed if recovery transfer did not occured          */
  /*********************************************************************/
  if (recoverytransfer == 0U)
  {
    status = VerifyPagesFullWriteVariable(0U, 0U);

    /* The dummy write can be skipped in case pages are full
       because in this case potential instability can not happen */
    if ((status != EE_OK) && (status != EE_PAGE_FULL))
    {
      return EE_WRITE_ERROR;
    }
  }

  return EE_OK;
}


 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, очевидно, что эта ошибка может возвращаться только из PageErase().

А тот, в свою очередь, зависит только от HAL_FLASHEx_Erase().

Вот тут и надо гулять отладчиком (если можно) или обвешивать всё printf'ами.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Понял , сейчас буду глубже копаться , я думал проблема на поверхности. Да ещё все совсем работать перестало. Что то с виртуальной таблицей что ли не так, или с конфигом. Отпишусь если что

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нашел где возникает ошибка 

не выполняется условие if (error != 0u)

в регистре FLASH->SR в данный момент 0x00000A0  а это соответствует PGSERR и PGAERROR 

почитал, что это значит, но почему возникает только после прошивки единожды пока не понял

HAL_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout)
{
  /* Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
     Even if the FLASH operation fails, the BUSY flag will be reset and an error
     flag will be set */

  uint32_t tickstart = HAL_GetTick();
  uint32_t error;

  while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY))
  {
    if(Timeout != HAL_MAX_DELAY)
    {
      if((HAL_GetTick() - tickstart) >= Timeout)
      {
        return HAL_TIMEOUT;
      }
    }
  }

  error = (FLASH->SR & FLASH_FLAG_SR_ERRORS);
  error |= (FLASH->ECCR & FLASH_FLAG_ECCD);

  if(error != 0u)
  {
    /*Save the error code*/
    pFlash.ErrorCode |= error;

    /* Clear error programming flags */
    __HAL_FLASH_CLEAR_FLAG(error);

    return HAL_ERROR;
  }

  /* Check FLASH End of Operation flag  */
  if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
  {
    /* Clear FLASH End of Operation pending bit */
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
  }

  /* If there is an error flag set */
  return HAL_OK;
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Mysteo said:

в регистре FLASH->SR в данный момент 0x00000A0  а это соответствует PGSERR и PGAERROR 

 почитал, что это значит, но почему возникает только после прошивки единожды пока не понял

Подозреваю, это отладчик у вас недостаточно корректно работает. При старте программы эти ошибки есть?

Самый простой способ - чистить эти ошибки перед инициализацией.

А вообще - ST'шники могли бы чистить ошибки перед началом записи...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

 

проверил..... получается что ошибка при старте сама по себе возникает единожды, притом сначала SR 0x80 выдает...и затем 0xA0

спасибо за наводку... я то думал у меня в коде что не так

 

кстати если прошить и запуститься без дебагера , то ошибок никаких нету

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня на разных STM32  - запись во флеш под дебаггером на одних процах работала, а на других нет (только делало вид).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...