344 lines
9.4 KiB
C
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
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|