Files
CherryUSB/demo/es32/Drivers/ALD/ES32F36xx/Source/ald_flash_ext.c
2022-05-29 15:22:56 +08:00

344 lines
9.4 KiB
C

/**
*********************************************************************************
*
* @file ald_flash_ext.c
* @brief FLASH extra module driver.
*
* @version V1.0
* @date 17 Jun 2019
* @author AE Team
* @note
* Change Logs:
* Date Author Notes
* 17 Jun 2019 AE Team The first version
*
* Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**********************************************************************************
* @verbatim
==============================================================================
##### FLASH Peripheral features #####
==============================================================================
[..]
Base address is 0x00000000
[..]
FLASH have just one programme mode , word programme.
word programme can programme 8 bytes once ;
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
(#) programme flash using ald_flash_write(uint32_t addr, uint8_t *buf, uint16_t len)
(++) call the function and supply all the three paraments is needs, addr means
the first address to write in this operation, buf is a pointer to the data which
need writing to flash.
(#) erase flash using ald_flash_erase(uint32_t addr, uint16_t len)
(++) call the function and supply two paraments, addr is the first address to erase,
len is the length to erase
(#) read flash using ald_flash_read(uint32_t *ram_addr, uint32_t addr, uint16_t len)
(++) read the flash and save to a buffer, ram_addr is the buffer's first address,
addr is the start reading address in flash, len is the length need read
@endverbatim
*/
#include "ald_conf.h"
/** @addtogroup ES32FXXX_ALD
* @{
*/
/** @addtogroup FLASH
* @{
*/
#ifdef ALD_FLASH
/** @addtogroup Flash_Private_Variables
* @{
*/
/* opration buffer*/
static uint8_t write_buf[FLASH_PAGE_SIZE];
/**
* @}
*/
/** @addtogroup Flash_Private_Functions
* @{
*/
/**
* @brief Check whether the flash between the given address section
* have been writen, if it have been writen, return TRUE, else
* return FALSE.
* @param begin_addr: The begin address.
* @param end_addr: The end address.
* @retval The check result
* - TRUE
* - FALSE
*/
static type_bool_t page_have_writen(uint32_t begin_addr, uint32_t end_addr)
{
uint8_t* addr_to_read;
uint8_t value;
uint32_t index;
/* Check the parameters */
assert_param(IS_FLASH_ADDRESS(begin_addr));
assert_param(IS_FLASH_ADDRESS(end_addr));
addr_to_read = (uint8_t *)begin_addr;
index = begin_addr;
value = 0xFF;
if (begin_addr > end_addr)
return FALSE;
while (index++ <= end_addr) {
value = *addr_to_read++;
if (value != 0xFF)
break;
}
return value == 0xFF ? FALSE : TRUE;
}
/**
* @}
*/
/** @defgroup Flash_Public_Functions Flash Public Functions
* @verbatim
===============================================================================
##### Flash operation functions #####
===============================================================================
[..]
This section provides functions allowing to operate flash, such as read and write.
@endverbatim
* @{
*/
/**
* @brief read the specified length bytes from flash, and store to the specified area.
* @param ram_addr: the specified area to store the reading bytes.
* @param addr: the start address.
* @param len: the length to read.
* @retval Status, see @ref ald_status_t.
*/
ald_status_t ald_flash_read(uint32_t *ram_addr, uint32_t addr, uint16_t len)
{
uint32_t i;
uint32_t temp;
assert_param(IS_4BYTES_ALIGN(ram_addr));
assert_param(IS_FLASH_ADDRESS(addr));
assert_param(IS_FLASH_ADDRESS(addr + len - 1));
temp = (uint32_t)ram_addr;
if (((temp & 0x3) != 0) || (((addr) & 0x3) != 0))
return ERROR;
for (i = 0; i < len; i++)
ram_addr[i] = ((uint32_t *)addr)[i];
return OK;
}
/**
* @brief Write the give bytes to the given address section.
* @param addr: The start address to write.
* @param buf: The bytes' address.
* @param len: The length to write,and multiple of 2.
* @retval Status, see @ref ald_status_t.
*/
ald_status_t ald_flash_write(uint32_t addr, uint8_t *buf, uint16_t len)
{
uint32_t index = 0;
uint32_t para = 0;
uint32_t index2 = 0;
uint32_t start_write_addr;
uint32_t end_write_addr;
uint32_t start_word_addr;
uint32_t end_word_addr;
uint16_t len_to_write;
uint32_t len_index;
type_bool_t need_erase_page;
assert_param(IS_FLASH_ADDRESS(addr));
assert_param(IS_FLASH_ADDRESS(addr + len - 1));
len_to_write = len;
__disable_irq();
while (len_to_write > 0) {
need_erase_page = FALSE;
for (index = 0; index < FLASH_PAGE_SIZE; index++)
write_buf[index] = 0xFF;
start_write_addr = addr + (len - len_to_write);
end_write_addr = addr + len - 1;
end_write_addr = FLASH_PAGE_ADDR(start_write_addr) == FLASH_PAGE_ADDR(end_write_addr)
? end_write_addr : FLASH_PAGEEND_ADDR(start_write_addr);
need_erase_page = page_have_writen(FLASH_WORD_ADDR(start_write_addr),
FLASH_WORDEND_ADDR(end_write_addr));
if (need_erase_page) {
if (ERROR == ald_flash_read((uint32_t *)write_buf, FLASH_PAGE_ADDR(start_write_addr),
FLASH_PAGE_SIZE >> 2)) {
__enable_irq();
return ERROR;
}
if (ERROR == flash_page_erase(FLASH_PAGE_ADDR(start_write_addr))) {
__enable_irq();
return ERROR;
}
para = end_write_addr & (FLASH_PAGE_SIZE - 1);
index = start_write_addr & (FLASH_PAGE_SIZE - 1);
index2 = len - len_to_write;
while (index <= para)
write_buf[index++] = buf[index2++];
index2 = 0;
index = FLASH_PAGE_ADDR(start_write_addr);
len_index = FLASH_PAGE_SIZE;
}
else {
para = end_write_addr & (FLASH_PAGE_SIZE - 1);
index = start_write_addr & (FLASH_PAGE_SIZE - 1);
index2 = len - len_to_write;
while (index <= para)
write_buf[index++] = buf[index2++];
start_word_addr = FLASH_WORD_ADDR(start_write_addr);
end_word_addr = FLASH_WORDEND_ADDR(end_write_addr);
index2 = (FLASH_WORD_ADDR(start_word_addr) - FLASH_PAGE_ADDR(start_word_addr));
index = start_word_addr;
len_index = end_word_addr - start_word_addr + 1;
}
if (ERROR == flash_word_program(index, (uint32_t *)(write_buf + index2), (len_index >> 3), FLASH_FIFO)) {
__enable_irq();
return ERROR;
}
len_to_write = len_to_write - (end_write_addr - start_write_addr + 1);
}
__enable_irq();
return OK;
}
/**
* @brief erase The flash between the given address section.
* @param addr: The start address to erase.
* @param len: The length to erase.
* @retval Status, see @ref ald_status_t.
*/
ald_status_t ald_flash_erase(uint32_t addr, uint16_t len)
{
uint32_t index;
int32_t para;
int32_t start_erase_addr;
int32_t end_erase_addr;
uint16_t len_not_erase;
uint32_t len_index;
type_bool_t page_need_save;
assert_param(IS_FLASH_ADDRESS(addr));
assert_param(IS_FLASH_ADDRESS(addr + len - 1));
len_not_erase = len;
__disable_irq();
while (len_not_erase > 0) {
page_need_save = FALSE;
start_erase_addr = addr + len - len_not_erase;
end_erase_addr = addr + len - 1;
end_erase_addr = (FLASH_PAGE_ADDR(start_erase_addr) == FLASH_PAGE_ADDR(end_erase_addr))
? end_erase_addr : FLASH_PAGEEND_ADDR(start_erase_addr);
if (start_erase_addr != FLASH_PAGE_ADDR(start_erase_addr)) {
if (page_have_writen(FLASH_PAGE_ADDR(start_erase_addr), (start_erase_addr - 1)))
page_need_save = TRUE;
}
if (end_erase_addr != FLASH_PAGEEND_ADDR(end_erase_addr)) {
if (page_have_writen((end_erase_addr + 1), FLASH_PAGEEND_ADDR(end_erase_addr)))
page_need_save = TRUE;
}
if (page_need_save) {
if (ERROR == ald_flash_read((uint32_t *)write_buf, FLASH_PAGE_ADDR(start_erase_addr),
FLASH_PAGE_SIZE >> 2)) {
__enable_irq();
return ERROR;
}
}
if (ERROR == flash_page_erase(FLASH_PAGE_ADDR(start_erase_addr))) {
__enable_irq();
return ERROR;
}
if (page_need_save) {
para = end_erase_addr & (FLASH_PAGE_SIZE - 1);
index = start_erase_addr & (FLASH_PAGE_SIZE - 1);
while (index <= para)
write_buf[index++] = 0xFF;
index = FLASH_PAGE_ADDR(start_erase_addr);
len_index = FLASH_PAGE_SIZE;
if (ERROR == flash_word_program(index, (uint32_t *)write_buf, (len_index >> 3), FLASH_FIFO)) {
__enable_irq();
return ERROR;
}
}
len_not_erase = len_not_erase - (end_erase_addr - start_erase_addr + 1);
}
__enable_irq();
return OK;
}
/**
* @}
*/
#endif
/**
* @}
*/
/**
* @}
*/