feat: 增加flash模拟eeprom接口

This commit is contained in:
2024-04-19 17:42:32 +08:00
parent 8408ab1cf3
commit 05cab94699
4 changed files with 724 additions and 6 deletions

View File

@@ -71,6 +71,9 @@
{ {
"path": "project/src/by_debug.c" "path": "project/src/by_debug.c"
}, },
{
"path": "project/src/eeprom.c"
},
{ {
"path": "project/src/main.c" "path": "project/src/main.c"
} }

80
project/inc/eeprom.h Normal file
View File

@@ -0,0 +1,80 @@
/**
**************************************************************************
* @file eeprom.h
* @version v2.0.0
* @date 2020-11-02
* @brief flash eeprom libray header file
**************************************************************************
* Copyright notice & Disclaimer
*
* The software Board Support Package (BSP) that is made available to
* download from Artery official website is the copyrighted work of Artery.
* Artery authorizes customers to use, copy, and distribute the BSP
* software and its related documentation for the purpose of design and
* development in conjunction with Artery microcontrollers. Use of the
* software is governed by this copyright notice and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
*
**************************************************************************
*/
/*!< define to prevent recursive inclusion -------------------------------------*/
#ifndef __EEPROM_H
#define __EEPROM_H
#ifdef __cplusplus
extern "C" {
#endif
/* includes ------------------------------------------------------------------*/
#include "at32f413.h"
/*
+-----------------------------------------------------+
| EEPROM |
+--------------------------+--------------------------+
| PAGE 0 | PAGE 1 |
+--------+--------+--------+--------+--------+--------+
| | | | | | |
| sector | sector | sector | sector | sector | sector |
| 0 | ... | N | N + 1 | ... | N + N |
| | | | | | |
+--------+--------+--------+--------+--------+--------+
*/
/*!< user defined */
#define EE_SECTOR_NUM ((uint32_t)1) /*!< sector number, support multiple sectors to from 1 page */
#define EE_SECTOR_SIZE ((uint32_t)(1024 * 2)) /*!< sector size */
/*!< user do not need to care */
#define EE_FLASH_SIZE (*(uint16_t *)0x1FFFF7E0) /*!< at32 flash size information */
#define EE_PAGE_SIZE ((uint32_t)(EE_SECTOR_NUM * EE_SECTOR_SIZE)) /*!< page size */
#define EE_BASE_ADDRESS ((uint32_t)(0x08000000 + 1024 * EE_FLASH_SIZE - EE_PAGE_SIZE * 2)) /*!< eeprom base address */
#define EE_PAGE0_ADDRESS ((uint32_t)(EE_BASE_ADDRESS)) /*!< eeprom page 0 base address */
#define EE_PAGE1_ADDRESS ((uint32_t)(EE_PAGE0_ADDRESS + EE_PAGE_SIZE)) /*!< eeprom page 1 base address */
#define EE_PARA_MAX_NUMBER ((uint16_t)(EE_PAGE_SIZE / 4 - 1)) /*!< maximum number of variables that can be stored */
flash_status_type flash_ee_init (void);
uint16_t flash_ee_data_read (uint16_t address, uint16_t* pdata);
flash_status_type flash_ee_data_write (uint16_t address, uint16_t data);
#ifdef __cplusplus
}
#endif
#endif

632
project/src/eeprom.c Normal file
View File

