/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-12-5 SummerGift first version */ #include "board.h" #ifdef BSP_USING_ON_CHIP_FLASH #include "drv_config.h" #include "drv_flash.h" #if defined(RT_USING_FAL) #include "fal.h" #endif //#define DRV_DEBUG #define LOG_TAG "drv.flash" #include /** * @brief Gets the page of a given address * @param Addr: Address of the FLASH Memory * @retval The page of a given address */ static uint32_t GetPage(uint32_t Addr) { uint32_t page = 0; if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { /* Bank 1 */ page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE; } else { /* Bank 2 */ page = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE; } return page; } /** * @brief Gets the bank of a given address * @param Addr: Address of the FLASH Memory * @retval The bank of a given address */ static uint32_t GetBank(uint32_t Addr) { uint32_t bank = 0; #ifndef FLASH_BANK_2 bank = FLASH_BANK_1; #else if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0) { /* No Bank swap */ if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { bank = FLASH_BANK_1; } else { bank = FLASH_BANK_2; } } else { /* Bank swap */ if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { bank = FLASH_BANK_2; } else { bank = FLASH_BANK_1; } } #endif return bank; } /** * Read data from flash. * @note This operation's units is word. * * @param addr flash address * @param buf buffer to store read data * @param size read bytes size * * @return result */ int stm32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size) { size_t i; if ((addr + size) > STM32_FLASH_END_ADDRESS) { LOG_E("read outrange flash size! addr is (0x%p)", (void*)(addr + size)); return -RT_EINVAL; } for (i = 0; i < size; i++, buf++, addr++) { *buf = *(rt_uint8_t *) addr; } return size; } /** * Write data to flash. * @note This operation's units is word. * @note This operation must after erase. @see flash_erase. * * @param addr flash address * @param buf the write data buffer * @param size write bytes size * * @return result */ int stm32_flash_write(rt_uint32_t addr, const uint8_t *buf, size_t size) { size_t i, j; rt_err_t result = 0; rt_uint64_t write_data = 0, temp_data = 0; if ((addr + size) > STM32_FLASH_END_ADDRESS) { LOG_E("ERROR: write outrange flash size! addr is (0x%p)\n", (void*)(addr + size)); return -RT_EINVAL; } if(addr % 8 != 0) { LOG_E("write addr must be 8-byte alignment"); return -RT_EINVAL; } HAL_FLASH_Unlock(); __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR); if (size < 1) { return -RT_ERROR; } for (i = 0; i < size;) { if ((size - i) < 8) { for (j = 0; (size - i) > 0; i++, j++) { temp_data = *buf; write_data = (write_data) | (temp_data << 8 * j); buf ++; } } else { for (j = 0; j < 8; j++, i++) { temp_data = *buf; write_data = (write_data) | (temp_data << 8 * j); buf ++; } } /* write data */ if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, write_data) == HAL_OK) { /* Check the written value */ if (*(uint64_t*)addr != write_data) { LOG_E("ERROR: write data != read data\n"); result = -RT_ERROR; goto __exit; } } else { result = -RT_ERROR; goto __exit; } temp_data = 0; write_data = 0; addr += 8; } __exit: HAL_FLASH_Lock(); if (result != 0) { return result; } return size; } /** * Erase data on flash. * @note This operation is irreversible. * @note This operation's units is different which on many chips. * * @param addr flash address * @param size erase bytes size * * @return result */ int stm32_flash_erase(rt_uint32_t addr, size_t size) { rt_err_t result = RT_EOK; uint32_t FirstPage = 0, NbOfPages = 0, BankNumber = 0; uint32_t PAGEError = 0; if ((addr + size) > STM32_FLASH_END_ADDRESS) { LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void*)(addr + size)); return -RT_EINVAL; } /*Variable used for Erase procedure*/ FLASH_EraseInitTypeDef EraseInitStruct; /* Unlock the Flash to enable the flash control register access *************/ HAL_FLASH_Unlock(); /* Clear OPTVERR bit set on virgin samples */ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR | FLASH_FLAG_PGSERR); /* Get the 1st page to erase */ FirstPage = GetPage(addr); /* Get the number of pages to erase from 1st page */ NbOfPages = GetPage(addr + size - 1) - FirstPage + 1; /* Get the bank */ BankNumber = GetBank(addr); /* Fill EraseInit structure*/ EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Banks = BankNumber; EraseInitStruct.Page = FirstPage; EraseInitStruct.NbPages = NbOfPages; if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) { result = -RT_ERROR; goto __exit; } __exit: HAL_FLASH_Lock(); if (result != RT_EOK) { return result; } LOG_D("erase done: addr (0x%p), size %d", (void*)addr, size); return size; } #if defined(RT_USING_FAL) static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size); static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size); static int fal_flash_erase(long offset, size_t size); const struct fal_flash_dev stm32_onchip_flash = { "onchip_flash", STM32_FLASH_START_ADRESS, STM32_FLASH_SIZE, FLASH_PAGE_SIZE, {NULL, fal_flash_read, fal_flash_write, fal_flash_erase} }; static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size) { return stm32_flash_read(stm32_onchip_flash.addr + offset, buf, size); } static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size) { return stm32_flash_write(stm32_onchip_flash.addr + offset, buf, size); } static int fal_flash_erase(long offset, size_t size) { return stm32_flash_erase(stm32_onchip_flash.addr + offset, size); } #endif #endif /* BSP_USING_ON_CHIP_FLASH */