Skip to content

Commit

Permalink
Improvements in STM32 flash driver V1
Browse files Browse the repository at this point in the history
- Add FLASH_WaitForLastOperation function.
- Rework erase and write functions to clear error flags and call wait for last operation.
- Fix wrong defines for STM32F0 series.
- Add define to clear error flags.
- Minor fixes in code style to follow guidelines.

Signed-off-by: José Simões <jose.simoes@eclo.solutions>
  • Loading branch information
josesimoes committed Oct 30, 2019
1 parent 808ef88 commit ec235d5
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,38 +33,73 @@ SMT32FlashDriver STM32FLASH;
// Unlock the FLASH control register access
bool HAL_FLASH_Unlock(void)
{
if (HAL_IS_BIT_SET(FLASH->CR, FLASH_CR_LOCK))
bool status = true;

if(READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET)
{
/* Authorize the FLASH Registers access */
// Authorize the FLASH Registers access
WRITE_REG(FLASH->KEYR, FLASH_KEY1);
WRITE_REG(FLASH->KEYR, FLASH_KEY2);
}
else
{
return false;

// Verify Flash is unlocked
if(READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET)
{
status = false;
}
}

return true;
return status;
}

// Locks the FLASH control register access
bool HAL_FLASH_Lock(void)
{
/* Set the LOCK Bit to lock the FLASH Registers access */
// Set the LOCK Bit to lock the FLASH Registers access
SET_BIT(FLASH->CR, FLASH_CR_LOCK);

return true;
}

bool FLASH_WaitForLastOperation(uint32_t timeout)
{
(void)timeout;

bool success = true;

// Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
// Even if the FLASH operation fails, the BUSY flag will be reset and an error flag will be set
// no need to overload this with a timeout workflow as the watchdog will quick-in if execution gets stuck

while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY));

// Check FLASH End of Operation flag
if( __HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP) )
{
// Clear FLASH End of Operation pending bit
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}

if( __HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR) ||
__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR))
{
// at this point we don't care about the details of the programming error
success = false;
}

return success;
}

///////////////////////////////////////////////////////////////////////////////
// Driver exported functions. //
///////////////////////////////////////////////////////////////////////////////

