You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
393 lines
14 KiB
C
393 lines
14 KiB
C
/*
|
|
* This file is part of the EasyFlash Library.
|
|
*
|
|
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Function: Portable interface for stm32f4xx platform.
|
|
* Created on: 2015-01-16
|
|
*/
|
|
|
|
#include "flash.h"
|
|
#include <rthw.h>
|
|
#include <rtthread.h>
|
|
#include <stm32f4xx_conf.h>
|
|
|
|
/* 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 */
|
|
/* the user setting size of ENV */
|
|
#define FLASH_USER_SETTING_ENV_SIZE (2 * 1024) /* 2K */
|
|
#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 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_user_size user setting ENV bytes size (@note must be word alignment)
|
|
* @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
|
|
*
|
|
* @return result
|
|
*/
|
|
FlashErrCode flash_port_init(uint32_t *env_addr, size_t *env_user_size, size_t *env_total_size,
|
|
size_t *erase_min_size, flash_env const **default_env, size_t *default_env_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_user_size = FLASH_USER_SETTING_ENV_SIZE;
|
|
*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]);
|
|
|
|
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);
|
|
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_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;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Allocate a block of memory with a minimum of 'size' bytes.
|
|
*
|
|
* @param size is the minimum size of the requested block in bytes.
|
|
*
|
|
* @return pointer to allocated memory or NULL if no free memory was found.
|
|
*/
|
|
void *flash_malloc(size_t size) {
|
|
return rt_malloc(size);
|
|
}
|
|
|
|
/**
|
|
* This function will release the previously allocated memory block by
|
|
* flash_malloc. The released memory block is taken back to system heap.
|
|
*
|
|
* @param p the pointer to allocated memory which will be released
|
|
*/
|
|
void flash_free(void *p) {
|
|
rt_free(p);
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|