libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
stm32_flash.hpp
1#pragma once
2
3#include <algorithm>
4#include <cstdint>
5#include <cstring>
6
7#include "flash.hpp"
8#include "libxr_def.hpp"
9#include "libxr_type.hpp"
10#include "main.h"
11
12namespace LibXR
13{
14
20{
21 uint32_t address; //< 扇区起始地址 / Start address of the sector
22 uint32_t size; //< 扇区大小 / Size of the sector
23};
24
25#ifndef __DOXYGEN__
26
27template <typename, typename = void>
28struct HasFlashPage : std::false_type
29{
30};
31
32template <typename, typename = void>
33struct HasFlashBank : std::false_type
34{
35};
36
37template <typename T>
38struct HasFlashPage<T, std::void_t<decltype(std::declval<T>().Page)>> : std::true_type
39{
40};
41
42template <typename T>
43struct HasFlashBank<T, std::void_t<decltype(std::declval<T>().Banks)>> : std::true_type
44{
45};
46
47template <typename T>
48// NOLINTNEXTLINE
49typename std::enable_if<!HasFlashPage<T>::value>::type SetNbPages(T& init, uint32_t addr,
50 uint32_t page)
51{
52 UNUSED(page);
53 init.PageAddress = addr;
54}
55
56template <typename T>
57// NOLINTNEXTLINE
58typename std::enable_if<HasFlashPage<T>::value>::type SetNbPages(T& init, uint32_t addr,
59 uint32_t page)
60{
61 UNUSED(addr);
62 init.Page = page;
63}
64
65template <typename T>
66// NOLINTNEXTLINE
67typename std::enable_if<!HasFlashBank<T>::value>::type SetBanks(T& init)
68{
69 UNUSED(init);
70}
71
72template <typename T>
73// NOLINTNEXTLINE
74typename std::enable_if<HasFlashBank<T>::value>::type SetBanks(T& init)
75{
76 init.Banks = 1;
77}
78
79#endif
80
86template <size_t SECTOR_COUNT, size_t START_SECTOR>
87class STM32Flash : public Flash
88{
89 public:
95 STM32Flash(const FlashSector (&sectors)[SECTOR_COUNT])
96 : Flash(sectors[START_SECTOR - 1].size, DetermineMinWriteSize(),
97 {reinterpret_cast<void*>(sectors[START_SECTOR - 1].address),
98 sectors[SECTOR_COUNT - 1].address - sectors[START_SECTOR - 1].address +
99 sectors[SECTOR_COUNT - 1].size}),
100 sectors_(sectors),
101 base_address_(sectors[START_SECTOR - 1].address),
102 program_type_(DetermineProgramType())
103 {
104 }
105
106 ErrorCode Erase(size_t offset, size_t size) override
107 {
108 if (size == 0)
109 {
110 return ErrorCode::ARG_ERR;
111 }
112
113 uint32_t start_addr = base_address_ + offset;
114 uint32_t end_addr = start_addr + size;
115
116 HAL_FLASH_Unlock();
117
118 for (size_t i = 0; i < SECTOR_COUNT; ++i)
119 {
120 const auto& sector = sectors_[i];
121 if (sector.address + sector.size <= start_addr)
122 {
123 continue;
124 }
125 if (sector.address >= end_addr)
126 {
127 break;
128 }
129 FLASH_EraseInitTypeDef erase_init = {};
130
131#if defined(FLASH_TYPEERASE_PAGES) && defined(FLASH_PAGE_SIZE) // STM32F1/G4... series
132 erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
133 SetNbPages(erase_init, sector.address, i);
134 erase_init.NbPages = 1;
135 SetBanks(erase_init);
136#elif defined(FLASH_TYPEERASE_SECTORS) // STM32F4/F7/H7... series
137 erase_init.TypeErase = FLASH_TYPEERASE_SECTORS;
138 erase_init.Sector = static_cast<uint32_t>(i);
139 erase_init.NbSectors = 1;
140 erase_init.Banks = FLASH_BANK_1;
141#else
142 return ErrorCode::NOT_SUPPORT;
143#endif
144
145 uint32_t error = 0;
146 HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase_init, &error);
147 if (status != HAL_OK || error != 0xFFFFFFFFU)
148 {
149 HAL_FLASH_Lock();
150 return ErrorCode::FAILED;
151 }
152 }
153
154 HAL_FLASH_Lock();
155 return ErrorCode::OK;
156 }
157
158 ErrorCode Write(size_t offset, ConstRawData data) override
159 {
160 if (!data.addr_ || data.size_ == 0)
161 {
162 return ErrorCode::ARG_ERR;
163 }
164
165 uint32_t addr = base_address_ + offset;
166 if (!IsInRange(addr, data.size_))
167 {
168 return ErrorCode::OUT_OF_RANGE;
169 }
170
171 HAL_FLASH_Unlock();
172
173 const uint8_t* src = reinterpret_cast<const uint8_t*>(data.addr_);
174 size_t written = 0;
175
176#if defined(STM32H7) || defined(STM32H5)
177 alignas(32) uint32_t flash_word_buffer[8] = {0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu,
178 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu,
179 0xFFFFFFFFu, 0xFFFFFFFFu};
180 while (written < data.size_)
181 {
182 size_t chunk_size = LibXR::min<size_t>(min_write_size_, data.size_ - written);
183
184 std::memcpy(flash_word_buffer, src + written, chunk_size);
185
186 if (memcmp(reinterpret_cast<const uint8_t*>(addr + written), src + written,
187 chunk_size) == 0)
188 {
189 written += chunk_size;
190 continue;
191 }
192
193 if (HAL_FLASH_Program(program_type_, addr + written,
194 reinterpret_cast<uint32_t>(flash_word_buffer)) != HAL_OK)
195 {
196 HAL_FLASH_Lock();
197 return ErrorCode::FAILED;
198 }
199
200 written += chunk_size;
201 }
202
203#else
204 while (written < data.size_)
205 {
206 size_t chunk_size = LibXR::min<size_t>(min_write_size_, data.size_ - written);
207
208 if (memcmp(reinterpret_cast<const uint8_t*>(addr + written), src + written,
209 chunk_size) == 0)
210 {
211 written += chunk_size;
212 continue;
213 }
214
215 uint64_t word = 0xFFFFFFFFFFFFFFFF;
216 std::memcpy(&word, src + written, chunk_size);
217
218 if (HAL_FLASH_Program(program_type_, addr + written, word) != HAL_OK)
219 {
220 HAL_FLASH_Lock();
221 return ErrorCode::FAILED;
222 }
223
224 written += chunk_size;
225 }
226#endif
227
228 HAL_FLASH_Lock();
229 return ErrorCode::OK;
230 }
231
232 private:
233 const FlashSector* sectors_;
234 uint32_t base_address_;
235 uint32_t program_type_;
236
237 static constexpr uint32_t DetermineProgramType()
238 {
239#ifdef FLASH_TYPEPROGRAM_BYTE
240 return FLASH_TYPEPROGRAM_BYTE;
241#elif defined(FLASH_TYPEPROGRAM_HALFWORD)
242 return FLASH_TYPEPROGRAM_HALFWORD;
243#elif defined(FLASH_TYPEPROGRAM_WORD)
244 return FLASH_TYPEPROGRAM_WORD;
245#elif defined(FLASH_TYPEPROGRAM_DOUBLEWORD)
246 return FLASH_TYPEPROGRAM_DOUBLEWORD;
247#elif defined(FLASH_TYPEPROGRAM_FLASHWORD)
248 return FLASH_TYPEPROGRAM_FLASHWORD;
249#else
250#error "No supported FLASH_TYPEPROGRAM_xxx defined"
251#endif
252 }
253
254 static constexpr size_t DetermineMinWriteSize()
255 {
256#ifdef FLASH_TYPEPROGRAM_BYTE
257 return 1;
258#elif defined(FLASH_TYPEPROGRAM_HALFWORD)
259 return 2;
260#elif defined(FLASH_TYPEPROGRAM_WORD)
261 return 4;
262#elif defined(FLASH_TYPEPROGRAM_DOUBLEWORD)
263 return 8;
264#elif defined(FLASH_TYPEPROGRAM_FLASHWORD)
265 return FLASH_NB_32BITWORD_IN_FLASHWORD * 4;
266#else
267#error "No supported FLASH_TYPEPROGRAM_xxx defined"
268#endif
269 }
270
271 bool IsInRange(uint32_t addr, size_t size) const
272 {
273 uint32_t end = addr + size;
274 for (size_t i = 0; i < SECTOR_COUNT; ++i)
275 {
276 const auto& s = sectors_[i];
277 if (addr >= s.address && end <= s.address + s.size)
278 {
279 return true;
280 }
281 }
282 return false;
283 }
284};
285
286} // namespace LibXR
常量原始数据封装类。 A class for encapsulating constant raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
const void * addr_
数据存储地址(常量)。 The storage address of the data (constant).
Abstract base class representing a flash memory interface. 抽象基类,表示闪存接口。
Definition flash.hpp:16
size_t min_write_size_
Minimum writable block size in bytes. 最小可写块大小(字节)。
Definition flash.hpp:36
STM32Flash 通用类,构造时传入扇区列表,自动判断编程粒度。
ErrorCode Erase(size_t offset, size_t size) override
Erases a section of the flash memory. 擦除闪存的指定区域。
STM32Flash(const FlashSector(&sectors)[SECTOR_COUNT])
STM32Flash 类,构造时传入扇区列表,自动判断编程粒度。
ErrorCode Write(size_t offset, ConstRawData data) override
Writes data to the flash memory. 向闪存写入数据。
LibXR 命名空间
Definition ch32_gpio.hpp:9
constexpr auto min(T1 a, T2 b) -> typename std::common_type< T1, T2 >::type
计算两个数的最小值
STM32Flash 通用类,构造时传入扇区列表,自动判断编程粒度。