void flash_lld_init() {
void flash_lld_init()
{
stm32FlashObjectInit(&STM32FLASH);
}

void flash_lld_readBytes(uint32_t startAddress, uint32_t length, uint8_t* buffer) {
void flash_lld_readBytes(uint32_t startAddress, uint32_t length, uint8_t* buffer)
{

__IO uint8_t* cursor = (__IO uint8_t*)startAddress;
__IO uint8_t* endAddress = (__IO uint8_t*)(startAddress + length);
Expand All @@ -76,19 +111,24 @@ void flash_lld_readBytes(uint32_t startAddress, uint32_t length, uint8_t* buffer
}
}

int flash_lld_write(uint32_t startAddress, uint32_t length, const uint8_t* buffer) {

int flash_lld_write(uint32_t startAddress, uint32_t length, const uint8_t* buffer)
{
bool success = true;

__IO uint8_t* cursor = (__IO uint8_t*)startAddress;
__IO uint8_t* endAddress = (__IO uint8_t*)(startAddress + length);

// unlock the FLASH
if(HAL_FLASH_Unlock())
{
// proceed to program the flash by setting the PG Bit
SET_BIT(FLASH->CR, FLASH_CR_PG);
// Clear pending flags (if any)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);

while(cursor < endAddress)
{
// proceed to program the flash by setting the PG Bit
SET_BIT(FLASH->CR, FLASH_CR_PG);

// if buffer has enough data, program half-words (16 bits) in a single operation to speed up things
// NOTE: assuming that the supply voltage is able to cope with half-word programming
if((endAddress - cursor) >= 2)
Expand All @@ -107,28 +147,31 @@ int flash_lld_write(uint32_t startAddress, uint32_t length, const uint8_t* buffe
// update flash pointer by the 'extra' byte that was programmed
cursor += 2;
}

// wait for program operation to be completed
// TODO: add a timeout here using an OS function
while(((FLASH->SR) & (FLASH_FLAG_BSY)) == (FLASH_FLAG_BSY)){};

// wait for any flash operation to be completed
// timeout set to 0 on purpose
// watchdog will quick-in if execution gets stuck
success = FLASH_WaitForLastOperation(0);

if(!success)
{
// quit on failure
break;
}
}

// after the program operation is completed disable the PG Bit
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);

// lock the FLASH
HAL_FLASH_Lock();

// done here
return true;
}

// default to false
return false;
return success;
}

int flash_lld_isErased(uint32_t startAddress, uint32_t length) {

int flash_lld_isErased(uint32_t startAddress, uint32_t length)
{
__IO uint32_t* cursor = (__IO uint32_t*)startAddress;
__IO uint32_t* endAddress = (__IO uint32_t*)(startAddress + length);

Expand All @@ -152,32 +195,33 @@ uint8_t flash_lld_getSector(uint32_t address)
return (address - FLASH_BASE) / F0_SERIES_SECTOR_SIZE;
}

int flash_lld_erase(uint32_t address) {
int flash_lld_erase(uint32_t address)
{
bool success = true;

// unlock the FLASH
//unlock the FLASH
if(HAL_FLASH_Unlock())
{
// Clear pending flags (if any)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);

// erase the page
SET_BIT(FLASH->CR, FLASH_CR_PER);
WRITE_REG(FLASH->AR, address);
SET_BIT(FLASH->CR, FLASH_CR_STRT);

// wait for erase operation to be completed
// TODO: add a timeout here using an OS function
while(((FLASH->SR) & (FLASH_FLAG_BSY)) == (FLASH_FLAG_BSY)){};
// wait for any flash operation to be completed
// watchdog will quick-in if execution gets stuck
success = FLASH_WaitForLastOperation(0);

// after erase operation completed disable the PER Bit
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);

// lock the FLASH
HAL_FLASH_Lock();

// done here
return true;
}

// default to false
return false;
return success;
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,12 @@ typedef struct SMT32FlashDriver {
#define FLASH ((FLASH_TypeDef *) FLASH_R_BASE)
#define HAL_IS_BIT_SET(REG, BIT) (((REG) & (BIT)) != RESET)

#define FLASH_FLAG_EOP FLASH_SR_EOP /*!< FLASH End of Operation flag */
#define FLASH_FLAG_OPERR FLASH_SR_SOP /*!< FLASH operation Error flag */
#define FLASH_FLAG_WRPERR FLASH_SR_WRPERR /*!< FLASH Write protected error flag */
#define FLASH_FLAG_PGAERR FLASH_SR_PGAERR /*!< FLASH Programming Alignment error flag */
#define FLASH_FLAG_PGPERR FLASH_SR_PGPERR /*!< FLASH Programming Parallelism error flag */
#define FLASH_FLAG_PGSERR FLASH_SR_PGSERR /*!< FLASH Programming Sequence error flag */
#if defined(FLASH_SR_RDERR)
#define FLASH_FLAG_RDERR FLASH_SR_RDERR /*!< Read Protection error flag (PCROP) */
#endif /* FLASH_SR_RDERR */
#define FLASH_FLAG_BSY FLASH_SR_BSY /*!< FLASH Busy flag */
#define FLASH_FLAG_BSY FLASH_SR_BSY //!< FLASH Busy flag
#define FLASH_FLAG_PGERR FLASH_SR_PGERR //!< FLASH Programming error flag
#define FLASH_FLAG_WRPERR FLASH_SR_WRPERR //!< FLASH Write protected error flag
#define FLASH_FLAG_EOP FLASH_SR_EOP //!< FLASH End of Operation flag

#define FLASH_FLAG_ALL_ERRORS ( FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR )

// FLASH_Program_Parallelism FLASH Program Parallelism
#define FLASH_PSIZE_BYTE ((uint32_t)0x00000000U)
Expand Down

0 comments on commit ec235d5

Please sign in to comment.