#include "bsp_flash.h"
const uint16_t FlashSec_Tab[24][2] =
{
{0,FLASH_Sector_0},
{1,FLASH_Sector_1},
{2,FLASH_Sector_2},
{3,FLASH_Sector_3},
{4,FLASH_Sector_4},
{5,FLASH_Sector_5},
{6,FLASH_Sector_6},
{7,FLASH_Sector_7},
{8,FLASH_Sector_8},
{9,FLASH_Sector_9},
{10,FLASH_Sector_10},
{11,FLASH_Sector_11},
{12,FLASH_Sector_12},
{13,FLASH_Sector_13},
{14,FLASH_Sector_14},
{15,FLASH_Sector_15},
{16,FLASH_Sector_16},
{17,FLASH_Sector_17},
{18,FLASH_Sector_18},
{19,FLASH_Sector_19},
{20,FLASH_Sector_20},
{21,FLASH_Sector_21},
{22,FLASH_Sector_22},
{23,FLASH_Sector_23},
};
static uint8_t Fmc_get_Sector_index( int sector_num)
{
uint8_t index = 0;
for(int i = 0; i < 24; i++)
{
if(sector_num == FlashSec_Tab[i][1])
{
index = i;
break;
}
}
return index;
}
/*!
\brief 连续擦除多个扇区
\param[in] sec_num 起始扇区号( FLASH_Sector_0 ~ FLASH_Sector_23)
\param[in] sec_count 扇区数量
\retval none
*/
ErrStatus BSP_fmc_erase_sectors(uint32_t sec_num, int sec_count)
{
uint8_t index = 0;
fmc_unlock();
/* clear pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR\
| FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
index = Fmc_get_Sector_index( sec_num );
for(int i = 0; i < sec_count; i++)
{
fmc_sector_erase(CTL_SN(index + i));
//printf("Erase sector index = %d!\r\n", (index+i));
}
/* lock the flash program erase controller */
fmc_lock();
return SUCCESS;
}
/********************************************************************
\brief 从address 起始地址处 连续读出length个字到 Outbuff中,
\param[1] length 为字的数量, sizeof = length*4
\param[2] 读出来的 Outbuff指针
\retval none
********************************************************************/
void BSP_fmc_read_Wrod(uint32_t address, uint16_t length, uint32_t* Outbuff)
{
for(int i = 0; i < length; i++)
{
Outbuff[i] = *(volatile uint32_t*)(address);
address = address + 4;
}
}
/********************************************************************
\brief 不检查 连续写入length个字到flash
\param[1] length 为字的数量, sizeof = length*4
\param[2] 要写入的 u32 buff
\retval none
********************************************************************/
void BSP_fmc_write_Word_NoCheck(uint32_t address, uint32_t length, uint32_t* data_32)
{
/* unlock the flash program erase controller */
fmc_unlock();
/* clear pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
/* write data_32 to the corresponding address */
for(int i=0; i<length; i++)
{
if(FMC_READY == fmc_word_program(address, data_32[i]))
{
address = address + 4;
}
}
fmc_lock();
}
/********************************************************************
\brief 擦除某个扇区中的某一页(4KB)
\param[1] Sector起始地址
\param[2] 页 index: 0 ~ 31
\retval none
********************************************************************/
void BSP_fmc_erase_page(uint32_t sector_addr, int index)
{
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END| FMC_FLAG_WPERR| FMC_FLAG_PGMERR);
fmc_page_erase(sector_addr + FMC_PAGE_SIZE*index);
fmc_lock();
}
/********************************************************************
\brief 擦除某个扇区中的多页(4KB)
\param[1] Sector起始地址
\param[2] start_page_index 起始页 : 0 ~ 63
\param[3] page_num 页数量 : 1 ~ 64(256kb)
\note 跨扇区擦除,最多支持2个连续的扇区
\retval none
********************************************************************/
void BSP_fmc_erase_multi_pages(uint32_t sector_addr, int start_page_index, int page_num)
{
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END| FMC_FLAG_WPERR| FMC_FLAG_PGMERR);
for(int i = start_page_index; i < (page_num + start_page_index); i++)
{
fmc_page_erase(sector_addr + FMC_PAGE_SIZE*i);
}
fmc_lock();
}
/********************************************************************
\brief 擦除整个bank
\param[1] void
\note erase whole bank1
\retval none
********************************************************************/
void BSP_fmc_erase_bank1(void)
{
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END| FMC_FLAG_WPERR| FMC_FLAG_PGMERR);
fmc_bank1_erase();
fmc_lock();
}
/*!
\brief CHECK 4KB 页内容是否为空(FF)
\param[in] address 实际地址(Must 4KB 对齐)
\param[in] sec_count 扇区数量
\retval TRUE Blank FALSE Not Blank
*/
bool BSP_fmc_page_is_blank_Check(uint32_t address)
{
uint32_t readout = 0;
for(int i = 0; i < FMC_PAGE_SIZE; i+=4)
{
readout = *(volatile int32_t*)(address + i);
if(readout != 0xffffffff)
{
return false;
}
}
return true;
}
/*!
\brief CHECK 一个扇区内容是否为空(FF)
\param[in] address 实际地址(Must 扇区 对齐)
\retval TRUE Blank FALSE Not Blank
\note: 此函数只针对128kb大小的扇区
*/
bool BSP_fmc_sectors_is_blank_Check(uint32_t address)
{
uint32_t buff;
for(int i = 0; i < SIZE_128KB; i+=4)
{
buff = *(volatile uint32_t*)(address + i);
if(buff != 0xffffffff)
{
return false;
}
}
return true;
}
/*!
\brief get the sector number, size and range of the given address
\param[in] address: The flash address
\param[out] none
\retval fmc_sector_info_struct: The information of a sector
*/
fmc_sector_info_struct fmc_sector_info_get(uint32_t addr)
{
fmc_sector_info_struct sector_info;
uint32_t temp = 0x00000000U;
if((FMC_START_ADDRESS <= addr)&&(FMC_END_ADDRESS >= addr)) {
if ((FMC_BANK1_START_ADDRESS > addr)) {
/* bank0 area */
temp = (addr - FMC_BANK0_START_ADDRESS) / SIZE_16KB;
if (4U > temp) {
sector_info.sector_name = (uint32_t)temp;
sector_info.sector_num = CTL_SN(temp);
sector_info.sector_size = SIZE_16KB;
sector_info.sector_start_addr = FMC_BANK0_START_ADDRESS + (SIZE_16KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_16KB - 1;
} else if (8U > temp) {
sector_info.sector_name = 0x00000004U;
sector_info.sector_num = CTL_SN(4);
sector_info.sector_size = SIZE_64KB;
sector_info.sector_start_addr = 0x08010000U;
sector_info.sector_end_addr = 0x0801FFFFU;
} else {
temp = (addr - FMC_BANK0_START_ADDRESS) / SIZE_128KB;
sector_info.sector_name = (uint32_t)(temp + 4);
sector_info.sector_num = CTL_SN(temp + 4);
sector_info.sector_size = SIZE_128KB;
sector_info.sector_start_addr = FMC_BANK0_START_ADDRESS + (SIZE_128KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_128KB - 1;
}
} else {
/* bank1 area */
temp = (addr - FMC_BANK1_START_ADDRESS) / SIZE_16KB;
if (4U > temp) {
sector_info.sector_name = (uint32_t)(temp + 12);
sector_info.sector_num = CTL_SN(temp + 16);
sector_info.sector_size = SIZE_16KB;
sector_info.sector_start_addr = FMC_BANK0_START_ADDRESS + (SIZE_16KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_16KB - 1;
} else if (8U > temp) {
sector_info.sector_name = 0x00000010;
sector_info.sector_num = CTL_SN(20);
sector_info.sector_size = SIZE_64KB;
sector_info.sector_start_addr = 0x08110000U;
sector_info.sector_end_addr = 0x0811FFFFU;
} else if (64U > temp){
temp = (addr - FMC_BANK1_START_ADDRESS) / SIZE_128KB;
sector_info.sector_name = (uint32_t)(temp + 16);
sector_info.sector_num = CTL_SN(temp + 20);
sector_info.sector_size = SIZE_128KB;
sector_info.sector_start_addr = FMC_BANK1_START_ADDRESS + (SIZE_128KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_128KB - 1;
} else {
temp = (addr - FMC_BANK1_START_ADDRESS) / SIZE_256KB;
sector_info.sector_name = (uint32_t)(temp + 20);
sector_info.sector_num = CTL_SN(temp + 8);
sector_info.sector_size = SIZE_256KB;
sector_info.sector_start_addr = FMC_BANK1_START_ADDRESS + (SIZE_256KB * temp);
sector_info.sector_end_addr = sector_info.sector_start_addr + SIZE_256KB - 1;
}
}
} else {
/* invalid address */
sector_info.sector_name = FMC_WRONG_SECTOR_NAME;
sector_info.sector_num = FMC_WRONG_SECTOR_NUM;
sector_info.sector_size = FMC_INVALID_SIZE;
sector_info.sector_start_addr = FMC_INVALID_ADDR;
sector_info.sector_end_addr = FMC_INVALID_ADDR;
}
return sector_info;
}
/*!
\brief get the sector number by a given sector name
\param[in] address: a given sector name
\param[out] none
\retval uint32_t: sector number
*/
uint32_t sector_name_to_number(uint32_t sector_name)
{
if(11 >= sector_name){
return CTL_SN(sector_name);
}else if(23 >= sector_name){
return CTL_SN(sector_name + 4);
}else if(27 >= sector_name){
return CTL_SN(sector_name - 12);
}else{
while(1);
}
}
int bsw_drv_flash_erase ( uint32_t address )
{
fmc_sector_info_struct sector_info;
// printf("\r\nFMC erase operation:\n");
/* get information about the sector in which the specified address is located */
sector_info = fmc_sector_info_get(address);
if(FMC_WRONG_SECTOR_NAME == sector_info.sector_name){
// printf("\r\nWrong address!\n");
return CL_FAIL;
}else{
// printf("\r\nErase start ......\n");
/* unlock the flash program erase controller */
fmc_unlock();
/* clear pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
/* wait the erase operation complete*/
if(FMC_READY != fmc_sector_erase(sector_info.sector_num)){
return CL_FAIL;
}
/* lock the flash program erase controller */
fmc_lock();
// printf("\r\nAddress 0x%08X is located in the : SECTOR_NUMBER_%d !\n", address, sector_info.sector_name);
// printf("\r\nSector range: 0x%08X to 0x%08X\n", sector_info.sector_start_addr, sector_info.sector_end_addr);
// printf("\r\nSector size: %d KB\n", (sector_info.sector_size/1024));
// printf("\r\nErase success!\n");
// printf("\r\n");
return CL_OK;
}
}
//写数据前会自动先擦除
int bsw_drv_flash_write ( uint32_t address , uint8_t* buf , uint16_t length )
{
uint16_t writeNum;
uint32_t data = 0;
fmc_sector_info_struct start_sector_info;
fmc_sector_info_struct end_sector_info;
uint32_t sector_num,i;
// printf("\r\nFMC word programe operation:\n");
/* unlock the flash program erase controller */
fmc_unlock();
/* clear pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
/* get the information of the start and end sectors */
start_sector_info = fmc_sector_info_get(address);
end_sector_info = fmc_sector_info_get(address + length);
/* erase sector */
for(i = start_sector_info.sector_name; i <= end_sector_info.sector_name; i++){
sector_num = sector_name_to_number(i);
if(FMC_READY != fmc_sector_erase(sector_num)){
return CL_FAIL;
}
}
if ( length % 4 == 0 )
{
writeNum = length / 4;
}
else
{
writeNum = length / 4 + 1;
}
/* write data_32 to the corresponding address */
for(i=0; i<writeNum; i++){
memcpy ( &data , buf + i * 4 , 4 );
if(FMC_READY == fmc_word_program(address, data)){
address = address + 4;
}else{
return CL_FAIL;
}
}
/* lock the flash program erase controller */
fmc_lock();
// printf("\r\nWrite complete!\n");
// printf("\r\n");
return CL_OK;
}
int bsw_drv_flash_read ( uint32_t address , uint8_t* data_8 , uint16_t length )
{
uint16_t i;
if ( address < FLASH_BASE ) //非法地址
{
return CL_FAIL;
}
for(i=0; i<length; i++){
data_8[i] = (*(volatile uint8_t *)(uint32_t)(address));
address++;
}
return CL_OK;
}