This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/system/bsp/flash.c

531 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file flash.c
* @author xxx
* @date 2024-02-07 11:49:34
* @brief
* @copyright Copyright (c) 2024 by xxx, All Rights Reserved.
* @attention
*
* ST 的官方驱动 LL 库并没有 flash 驱动。这里自己实现。
*
* 1. 由于在 stm32l4xx_ll_system.h 中存在部分 FLASH 操作函数ACR寄存器的处理且不全面
* 因此这里需要额外处理(重命名)
*
* 2. Main memory
* 1 FLASH_ACR 完成
* 2 FLASH_PDKEYR 完成
* 3 FLASH_KEYR 完成
* 4 FLASH_OPTKEYR 完成
* 5 FLASH_SR 完成
* 6 FLASH_CR 完成
* 7 FLASH_ECCR 完成
* 8 FLASH_OPTR 未完成
* 9 FLASH_PCROP1SR 未完成
* 后续寄存器 均未完成
* 3. Information block
* - System memory
* - OTP area
* - Option bytes
* 4. 根据 HAL 库的实现,相比于与手册的推荐流程,擦写的执行序列还有其他操作。
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "flash.h"
#include "stm32l4xx_ll_rcc.h"
#include "stm32l4xx_ll_system.h"
#include "stm32l4xx_ll_pwr.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
#define WHILE_MAX 10000U
/** @addtogroup STM32L4xx_LL_Driver
* @{
*/
/** @addtogroup FLASH_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup FLASH_LL_Private_Constants
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup FLASH_LL_Private_Macros
* @{
*/
#define IS_LL_FLASH_WRITE_ADDR(__ADDR__) ((__ADDR__) % LL_FLASH_ALIGNMENT_MIN_SIZE == 0)
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup FLASH_LL_Private_Functions FLASH Private functions
* @{
*/
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup FLASH_LL_Exported_Functions
* @{
*/
/**
* @brief Clear All Error in SR
* @param FLASHx FLASH Instance
* @retval None
*/
void LL_FLASH_ClearAllErrorFlag(void)
{
LL_FLASH_ClearFlag_OPTVERR(FLASH);
LL_FLASH_ClearFlag_RDERR(FLASH);
LL_FLASH_ClearFlag_FASTERR(FLASH);
LL_FLASH_ClearFlag_MISERR(FLASH);
LL_FLASH_ClearFlag_PGSERR(FLASH);
LL_FLASH_ClearFlag_SIZERR(FLASH);
LL_FLASH_ClearFlag_PGAERR(FLASH);
LL_FLASH_ClearFlag_WRPERR(FLASH);
LL_FLASH_ClearFlag_PROGERR(FLASH);
LL_FLASH_ClearFlag_OPERR(FLASH);
}
/**
* @brief Flush the instruction and data caches.
* @retval None
*/
void LL_FLASH_FlushCaches(void)
{
/* Flush instruction cache */
if (LL_FLASH_IsEnabledInstructionCache(FLASH))
{
LL_FLASH_DisableInstructionCache(FLASH);
/* Reset instruction cache */
LL_FLASH_InstructionCacheReset(FLASH);
/* Enable instruction cache */
LL_FLASH_EnableInstructionCache(FLASH);
}
/* Flush data cache */
if (LL_FLASH_IsEnabledDataCache(FLASH))
{
LL_FLASH_ZCS_DisableDataCache(FLASH);
/* Reset data cache */
LL_FLASH_DataCacheReset(FLASH);
/* Enable data cache */
LL_FLASH_ZCS_EnableDataCache(FLASH);
}
}
/**
* @brief Erase Page
* @param pageno Page number
* @retval None
*/
ErrorStatus LL_FLASH_ErasePage(uint32_t pageno)
{
uint16_t count = 0;
/* Check that no Flash memory operation is ongoing by checking the BSY bit */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */
LL_FLASH_ClearAllErrorFlag();
/* Set the PER bit and select the page you wish to erase (PNB) with the associated bank (BKER) in the Flash control register (FLASH_CR). */
LL_FLASH_EnablePageErase(FLASH);
if (pageno >= LL_FLASH_BANK1_PAGE_NUM)
{
pageno -= LL_FLASH_BANK1_PAGE_NUM;
LL_FLASH_SetErasePageBank(FLASH, LL_FLASH_BANK2);
}
else
{
LL_FLASH_SetErasePageBank(FLASH, LL_FLASH_BANK1);
}
LL_FLASH_SetErasePageNo(FLASH, pageno);
/* Set the STRT bit in the FLASH_CR register. */
LL_FLASH_EraseStart(FLASH);
/* Wait for the BSY bit to be cleared in the FLASH_SR register. */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* 完成只有需要清除擦除标志. */
LL_FLASH_DisablePageErase(FLASH);
/* Flush the caches to be sure of the data consistency */
LL_FLASH_FlushCaches();
return SUCCESS;
}
/**
* @brief Erase bank
* @param bank This parameter can be one of the following values:
* @arg @ref LL_FLASH_BANK1
* @arg @ref LL_FLASH_BANK2
* @retval None
*/
ErrorStatus LL_FLASH_EraseBank(uint32_t bank)
{
uint16_t count = 0;
/* Check that no Flash memory operation is ongoing by checking the BSY bit */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */
LL_FLASH_ClearAllErrorFlag();
/* Set the MER1 bit or/and MER2 (depending on the bank) in the Flash control register (FLASH_CR).
Both banks can be selected in the same operation. */
if (bank == LL_FLASH_BANK1)
{
LL_FLASH_EnableBank1Erase(FLASH);
}
else
{
LL_FLASH_EnableBank2Erase(FLASH);
}
/* Set the STRT bit in the FLASH_CR register. */
LL_FLASH_EraseStart(FLASH);
/* Wait for the BSY bit to be cleared in the FLASH_SR register. */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* 完成只有需要清除擦除标志. */
LL_FLASH_DisableBank1Erase(FLASH);
LL_FLASH_DisableBank2Erase(FLASH);
/* Flush the caches to be sure of the data consistency */
LL_FLASH_FlushCaches();
return SUCCESS;
}
/**
* @brief Erase Chip
* @param None
* @retval None
*/
ErrorStatus LL_FLASH_EraseChip(void)
{
uint16_t count = 0;
/* Check that no Flash memory operation is ongoing by checking the BSY bit */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */
LL_FLASH_ClearAllErrorFlag();
/* Set the MER1 bit or/and MER2 (depending on the bank) in the Flash control register (FLASH_CR).
Both banks can be selected in the same operation. */
LL_FLASH_EnableBank1Erase(FLASH);
LL_FLASH_EnableBank2Erase(FLASH);
/* Set the STRT bit in the FLASH_CR register. */
LL_FLASH_EraseStart(FLASH);
/* Wait for the BSY bit to be cleared in the FLASH_SR register. */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* 完成只有需要清除擦除标志. */
LL_FLASH_DisableBank1Erase(FLASH);
LL_FLASH_DisableBank2Erase(FLASH);
/* Flush the caches to be sure of the data consistency */
LL_FLASH_FlushCaches();
return SUCCESS;
}
/**
* @brief Program Double Word
* @param address specifies the address to be programmed.
* @param data specifies the data to be programmed.
* @retval An ErrorStatus enumeration value:
* - SUCCESS: Write successfully
* - ERROR: error
*/
ErrorStatus LL_FLASH_ProgramDoubleWord(uint32_t address, uint64_t data)
{
assert_param(!IS_LL_FLASH_WRITE_ADDR(address));
uint16_t count = 0;
/* Check that no Flash memory operation is ongoing by checking the BSY bit */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */
LL_FLASH_ClearAllErrorFlag();
/* Set the PG bit in the Flash control register (FLASH_CR). */
LL_FLASH_EnableProgram(FLASH);
/* Perform the data write operation at the desired memory address, inside main memory
block or OTP area. Only double word can be programmed. */
/* Program the double word */
*(__IO uint32_t *)address = (uint32_t)data;
*(__IO uint32_t *)(address + 4U) = (uint32_t)(data >> 32);
/* Check that no Flash memory operation is ongoing by checking the BSY bit */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* Check that EOP flag is set in the FLASH_SR register (meaning that the programming
operation has succeed), and clear it by software. */
if (LL_FLASH_IsActiveFlag_EOP(FLASH))
{
LL_FLASH_ClearFlag_EOP(FLASH);
}
/* Clear the PG bit in the FLASH_CR register if there no more programming request anymore. */
LL_FLASH_DisableProgram(FLASH);
/* Flush the caches to be sure of the data consistency */
LL_FLASH_FlushCaches();
return SUCCESS;
}
/**
* @brief Program
* @param address specifies the address to be programmed.
* @param data specifies the data to be programmed.
* @param num specifies the data number
* @retval An ErrorStatus enumeration value:
* - SUCCESS: Write successfully
* - ERROR: error
*/
ErrorStatus LL_FLASH_Program(uint32_t address, uint8_t data[], uint32_t num)
{
static uint64_t DataT = 0;
uint32_t T = 0, S = 0;
uint16_t count = 0;
assert_param(!IS_LL_FLASH_WRITE_ADDR(address));
if (num == 0)
{
return SUCCESS;
}
/* Check that no Flash memory operation is ongoing by checking the BSY bit */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* Check and clear all error programming flags due to a previous programming. If not, PGSERR is set. */
LL_FLASH_ClearAllErrorFlag();
/* Set the PG bit in the Flash control register (FLASH_CR). */
LL_FLASH_EnableProgram(FLASH);
/* Perform the data write operation at the desired memory address, inside main memory
block or OTP area. Only double word can be programmed. */
T = num;
while (num > 0)
{
DataT = 0;
if (num >= 8)
{
for (int i = 0; i < LL_FLASH_ALIGNMENT_MIN_SIZE; i++)
{
DataT = DataT << 8;
DataT |= data[S + 7 - i];
}
S += LL_FLASH_ALIGNMENT_MIN_SIZE;
num -= LL_FLASH_ALIGNMENT_MIN_SIZE;
}
else
{
for (int i = 0; i < num; i++)
{
DataT = DataT << 8;
DataT |= data[T - 1 - i];
}
num = 0;
}
/* Program the double word */
*(__IO uint32_t *)address = (uint32_t)DataT;
*(__IO uint32_t *)(address + 4U) = (uint32_t)(DataT >> 32);
/* Check that no Flash memory operation is ongoing by checking the BSY bit */
while (LL_FLASH_IsActiveFlag_BSY(FLASH))
{
if (count++ > WHILE_MAX)
{
return ERROR;
}
}
count = 0;
/* Check that EOP flag is set in the FLASH_SR register (meaning that the programming
operation has succeed), and clear it by software. */
if (LL_FLASH_IsActiveFlag_EOP(FLASH))
{
LL_FLASH_ClearFlag_EOP(FLASH);
}
address += LL_FLASH_ALIGNMENT_MIN_SIZE;
}
/* Clear the PG bit in the FLASH_CR register if there no more programming request anymore. */
LL_FLASH_DisableProgram(FLASH);
/* Flush the caches to be sure of the data consistency */
LL_FLASH_FlushCaches();
return SUCCESS;
}
/**
* @}
*/
/** @addtogroup FLASH_LL_Private_Functions
* @{
*/
/**
* @brief Fast program a row double-word (64-bit) at a specified address.
* @param address: specifies the address to be programmed.
* @param DataAddress: specifies the address where the data are stored.
* @retval None
*/
void LL_FLASH_ProgramFast(uint32_t address, uint32_t DataAddress)
{
uint8_t row_index = (2 * LL_FLASH_ROW_SIZE);
__IO uint32_t *dest_addr = (__IO uint32_t *)address;
__IO uint32_t *src_addr = (__IO uint32_t *)DataAddress;
/* Check the parameters */
assert_param(IS_FLASH_MAIN_MEM_ADDRESS(address));
/* Set FSTPG bit */
LL_FLASH_EnableFastProgram(FLASH);
/* Disable interrupts to avoid any interruption during the loop */
__disable_irq();
/* Program the double word of the row */
do
{
*dest_addr = *src_addr;
dest_addr++;
src_addr++;
row_index--;
} while (row_index != 0U);
/* Re-enable the interrupts */
__enable_irq();
LL_FLASH_DisableFastProgram(FLASH);
}
/**
* @brief Fast program a row double-word (64-bit) at a specified address.
* @param address: specifies the address to be programmed.
* @param data: specifies the data to be programmed.
* @retval None
*/
ErrorStatus LL_FLASH_Read(uint32_t address, uint8_t data[], uint32_t num)
{
if (num == 0)
{
return SUCCESS;
}
for (uint32_t i = 0; i < num; i++)
{
data[i] = *(__IO uint8_t *)(address + i);
}
return SUCCESS;
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/