-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathFlashStorage.h
More file actions
124 lines (107 loc) · 4.63 KB
/
FlashStorage.h
File metadata and controls
124 lines (107 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/* -*- mode: c++ -*-
* Copyright (c) 2020 GigaDevice Semiconductor Inc.
* 2021, 2022 Keyboard.io, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <Arduino.h>
template <uint32_t _storage_size,
uint32_t _fmc_end = ARDUINO_UPLOAD_MAXIMUM_SIZE>
class FlashStorage
{
static_assert(_storage_size % 4096 == 0,
"Storage must be page aligned, with a size multiple of 4096.");
private:
uint8_t buffer_[_storage_size];
static constexpr uint32_t fmc_base_address = 0x08000000;
static constexpr uint32_t bank0_size = 512 * 1024;
static constexpr uint32_t bank0_end = fmc_base_address + bank0_size - 1;
static constexpr uint32_t fmc_end_address = fmc_base_address + _fmc_end;
static constexpr uint32_t data_area_start = fmc_end_address - _storage_size;
uint16_t pageSizeForAddress(uint32_t addr)
{
if (addr > bank0_end)
return 4096;
else
return 2048;
}
public:
void begin()
{
fmc_unlock();
uint8_t *src = (uint8_t *)data_area_start;
for (uint32_t i = 0; i < _storage_size; i++) {
buffer_[i] = src[i];
}
fmc_lock();
}
uint32_t length()
{
return _storage_size;
}
void read(uint32_t offset, uint8_t *data, uint32_t data_size)
{
// We always read from the buffer, as that's the most up-to-date. Flash is
// lagging behind until we commit(), but we may want to read before doing
// so.
// If we're out of bounds, or try to read too much, bail out.
if (offset > _storage_size || (data_size > (_storage_size - offset)))
return;
for (uint32_t i = 0; i < data_size; i++) {
data[i] = buffer_[i + offset];
}
}
void write(uint32_t offset, const uint8_t *data, uint32_t data_size)
{
// If we're out of bounds, or try to write too much, bail out.
if (offset > _storage_size || data_size > _storage_size)
return;
for (uint32_t i = 0; i < data_size; i++) {
buffer_[offset + i] = data[i];
}
}
void commit()
{
fmc_unlock();
uint32_t address = data_area_start;
uint32_t *ptrs = (uint32_t *)buffer_;
do {
uint16_t page_size = pageSizeForAddress(address);
/* clear all pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
fmc_page_erase(address);
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
uint32_t word_count = page_size / 4;
uint32_t i = 0;
do {
fmc_word_program(address, *ptrs++);
address += 4U;
} while (++i < word_count);
} while (address < fmc_end_address);
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGERR);
fmc_lock();
}
};