Skip to content

Commit

Permalink
[flash] Add simple STM32 Flash implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Jun 11, 2020
1 parent 965ba50 commit 47d9f4f
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 0 deletions.
109 changes: 109 additions & 0 deletions src/modm/platform/flash/stm32/flash.cpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2020, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include "flash.hpp"

static constexpr uint32_t FLASH_SR_ERR = 0xfffe;

namespace modm::platform
{

bool
Flash::unlock()
{
Flash::enable();
if (isLocked())
{
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
}
return not isLocked();
}

uint8_t
Flash::getPage(uintptr_t offset)
{
const uint8_t index = (offset >> {{ shift }});
%% if has_sectors
uint8_t small_index{0};
// 128kB Block 0 and 8 are subdivided into 4x16kB + 64kB
if (index == 0 or index == 8)
{
if (index == 8) small_index += 4;
// Check upper 64kB first
if (offset & 0x1'0000ul) small_index += 4;
// Otherwise check lower 16kB
else small_index += ((offset & 0xC000) >> 14);
}
else small_index += 4;
// 128kB Blocks
return index + small_index;
%% else
return index;
%% endif
}

modm_ramcode uint32_t
%% if has_sectors
Flash::erase(uint8_t index, WordSize size)
%% else
Flash::erase(uint8_t index)
%% endif
{
FLASH->SR = FLASH_SR_ERR;
%% if has_sectors
FLASH->CR = FLASH_CR_STRT | FLASH_CR_SER | uint32_t(size) |
((index << FLASH_CR_SNB_Pos) & FLASH_CR_SNB_Msk);
%% else
FLASH->CR = FLASH_CR_STRT | FLASH_CR_PER |
((index << FLASH_CR_PNB_Pos) & FLASH_CR_PNB_Msk);
%% endif

while(isBusy()) ;
FLASH->CR = 0;

return FLASH->SR & FLASH_SR_ERR;
}

modm_ramcode uint32_t
%% if has_sectors
Flash::program(uintptr_t addr, MaxWordType data, WordSize size)
%% else
Flash::program(uintptr_t addr, MaxWordType data)
%% endif
{
FLASH->SR = FLASH_SR_ERR;
%% if has_sectors
FLASH->CR = FLASH_CR_PG | uint32_t(size);
switch(size)
{
case WordSize::B8:
*(uint8_t *) addr = data;
break;
case WordSize::B16:
*(uint16_t *) addr = data;
break;
default:
*(uint32_t *) addr = data;
break;
}
%% else
FLASH->CR = FLASH_CR_PG;
*(uint64_t*) addr = data;
%% endif

while(isBusy()) ;
FLASH->CR = 0;

return FLASH->SR & FLASH_SR_ERR;
}

} // namespace modm::platform
111 changes: 111 additions & 0 deletions src/modm/platform/flash/stm32/flash.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2020, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once
#include "../device.hpp"
#include <modm/platform/clock/rcc.hpp>
#include <modm/architecture/interface/register.hpp>

namespace modm::platform
{

/// @ingroup modm_platform_flash
class Flash
{
public:
static constexpr uintptr_t OriginAddr{ 0x{{ "%0x" | format(start) }} };
static constexpr size_t Size{ 0x{{ "%0x" | format(size) }} };
static inline uint8_t *const Origin{(uint8_t*)OriginAddr};
using MaxWordType = uint{{ 32 if has_sectors else 64 }}_t;

%% if has_sectors
enum class
WordSize : uint32_t
{
B8 = 0,
B16 = FLASH_CR_PSIZE_0,
B32 = FLASH_CR_PSIZE_1,
};
%% endif

public:
inline static void
enable()
{
%% if not has_sectors
Rcc::enable<Peripheral::Flash>();
%% endif
}

inline static void
disable()
{
%% if not has_sectors
Rcc::disable<Peripheral::Flash>();
%% endif

}

static bool
isLocked()
{ return FLASH->CR & FLASH_CR_LOCK; }

static inline bool
isBusy()
%% if has_sectors
{ return FLASH->SR & FLASH_SR_BSY; }
%% else
{ return FLASH->SR & FLASH_SR_BSY1; }
%% endif

static bool
unlock();

static inline uint8_t
getSector(uint8_t *ptr)
{ return getPage(ptr - Flash::Origin); }

static uint8_t
getSector(uintptr_t offset)
{ return getPage(offset); }

static inline uint8_t
getPage(uint8_t *ptr)
{ return getPage(ptr - Flash::Origin); }

static uint8_t
getPage(uintptr_t offset);

static uint32_t
%% if has_sectors
erase(uint8_t {{ type }}, WordSize size = WordSize::B32);
%% else
erase(uint8_t {{ type }});
%% endif

%% if has_sectors
static inline uint32_t
program(uintptr_t addr, uint8_t data)
{ return program(addr, data, WordSize::B8); }

static inline uint32_t
program(uintptr_t addr, uint16_t data)
{ return program(addr, data, WordSize::B16); }

static uint32_t
program(uintptr_t addr, MaxWordType data, WordSize size = WordSize::B32);
%% else
static uint32_t
program(uintptr_t addr, MaxWordType data);
%% endif
};

} // namespace modm::platform
50 changes: 50 additions & 0 deletions src/modm/platform/flash/stm32/module.lb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016-2018, Niklas Hauser
# Copyright (c) 2017, Fabian Greif
#
# This file is part of the modm project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# -----------------------------------------------------------------------------

def init(module):
module.name = ":platform:flash"
module.description = "Flash Memory"

def prepare(module, options):
device = options[":target"]
if device.identifier.family not in ["g0", "f4"]:
return False
if not device.has_driver("flash:stm32*"):
return False

module.depends(":cmsis:device", ":platform:rcc",
":architecture:register")
return True

def build(env):
target = env[":target"].identifier
memories = listify(env[":target"].get_driver("core")["memory"])
flash = next(filter(lambda m: m["name"] == "flash", memories))

if target.family in ["f4"]:
block_shift = 17
ftype = "sector"
elif target.family in ["g0"]:
block_shift = 11
ftype = "page"

env.substitutions = {
"start": int(flash["start"], 16),
"size": int(flash["size"]),
"type": ftype,
"shift": block_shift,
"has_sectors": ftype == "sector",
}
env.outbasepath = "modm/src/modm/platform/flash"
env.template("flash.hpp.in")
env.template("flash.cpp.in")

0 comments on commit 47d9f4f

Please sign in to comment.