209 lines
4.4 KiB
C
209 lines
4.4 KiB
C
/*
|
|
* Copyright (c) 2016 RnDity Sp. z o.o.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <clock_control/stm32_clock_control.h>
|
|
#include <misc/__assert.h>
|
|
#include <string.h>
|
|
|
|
#include "flash_stm32f3x.h"
|
|
|
|
void flash_stm32_unlock(struct device *flash)
|
|
{
|
|
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
|
|
|
|
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
|
|
|
|
if ((reg->cr & FLASH_CR_LOCK) != 0) {
|
|
/* Authorize the FLASH Registers access */
|
|
reg->keyr = FLASH_KEY1;
|
|
reg->keyr = FLASH_KEY2;
|
|
}
|
|
}
|
|
|
|
void flash_stm32_lock(struct device *flash)
|
|
{
|
|
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
|
|
|
|
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
|
|
|
|
reg->cr |= FLASH_CR_LOCK;
|
|
}
|
|
|
|
uint8_t flash_stm32_program_halfword(struct device *flash,
|
|
uint32_t address,
|
|
uint16_t data)
|
|
{
|
|
uint8_t status = FLASH_COMPLETE;
|
|
|
|
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
|
|
|
|
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
|
|
|
|
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(address));
|
|
|
|
status = flash_stm32_wait_for_last_operation(flash,
|
|
FLASH_ER_PRG_TIMEOUT);
|
|
|
|
if (status == FLASH_COMPLETE) {
|
|
reg->cr |= FLASH_CR_PG;
|
|
|
|
*(volatile uint16_t *)address = data;
|
|
|
|
status = flash_stm32_wait_for_last_operation(flash,
|
|
FLASH_ER_PRG_TIMEOUT);
|
|
|
|
reg->cr &= ~FLASH_CR_PG;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
uint8_t flash_stm32_program_word(struct device *flash,
|
|
uint32_t address,
|
|
uint32_t data)
|
|
{
|
|
uint8_t status = FLASH_COMPLETE;
|
|
|
|
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
|
|
|
|
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
|
|
|
|
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(address));
|
|
|
|
status = flash_stm32_wait_for_last_operation(flash,
|
|
FLASH_ER_PRG_TIMEOUT);
|
|
|
|
if (status == FLASH_COMPLETE) {
|
|
reg->cr |= FLASH_CR_PG;
|
|
|
|
*(volatile uint16_t *)address = (uint16_t)data;
|
|
|
|
status = flash_stm32_wait_for_last_operation(flash,
|
|
FLASH_ER_PRG_TIMEOUT);
|
|
|
|
if (status == FLASH_COMPLETE) {
|
|
address += 2;
|
|
|
|
*(volatile uint16_t *)address = data >> 16;
|
|
|
|
status = flash_stm32_wait_for_last_operation(flash,
|
|
FLASH_ER_PRG_TIMEOUT);
|
|
}
|
|
|
|
reg->cr &= ~FLASH_CR_PG;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
uint8_t flash_stm32_wait_for_last_operation(struct device *flash,
|
|
uint32_t timeout)
|
|
{
|
|
uint8_t status = FLASH_COMPLETE;
|
|
|
|
/* Check for the FLASH Status */
|
|
status = flash_stm32_get_status(flash);
|
|
|
|
/* Wait for a FLASH operation to complete or a TIMEOUT to occur. */
|
|
while ((status == FLASH_BUSY) && (timeout != 0x00)) {
|
|
status = flash_stm32_get_status(flash);
|
|
timeout--;
|
|
}
|
|
|
|
if (timeout == 0x00) {
|
|
status = FLASH_TIMEOUT;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
uint8_t flash_stm32_get_status(struct device *flash)
|
|
{
|
|
uint8_t status = FLASH_COMPLETE;
|
|
|
|
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
|
|
|
|
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
|
|
|
|
do {
|
|
if ((reg->sr & FLASH_SR_BSY) == FLASH_SR_BSY) {
|
|
status = FLASH_BUSY;
|
|
break;
|
|
}
|
|
|
|
if ((reg->sr & FLASH_SR_WRPERR) != (uint32_t)0x00) {
|
|
status = FLASH_ERROR_WRITE_PROTECTION;
|
|
break;
|
|
}
|
|
|
|
if ((reg->sr & FLASH_SR_PGERR) != (uint32_t)0x00) {
|
|
status = FLASH_ERROR_PROGRAM;
|
|
break;
|
|
}
|
|
} while (0);
|
|
|
|
return status;
|
|
}
|
|
|
|
uint8_t flash_stm32_erase_page(struct device *flash,
|
|
uint32_t page_address)
|
|
{
|
|
uint8_t status = FLASH_COMPLETE;
|
|
|
|
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
|
|
|
|
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
|
|
|
|
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(page_address));
|
|
|
|
status = flash_stm32_wait_for_last_operation(flash,
|
|
FLASH_ER_PRG_TIMEOUT);
|
|
|
|
if (status == FLASH_COMPLETE) {
|
|
reg->cr |= FLASH_CR_PER;
|
|
reg->ar = page_address;
|
|
reg->cr |= FLASH_CR_STRT;
|
|
|
|
status = flash_stm32_wait_for_last_operation(flash,
|
|
FLASH_ER_PRG_TIMEOUT);
|
|
|
|
reg->cr &= ~FLASH_CR_PER;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
uint8_t flash_stm32_erase_all_pages(struct device *flash)
|
|
{
|
|
uint8_t status = FLASH_COMPLETE;
|
|
|
|
const struct flash_stm32_dev_config *config = FLASH_CFG(flash);
|
|
|
|
volatile struct stm32_flash *reg = FLASH_STRUCT(config->base);
|
|
|
|
status = flash_stm32_wait_for_last_operation(flash,
|
|
FLASH_ER_PRG_TIMEOUT);
|
|
|
|
if (status == FLASH_COMPLETE) {
|
|
reg->cr |= FLASH_CR_MER;
|
|
reg->cr |= FLASH_CR_STRT;
|
|
|
|
status = flash_stm32_wait_for_last_operation(flash,
|
|
FLASH_ER_PRG_TIMEOUT);
|
|
|
|
reg->cr &= ~FLASH_CR_MER;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
void flash_stm32_read_data(void *data, uint32_t address, size_t len)
|
|
{
|
|
uint8_t *addr = INT_TO_POINTER(address);
|
|
|
|
memcpy(data, addr, len);
|
|
}
|