/***********************************************************************************************************************
* Copyright (C) All rights reserved.
***********************************************************************************************************************/
/***********************************************************************************************************************
* @file flash.c
* @brief This file implements flash sector erase and program.
* @version 1.0.0
* @date 2019/12/24
***********************************************************************************************************************/
/***********************************************************************************************************************
Includes
***********************************************************************************************************************/
#include "flash.h"
uint32_t flash_protect_flag = 0;
#if defined (__CC_ARM)
#pragma arm section code = "ram_fetch_code" // Arm Compiler 5
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION > 6010050)
#pragma clang section text = "ram_fetch_code" // Arm Compiler 6
#endif
/***********************************************************************************************************************
* Function Name: EraseChip
* @brief Chip Erase Flash
* @param adr - Any address of user code flash
* @return status: 0 - OK, 1 - Failed
***********************************************************************************************************************/
int EraseChip (uint32_t adr)
{
#ifdef FLASH_PROTCET
if(flash_protect_flag != PROTECT_VALUE)
{
return(1);
}
flash_protect_flag = 0;
#endif
__DI;
FMC->FLERMD = 0x08;
FMC->FLPROT = 0xF1;
FMC->FLOPMD1 = 0x55;
FMC->FLOPMD2 = 0xAA;
// Write data to start address of sector to trigger Erase Operation
*(uint32_t *) adr = 0xFFFFFFFF;
// polling OVER Flag
while((FMC->FLSTS & FMC_FLSTS_OVF_Msk) == 0);
FMC->FLSTS = FMC_FLSTS_OVF_Msk;
FMC->FLERMD = 0x00;
FMC->FLPROT = 0xF0;
__EI;
return(0);
}
/***********************************************************************************************************************
* Function Name: EraseSector
* @brief Sector Erase Flash
* @param adr - sector address of user code flash
* @return status: 0 - OK, 1 - Failed
***********************************************************************************************************************/
int EraseSector (uint32_t adr)
{
#ifdef FLASH_PROTCET
if(flash_protect_flag != PROTECT_VALUE)
{
return(1);
}
flash_protect_flag = 0;
#endif
__DI;
FMC->FLERMD = 0x10;
FMC->FLPROT = 0xF1;
FMC->FLOPMD1 = 0x55;
FMC->FLOPMD2 = 0xAA;
// Write data to start address of sector to trigger Erase Operation
*(uint32_t *) adr = 0xFFFFFFFF;
// polling Erase Over Flag
while((FMC->FLSTS & FMC_FLSTS_OVF_Msk) == 0);
FMC->FLSTS = FMC_FLSTS_OVF_Msk;
FMC->FLERMD = 0x00;
FMC->FLPROT = 0xF0;
if(FMC->FLSTS & FMC_FLSTS_EVF_Msk)
{
FMC->FLSTS = FMC_FLSTS_EVF_Msk;
__EI;
return(1); /* verify ng */
}
else
{
__EI;
return(0); /* verify ok */
}
}
/***********************************************************************************************************************
* Function Name: ProgramPage
* @brief Write data to Flash
* @param adr - Page Start Address
* @param sz - Page Size
* @param buf - Page Data
* @return status: 0 - OK, 1 - Failed
***********************************************************************************************************************/
int ProgramPage (uint32_t adr, uint32_t sz, uint8_t *buf)
{
uint32_t i;
uint8_t *ptr;
ptr = (uint8_t *) adr;
#ifdef FLASH_PROTCET
if(flash_protect_flag != PROTECT_VALUE)
{
return(1);
}
flash_protect_flag = 0;
#endif
FMC->FLPROT = 0xF1;
for(i=0; i<sz; i++)
{
__DI;
FMC->FLOPMD1 = 0xAA;
FMC->FLOPMD2 = 0x55;
*ptr++ = *buf++;
__EI;
// polling OVER Flag
while((FMC->FLSTS & FMC_FLSTS_OVF_Msk) == 0);
FMC->FLSTS = FMC_FLSTS_OVF_Msk;
}
FMC->FLPROT = 0xF0;
return (0);
}
/***********************************************************************************************************************
* Function Name: flash_write
* @brief Write data to Flash area. Automatically determines if erasure is needed.
* If the destination area is blank, omits Erase and Pragram directly.
* Otherwise, save data of flash to ram, erase flash, and then write flash.
* @param adr - Page Start Address
* @param sz - Page Size
* @param buf - Page Data
* @return status - MD_OK or MD_ERROR
* @note sz must be less then or equal to SECTOR_SIZE, if not, return MD_ERROR and don't change flash contents.
***********************************************************************************************************************/
FLASH_STATUS flash_write(uint32_t adr, uint32_t sz, uint8_t *buf)
{
FLASH_STATUS status = FS_OK;
uint8_t dat, tmp[SECTOR_SIZE *2];
uint8_t blank = 1;
uint8_t cross;
uint8_t *ptr;
uint8_t *ptr_base; /* sector base address */
uint16_t offset;
uint16_t i;
uint32_t sector_num;
#ifdef FLASH_PROTCET
if(flash_protect_flag != PROTECT_VALUE)
{
return(FS_ERROR);
}
flash_protect_flag = 0;
#endif
if(sz > SECTOR_SIZE)
{
status = FS_ERROR;
return(status);
}
ptr = (uint8_t *)adr;
/* Determine if the target area is blank */
for(i=0; i<sz; i++)
{
dat = *ptr++;
if(dat != 0xFFU)
{
blank = 0; /* Not blank */
}
}
/* if it is blank, omits erase and program directlly. */
if(blank)
{
/* write data to flash data */
flash_protect_flag = PROTECT_VALUE;
ProgramPage(adr, sz, buf);
/* if it isn't blank, erase and then program */
}
else
{
sector_num = (adr & ~(SECTOR_SIZE-1)) >> 9;
if((adr+sz) > ((sector_num+1) << 9))
{
cross = 1; /* write area cross sectors */
}
else
{
cross = 0;
}
ptr_base = (uint8_t *)(adr & ~(SECTOR_SIZE-1)); /* get sector base address: Each sector is 512 bytes (i.e. 128 words) */
offset = adr & (SECTOR_SIZE-1); /* get offset */
/* Save the Flash data temporarily */
if(cross)
{
/* read two sectors */
for(i = 0; i < SECTOR_SIZE * 2; i++)
{
tmp[i] = *ptr_base++;
}
}
else
{
/* read one sector */
for(i = 0; i < SECTOR_SIZE; i++)
{
tmp[i] = *ptr_base++;
}
}
/* replace flash data with write data */
for(i = 0; i < sz; i++)
{
tmp[offset+i] = *buf++;
}
/* write data to flash data */
if(cross)
{
flash_protect_flag = PROTECT_VALUE;
EraseSector((sector_num + 0 ) << 9);
flash_protect_flag = PROTECT_VALUE;
EraseSector((sector_num + 1 ) << 9);
flash_protect_flag = PROTECT_VALUE;
ProgramPage(sector_num << 9, SECTOR_SIZE * 2, tmp);
}
else
{
flash_protect_flag = PROTECT_VALUE;
EraseSector((sector_num + 0 ) << 9);
flash_protect_flag = PROTECT_VALUE;
ProgramPage(sector_num << 9, SECTOR_SIZE * 1, tmp);
}
}
return (status);
}
void flashRead(uint8_t *read_address, uint16_t size, uint8_t *readbuf)
{
uint8_t *w_ptr;
uint32_t i;
w_ptr = (uint8_t *)read_address;
for (i = 0; i < size; i++)
{
*readbuf = *w_ptr++;
readbuf++;
}
}
#if defined (__CC_ARM)
#pragma arm section code // Arm Compiler 5
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION > 6010050)
#pragma clang section text = "" // Arm Compiler 6
#endif