/* * This file is part of the EasyFlash Library. * * Copyright (c) 2015, Armink, * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Function: Portable interface for stm32f4xx platform. * Created on: 2015-01-16 */ #include "flash.h" #include #include #include /* ENV start address */ #define FLASH_ENV_START_ADDR (FLASH_BASE + 256 * 1024) /* on the chip position: 256KB */ /* the minimum size of flash erasure */ #define FLASH_ERASE_MIN_SIZE (128 * 1024) /* it is 128K for compatibility */ #ifdef FLASH_ENV_USING_WEAR_LEVELING_MODE /* ENV section total bytes size in wear leveling mode. */ #define FLASH_ENV_SECTION_SIZE (4 * FLASH_ERASE_MIN_SIZE)/* 512K */ #else /* ENV section total bytes size in normal mode. It's equal with FLASH_USER_SETTING_ENV_SIZE */ #define FLASH_ENV_SECTION_SIZE (FLASH_USER_SETTING_ENV_SIZE) #endif /* print debug information of flash */ #define FLASH_PRINT_DEBUG /* base address of the flash sectors */ #define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base address of Sector 0, 16 K bytes */ #define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base address of Sector 1, 16 K bytes */ #define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base address of Sector 2, 16 K bytes */ #define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base address of Sector 3, 16 K bytes */ #define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base address of Sector 4, 64 K bytes */ #define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base address of Sector 5, 128 K bytes */ #define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base address of Sector 6, 128 K bytes */ #define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base address of Sector 7, 128 K bytes */ #define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base address of Sector 8, 128 K bytes */ #define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base address of Sector 9, 128 K bytes */ #define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base address of Sector 10, 128 K bytes */ #define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base address of Sector 11, 128 K bytes */ #define ADDR_FLASH_SECTOR_12 ((uint32_t)0x08100000) /* Base address of Sector 12, 16 K bytes */ #define ADDR_FLASH_SECTOR_13 ((uint32_t)0x08104000) /* Base address of Sector 13, 16 K bytes */ #define ADDR_FLASH_SECTOR_14 ((uint32_t)0x08108000) /* Base address of Sector 14, 16 K bytes */ #define ADDR_FLASH_SECTOR_15 ((uint32_t)0x0810C000) /* Base address of Sector 15, 16 K bytes */ #define ADDR_FLASH_SECTOR_16 ((uint32_t)0x08110000) /* Base address of Sector 16, 64 K bytes */ #define ADDR_FLASH_SECTOR_17 ((uint32_t)0x08120000) /* Base address of Sector 17, 128 K bytes */ #define ADDR_FLASH_SECTOR_18 ((uint32_t)0x08140000) /* Base address of Sector 18, 128 K bytes */ #define ADDR_FLASH_SECTOR_19 ((uint32_t)0x08160000) /* Base address of Sector 19, 128 K bytes */ #define ADDR_FLASH_SECTOR_20 ((uint32_t)0x08180000) /* Base address of Sector 20, 128 K bytes */ #define ADDR_FLASH_SECTOR_21 ((uint32_t)0x081A0000) /* Base address of Sector 21, 128 K bytes */ #define ADDR_FLASH_SECTOR_22 ((uint32_t)0x081C0000) /* Base address of Sector 22, 128 K bytes */ #define ADDR_FLASH_SECTOR_23 ((uint32_t)0x081E0000) /* Base address of Sector 23, 128 K bytes */ /* default ENV set for user */ static const flash_env default_env_set[] = { {"iap_need_copy_app","0"}, {"iap_copy_app_size","0"}, {"stop_in_bootloader","0"}, {"device_id","1"}, {"boot_times","0"}, }; static char log_buf[RT_CONSOLEBUF_SIZE]; static struct rt_semaphore env_cache_lock; static uint32_t stm32_get_sector(uint32_t address); static uint32_t stm32_get_sector_size(uint32_t sector); /** * Flash port for hardware initialize. * * @param env_addr ENV start address * @param env_total_size ENV sector total bytes size (@note must be word alignment) * @param erase_min_size the minimum size of Flash erasure * @param default_env default ENV set for user * @param default_env_size default ENV size * @param log_total_size saved log area size * * @return result */ FlashErrCode flash_port_init(uint32_t *env_addr, size_t *env_total_size, size_t *erase_min_size, flash_env const **default_env, size_t *default_env_size, size_t *log_size) { FlashErrCode result = FLASH_NO_ERR; FLASH_ASSERT(FLASH_USER_SETTING_ENV_SIZE % 4 == 0); FLASH_ASSERT(FLASH_ENV_SECTION_SIZE % 4 == 0); *env_addr = FLASH_ENV_START_ADDR; *env_total_size = FLASH_ENV_SECTION_SIZE; *erase_min_size = FLASH_ERASE_MIN_SIZE; *default_env = default_env_set; *default_env_size = sizeof(default_env_set)/sizeof(default_env_set[0]); rt_sem_init(&env_cache_lock, "env lock", 1, RT_IPC_FLAG_PRIO); return result; } /** * 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 */ FlashErrCode flash_read(uint32_t addr, uint32_t *buf, size_t size) { FlashErrCode result = FLASH_NO_ERR; FLASH_ASSERT(size % 4 == 0); /*copy from flash to ram */ for (; size > 0; size -= 4, addr += 4, buf++) { *buf = *(uint32_t *) addr; } return result; } /** * 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 */ FlashErrCode flash_erase(uint32_t addr, size_t size) { FlashErrCode result = FLASH_NO_ERR; FLASH_Status flash_status; size_t erased_size = 0; uint32_t cur_erase_sector; /* make sure the start address is a multiple of FLASH_ERASE_MIN_SIZE */ FLASH_ASSERT(addr % FLASH_ERASE_MIN_SIZE == 0); /* start erase */ FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); /* it will stop when erased size is greater than setting size */ while(erased_size < size) { cur_erase_sector = stm32_get_sector(addr + erased_size); flash_status = FLASH_EraseSector(cur_erase_sector, VoltageRange_3); if (flash_status != FLASH_COMPLETE) { result = FLASH_ERASE_ERR; break; } erased_size += stm32_get_sector_size(cur_erase_sector); } FLASH_Lock(); return result; } /** * 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 */ FlashErrCode flash_write(uint32_t addr, const uint32_t *buf, size_t size) { FlashErrCode result = FLASH_NO_ERR; size_t i; uint32_t read_data; FLASH_ASSERT(size % 4 == 0); FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); for (i = 0; i < size; i += 4, buf++, addr += 4) { /* write data */ FLASH_ProgramWord(addr, *buf); read_data = *(uint32_t *)addr; /* check data */ if (read_data != *buf) { result = FLASH_WRITE_ERR; break; } } FLASH_Lock(); return result; } /** * lock the ENV ram cache */ void flash_env_lock(void) { rt_sem_take(&env_cache_lock, RT_WAITING_FOREVER); } /** * unlock the ENV ram cache */ void flash_env_unlock(void) { rt_sem_release(&env_cache_lock); } /** * Get the sector of a given address * * @param address flash address * * @return The sector of a given address */ static uint32_t stm32_get_sector(uint32_t address) { uint32_t sector = 0; if ((address < ADDR_FLASH_SECTOR_1) && (address >= ADDR_FLASH_SECTOR_0)) { sector = FLASH_Sector_0; } else if ((address < ADDR_FLASH_SECTOR_2) && (address >= ADDR_FLASH_SECTOR_1)) { sector = FLASH_Sector_1; } else if ((address < ADDR_FLASH_SECTOR_3) && (address >= ADDR_FLASH_SECTOR_2)) { sector = FLASH_Sector_2; } else if ((address < ADDR_FLASH_SECTOR_4) && (address >= ADDR_FLASH_SECTOR_3)) { sector = FLASH_Sector_3; } else if ((address < ADDR_FLASH_SECTOR_5) && (address >= ADDR_FLASH_SECTOR_4)) { sector = FLASH_Sector_4; } else if ((address < ADDR_FLASH_SECTOR_6) && (address >= ADDR_FLASH_SECTOR_5)) { sector = FLASH_Sector_5; } else if ((address < ADDR_FLASH_SECTOR_7) && (address >= ADDR_FLASH_SECTOR_6)) { sector = FLASH_Sector_6; } else if ((address < ADDR_FLASH_SECTOR_8) && (address >= ADDR_FLASH_SECTOR_7)) { sector = FLASH_Sector_7; } else if ((address < ADDR_FLASH_SECTOR_9) && (address >= ADDR_FLASH_SECTOR_8)) { sector = FLASH_Sector_8; } else if ((address < ADDR_FLASH_SECTOR_10) && (address >= ADDR_FLASH_SECTOR_9)) { sector = FLASH_Sector_9; } else if ((address < ADDR_FLASH_SECTOR_11) && (address >= ADDR_FLASH_SECTOR_10)) { sector = FLASH_Sector_10; } else if ((address < ADDR_FLASH_SECTOR_12) && (address >= ADDR_FLASH_SECTOR_11)) { sector = FLASH_Sector_11; } else if ((address < ADDR_FLASH_SECTOR_13) && (address >= ADDR_FLASH_SECTOR_12)) { sector = FLASH_Sector_12; } else if ((address < ADDR_FLASH_SECTOR_14) && (address >= ADDR_FLASH_SECTOR_13)) { sector = FLASH_Sector_13; } else if ((address < ADDR_FLASH_SECTOR_15) && (address >= ADDR_FLASH_SECTOR_14)) { sector = FLASH_Sector_14; } else if ((address < ADDR_FLASH_SECTOR_16) && (address >= ADDR_FLASH_SECTOR_15)) { sector = FLASH_Sector_15; } else if ((address < ADDR_FLASH_SECTOR_17) && (address >= ADDR_FLASH_SECTOR_16)) { sector = FLASH_Sector_16; } else if ((address < ADDR_FLASH_SECTOR_18) && (address >= ADDR_FLASH_SECTOR_17)) { sector = FLASH_Sector_17; } else if ((address < ADDR_FLASH_SECTOR_19) && (address >= ADDR_FLASH_SECTOR_18)) { sector = FLASH_Sector_18; } else if ((address < ADDR_FLASH_SECTOR_20) && (address >= ADDR_FLASH_SECTOR_19)) { sector = FLASH_Sector_19; } else if ((address < ADDR_FLASH_SECTOR_21) && (address >= ADDR_FLASH_SECTOR_20)) { sector = FLASH_Sector_20; } else if ((address < ADDR_FLASH_SECTOR_22) && (address >= ADDR_FLASH_SECTOR_21)) { sector = FLASH_Sector_21; } else if ((address < ADDR_FLASH_SECTOR_23) && (address >= ADDR_FLASH_SECTOR_22)) { sector = FLASH_Sector_22; } else /*(address < FLASH_END_ADDR) && (address >= ADDR_FLASH_SECTOR_23))*/ { sector = FLASH_Sector_23; } return sector; } /** * Get the sector size * * @param sector sector * * @return sector size */ static uint32_t stm32_get_sector_size(uint32_t sector) { FLASH_ASSERT(IS_FLASH_SECTOR(sector)); switch (sector) { case 0: return 16 * 1024; case 1: return 16 * 1024; case 2: return 16 * 1024; case 3: return 16 * 1024; case 4: return 64 * 1024; case 5: return 128 * 1024; case 6: return 128 * 1024; case 7: return 128 * 1024; case 8: return 128 * 1024; case 9: return 128 * 1024; case 10: return 128 * 1024; case 11: return 128 * 1024; case 12: return 16 * 1024; case 13: return 16 * 1024; case 14: return 16 * 1024; case 15: return 16 * 1024; case 16: return 64 * 1024; case 17: return 128 * 1024; case 18: return 128 * 1024; case 19: return 128 * 1024; case 20: return 128 * 1024; case 21: return 128 * 1024; case 22: return 128 * 1024; case 23: return 128 * 1024; default : return 128 * 1024; } } /** * This function is print flash debug info. * * @param file the file which has call this function * @param line the line number which has call this function * @param format output format * @param ... args * */ void flash_log_debug(const char *file, const long line, const char *format, ...) { #ifdef FLASH_PRINT_DEBUG va_list args; /* args point to the first variable parameter */ va_start(args, format); flash_print("[Flash](%s:%ld) ", file, line); /* must use vprintf to print */ rt_vsprintf(log_buf, format, args); flash_print("%s", log_buf); va_end(args); #endif } /** * This function is print flash routine info. * * @param format output format * @param ... args */ void flash_log_info(const char *format, ...) { va_list args; /* args point to the first variable parameter */ va_start(args, format); flash_print("[Flash]"); /* must use vprintf to print */ rt_vsprintf(log_buf, format, args); flash_print("%s", log_buf); va_end(args); } /** * This function is print flash non-package info. * * @param format output format * @param ... args */ void flash_print(const char *format, ...) { va_list args; /* args point to the first variable parameter */ va_start(args, format); /* must use vprintf to print */ rt_vsprintf(log_buf, format, args); rt_kprintf("%s", log_buf); va_end(args); }