libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
stm32_flash.cpp
1#include "stm32_flash.hpp"
2
3#ifdef HAL_FLASH_MODULE_ENABLED
4
5using namespace LibXR;
6
7namespace
8{
11class FlashOperationGuard
12{
13 public:
14 FlashOperationGuard()
15 {
16#if defined(ICACHE) && defined(ICACHE_CR_EN) && defined(ICACHE_SR_BUSYF)
17 standalone_enabled_ = (ICACHE->CR & ICACHE_CR_EN) != 0U;
18 if (standalone_enabled_)
19 {
20 // 关闭独立 ICACHE 会自动失效;等硬件空闲,不消费共享的完成标志。
21 // Disabling standalone ICACHE invalidates it; wait for idle without consuming
22 // the shared completion flag.
23 CLEAR_BIT(ICACHE->CR, ICACHE_CR_EN);
24 __DSB();
25 __ISB();
26 const uint32_t start = HAL_GetTick();
27 while ((ICACHE->CR & ICACHE_CR_EN) != 0U || (ICACHE->SR & ICACHE_SR_BUSYF) != 0U)
28 {
29 if (static_cast<uint32_t>(HAL_GetTick() - start) > 1U)
30 {
31 // 抢占期间可能已完成,超时报错前重新确认。
32 // Completion may occur during preemption; recheck before failing.
33 REQUIRE((ICACHE->CR & ICACHE_CR_EN) == 0U &&
34 (ICACHE->SR & ICACHE_SR_BUSYF) == 0U);
35 }
36 }
37 }
38#endif
39#if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
40 i_cache_enabled_ = (SCB->CCR & SCB_CCR_IC_Msk) != 0U;
41 if (i_cache_enabled_) SCB_DisableICache();
42#endif
43#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
44 d_cache_enabled_ = (SCB->CCR & SCB_CCR_DC_Msk) != 0U;
45 if (d_cache_enabled_) SCB_DisableDCache();
46#endif
47 HAL_FLASH_Unlock();
48 }
49
50 ~FlashOperationGuard()
51 {
52 HAL_FLASH_Lock();
53#if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
54 if (i_cache_enabled_) SCB_EnableICache();
55#endif
56#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
57 if (d_cache_enabled_) SCB_EnableDCache();
58#endif
59#if defined(ICACHE) && defined(ICACHE_CR_EN) && defined(ICACHE_SR_BUSYF)
60 if (standalone_enabled_)
61 {
62 __DSB();
63 SET_BIT(ICACHE->CR, ICACHE_CR_EN);
64 __DSB();
65 __ISB();
66 }
67#endif
68 }
69
70 FlashOperationGuard(const FlashOperationGuard&) = delete;
71 FlashOperationGuard& operator=(const FlashOperationGuard&) = delete;
72
73 private:
74#if defined(ICACHE) && defined(ICACHE_CR_EN) && defined(ICACHE_SR_BUSYF)
75 bool standalone_enabled_ = false;
76#endif
77#if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
78 bool i_cache_enabled_ = false;
79#endif
80#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
81 bool d_cache_enabled_ = false;
82#endif
83};
84
86uint32_t TableEnd(const FlashRegion* regions, size_t region_count)
87{
88 const auto& last = regions[region_count - 1];
89 return last.address + last.sector_size * last.sector_count;
90}
91
93uint32_t SectorSizeAt(const FlashRegion* regions, size_t region_count, uint32_t address)
94{
95 for (size_t i = 0; i < region_count; ++i)
96 {
97 const auto& region = regions[i];
98 if (address >= region.address &&
99 address - region.address < region.sector_size * region.sector_count)
100 {
101 ASSERT((address - region.address) % region.sector_size == 0U);
102 return region.sector_size;
103 }
104 }
105 ASSERT(false);
106 return 0U;
107}
108
110uint32_t SecondToLastSector(const FlashRegion* regions, size_t region_count)
111{
112 const auto& last = regions[region_count - 1];
113 if (last.sector_count >= 2U)
114 {
115 return last.address + last.sector_size * (last.sector_count - 2U);
116 }
117 ASSERT(region_count >= 2U);
118 const auto& previous = regions[region_count - 2];
119 return previous.address + previous.sector_size * (previous.sector_count - 1U);
120}
121} // namespace
122
123STM32Flash::STM32Flash(const FlashRegion* regions, size_t region_count,
124 uint32_t start_address)
125 : Flash(SectorSizeAt(regions, region_count, start_address), MIN_WRITE_SIZE,
126 {reinterpret_cast<void*>(start_address),
127 TableEnd(regions, region_count) - start_address}),
128 regions_(regions),
129 base_address_(start_address),
130 program_type_(DetermineProgramType()),
131 region_count_(region_count)
132{
133}
134
135STM32Flash::STM32Flash(const FlashRegion* regions, size_t region_count)
136 : STM32Flash(regions, region_count, SecondToLastSector(regions, region_count))
137{
138}
139
140ErrorCode STM32Flash::Erase(size_t offset, size_t size)
141{
142 if (size == 0)
143 {
144 return ErrorCode::ARG_ERR;
145 }
146
147 uint32_t start_addr = base_address_ + offset;
148 uint32_t end_addr = start_addr + size;
149
150 FlashOperationGuard operation;
151
152 // 表按地址排列;index 是跨段的扇区序号,bank_entries 记录每个 bank 中已经走过的扇区
153 // 数,即下一个扇区在该 bank 内的序号。bank 2 的起点由表给出,小容量型号上它与 bank 1
154 // 之间可能有空洞(如 H743xG 在 0x08100000,G474xC 在 0x08040000)。
155 // The table is ordered by address; index is the sector number across runs, and
156 // bank_entries counts the sectors already passed in each bank, which is the next
157 // sector's number within that bank. The table gives where bank 2 starts, after a gap on
158 // smaller parts (H743xG at 0x08100000, G474xC at 0x08040000).
159 uint32_t bank_entries[2] = {0U, 0U};
160 [[maybe_unused]] uint32_t index = 0U;
161 for (size_t r = 0; r < region_count_; ++r)
162 {
163 const auto& region = regions_[r];
164 for (uint32_t k = 0; k < region.sector_count; ++k, ++index)
165 {
166 const uint32_t address = region.address + region.sector_size * k;
167#if defined(FLASH_BANK_2)
168 const size_t bank_slot = (STM32FlashBankOf(address) == FLASH_BANK_2) ? 1U : 0U;
169#else
170 const size_t bank_slot = 0U;
171#endif
172 [[maybe_unused]] const uint32_t number_in_bank = bank_entries[bank_slot]++;
173 if (address + region.sector_size <= start_addr)
174 {
175 continue;
176 }
177 if (address >= end_addr)
178 {
179 return ErrorCode::OK;
180 }
181 FLASH_EraseInitTypeDef erase_init = {};
182
183#if defined(FLASH_TYPEERASE_PAGES) && defined(FLASH_PAGE_SIZE) // STM32F1/G4... series
184 // 有 Page 字段的系列(G0、G4、L4、L5、U5 等)按 bank 内页号编号;其余系列用页地址。
185 // Families with a Page field (G0, G4, L4, L5, U5, ...) number pages within each
186 // bank; the others take the page address.
187 erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
188 SetNbPages(erase_init, address, number_in_bank);
189 erase_init.NbPages = 1;
190 SetBanks(erase_init, address);
191#elif defined(FLASH_TYPEERASE_SECTORS) // STM32F4/F7/H7... series
192 erase_init.TypeErase = FLASH_TYPEERASE_SECTORS;
193#if defined(FLASH_SECTOR_SIZE)
194 // H5、H7 的扇区大小一致,按 bank 内扇区号编号。
195 // H5 and H7 have uniform sectors numbered within each bank.
196 erase_init.Sector = number_in_bank;
197#elif defined(FLASH_SECTOR_TOTAL)
198 // F2、F4、F7 的扇区号跨两个 bank 连续编号,等于跨段的扇区序号。
199 // F2, F4 and F7 number sectors across both banks, as the index across runs does.
200 erase_init.Sector = index;
201#else
202#error "No supported Flash sector numbering defined"
203#endif
204 erase_init.NbSectors = 1;
205#if defined(FLASH_BANK_1)
206 erase_init.Banks = STM32FlashBankOf(address);
207#endif
208#if defined(FLASH_CR_PSIZE)
209 erase_init.VoltageRange = FLASH_VOLTAGE_RANGE_1;
210#endif
211#else
213#endif
214
215 uint32_t error = 0;
216 HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase_init, &error);
217 if (status != HAL_OK || error != 0xFFFFFFFFU)
218 {
219 return ErrorCode::FAILED;
220 }
221 }
222 }
223
224 return ErrorCode::OK;
225}
226
228{
229 if (!data.addr_ || data.size_ == 0)
230 {
231 return ErrorCode::ARG_ERR;
232 }
233
234 uint32_t addr = base_address_ + offset;
235 if (!IsInRange(addr, data.size_))
236 {
238 }
239
240 FlashOperationGuard operation;
241
242 const uint8_t* src = reinterpret_cast<const uint8_t*>(data.addr_);
243 size_t written = 0;
244
245#if defined(FLASH_TYPEPROGRAM_FLASHWORD) || defined(FLASH_TYPEPROGRAM_QUADWORD)
247 uint32_t flash_word_buffer[MIN_WRITE_SIZE / sizeof(uint32_t)];
248 while (written < data.size_)
249 {
250 size_t chunk_size = LibXR::min<size_t>(MinWriteSize(), data.size_ - written);
251
252 Memory::FastSet(flash_word_buffer, 0xFF, sizeof(flash_word_buffer));
253 Memory::FastCopy(flash_word_buffer, src + written, chunk_size);
254
255 if (Memory::FastCmp(reinterpret_cast<const uint8_t*>(addr + written), src + written,
256 chunk_size) == 0)
257 {
258 written += chunk_size;
259 continue;
260 }
261
262 if (HAL_FLASH_Program(program_type_, addr + written,
263 reinterpret_cast<uint32_t>(flash_word_buffer)) != HAL_OK)
264 {
265 return ErrorCode::FAILED;
266 }
267
268 written += chunk_size;
269 }
270
271#else
272 while (written < data.size_)
273 {
274 size_t chunk_size = LibXR::min<size_t>(MinWriteSize(), data.size_ - written);
275
276 if (Memory::FastCmp(reinterpret_cast<const uint8_t*>(addr + written), src + written,
277 chunk_size) == 0)
278 {
279 written += chunk_size;
280 continue;
281 }
282
283 uint64_t word = 0xFFFFFFFFFFFFFFFF;
284 Memory::FastCopy(&word, src + written, chunk_size);
285
286 if (HAL_FLASH_Program(program_type_, addr + written, word) != HAL_OK)
287 {
288 return ErrorCode::FAILED;
289 }
290
291 written += chunk_size;
292 }
293#endif
294
295 return ErrorCode::OK;
296}
297
298bool STM32Flash::IsInRange(uint32_t addr, size_t size) const
299{
300 const uint32_t BEGIN = base_address_;
301 const uint32_t LIMIT = TableEnd(regions_, region_count_);
302 const uint32_t END = addr + size;
303 return (addr >= BEGIN) && (END <= LIMIT) && (END >= addr); // 最后一项防溢出
304}
305
306#endif
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
抽象基类,表示闪存接口。 Abstract base class representing a flash memory interface.
Definition flash.hpp:32
size_t MinWriteSize() const
获取最小可写块大小(字节) / Returns the minimum writable block size in bytes.
Definition flash.hpp:83
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill
static int FastCmp(const void *a, const void *b, size_t size)
快速内存比较 / Fast memory comparison
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
STM32 闪存驱动实现 / STM32 flash driver implementation.
STM32Flash(const FlashRegion *regions, size_t region_count, uint32_t start_address)
构造闪存对象 / Construct flash object
static constexpr size_t MIN_WRITE_SIZE
最小写入单位(字节),由 HAL 的 FLASH_TYPEPROGRAM_* 宏确定;可直接作为 DatabaseRaw 的模板参数 / Minimum write unit in bytes,...
ErrorCode Write(size_t offset, ConstRawData data) override
向闪存写入数据 / Writes data to the flash memory.
ErrorCode Erase(size_t offset, size_t size) override
擦除闪存的指定区域 / Erases a section of the flash memory.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ OUT_OF_RANGE
超出范围 / Out of range
@ NOT_SUPPORT
不支持 / Not supported
@ FAILED
操作失败 / Operation failed
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
constexpr auto min(LeftType a, RightType b) -> std::common_type_t< LeftType, RightType >
计算两个数的最小值 / Computes the minimum of two numbers
constexpr size_t HW_CACHE_LINE_SIZE
真实硬件缓存行大小(用于 DMA / cache coherency) / Hardware cache-line size used for DMA/cache-coherency boundarie...
Definition libxr_def.hpp:54
一段连续、大小相同的扇区 / A run of contiguous sectors of equal size
Definition flash.hpp:20
uint32_t address
第一个扇区的地址 / Address of the first sector
Definition flash.hpp:21