Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
Stm32Flash.hxx
Go to the documentation of this file.
1
36#include <algorithm>
37
38#include "utils/logging.h"
39
40#include "stm32f_hal_conf.hxx"
41
44template <uint32_t ERASE_PAGE_SIZE> struct FlashFixedSectors
45{
51 static uint32_t next_sector_address(uint32_t addr)
52 {
53 static_assert(
54 ((ERASE_PAGE_SIZE - 1) << 1) & ERASE_PAGE_SIZE == ERASE_PAGE_SIZE,
55 "Erase page size must be a power of two.");
56 return (addr + ERASE_PAGE_SIZE - 1) & ~(ERASE_PAGE_SIZE - 1);
57 }
58
61 static std::pair<unsigned, uint32_t> lookup_sector(uint32_t addr)
62 {
63 uint32_t next = next_sector_address(addr);
64 unsigned sector = (next - FLASH_BASE) / ERASE_PAGE_SIZE;
65 return {sector, next};
66 }
67};
68
69static constexpr uint32_t FLASH_EOF = 0xFFFFFFFFul;
70
74{
78 constexpr FlashVariableSectors(uint32_t *bank_config)
79 : bankConfig_(bank_config)
80 { }
81
87 uint32_t next_sector_address(uint32_t addr)
88 {
89 if (addr == bankConfig_[0])
90 {
91 lastIndex_ = 0;
92 return addr;
93 }
94 if (bankConfig_[lastIndex_] >= addr)
95 {
96 lastIndex_ = 0;
97 }
99 while (bankConfig_[lastIndex_ + 1] < addr)
100 {
101 ++lastIndex_;
102 }
103 // now: bankConfig_[lastIndex_] < addr and
104 // bankConfig_[lastIndex_+1] >= addr
105 return bankConfig_[lastIndex_ + 1];
106 }
107
110 std::pair<unsigned, uint32_t> lookup_sector(uint32_t addr)
111 {
112 uint32_t next = next_sector_address(addr);
113 return {lastIndex_ + 1, next};
114 }
115
116protected:
119 unsigned lastIndex_ {0};
120
121private:
123 uint32_t *bankConfig_;
124};
125
126extern uint32_t STM32F7_DUAL_BANK_2M_FLASH[];
127extern uint32_t STM32F7_SINGLE_BANK_2M_FLASH[];
128
129template <class SectorLookup> class Stm32Flash : public SectorLookup {
130public:
131 template <typename... Args>
132 constexpr Stm32Flash(Args &&...args)
133 : SectorLookup(std::forward<Args>(args)...)
134 { }
135
136void read(uint32_t addr, uint32_t size, uint8_t *dst)
137{
138 memcpy(dst, (void *)addr, size);
139}
140
141void write(uint32_t addr, uint32_t size, uint8_t *src)
142{
143 union WriteWord
144 {
145 uint8_t data[4];
146 uint32_t data_word;
147 };
148
149 HAL_FLASH_Unlock();
150
151 if ((addr % 4) && ((addr % 4) + size) < 4)
152 {
153 // single unaligned write in the middle of a word.
154 WriteWord ww;
155 ww.data_word = 0xFFFFFFFF;
156
157 memcpy(ww.data + (addr % 4), src, size);
158 ww.data_word &= *((uint32_t*)(addr & (~0x3)));
159 HASSERT(HAL_OK ==
160 HAL_FLASH_Program(
161 FLASH_TYPEPROGRAM_WORD, addr & (~0x3), ww.data_word));
162
163 HAL_FLASH_Lock();
164 return;
165 }
166
167 int misaligned = (addr + size) % 4;
168 if (misaligned != 0)
169 {
170 // last write unaligned data
171 WriteWord ww;
172 ww.data_word = 0xFFFFFFFF;
173
174 memcpy(&ww.data_word, src + size - misaligned, misaligned);
175 ww.data_word &= *((uint32_t*)((addr + size) & (~0x3)));
176 HASSERT(HAL_OK ==
177 HAL_FLASH_Program(
178 FLASH_TYPEPROGRAM_WORD, (addr + size) & (~0x3), ww.data_word));
179
180 size -= misaligned;
181 }
182
183 misaligned = addr % 4;
184 if (size && misaligned != 0)
185 {
186 // first write unaligned data
187 WriteWord ww;
188 ww.data_word = 0xFFFFFFFF;
189
190 memcpy(ww.data + misaligned, src, 4 - misaligned);
191 ww.data_word &= *((uint32_t*)(addr & (~0x3)));
192 HASSERT(HAL_OK ==
193 HAL_FLASH_Program(
194 FLASH_TYPEPROGRAM_WORD, addr & (~0x3), ww.data_word));
195 addr += 4 - misaligned;
196 size -= 4 - misaligned;
197 src += 4 - misaligned;
198 }
199
200 HASSERT((addr % 4) == 0);
201 HASSERT((size % 4) == 0);
202
203 if (size)
204 {
205 // the rest of the aligned data
206 uint8_t *flash = (uint8_t *)addr;
207 for (uint32_t i = 0; i < size; i += 4)
208 {
209 src[i + 0] &= flash[i + 0];
210 src[i + 1] &= flash[i + 1];
211 src[i + 2] &= flash[i + 2];
212 src[i + 3] &= flash[i + 3];
213 HASSERT(HAL_OK ==
214 HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + i,
215 *(unsigned long *)(src + i)));
216 }
217 }
218
219 HAL_FLASH_Lock();
220}
221
222void erase(uint32_t addr, uint32_t size)
223{
224 FLASH_EraseInitTypeDef erase_init;
225 memset(&erase_init, 0, sizeof(erase_init));
226
227 erase_init.TypeErase = TYPEERASE_SECTORS;
228
229 auto sa = this->lookup_sector(addr);
230 HASSERT(sa.second == addr); // start of erase must fall on sector boundary.
231 erase_init.Sector = sa.first;
232
233 unsigned count = 0;
234 // Figure out how many total sectors we need to erase.
235 do {
236 ++count;
237 sa = this->lookup_sector(sa.second + 1);
238 } while (sa.second < addr + size);
239
240 HASSERT(sa.second == addr + size || sa.second == FLASH_EOF);
241
242 erase_init.NbSectors = count;
243 erase_init.VoltageRange = FLASH_VOLTAGE_RANGE_3; // 3.3 to 3.6 volts powered.
244 HAL_FLASH_Unlock();
245 uint32_t sector_error;
246 HASSERT(HAL_OK == HAL_FLASHEx_Erase(&erase_init, &sector_error));
247 HAL_FLASH_Lock();
248}
249
250}; // class Stm32Flash
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
Strategy module for finding flash erase sector numbers when the sectors are constant size.
static std::pair< unsigned, uint32_t > lookup_sector(uint32_t addr)
Lookup the next sector for an address, and return the {sector number, address} pair.
static uint32_t next_sector_address(uint32_t addr)
Aligns an address to the next possible sector start (i.e., rounds up to sector boundary).
Strategy module for finding flash erase sector numbers when the sectors are different sizes.
uint32_t * bankConfig_
Contains an array of the start addresses of the erase sectors.
constexpr FlashVariableSectors(uint32_t *bank_config)
bank_config is an array of uint32 addresses, containing the start of each sector.
uint32_t next_sector_address(uint32_t addr)
Aligns an address to the next possible sector start (i.e., rounds up to sector boundary).
std::pair< unsigned, uint32_t > lookup_sector(uint32_t addr)
Lookup the next sector for an address, and return the {sector number, address} pair.
unsigned lastIndex_
1-element cache on where to start looking for sectors.