2#include "ch32_flash.hpp"
13extern "C" __attribute__((noinline))
ErrorCode CH32FlashWriteHotPath(uint32_t start_addr,
19using CH32FlashEraseHotPathFn =
ErrorCode (*)(uint32_t erase_begin, uint32_t erase_end);
20using CH32FlashWriteHotLoopFn =
ErrorCode (*)(uint32_t start_addr, uint32_t end_addr,
22using CH32FlashWritePageFn =
ErrorCode (*)(uint32_t start_addr, uint32_t end_addr,
25struct CH32FlashHotPaths
27 CH32FlashEraseHotPathFn erase =
nullptr;
28 CH32FlashWriteHotLoopFn write_halfword =
nullptr;
29 CH32FlashWritePageFn write_page =
nullptr;
32constexpr size_t routine_align = 16u;
33constexpr size_t ch32_flash_erase_hot_path_size = 0x78u;
34constexpr size_t ch32_flash_write_hot_loop_size = 0xD2u;
35constexpr size_t ch32_flash_write_page_size = 0x13Cu;
37static CH32FlashHotPaths g_ch32_flash_hot_paths;
38static void InitHotPathsOnce();
42static void flash_set_access_clock_half_sysclk(
void)
45 FLASH->CTLR &= ~(1u << 25);
50static void flash_set_access_clock_sysclk(
void)
53 FLASH->CTLR |= (1u << 25);
57static inline void flash_exit_enhanced_read_if_enabled()
59 if (FLASH->STATR & (1u << 7))
62 FLASH->CTLR &= ~(1u << 24);
63 FLASH->CTLR |= (1u << 22);
68static inline void flash_fast_unlock()
72 FLASH->MODEKEYR = 0x45670123u;
73 FLASH->MODEKEYR = 0xCDEF89ABu;
76static inline void flash_fast_lock()
79 FLASH->CTLR |= (1u << 15);
83static inline void flash_clear_flags_once()
86 FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
88 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
102 flash_exit_enhanced_read_if_enabled();
103 flash_set_access_clock_half_sysclk();
106 flash_clear_flags_once();
113 flash_set_access_clock_sysclk();
120inline void CH32Flash::ClearFlashFlagsOnce() { flash_clear_flags_once(); }
123 :
Flash(sectors[start_sector - 1].size, MinWriteSize(),
124 {
reinterpret_cast<void*
>(sectors[start_sector - 1].
address),
125 sectors[sector_count - 1].
address - sectors[start_sector - 1].
address +
126 sectors[sector_count - 1].
size}),
128 base_address_(sectors[start_sector - 1].address),
129 sector_count_(sector_count)
146 ASSERT(SystemCoreClock <= 120000000);
148 const uint32_t START_ADDR = base_address_ +
static_cast<uint32_t
>(offset);
149 if (!IsInRange(START_ADDR, size))
153 const uint32_t END_ADDR = START_ADDR +
static_cast<uint32_t
>(size);
154 const auto erase_hot_path = g_ch32_flash_hot_paths.erase;
155 ASSERT(erase_hot_path !=
nullptr);
163 const uint32_t fast_size = 256u;
164 const uint32_t ERASE_BEGIN = START_ADDR & ~(fast_size - 1u);
165 const uint32_t ERASE_END = (END_ADDR + fast_size - 1u) & ~(fast_size - 1u);
166 if (ERASE_END <= ERASE_BEGIN)
171 return erase_hot_path(ERASE_BEGIN, ERASE_END);
176 ASSERT(SystemCoreClock <= 120000000);
184 const uint32_t START_ADDR = base_address_ +
static_cast<uint32_t
>(offset);
185 if (!IsInRange(START_ADDR, data.
size_))
191 const uint8_t* src =
reinterpret_cast<const uint8_t*
>(data.
addr_);
192 const uint32_t END_ADDR = START_ADDR +
static_cast<uint32_t
>(data.
size_);
193 return CH32FlashWriteHotPath(START_ADDR, END_ADDR, src);
196extern "C" __attribute__((noinline))
ErrorCode CH32FlashWriteHotPath(uint32_t start_addr,
200 const auto write_hot_loop = g_ch32_flash_hot_paths.write_halfword;
201 const auto write_page = g_ch32_flash_hot_paths.write_page;
202 constexpr uint32_t page_size = 256u;
203 ASSERT(write_hot_loop !=
nullptr && write_page !=
nullptr);
215 const uint32_t aligned_begin = (start_addr + page_size - 1u) & ~(page_size - 1u);
216 const uint32_t aligned_end = end_addr & ~(page_size - 1u);
218 const uint32_t head_end = (aligned_begin < end_addr) ? aligned_begin : end_addr;
219 if (start_addr < head_end)
221 ec = write_hot_loop(start_addr, head_end, src);
224 const bool has_full_pages = (aligned_begin < aligned_end);
227 ec = write_page(aligned_begin, aligned_end, src + (aligned_begin - start_addr));
236 const uint32_t tail_begin = has_full_pages ? aligned_end : head_end;
239 ec = write_hot_loop(tail_begin, end_addr, src + (tail_begin - start_addr));
245bool CH32Flash::IsInRange(uint32_t addr,
size_t size)
const
247 const uint32_t BEGIN = base_address_;
248 const uint32_t LIMIT =
249 sectors_[sector_count_ - 1].
address + sectors_[sector_count_ - 1].
size;
250 const uint32_t END = addr +
static_cast<uint32_t
>(size);
251 return (addr >= BEGIN) && (END <= LIMIT) && (END >= addr);
265alignas(routine_align)
static uint8_t g_ch32_flash_erase_hot[ch32_flash_erase_hot_path_size] = {
266 0x63, 0x79, 0xb5, 0x04, 0x01, 0x76, 0x7d, 0x16, 0xb7, 0x26, 0x02, 0x40, 0x37, 0x08,
267 0x02, 0x00, 0x93, 0x08, 0x00, 0x02, 0x9c, 0x4a, 0x37, 0x47, 0x0f, 0x00, 0x13, 0x07,
268 0x17, 0x24, 0xb3, 0xe7, 0x07, 0x01, 0x9c, 0xca, 0xc8, 0xca, 0x9c, 0x4a, 0x93, 0xe7,
269 0x07, 0x04, 0x9c, 0xca, 0x11, 0xa0, 0x1d, 0xc3, 0xdc, 0x46, 0x7d, 0x17, 0x85, 0x8b,
270 0xe5, 0xff, 0xdc, 0x46, 0xc1, 0x8b, 0x9d, 0xe3, 0x9c, 0x4a, 0x13, 0x05, 0x05, 0x10,
271 0xf1, 0x8f, 0x9c, 0xca, 0x23, 0xa6, 0x16, 0x01, 0xe3, 0x63, 0xb5, 0xfc, 0x01, 0x45,
272 0x82, 0x80, 0x9c, 0x4a, 0x01, 0x77, 0x7d, 0x17, 0xf9, 0x8f, 0x9c, 0xca, 0x51, 0x55,
273 0x82, 0x80, 0x9c, 0x4a, 0x01, 0x77, 0x7d, 0x17, 0xf9, 0x8f, 0x9c, 0xca, 0x93, 0x07,
274 0x00, 0x03, 0xdc, 0xc6, 0x71, 0x55, 0x82, 0x80};
276alignas(routine_align)
static uint8_t g_ch32_flash_write_hot[ch32_flash_write_hot_loop_size] = {
277 0x13, 0x78, 0xe5, 0xff, 0x13, 0x8e, 0x15, 0x00, 0xb3, 0x07, 0xa8, 0x40, 0xc9, 0x7e,
278 0x13, 0x7e, 0xee, 0xff, 0x33, 0x03, 0xf6, 0x00, 0x93, 0x68, 0x15, 0x00, 0x93, 0x8e,
279 0x7e, 0xcc, 0xb7, 0x26, 0x02, 0x40, 0x13, 0x0f, 0x00, 0x02, 0x63, 0x72, 0xc8, 0x09,
280 0x83, 0x57, 0x08, 0x00, 0xc2, 0x07, 0xc1, 0x83, 0x63, 0x6e, 0xa8, 0x06, 0x63, 0x7c,
281 0xb8, 0x06, 0x03, 0x47, 0x03, 0x00, 0x13, 0xf6, 0x07, 0xf0, 0x59, 0x8e, 0x63, 0xfa,
282 0xb8, 0x00, 0x03, 0x47, 0x13, 0x00, 0x13, 0x76, 0xf6, 0x0f, 0x13, 0x77, 0xf7, 0x0f,
283 0x22, 0x07, 0x59, 0x8e, 0x63, 0x04, 0xf6, 0x04, 0x13, 0xc7, 0xf7, 0xff, 0x71, 0x8f,
284 0x19, 0xc3, 0xf6, 0x97, 0xb5, 0xe3, 0x9c, 0x4a, 0x37, 0x47, 0x0f, 0x00, 0x13, 0x07,
285 0x17, 0x24, 0x93, 0xe7, 0x17, 0x00, 0x9c, 0xca, 0x23, 0x10, 0xc8, 0x00, 0x11, 0xa0,
286 0x15, 0xcf, 0xdc, 0x46, 0x7d, 0x17, 0x85, 0x8b, 0xe5, 0xff, 0x9c, 0x4a, 0xf9, 0x9b,
287 0x9c, 0xca, 0xdc, 0x46, 0xc1, 0x8b, 0x8d, 0xeb, 0x83, 0x57, 0x08, 0x00, 0x63, 0x9b,
288 0xc7, 0x02, 0x23, 0xa6, 0xe6, 0x01, 0x09, 0x08, 0x89, 0x08, 0x09, 0x03, 0xe3, 0x62,
289 0xc8, 0xf9, 0x01, 0x45, 0x82, 0x80, 0xe3, 0xf9, 0xb8, 0xfe, 0xe3, 0xe7, 0xa8, 0xfe,
290 0x3e, 0x86, 0x41, 0xbf, 0x9c, 0x4a, 0x51, 0x55, 0xf9, 0x9b, 0x9c, 0xca, 0x82, 0x80,
291 0x93, 0x07, 0x00, 0x03, 0xdc, 0xc6, 0x71, 0x55, 0x82, 0x80, 0x69, 0x55, 0x82, 0x80};
293alignas(routine_align)
static uint8_t g_ch32_flash_write_page[ch32_flash_write_page_size] = {
294 0x63, 0x77, 0xb5, 0x12, 0x13, 0x0e, 0x06, 0x10, 0xb7, 0x28, 0x02, 0x40, 0xc1, 0x6e,
295 0x83, 0xa7, 0x08, 0x01, 0x37, 0x47, 0x0f, 0x00, 0x13, 0x07, 0x17, 0x24, 0xb3, 0xe7,
296 0xd7, 0x01, 0x23, 0xa8, 0xf8, 0x00, 0x11, 0xa0, 0x79, 0xcf, 0x83, 0xa7, 0xc8, 0x00,
297 0x7d, 0x17, 0x85, 0x8b, 0xfd, 0xfb, 0x37, 0x47, 0x0f, 0x00, 0x13, 0x07, 0x17, 0x24,
298 0xb7, 0x26, 0x02, 0x40, 0x11, 0xa0, 0x5d, 0xcb, 0xdc, 0x46, 0x7d, 0x17, 0x89, 0x8b,
299 0xe5, 0xff, 0x32, 0x88, 0xb3, 0x0f, 0xc5, 0x40, 0xb7, 0x26, 0x02, 0x40, 0x83, 0x47,
300 0x18, 0x00, 0x03, 0x43, 0x28, 0x00, 0x03, 0x4f, 0x08, 0x00, 0x03, 0x47, 0x38, 0x00,
301 0x42, 0x03, 0xa2, 0x07, 0xb3, 0xe7, 0x67, 0x00, 0x62, 0x07, 0xb3, 0xe7, 0xe7, 0x01,
302 0xd9, 0x8f, 0x33, 0x83, 0x0f, 0x01, 0x37, 0x47, 0x0f, 0x00, 0x23, 0x20, 0xf3, 0x00,
303 0x13, 0x07, 0x17, 0x24, 0x11, 0xa0, 0x25, 0xcb, 0xdc, 0x46, 0x7d, 0x17, 0x89, 0x8b,
304 0xe5, 0xff, 0x11, 0x08, 0xe3, 0x11, 0x0e, 0xfd, 0x9c, 0x4a, 0x37, 0x08, 0x20, 0x00,
305 0x37, 0x47, 0x0f, 0x00, 0xb3, 0xe7, 0x07, 0x01, 0x9c, 0xca, 0x13, 0x07, 0x17, 0x24,
306 0xb7, 0x26, 0x02, 0x40, 0x11, 0xa0, 0x39, 0xc3, 0xdc, 0x46, 0x7d, 0x17, 0x85, 0x8b,
307 0xe5, 0xff, 0x9c, 0x4a, 0x41, 0x77, 0x7d, 0x17, 0xf9, 0x8f, 0x9c, 0xca, 0xdc, 0x46,
308 0xc1, 0x8b, 0xb5, 0xe7, 0x32, 0x87, 0x19, 0xa0, 0x63, 0x04, 0xc7, 0x05, 0x83, 0x47,
309 0x17, 0x00, 0x03, 0x48, 0x07, 0x00, 0xb3, 0x06, 0xf7, 0x01, 0xa2, 0x07, 0xb3, 0xe7,
310 0x07, 0x01, 0x83, 0xd6, 0x06, 0x00, 0xc2, 0x07, 0xc1, 0x83, 0x09, 0x07, 0xe3, 0x80,
311 0xd7, 0xfe, 0x69, 0x55, 0x82, 0x80, 0x9c, 0x4a, 0x41, 0x77, 0x7d, 0x17, 0xf9, 0x8f,
312 0x9c, 0xca, 0x51, 0x55, 0x82, 0x80, 0x83, 0xa7, 0x08, 0x01, 0x41, 0x77, 0x7d, 0x17,
313 0xf9, 0x8f, 0x23, 0xa8, 0xf8, 0x00, 0x51, 0x55, 0x82, 0x80, 0xb7, 0x27, 0x02, 0x40,
314 0x13, 0x07, 0x00, 0x02, 0x13, 0x05, 0x05, 0x10, 0xd8, 0xc7, 0x13, 0x0e, 0x0e, 0x10,
315 0x13, 0x06, 0x06, 0x10, 0xe3, 0x62, 0xb5, 0xee, 0x01, 0x45, 0x82, 0x80, 0x93, 0x07,
316 0x00, 0x03, 0xdc, 0xc6, 0x71, 0x55, 0x82, 0x80};
319static void InitHotPathsOnce()
321 static bool inited =
false;
332 static_assert(
sizeof(g_ch32_flash_erase_hot) == ch32_flash_erase_hot_path_size);
333 static_assert(
sizeof(g_ch32_flash_write_hot) == ch32_flash_write_hot_loop_size);
334 static_assert(
sizeof(g_ch32_flash_write_page) == ch32_flash_write_page_size);
340 __builtin___clear_cache(
341 reinterpret_cast<char*
>(g_ch32_flash_erase_hot),
342 reinterpret_cast<char*
>(g_ch32_flash_erase_hot +
sizeof(g_ch32_flash_erase_hot)));
343 __builtin___clear_cache(
344 reinterpret_cast<char*
>(g_ch32_flash_write_hot),
345 reinterpret_cast<char*
>(g_ch32_flash_write_hot +
sizeof(g_ch32_flash_write_hot)));
346 __builtin___clear_cache(
347 reinterpret_cast<char*
>(g_ch32_flash_write_page),
348 reinterpret_cast<char*
>(g_ch32_flash_write_page +
sizeof(g_ch32_flash_write_page)));
350 g_ch32_flash_hot_paths.erase =
351 reinterpret_cast<CH32FlashEraseHotPathFn
>(g_ch32_flash_erase_hot);
352 g_ch32_flash_hot_paths.write_halfword =
353 reinterpret_cast<CH32FlashWriteHotLoopFn
>(g_ch32_flash_write_hot);
354 g_ch32_flash_hot_paths.write_page =
355 reinterpret_cast<CH32FlashWritePageFn
>(g_ch32_flash_write_page);
CH32Flash(const FlashSector *sectors, size_t sector_count, size_t start_sector)
构造闪存对象 / Construct flash object
ErrorCode Erase(size_t offset, size_t size) override
Erases a section of the flash memory. 擦除闪存的指定区域。
ErrorCode Write(size_t offset, ConstRawData data) override
Writes data to the flash memory. 向闪存写入数据。
只读原始数据视图 / 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. 抽象基类,表示闪存接口。
@ OUT_OF_RANGE
超出范围 | Out of range
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error
闪存扇区描述 / Flash sector descriptor
uint32_t size
扇区大小(字节) / Sector size in bytes
uint32_t address
扇区起始地址 / Sector base address