Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flash] Add simple STM32 Flash driver #417

Merged
merged 2 commits into from
Jun 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions examples/nucleo_f042k6/lp503x/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <modm/driver/pwm/lp503x.hpp>

using namespace Board;
using namespace std::chrono_literals;

/*
* Example to demonstrate LP503x driver
Expand Down Expand Up @@ -51,7 +52,7 @@ main()
RF_CALL_BLOCKING(leds.setChannelBrightness(channel, brightness));
}

modm::delayMilliseconds(1000);
modm::delay(1s);

// Configure outputs 0-5 (rgb led 0-1) in bank mode
using LedBankMode = modm::lp503x::LedBankMode;
Expand All @@ -66,8 +67,8 @@ main()
// Blink leds in bank mode
while(true) {
RF_CALL_BLOCKING(leds.setBankBrightness(255));
modm::delayMilliseconds(500);
modm::delay(0.5s);
RF_CALL_BLOCKING(leds.setBankBrightness(0));
modm::delayMilliseconds(500);
modm::delay(0.5s);
}
}
76 changes: 76 additions & 0 deletions examples/nucleo_f446re/flash/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 <modm/board.hpp>
#include <modm/processing.hpp>

using namespace std::chrono_literals;

#undef MODM_LOG_LEVEL
#define MODM_LOG_LEVEL modm::log::INFO

// ----------------------------------------------------------------------------
int
main()
{
Board::initialize();

MODM_LOG_INFO << "\n\nReboot\n";
if (not Flash::unlock()) {
MODM_LOG_INFO << "Flash unlock failed!" << modm::endl;
}

for (uintptr_t offset{0}, sector{255}; offset < Flash::Size; offset += 1)
{
const uint8_t nsector = Flash::getSector(offset);
if (sector != nsector) {
MODM_LOG_INFO << "Sector " << nsector << " found at boundary " <<
(Flash::Origin + offset) << modm::endl;
sector = nsector;
}
}

{
uint32_t err{0};
const uint8_t sector_start = Flash::getSector(Flash::Size/2);
const uint8_t sector_end = Flash::getSector(Flash::Size);
MODM_LOG_INFO << "Erasing sectors [" << sector_start << ", " << sector_end << ")" << modm::endl;
MODM_LOG_INFO.flush();
modm::delay(1s);

const modm::PreciseTimestamp start = modm::PreciseClock::now();

for (uint8_t sector{sector_start}; sector < sector_end; sector++)
err |= Flash::erase(sector);

const auto diff = (modm::PreciseClock::now() - start);
MODM_LOG_INFO << "Erasing done in " << diff << " with errors: " << err << modm::endl;
MODM_LOG_INFO << "Erasing with " << (Flash::Size/2 / (diff.count() >> 10) ) << "kiB/s" << modm::endl;
MODM_LOG_INFO.flush();
}

{
uint32_t err{0};
const modm::PreciseTimestamp start = modm::PreciseClock::now();
for (uint32_t dst_addr{Flash::OriginAddr + Flash::Size/2}, src_addr{Flash::OriginAddr};
src_addr < (Flash::OriginAddr + Flash::Size/2);
src_addr += sizeof(Flash::MaxWordType), dst_addr += sizeof(Flash::MaxWordType))
{
err |= Flash::program(dst_addr, *(Flash::MaxWordType*)src_addr);
}

const auto diff = (modm::PreciseClock::now() - start);
MODM_LOG_INFO << "Programming done in " << diff << " with errors: " << err << modm::endl;
MODM_LOG_INFO << "Programming with " << (Flash::Size/2 / (diff.count() >> 10) ) << "kiB/s" << modm::endl;
}

while(1) ;
return 0;
}
12 changes: 12 additions & 0 deletions examples/nucleo_f446re/flash/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<library>
<extends>modm:nucleo-f446re</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_f446re/flash</option>
</options>
<modules>
<module>modm:platform:gpio</module>
<module>modm:platform:flash</module>
<module>modm:processing:timer</module>
<module>modm:build:scons</module>
</modules>
</library>
63 changes: 63 additions & 0 deletions examples/nucleo_g071rb/flash/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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 <modm/board.hpp>
#include <modm/processing.hpp>

#undef MODM_LOG_LEVEL
#define MODM_LOG_LEVEL modm::log::INFO

// ----------------------------------------------------------------------------
int
main()
{
Board::initialize();

MODM_LOG_INFO << "\n\nReboot\n";
if (not Flash::unlock()) {
MODM_LOG_INFO << "Flash unlock failed!" << modm::endl;
}

{
uint32_t err{0};
MODM_LOG_INFO << "Erasing sectors [32, 64)" << modm::endl;
MODM_LOG_INFO.flush();
modm::delay(1s);

const modm::PreciseTimestamp start = modm::PreciseClock::now();

for (uint8_t page{32}; page < 64u; page++)
err |= Flash::erase(page);

const auto diff = (modm::PreciseClock::now() - start);
MODM_LOG_INFO << "Erasing done in " << diff << " with errors: " << err << modm::endl;
MODM_LOG_INFO << "Erasing with " << (Flash::Size/2 / (diff.count() >> 10) ) << "kiB/s" << modm::endl;
MODM_LOG_INFO.flush();
}


{
uint32_t err{0};
const modm::PreciseTimestamp start = modm::PreciseClock::now();
for (uint32_t dst_addr{Flash::OriginAddr + Flash::Size/2}, src_addr{Flash::OriginAddr};
src_addr < (Flash::OriginAddr + Flash::Size/2);
src_addr += sizeof(Flash::MaxWordType), dst_addr += sizeof(Flash::MaxWordType))
{
err |= Flash::program(dst_addr, *(Flash::MaxWordType*)src_addr);
}

const auto diff = (modm::PreciseClock::now() - start);
MODM_LOG_INFO << "Programming done in " << diff << " with errors: " << err << modm::endl;
MODM_LOG_INFO << "Programming with " << (Flash::Size/2 / (diff.count() >> 10) ) << "kiB/s" << modm::endl;
}

while(1) ;
return 0;
}
12 changes: 12 additions & 0 deletions examples/nucleo_g071rb/flash/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<library>
<extends>modm:nucleo-g071rb</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_g071rb/flash</option>
</options>
<modules>
<module>modm:platform:gpio</module>
<module>modm:platform:flash</module>
<module>modm:processing:timer</module>
<module>modm:build:scons</module>
</modules>
</library>
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
Loading