flash/stm32: flash driver for STM32F3x series microcontrollers
Change-Id: I0b41a50507a09a513a67d13374323d831a0ec86a Signed-off-by: Adam Podogrocki <adam.podogrocki@rndity.com>
This commit is contained in:
parent
c80023fca3
commit
61cc74c425
9 changed files with 512 additions and 7 deletions
|
@ -27,6 +27,10 @@ config SRAM_SIZE
|
|||
config FLASH_SIZE
|
||||
default 256
|
||||
|
||||
config FLASH_PAGE_SIZE
|
||||
hex
|
||||
default 0x800
|
||||
|
||||
config NUM_IRQS
|
||||
int
|
||||
default 82
|
||||
|
|
|
@ -27,6 +27,10 @@ config SRAM_SIZE
|
|||
config FLASH_SIZE
|
||||
default 64
|
||||
|
||||
config FLASH_PAGE_SIZE
|
||||
hex
|
||||
default 0x800
|
||||
|
||||
config NUM_IRQS
|
||||
int
|
||||
default 82
|
||||
|
|
|
@ -27,6 +27,10 @@ config SRAM_SIZE
|
|||
config FLASH_SIZE
|
||||
default 256
|
||||
|
||||
config FLASH_PAGE_SIZE
|
||||
hex
|
||||
default 0x800
|
||||
|
||||
config NUM_IRQS
|
||||
int
|
||||
default 82
|
||||
|
|
|
@ -108,6 +108,14 @@ config SOC_FLASH_QMSI_SYS_SIZE
|
|||
help
|
||||
Specify system flash size on the quark SOC.
|
||||
|
||||
config SOC_FLASH_QMSI_API_REENTRANCY
|
||||
bool
|
||||
prompt "flash driver API reentrancy for QMSI shim driver"
|
||||
depends on SOC_FLASH_QMSI
|
||||
default n
|
||||
help
|
||||
Enable support for QMSI flash driver API reentrancy.
|
||||
|
||||
config SOC_FLASH_NRF5
|
||||
bool "Nordic Semiconductor nRF5X flash driver"
|
||||
depends on FLASH && SOC_FAMILY_NRF5
|
||||
|
@ -140,10 +148,4 @@ config SOC_FLASH_MCUX_DEV_NAME
|
|||
help
|
||||
Specify the device name for the flash driver.
|
||||
|
||||
config SOC_FLASH_QMSI_API_REENTRANCY
|
||||
bool
|
||||
prompt "flash driver API reentrancy for QMSI shim driver"
|
||||
depends on SOC_FLASH_QMSI
|
||||
default n
|
||||
help
|
||||
Enable support for QMSI flash driver API reentrancy.
|
||||
source "drivers/flash/Kconfig.stm32f3x"
|
||||
|
|
35
drivers/flash/Kconfig.stm32f3x
Normal file
35
drivers/flash/Kconfig.stm32f3x
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Kconfig - ST Microelectronics STM32F3x MCUs Flash driver config
|
||||
#
|
||||
# Copyright (c) 2016 RnDity Sp. z o.o.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
if FLASH && SOC_SERIES_STM32F3X
|
||||
|
||||
menuconfig SOC_FLASH_STM32
|
||||
bool
|
||||
prompt "STM32 flash driver"
|
||||
depends on SOC_SERIES_STM32F3X && FLASH
|
||||
default n
|
||||
help
|
||||
Enable STM32F3X series MCUs flash driver.
|
||||
|
||||
config SOC_FLASH_STM32_DEV_NAME
|
||||
string "STM32 flash device name"
|
||||
depends on SOC_FLASH_STM32
|
||||
default "FLASH_STM32"
|
||||
help
|
||||
Specify the device name for the flash driver.
|
||||
|
||||
endif
|
|
@ -2,3 +2,8 @@ obj-$(CONFIG_SPI_FLASH_W25QXXDV) += spi_flash_w25qxxdv.o
|
|||
obj-$(CONFIG_SOC_FLASH_QMSI) += soc_flash_qmsi.o
|
||||
obj-$(CONFIG_SOC_FLASH_NRF5) += soc_flash_nrf5.o
|
||||
obj-$(CONFIG_SOC_FLASH_MCUX) += soc_flash_mcux.o
|
||||
|
||||
ifeq ($(CONFIG_SOC_SERIES_STM32F3X),y)
|
||||
obj-$(CONFIG_SOC_FLASH_STM32) += flash_stm32f3x.o
|
||||
obj-$(CONFIG_SOC_FLASH_STM32) += flash_stm32f3x_priv.o
|
||||
endif
|
||||
|
|
159
drivers/flash/flash_stm32f3x.c
Normal file
159
drivers/flash/flash_stm32f3x.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2016 RnDity Sp. z o.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flash_stm32f3x.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <misc/__assert.h>
|
||||
#include <clock_control/stm32_clock_control.h>
|
||||
|
||||
static int flash_stm32_erase(struct device *dev, off_t offset, size_t size)
|
||||
{
|
||||
uint32_t first_page_addr = 0;
|
||||
uint32_t last_page_addr = 0;
|
||||
uint16_t no_of_pages = size / CONFIG_FLASH_PAGE_SIZE;
|
||||
uint16_t page_index = 0;
|
||||
|
||||
/* Check offset and size alignment. */
|
||||
if (((offset % CONFIG_FLASH_PAGE_SIZE) != 0) ||
|
||||
((size % CONFIG_FLASH_PAGE_SIZE) != 0) ||
|
||||
(no_of_pages == 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Find address of the first page to be erased. */
|
||||
page_index = offset / CONFIG_FLASH_PAGE_SIZE;
|
||||
|
||||
first_page_addr = CONFIG_FLASH_BASE_ADDRESS +
|
||||
page_index * CONFIG_FLASH_PAGE_SIZE;
|
||||
|
||||
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(first_page_addr));
|
||||
|
||||
/* Find address of the last page to be erased. */
|
||||
page_index = ((offset + size) / CONFIG_FLASH_PAGE_SIZE) - 1;
|
||||
|
||||
last_page_addr = CONFIG_FLASH_BASE_ADDRESS +
|
||||
page_index * CONFIG_FLASH_PAGE_SIZE;
|
||||
|
||||
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(last_page_addr));
|
||||
|
||||
while (no_of_pages) {
|
||||
if (flash_stm32_erase_page(dev, first_page_addr)
|
||||
!= FLASH_COMPLETE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
no_of_pages--;
|
||||
first_page_addr += CONFIG_FLASH_PAGE_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_stm32_read(struct device *dev, off_t offset,
|
||||
void *data, size_t len)
|
||||
{
|
||||
uint32_t address = CONFIG_FLASH_BASE_ADDRESS + offset;
|
||||
|
||||
__ASSERT_NO_MSG(IS_FLASH_PROGRAM_ADDRESS(address));
|
||||
|
||||
flash_stm32_read_data(data, address, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_stm32_write(struct device *dev, off_t offset,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
uint16_t halfword = 0;
|
||||
|
||||
uint32_t address =
|
||||
CONFIG_FLASH_BASE_ADDRESS + offset;
|
||||
|
||||
uint8_t remainder = 0;
|
||||
|
||||
if ((len % 2) != 0) {
|
||||
remainder = 1;
|
||||
}
|
||||
|
||||
len = len / 2;
|
||||
|
||||
while (len--) {
|
||||
halfword = *((uint8_t *)data++);
|
||||
halfword |= *((uint8_t *)data++) << 8;
|
||||
if (flash_stm32_program_halfword(dev, address, halfword)
|
||||
!= FLASH_COMPLETE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
address += 2;
|
||||
}
|
||||
|
||||
if (remainder) {
|
||||
halfword = (*((uint16_t *)data)) & 0x00FF;
|
||||
if (flash_stm32_program_halfword(dev, address, halfword)
|
||||
!= FLASH_COMPLETE) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_stm32_protection_set(struct device *dev, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
flash_stm32_lock(dev);
|
||||
} else {
|
||||
flash_stm32_unlock(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_stm32_init(struct device *dev)
|
||||
{
|
||||
const struct flash_stm32_dev_config *cfg = FLASH_CFG(dev);
|
||||
|
||||
struct device *clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);
|
||||
|
||||
if (clock_control_on(clk, cfg->clock_subsys) != 0)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct flash_driver_api flash_stm32_api = {
|
||||
.read = flash_stm32_read,
|
||||
.write = flash_stm32_write,
|
||||
.erase = flash_stm32_erase,
|
||||
.write_protection = flash_stm32_protection_set,
|
||||
};
|
||||
|
||||
static const struct flash_stm32_dev_config flash_device_config = {
|
||||
.base = (uint32_t *)FLASH_R_BASE,
|
||||
.clock_subsys = UINT_TO_POINTER(STM32F3X_CLOCK_SUBSYS_FLITF),
|
||||
};
|
||||
|
||||
static struct flash_stm32_dev_data flash_device_data = {
|
||||
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(flash_stm32, CONFIG_SOC_FLASH_STM32_DEV_NAME,
|
||||
flash_stm32_init,
|
||||
&flash_device_data,
|
||||
&flash_device_config,
|
||||
POST_KERNEL,
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||
&flash_stm32_api);
|
76
drivers/flash/flash_stm32f3x.h
Normal file
76
drivers/flash/flash_stm32f3x.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2016 RnDity Sp. z o.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef DRIVERS_FLASH_FLASH_STM32_H_
|
||||
#define DRIVERS_FLASH_FLASH_STM32_H_
|
||||
|
||||
#include <soc.h>
|
||||
#include <flash.h>
|
||||
#include <clock_control.h>
|
||||
#include <flash_registers.h>
|
||||
|
||||
struct flash_stm32_dev_config {
|
||||
uint32_t *base;
|
||||
clock_control_subsys_t clock_subsys;
|
||||
};
|
||||
|
||||
struct flash_stm32_dev_data {
|
||||
/* For future use. */
|
||||
};
|
||||
|
||||
#define FLASH_CFG(dev) \
|
||||
((const struct flash_stm32_dev_config * const)(dev)->config->config_info)
|
||||
#define FLASH_DATA(dev) \
|
||||
((struct flash_stm32_dev_data * const)(dev)->driver_data)
|
||||
#define FLASH_STRUCT(base) \
|
||||
(volatile struct stm32_flash *)(base)
|
||||
|
||||
/* Flash programming timeout definition. */
|
||||
#define FLASH_ER_PRG_TIMEOUT ((uint32_t)0x000B0000)
|
||||
|
||||
enum flash_status {
|
||||
FLASH_BUSY = 1,
|
||||
FLASH_ERROR_WRITE_PROTECTION,
|
||||
FLASH_ERROR_PROGRAM,
|
||||
FLASH_COMPLETE,
|
||||
FLASH_TIMEOUT
|
||||
};
|
||||
|
||||
void flash_stm32_lock(struct device *flash);
|
||||
|
||||
void flash_stm32_unlock(struct device *flash);
|
||||
|
||||
uint8_t flash_stm32_program_halfword(struct device *flash,
|
||||
uint32_t address,
|
||||
uint16_t data);
|
||||
|
||||
uint8_t flash_stm32_program_word(struct device *flash,
|
||||
uint32_t address,
|
||||
uint32_t data);
|
||||
|
||||
void flash_stm32_read_data(void *data, uint32_t address, size_t len);
|
||||
|
||||
uint8_t flash_stm32_wait_for_last_operation(struct device *flash,
|
||||
uint32_t timeout);
|
||||
|
||||
uint8_t flash_stm32_get_status(struct device *flash);
|
||||
|
||||
uint8_t flash_stm32_erase_page(struct device *flash,
|
||||
uint32_t page_address);
|
||||
|
||||
uint8_t flash_stm32_erase_all_pages(struct device *flash);
|
||||
|
||||
#endif /* DRIVERS_FLASH_FLASH_STM32_H_ */
|
216
drivers/flash/flash_stm32f3x_priv.c
Normal file
216
drivers/flash/flash_stm32f3x_priv.c
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright (c) 2016 RnDity Sp. z o.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flash_stm32f3x.h"
|
||||
#include <misc/__assert.h>
|
||||
#include <string.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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue