2#include "ch32_flash.hpp"
13extern "C" LIBXR_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();
41uint32_t TableEnd(
const FlashRegion* regions,
size_t region_count)
43 const auto& last = regions[region_count - 1];
44 return last.
address + last.sector_size * last.sector_count;
48uint32_t SectorSizeAt(
const FlashRegion* regions,
size_t region_count, uint32_t address)
50 for (
size_t i = 0; i < region_count; ++i)
52 const auto& region = regions[i];
53 if (address >= region.address &&
54 address - region.address < region.sector_size * region.sector_count)
56 ASSERT((address - region.address) % region.sector_size == 0U);
57 return region.sector_size;
65uint32_t SecondToLastSector(
const FlashRegion* regions,
size_t region_count)
67 const auto& last = regions[region_count - 1];
68 if (last.sector_count >= 2U)
70 return last.address + last.sector_size * (last.sector_count - 2U);
72 ASSERT(region_count >= 2U);
73 const auto& previous = regions[region_count - 2];
74 return previous.
address + previous.sector_size * (previous.sector_count - 1U);
79static void flash_set_access_clock_half_sysclk(
void)
82 FLASH->CTLR &= ~(1u << 25);
87static void flash_set_access_clock_sysclk(
void)
90 FLASH->CTLR |= (1u << 25);
94static inline void flash_exit_enhanced_read_if_enabled()
96 if (FLASH->STATR & (1u << 7))
99 FLASH->CTLR &= ~(1u << 24);
100 FLASH->CTLR |= (1u << 22);
105static inline void flash_fast_unlock()
109 FLASH->MODEKEYR = 0x45670123u;
110 FLASH->MODEKEYR = 0xCDEF89ABu;
113static inline void flash_fast_lock()
116 FLASH->CTLR |= (1u << 15);
120static inline void flash_clear_flags_once()
123 FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
125 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
139 flash_exit_enhanced_read_if_enabled();
140 flash_set_access_clock_half_sysclk();
143 flash_clear_flags_once();
150 flash_set_access_clock_sysclk();
157inline void CH32Flash::ClearFlashFlagsOnce() { flash_clear_flags_once(); }
160 uint32_t start_address)
161 :
Flash(SectorSizeAt(regions, region_count, start_address), MinWriteSize(),
162 {
reinterpret_cast<void*
>(start_address),
163 TableEnd(regions, region_count) - start_address}),
165 base_address_(start_address),
166 region_count_(region_count)
177 :
CH32Flash(regions, region_count, SecondToLastSector(regions, region_count))
188 ASSERT(SystemCoreClock <= 120000000);
190 const uint32_t START_ADDR = base_address_ +
static_cast<uint32_t
>(offset);
191 if (!IsInRange(START_ADDR, size))
195 const uint32_t END_ADDR = START_ADDR +
static_cast<uint32_t
>(size);
196 const auto erase_hot_path = g_ch32_flash_hot_paths.erase;
197 DEV_ASSERT(erase_hot_path !=
nullptr);
205 const uint32_t fast_size = 256u;
206 const uint32_t ERASE_BEGIN = START_ADDR & ~(fast_size - 1u);
207 const uint32_t ERASE_END = (END_ADDR + fast_size - 1u) & ~(fast_size - 1u);
208 if (ERASE_END <= ERASE_BEGIN)
213 return erase_hot_path(ERASE_BEGIN, ERASE_END);
218 ASSERT(SystemCoreClock <= 120000000);
225 const uint32_t START_ADDR = base_address_ +
static_cast<uint32_t
>(offset);
226 if (!IsInRange(START_ADDR, data.
size_))
231 const uint8_t* src =
reinterpret_cast<const uint8_t*
>(data.
addr_);
232 const uint32_t END_ADDR = START_ADDR +
static_cast<uint32_t
>(data.
size_);
233 return CH32FlashWriteHotPath(START_ADDR, END_ADDR, src);
236extern "C" LIBXR_NOINLINE
ErrorCode CH32FlashWriteHotPath(uint32_t start_addr,
240 const auto write_hot_loop = g_ch32_flash_hot_paths.write_halfword;
241 const auto write_page = g_ch32_flash_hot_paths.write_page;
242 constexpr uint32_t page_size = 256u;
243 DEV_ASSERT(write_hot_loop !=
nullptr && write_page !=
nullptr);
255 const uint32_t aligned_begin = (start_addr + page_size - 1u) & ~(page_size - 1u);
256 const uint32_t aligned_end = end_addr & ~(page_size - 1u);
258 const uint32_t head_end = (aligned_begin < end_addr) ? aligned_begin : end_addr;
259 if (start_addr < head_end)
261 ec = write_hot_loop(start_addr, head_end, src);
264 const bool has_full_pages = (aligned_begin < aligned_end);
267 ec = write_page(aligned_begin, aligned_end, src + (aligned_begin - start_addr));
276 const uint32_t tail_begin = has_full_pages ? aligned_end : head_end;
279 ec = write_hot_loop(tail_begin, end_addr, src + (tail_begin - start_addr));
285bool CH32Flash::IsInRange(uint32_t addr,
size_t size)
const
287 const uint32_t BEGIN = base_address_;
288 const uint32_t LIMIT = TableEnd(regions_, region_count_);
289 const uint32_t END = addr +
static_cast<uint32_t
>(size);
290 return (addr >= BEGIN) && (END <= LIMIT) && (END >= addr);
304alignas(routine_align)
static uint8_t g_ch32_flash_erase_hot[ch32_flash_erase_hot_path_size] = {
305 0x63, 0x79, 0xb5, 0x04, 0x01, 0x76, 0x7d, 0x16, 0xb7, 0x26, 0x02, 0x40, 0x37, 0x08,
306 0x02, 0x00, 0x93, 0x08, 0x00, 0x02, 0x9c, 0x4a, 0x37, 0x47, 0x0f, 0x00, 0x13, 0x07,
307 0x17, 0x24, 0xb3, 0xe7, 0x07, 0x01, 0x9c, 0xca, 0xc8, 0xca, 0x9c, 0x4a, 0x93, 0xe7,
308 0x07, 0x04, 0x9c, 0xca, 0x11, 0xa0, 0x1d, 0xc3, 0xdc, 0x46, 0x7d, 0x17, 0x85, 0x8b,
309 0xe5, 0xff, 0xdc, 0x46, 0xc1, 0x8b, 0x9d, 0xe3, 0x9c, 0x4a, 0x13, 0x05, 0x05, 0x10,
310 0xf1, 0x8f, 0x9c, 0xca, 0x23, 0xa6, 0x16, 0x01, 0xe3, 0x63, 0xb5, 0xfc, 0x01, 0x45,
311 0x82, 0x80, 0x9c, 0x4a, 0x01, 0x77, 0x7d, 0x17, 0xf9, 0x8f, 0x9c, 0xca, 0x51, 0x55,
312 0x82, 0x80, 0x9c, 0x4a, 0x01, 0x77, 0x7d, 0x17, 0xf9, 0x8f, 0x9c, 0xca, 0x93, 0x07,
313 0x00, 0x03, 0xdc, 0xc6, 0x71, 0x55, 0x82, 0x80};
315alignas(routine_align)
static uint8_t g_ch32_flash_write_hot[ch32_flash_write_hot_loop_size] = {
316 0x13, 0x78, 0xe5, 0xff, 0x13, 0x8e, 0x15, 0x00, 0xb3, 0x07, 0xa8, 0x40, 0xc9, 0x7e,
317 0x13, 0x7e, 0xee, 0xff, 0x33, 0x03, 0xf6, 0x00, 0x93, 0x68, 0x15, 0x00, 0x93, 0x8e,
318 0x7e, 0xcc, 0xb7, 0x26, 0x02, 0x40, 0x13, 0x0f, 0x00, 0x02, 0x63, 0x72, 0xc8, 0x09,
319 0x83, 0x57, 0x08, 0x00, 0xc2, 0x07, 0xc1, 0x83, 0x63, 0x6e, 0xa8, 0x06, 0x63, 0x7c,
320 0xb8, 0x06, 0x03, 0x47, 0x03, 0x00, 0x13, 0xf6, 0x07, 0xf0, 0x59, 0x8e, 0x63, 0xfa,
321 0xb8, 0x00, 0x03, 0x47, 0x13, 0x00, 0x13, 0x76, 0xf6, 0x0f, 0x13, 0x77, 0xf7, 0x0f,
322 0x22, 0x07, 0x59, 0x8e, 0x63, 0x04, 0xf6, 0x04, 0x13, 0xc7, 0xf7, 0xff, 0x71, 0x8f,
323 0x19, 0xc3, 0xf6, 0x97, 0xb5, 0xe3, 0x9c, 0x4a, 0x37, 0x47, 0x0f, 0x00, 0x13, 0x07,
324 0x17, 0x24, 0x93, 0xe7, 0x17, 0x00, 0x9c, 0xca, 0x23, 0x10, 0xc8, 0x00, 0x11, 0xa0,
325 0x15, 0xcf, 0xdc, 0x46, 0x7d, 0x17, 0x85, 0x8b, 0xe5, 0xff, 0x9c, 0x4a, 0xf9, 0x9b,
326 0x9c, 0xca, 0xdc, 0x46, 0xc1, 0x8b, 0x8d, 0xeb, 0x83, 0x57, 0x08, 0x00, 0x63, 0x9b,
327 0xc7, 0x02, 0x23, 0xa6, 0xe6, 0x01, 0x09, 0x08, 0x89, 0x08, 0x09, 0x03, 0xe3, 0x62,
328 0xc8, 0xf9, 0x01, 0x45, 0x82, 0x80, 0xe3, 0xf9, 0xb8, 0xfe, 0xe3, 0xe7, 0xa8, 0xfe,
329 0x3e, 0x86, 0x41, 0xbf, 0x9c, 0x4a, 0x51, 0x55, 0xf9, 0x9b, 0x9c, 0xca, 0x82, 0x80,
330 0x93, 0x07, 0x00, 0x03, 0xdc, 0xc6, 0x71, 0x55, 0x82, 0x80, 0x69, 0x55, 0x82, 0x80};
332alignas(routine_align)
static uint8_t g_ch32_flash_write_page[ch32_flash_write_page_size] = {
333 0x63, 0x77, 0xb5, 0x12, 0x13, 0x0e, 0x06, 0x10, 0xb7, 0x28, 0x02, 0x40, 0xc1, 0x6e,
334 0x83, 0xa7, 0x08, 0x01, 0x37, 0x47, 0x0f, 0x00, 0x13, 0x07, 0x17, 0x24, 0xb3, 0xe7,
335 0xd7, 0x01, 0x23, 0xa8, 0xf8, 0x00, 0x11, 0xa0, 0x79, 0xcf, 0x83, 0xa7, 0xc8, 0x00,
336 0x7d, 0x17, 0x85, 0x8b, 0xfd, 0xfb, 0x37, 0x47, 0x0f, 0x00, 0x13, 0x07, 0x17, 0x24,
337 0xb7, 0x26, 0x02, 0x40, 0x11, 0xa0, 0x5d, 0xcb, 0xdc, 0x46, 0x7d, 0x17, 0x89, 0x8b,
338 0xe5, 0xff, 0x32, 0x88, 0xb3, 0x0f, 0xc5, 0x40, 0xb7, 0x26, 0x02, 0x40, 0x83, 0x47,
339 0x18, 0x00, 0x03, 0x43, 0x28, 0x00, 0x03, 0x4f, 0x08, 0x00, 0x03, 0x47, 0x38, 0x00,
340 0x42, 0x03, 0xa2, 0x07, 0xb3, 0xe7, 0x67, 0x00, 0x62, 0x07, 0xb3, 0xe7, 0xe7, 0x01,
341 0xd9, 0x8f, 0x33, 0x83, 0x0f, 0x01, 0x37, 0x47, 0x0f, 0x00, 0x23, 0x20, 0xf3, 0x00,
342 0x13, 0x07, 0x17, 0x24, 0x11, 0xa0, 0x25, 0xcb, 0xdc, 0x46, 0x7d, 0x17, 0x89, 0x8b,
343 0xe5, 0xff, 0x11, 0x08, 0xe3, 0x11, 0x0e, 0xfd, 0x9c, 0x4a, 0x37, 0x08, 0x20, 0x00,
344 0x37, 0x47, 0x0f, 0x00, 0xb3, 0xe7, 0x07, 0x01, 0x9c, 0xca, 0x13, 0x07, 0x17, 0x24,
345 0xb7, 0x26, 0x02, 0x40, 0x11, 0xa0, 0x39, 0xc3, 0xdc, 0x46, 0x7d, 0x17, 0x85, 0x8b,
346 0xe5, 0xff, 0x9c, 0x4a, 0x41, 0x77, 0x7d, 0x17, 0xf9, 0x8f, 0x9c, 0xca, 0xdc, 0x46,
347 0xc1, 0x8b, 0xb5, 0xe7, 0x32, 0x87, 0x19, 0xa0, 0x63, 0x04, 0xc7, 0x05, 0x83, 0x47,
348 0x17, 0x00, 0x03, 0x48, 0x07, 0x00, 0xb3, 0x06, 0xf7, 0x01, 0xa2, 0x07, 0xb3, 0xe7,
349 0x07, 0x01, 0x83, 0xd6, 0x06, 0x00, 0xc2, 0x07, 0xc1, 0x83, 0x09, 0x07, 0xe3, 0x80,
350 0xd7, 0xfe, 0x69, 0x55, 0x82, 0x80, 0x9c, 0x4a, 0x41, 0x77, 0x7d, 0x17, 0xf9, 0x8f,
351 0x9c, 0xca, 0x51, 0x55, 0x82, 0x80, 0x83, 0xa7, 0x08, 0x01, 0x41, 0x77, 0x7d, 0x17,
352 0xf9, 0x8f, 0x23, 0xa8, 0xf8, 0x00, 0x51, 0x55, 0x82, 0x80, 0xb7, 0x27, 0x02, 0x40,
353 0x13, 0x07, 0x00, 0x02, 0x13, 0x05, 0x05, 0x10, 0xd8, 0xc7, 0x13, 0x0e, 0x0e, 0x10,
354 0x13, 0x06, 0x06, 0x10, 0xe3, 0x62, 0xb5, 0xee, 0x01, 0x45, 0x82, 0x80, 0x93, 0x07,
355 0x00, 0x03, 0xdc, 0xc6, 0x71, 0x55, 0x82, 0x80};
358static void InitHotPathsOnce()
360 static bool inited =
false;
371 static_assert(
sizeof(g_ch32_flash_erase_hot) == ch32_flash_erase_hot_path_size);
372 static_assert(
sizeof(g_ch32_flash_write_hot) == ch32_flash_write_hot_loop_size);
373 static_assert(
sizeof(g_ch32_flash_write_page) == ch32_flash_write_page_size);
379 __builtin___clear_cache(
380 reinterpret_cast<char*
>(g_ch32_flash_erase_hot),
381 reinterpret_cast<char*
>(g_ch32_flash_erase_hot +
sizeof(g_ch32_flash_erase_hot)));
382 __builtin___clear_cache(
383 reinterpret_cast<char*
>(g_ch32_flash_write_hot),
384 reinterpret_cast<char*
>(g_ch32_flash_write_hot +
sizeof(g_ch32_flash_write_hot)));
385 __builtin___clear_cache(
386 reinterpret_cast<char*
>(g_ch32_flash_write_page),
387 reinterpret_cast<char*
>(g_ch32_flash_write_page +
sizeof(g_ch32_flash_write_page)));
389 g_ch32_flash_hot_paths.erase =
390 reinterpret_cast<CH32FlashEraseHotPathFn
>(g_ch32_flash_erase_hot);
391 g_ch32_flash_hot_paths.write_halfword =
392 reinterpret_cast<CH32FlashWriteHotLoopFn
>(g_ch32_flash_write_hot);
393 g_ch32_flash_hot_paths.write_page =
394 reinterpret_cast<CH32FlashWritePageFn
>(g_ch32_flash_write_page);
CH32 闪存驱动实现 / CH32 flash driver implementation.
CH32Flash(const FlashRegion *regions, size_t region_count, uint32_t start_address)
构造闪存对象 / 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.
LibXR 命名空间 / LibXR namespace.
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ OUT_OF_RANGE
超出范围 / Out of range
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
一段连续、大小相同的扇区 / A run of contiguous sectors of equal size
uint32_t address
第一个扇区的地址 / Address of the first sector