@@ -0,0 +1,632 @@
/**
**************************************************************************
* @file eeprom.c
* @version v2.0.0
* @date 2020-11-02
* @brief the driver library of the flash eeprom
**************************************************************************
* Copyright notice & Disclaimer
*
* The software Board Support Package (BSP) that is made available to
* download from Artery official website is the copyrighted work of Artery.
* Artery authorizes customers to use, copy, and distribute the BSP
* software and its related documentation for the purpose of design and
* development in conjunction with Artery microcontrollers. Use of the
* software is governed by this copyright notice and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
*
**************************************************************************
*/
#include "eeprom.h"
#define EE_VALID_PAGE0 ((uint16_t)0x0000) /*!< the effective page is page 0 */
#define EE_VALID_PAGE1 ((uint16_t)0x0001) /*!< the effective page is page 1 */
#define EE_VALID_PAGE_NONE ((uint16_t)0x0002) /*!< no valid page found */
#define EE_PAGE_ERASED ((uint16_t)0xFFFF) /*!< page is in erased state */
#define EE_PAGE_TRANSFER ((uint16_t)0xCCCC) /*!< page is in transfer state */
#define EE_PAGE_VALID ((uint16_t)0x0000) /*!< page is in valid state */
/**
* @brief flash eeprom valid page get mode
*/
typedef enum
{
EE_VALID_PAGE_READ = 0x01, /*!< get valid page in read mode */
EE_VALID_PAGE_WRITE = 0x02, /*!< get valid page in write mode */
} ee_valid_page_type;
/**
* @brief erase eeprom page, one page can contain one or more sectors.
* @param page_address:
* this parameter can be one of the following values:
* - EE_PAGE0_ADDRESS: erase page 0
* - EE_PAGE1_ADDRESS: erase page 1
* @retval flash_status
*/
flash_status_type flash_ee_page_erase(uint32_t page_address)
{
uint16_t i;
uint32_t erase_address;
flash_status_type flash_status;
/* erase one or more sectors */
for(i = 0; i < EE_SECTOR_NUM; i++)
{
/* calculate the erase address */
erase_address = page_address + i * EE_SECTOR_SIZE;
/* erase sector */
if ((flash_status = flash_sector_erase(erase_address)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
}
return FLASH_OPERATE_DONE;
}
/**
* @brief get the valid eeprom page.
* @param mode
* - EE_VALID_PAGE_READ: get valid page in read mode
* - EE_VALID_PAGE_WRITE: get valid page in write mode
* @retval valid page
* - EE_VALID_PAGE0: page 0 is valid
* - EE_VALID_PAGE1: page 1 is valid
* - EE_VALID_PAGE_NONE: no valid page
*/
uint16_t flash_ee_valid_page_get(ee_valid_page_type mode)
{
uint16_t page0_status;
uint16_t page1_status;
/* get page 0 status */
page0_status = (*(__IO uint16_t*)EE_PAGE0_ADDRESS);
/* get page 1 status */
page1_status = (*(__IO uint16_t*)EE_PAGE1_ADDRESS);
if (mode == EE_VALID_PAGE_READ)
{
if (page0_status == EE_PAGE_VALID)
{
/* page 0 is valid */
return EE_VALID_PAGE0;
}
else if (page1_status == EE_PAGE_VALID)
{
/* page 1 is valid */
return EE_VALID_PAGE1;
}
}
else
{
if (page0_status == EE_PAGE_TRANSFER)
{
/* page 0 is valid */
return EE_VALID_PAGE0;
}
else if (page1_status == EE_PAGE_TRANSFER)
{
/* page 1 is valid */
return EE_VALID_PAGE1;
}
else if (page0_status == EE_PAGE_VALID)
{
/* page 0 is valid */
return EE_VALID_PAGE0;
}
else if (page1_status == EE_PAGE_VALID)
{
/* page 1 is valid */
return EE_VALID_PAGE1;
}
}
/* no valid page found */
return EE_VALID_PAGE_NONE;
}
/**
* @brief write data to the eeprom.
* @param address: variable address.
* @param data: data.
* @retval flash_status.
*/
flash_status_type flash_ee_write_no_check(uint16_t address, uint16_t data)
{
uint16_t valid_page;
uint32_t find_address;
uint32_t end_address;
flash_status_type flash_status = FLASH_OPERATE_DONE;
/* get the valid page */
valid_page = flash_ee_valid_page_get(EE_VALID_PAGE_WRITE);
if (valid_page == EE_VALID_PAGE_NONE)
{
return FLASH_PROGRAM_ERROR;
}
/* find address calculation */
find_address = EE_BASE_ADDRESS + valid_page * EE_PAGE_SIZE;
/* end address calculation */
end_address = EE_BASE_ADDRESS + valid_page * EE_PAGE_SIZE + EE_PAGE_SIZE - 2;
while (find_address < end_address)
{
/* find addresses without data */
if ((*(__IO uint32_t*)find_address) == 0xFFFFFFFF)
{
/* write data to flash */
if ((flash_status = flash_halfword_program(find_address, data)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
/* write variable address to flash */
if ((flash_status = flash_halfword_program(find_address + 2, address)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
return FLASH_OPERATE_DONE;
}
else
{
/* find address + 4 */
find_address += 4;
}
}
return FLASH_PROGRAM_ERROR;
}
/**
* @brief transfer full page data to empty page.
* @param none
* @retval flash_status
*/
flash_status_type flash_ee_copy_to_new_page(void)
{
uint16_t data;
uint16_t idx, valid_page;
uint32_t full_page_address;
uint32_t empty_page_address;
flash_status_type flash_status = FLASH_OPERATE_DONE;
/* get valid page */
valid_page = flash_ee_valid_page_get(EE_VALID_PAGE_READ);
if (valid_page == EE_VALID_PAGE0)
{
/* empty page is page 1 */
empty_page_address = EE_PAGE1_ADDRESS;
/* full page is pgae 0 */
full_page_address = EE_PAGE0_ADDRESS;
}
else if (valid_page == EE_VALID_PAGE1)
{
/* empty page is page 0 */
empty_page_address = EE_PAGE0_ADDRESS;
/* full page is pgae 1 */
full_page_address = EE_PAGE1_ADDRESS;
}
else
{
/* page status flag error */
return FLASH_PROGRAM_ERROR;
}
/* change the status of the empty page to TRANSFER */
if ((flash_status = flash_halfword_program(empty_page_address, EE_PAGE_TRANSFER)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
for (idx = 0; idx < EE_PARA_MAX_NUMBER; idx++)
{
/* find valid variables */
if (flash_ee_data_read(idx, &data) == 0)
{
/* store variable to new page */
if ((flash_status = flash_ee_write_no_check(idx, data)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
}
}
/* erase old page */
if ((flash_status = flash_ee_page_erase(full_page_address)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
/* change the status of the empty page to VALID */
if ((flash_status = flash_halfword_program(empty_page_address, EE_PAGE_VALID)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
return FLASH_OPERATE_DONE;
}
/**
* @brief erase all pages to format eeprom.
* @param none
* @retval flash_status
*/
flash_status_type flash_ee_format(void)
{
flash_status_type flash_status = FLASH_OPERATE_DONE;
/* erase page 0 */
if ((flash_status = flash_ee_page_erase(EE_PAGE0_ADDRESS)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
/* erase page 1 */
if ((flash_status = flash_ee_page_erase(EE_PAGE1_ADDRESS)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
/* mark the status of page 0 as VALID */
return flash_halfword_program(EE_PAGE0_ADDRESS, EE_PAGE_VALID);
}
/**
* @brief eeprom format validity check.
* @param page0_status: page0 status
* @param page1_status: page1 status
* @retval format status:
* - 0: the format is correct
* - 1: the format is incorrect
*/
uint16_t flash_ee_format_check(uint16_t page0_status, uint16_t page1_status)
{
/* the euqal status is invalid */
if (page0_status == page1_status)
{
return 1;
}
/* status is not known status is invalid status */
if ((page0_status != EE_PAGE_ERASED) && (page0_status != EE_PAGE_TRANSFER) && (page0_status != EE_PAGE_VALID))
{
return 1;
}
/* status is not known status is invalid status */
if ((page1_status != EE_PAGE_ERASED) && (page1_status != EE_PAGE_TRANSFER) && (page1_status != EE_PAGE_VALID))
{
return 1;
}
/* the format is correct */
return 0;
}
/**
* @brief check if eeprom page is full, when the page is full, transfer the data to erase page.
* @param none
* @retval flash_status
*/
flash_status_type flash_ee_full_check(void)
{
uint16_t valid_page;
uint32_t end_address;
flash_status_type flash_status = FLASH_OPERATE_DONE;
/* get the valid page */
valid_page = flash_ee_valid_page_get(EE_VALID_PAGE_READ);
if (valid_page == EE_VALID_PAGE_NONE)
{
return FLASH_PROGRAM_ERROR;
}
/* end address calculation */
end_address = EE_BASE_ADDRESS + valid_page * EE_PAGE_SIZE + EE_PAGE_SIZE - 2;
/* check if the page is full */
if ((*(__IO uint32_t*)(end_address - 2)) != 0xFFFFFFFF)
{
/* when the page is full, transfer the data to erase page */
if ((flash_status = flash_ee_copy_to_new_page()) != FLASH_OPERATE_DONE)
{
return flash_status;
}
}
/* page full check ok */
return FLASH_OPERATE_DONE;
}
/**
* @brief transition state processing, a page state is ERASE, a page state is TRANSFER,
* and the TRANSFER state is changed to VALID.
* @param page0_status: page0 status
* @param page1_status: page1 status
* @retval format status:
* - 0: the format is correct
* - 1: the format is incorrect
*/
flash_status_type flash_ee_erase_transfer(uint16_t page0_status, uint16_t page1_status)
{
if (page0_status == EE_PAGE_TRANSFER)
{
/* mark the status of page 0 as VALID */
return flash_halfword_program(EE_PAGE0_ADDRESS, EE_PAGE_VALID);
}
else
{
/* mark the status of page 1 as VALID */
return flash_halfword_program(EE_PAGE1_ADDRESS, EE_PAGE_VALID);
}
}
/**
* @brief transition state processing, one page state is VALID, one page state is TRANSFER,
* and the data is transferred to the TRANSFER state page.
* @param page0_status: page0 status
* @param page1_status: page1 status
* @retval format status:
* - 0: the format is correct
* - 1: the format is incorrect
*/
flash_status_type flash_ee_valid_transfer(uint16_t page0_status, uint16_t page1_status)
{
uint32_t erase_page_address;
flash_status_type flash_status;
/* find the page in the transfer state, erase the page, and retransmit the data */
if (page0_status == EE_PAGE_TRANSFER)
{
erase_page_address = EE_PAGE0_ADDRESS;
}
else
{
erase_page_address = EE_PAGE1_ADDRESS;
}
/* erase the transfer state page */
if ((flash_status = flash_ee_page_erase(erase_page_address)) != FLASH_OPERATE_DONE)
{
return flash_status;
}
/* retransmit data */
return flash_ee_copy_to_new_page();
}
/**
* @brief eeprom init.
+-------------------+---------------------------------------------------------------------------------------------+
| | PAGE 1 status |
| +-----------------------+----------------------------------+----------------------------------+
| | ERASE | TRANSFER | VALID |
+--------+----------+-----------------------+----------------------------------+----------------------------------+
| | | erase page 0 | erase page 0 | |
| | ERASE | erase page 1 | mark page 1 VALID | erase page 0 |
| | | mark page 0 VALID | | |
| +----------+-----------------------+----------------------------------+----------------------------------+
| | | erase page 1 | erase page 0 | erase page 0 |
| PAGE 0 | TRANSFER | mark page 0 VALID | erase page 1 | copy data from page 1 to page 0 |
| status | | | mark page 0 VALID | erase page 1 |
| | | | | mark page 0 VALID |
| +----------+-----------------------+----------------------------------+----------------------------------+
| | | | erase page 1 | erase page 0 |
| | VALID | erase page 1 | copy data from page 0 to page 1 | erase page 1 |
| | | | erase page 0 | mark page 0 VALID |
| | | | mark page 1 VALID | |
+--------+----------+-----------------------+----------------------------------+----------------------------------+
* @param none
* @retval flash status.
*/
flash_status_type flash_ee_init(void)
{
uint16_t page0_status;
uint16_t page1_status;
flash_status_type flash_status = FLASH_OPERATE_DONE;
/* flash unlock */
flash_unlock();
/* get page 0 status */
page0_status = (*(__IO uint16_t*)EE_PAGE0_ADDRESS);
/* get page 2 status */
page1_status = (*(__IO uint16_t*)EE_PAGE1_ADDRESS);
/* ensure that the sector data is completely erased */
if (page0_status == EE_PAGE_ERASED)
{
/* erase page 0 */
if ((flash_status = flash_ee_page_erase(EE_PAGE0_ADDRESS)) != FLASH_OPERATE_DONE)
{
/* flash lock */
flash_lock();
return flash_status;
}
}
/* ensure that the sector data is completely erased */
if (page1_status == EE_PAGE_ERASED)
{
/* erase page 1 */
if ((flash_status = flash_ee_page_erase(EE_PAGE1_ADDRESS)) != FLASH_OPERATE_DONE)
{
/* flash lock */
flash_lock();
return flash_status;
}
}
/* format validity check */
if (flash_ee_format_check(page0_status, page1_status) != 0)
{
/* if the format is invalid, reformat */
if ((flash_status = flash_ee_format()) != FLASH_OPERATE_DONE)
{
/* flash lock */
flash_lock();
return flash_status;
}
}
/* transition state processing, a page state is ERASE, a page state is TRANSFER, and the TRANSFER state is changed to VALID */
if (((page0_status == EE_PAGE_ERASED) && (page1_status == EE_PAGE_TRANSFER)) ||
((page0_status == EE_PAGE_TRANSFER) && (page1_status == EE_PAGE_ERASED)))
{
if ((flash_status = flash_ee_erase_transfer(page0_status, page1_status)) != FLASH_OPERATE_DONE)
{
/* flash lock */
flash_lock();
return flash_status;
}
}
/* transition state processing, one page state is VALID, one page state is TRANSFER, and the data is transferred to the TRANSFER state page */
if (((page0_status == EE_PAGE_VALID) && (page1_status == EE_PAGE_TRANSFER)) ||
((page0_status == EE_PAGE_TRANSFER) && (page1_status == EE_PAGE_VALID)))
{
if ((flash_status = flash_ee_valid_transfer(page0_status, page1_status)) != FLASH_OPERATE_DONE)
{
/* flash lock */
flash_lock();
return flash_status;
}
}
/* check if the page is full, when the page is full, transfer the data to erase page */
if ((flash_status = flash_ee_full_check()) != FLASH_OPERATE_DONE)
{
/* flash lock */
flash_lock();
return flash_status;
}
/* flash lock */
flash_lock();
return FLASH_OPERATE_DONE;
}
/**
* @brief write data to the eeprom.
* @param address: variable address.
* @param data: data.
* @retval flash_status.
*/
flash_status_type flash_ee_data_write(uint16_t address, uint16_t data)
{
flash_status_type flash_status = FLASH_OPERATE_DONE;
/* flash unlock */
flash_unlock();
/* check if the page is full, when the page is full, transfer the data to erase page */
if ((flash_status = flash_ee_full_check()) != FLASH_OPERATE_DONE)
{
/* flash lock */
flash_lock();
return flash_status;
}
/* write data to flash */
if ((flash_status = flash_ee_write_no_check(address, data)) != FLASH_OPERATE_DONE)
{
/* flash lock */
flash_lock();
return flash_status;
}
/* check if the page is full, when the page is full, transfer the data to erase page */
if ((flash_status = flash_ee_full_check()) != FLASH_OPERATE_DONE)
{
/* flash lock */
flash_lock();
return flash_status;
}
/* flash lock */
flash_lock();
return FLASH_OPERATE_DONE;
}
/**
* @brief read data from the eeprom.
* @param address: variable address.
* @param pdata: data pointer.
* @retval read status:
* - 0: data successfully read
* - 1: failed to read data
*/
uint16_t flash_ee_data_read(uint16_t address, uint16_t* pdata)
{
uint16_t valid_page;
uint16_t data_address;
uint32_t find_address;
uint32_t start_address;
/* get the valid page */
valid_page = flash_ee_valid_page_get(EE_VALID_PAGE_READ);
if (valid_page == EE_VALID_PAGE_NONE)
{
return EE_VALID_PAGE_NONE;
}
/* start address calculation */
start_address = EE_BASE_ADDRESS + valid_page * EE_PAGE_SIZE + 4;
/* find address calculation */
find_address = EE_BASE_ADDRESS + valid_page * EE_PAGE_SIZE + EE_PAGE_SIZE - 2;
while (find_address > start_address)
{
/* read variable address */
data_address = (*(__IO uint16_t*)find_address);
/* variable address matching */
if (address == data_address)
{
/* read data */
*pdata = (*(__IO uint16_t*)(find_address - 2));
/* data successfully read */
return 0;
}
/* find address - 4 */
find_address -= 4;
}
/* failed to read data */
return 1;
}

View File

@@ -30,6 +30,7 @@
/* private includes ----------------------------------------------------------*/ /* private includes ----------------------------------------------------------*/
/* add user code begin private includes */ /* add user code begin private includes */
#include "dwt_delay.h" #include "dwt_delay.h"
#include "eeprom.h"
#include "by_debug.h" #include "by_debug.h"
#include "by_can.h" #include "by_can.h"
@@ -114,14 +115,16 @@ int main(void)
DWT_Init(); DWT_Init();
LOGD("dwt init done"); LOGD("dwt init done");
flash_ee_init();
LOGD("eeprom init done");
by_motion_init(); by_motion_init();
LOGD("motion init done"); LOGD("motion init done");
LOGI("init done"); LOGI("init done");
/* add user code end 2 */ /* add user code end 2 */
while(1) while (1) {
{
/* add user code begin 3 */ /* add user code begin 3 */
/* add user code end 3 */ /* add user code end 3 */
} }