libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_flash.cpp
1// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
2#include "ch32_flash.hpp"
3
4using namespace LibXR;
5
6// 访问时钟切半
7static void flash_set_access_clock_half_sysclk(void)
8{
9 FLASH_Unlock(); // Unlock FPEC/CTL.
10 FLASH->CTLR &= ~(1u << 25); // SCKMOD=0 => SYSCLK/2.
11 FLASH_Lock(); // Optional relock.
12}
13
14// 访问时钟还原
15static void flash_set_access_clock_sysclk(void)
16{
17 FLASH_Unlock();
18 FLASH->CTLR |= (1u << 25); // SCKMOD=1 => access clock = SYSCLK.
19 FLASH_Lock();
20}
21
22static inline void flash_exit_enhanced_read_if_enabled()
23{
24 if (FLASH->STATR & (1u << 7))
25 { // EHMODS=1?
26 FLASH_Unlock();
27 FLASH->CTLR &= ~(1u << 24); // EHMOD=0.
28 FLASH->CTLR |= (1u << 22); // RSENACT=1 (write-only, auto-cleared by hardware).
29 FLASH_Lock();
30 }
31}
32
33static inline void flash_fast_unlock()
34{
35 FLASH_Unlock(); // Regular unlock sequence (KEYR).
36 // Fast-mode unlock sequence (MODEKEYR KEY1/KEY2).
37 FLASH->MODEKEYR = 0x45670123u;
38 FLASH->MODEKEYR = 0xCDEF89ABu;
39}
40
41static inline void flash_fast_lock()
42{
43 FLASH_Unlock();
44 FLASH->CTLR |= (1u << 15); // FLOCK=1.
45 FLASH_Lock();
46}
47
48static bool flash_wait_busy_clear(uint32_t spin = 1000000u)
49{
50 while (FLASH->STATR & 0x1u)
51 {
52 if (spin-- == 0)
53 {
54 return false;
55 }
56 }
57 return true;
58}
59
60inline void CH32Flash::ClearFlashFlagsOnce()
61{
62#ifdef FLASH_FLAG_BSY
63 FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
64#else
65 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
66#endif
67}
68
69CH32Flash::CH32Flash(const FlashSector* sectors, size_t sector_count, size_t start_sector)
70 : Flash(sectors[start_sector - 1].size, MinWriteSize(),
71 {reinterpret_cast<void*>(sectors[start_sector - 1].address),
72 sectors[sector_count - 1].address - sectors[start_sector - 1].address +
73 sectors[sector_count - 1].size}),
74 sectors_(sectors),
75 base_address_(sectors[start_sector - 1].address),
76 sector_count_(sector_count)
77{
78}
79
80ErrorCode CH32Flash::Erase(size_t offset, size_t size)
81{
82 if (size == 0)
83 {
84 return ErrorCode::ARG_ERR;
85 }
86
87 ASSERT(SystemCoreClock <= 120000000);
88
89 const uint32_t START_ADDR = base_address_ + static_cast<uint32_t>(offset);
90 if (!IsInRange(START_ADDR, size))
91 {
92 return ErrorCode::OUT_OF_RANGE;
93 }
94 const uint32_t END_ADDR = START_ADDR + static_cast<uint32_t>(size);
95
96 // 1) 退出增强读模式
97 flash_exit_enhanced_read_if_enabled(); // 进入擦写前必须退出 EHMOD
98
99 // 2) 访问时钟降为 SYSCLK/2(SCKMOD=0)
100 flash_set_access_clock_half_sysclk();
101
102 // 3) 解锁:常规 + 快速模式
103 flash_fast_unlock();
104 ClearFlashFlagsOnce();
105
106 // 4) 计算 256B 对齐区间
107 const uint32_t FAST_SZ = 256u;
108 const uint32_t ERASE_BEGIN = START_ADDR & ~(FAST_SZ - 1u);
109 const uint32_t ERASE_END = (END_ADDR + FAST_SZ - 1u) & ~(FAST_SZ - 1u);
110 if (ERASE_END <= ERASE_BEGIN)
111 {
112 flash_fast_lock();
113 flash_set_access_clock_sysclk();
114 return ErrorCode::OK;
115 }
116
117 // 5) 开启快速页擦除:CTLR.FTER=1
118 FLASH->CTLR |= (1u << 17);
119
120 // 6) 逐页(256B)擦除
121 for (uint32_t adr = ERASE_BEGIN; adr < ERASE_END; adr += FAST_SZ)
122 {
123 // 写入页首地址
124 FLASH->ADDR = adr;
125
126 // 触发 STRT
127 FLASH->CTLR |= (1u << 6);
128
129 // 等待 BSY=0
130 if (!flash_wait_busy_clear())
131 {
132 // 关闭 FTER & 复锁 & 还原时钟后返回
133 FLASH->CTLR &= ~(1u << 17);
134 flash_fast_lock();
135 flash_set_access_clock_sysclk();
136 return ErrorCode::FAILED;
137 }
138
139 // 检查错误并清标志
140 if (FLASH->STATR & (1u << 4))
141 { // WRPRTERR
142 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
143 FLASH->CTLR &= ~(1u << 17);
144 flash_fast_lock();
145 flash_set_access_clock_sysclk();
146 return ErrorCode::FAILED;
147 }
148
149 // 成功:清 EOP
150 FLASH_ClearFlag(FLASH_FLAG_EOP);
151 }
152
153 // 7) 关闭快速页擦除位,复锁快速模式与常规锁,并恢复访问时钟
154 FLASH->CTLR &= ~(1u << 17); // FTER=0
155 flash_fast_lock();
156 flash_set_access_clock_sysclk();
157
158 return ErrorCode::OK;
159}
160
161ErrorCode CH32Flash::Write(size_t offset, ConstRawData data)
162{
163 ASSERT(SystemCoreClock <= 120000000);
164
165 // 退出增强读模式 → 减少失败风险(手册要求在编程/擦除前退出)
166 flash_exit_enhanced_read_if_enabled();
167
168 // 访问时钟切半(SCKMOD=0)
169 flash_set_access_clock_half_sysclk();
170
171 if (!data.addr_ || data.size_ == 0)
172 {
173 flash_set_access_clock_sysclk();
174 ASSERT(false);
175 return ErrorCode::ARG_ERR;
176 }
177
178 const uint32_t START_ADDR = base_address_ + static_cast<uint32_t>(offset);
179 if (!IsInRange(START_ADDR, data.size_))
180 {
181 flash_set_access_clock_sysclk();
182 ASSERT(false);
183 return ErrorCode::OUT_OF_RANGE;
184 }
185
186 const uint8_t* src = reinterpret_cast<const uint8_t*>(data.addr_);
187 const uint32_t END_ADDR = START_ADDR + static_cast<uint32_t>(data.size_);
188
189 FLASH_Unlock();
190 ClearFlashFlagsOnce();
191
192 const uint32_t HW_BEGIN = START_ADDR & ~1u;
193 const uint32_t HW_END = (END_ADDR + 1u) & ~1u; // 向上取整到半字
194
195 for (uint32_t hw = HW_BEGIN; hw < HW_END; hw += 2u)
196 {
197 volatile uint16_t* p = reinterpret_cast<volatile uint16_t*>(hw);
198 volatile uint16_t orig = *p;
199 volatile uint16_t val = orig;
200
201 if (hw >= START_ADDR && hw < END_ADDR)
202 {
203 uint8_t b0 = src[hw - START_ADDR];
204 val = static_cast<uint16_t>((val & 0xFF00u) | b0);
205 }
206 if ((hw + 1u) >= START_ADDR && (hw + 1u) < END_ADDR)
207 {
208 uint8_t b1 = src[(hw + 1u) - START_ADDR];
209 val = static_cast<uint16_t>((val & 0x00FFu) | (static_cast<uint16_t>(b1) << 8));
210 }
211
212 if (val == orig)
213 {
214 continue; // 无变化
215 }
216
217 // 未擦除单元禁止 0->1 抬位
218 if (((~orig) & val) != 0u && orig != 0xE339u)
219 {
220 FLASH_Lock();
221 flash_set_access_clock_sysclk();
222 ASSERT(false);
223 return ErrorCode::FAILED;
224 }
225
226 if (FLASH_ProgramHalfWord(hw, val) != FLASH_COMPLETE)
227 {
228 FLASH_Lock();
229 flash_set_access_clock_sysclk();
230 ASSERT(false);
231 return ErrorCode::FAILED;
232 }
233
234 ASSERT(*p == val);
235
236 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
237 }
238
239 FLASH_Lock();
240 flash_set_access_clock_sysclk();
241 return ErrorCode::OK;
242}
243
244bool CH32Flash::IsInRange(uint32_t addr, size_t size) const
245{
246 const uint32_t BEGIN = base_address_;
247 const uint32_t LIMIT =
248 sectors_[sector_count_ - 1].address + sectors_[sector_count_ - 1].size;
249 const uint32_t END = addr + static_cast<uint32_t>(size);
250 return (addr >= BEGIN) && (END <= LIMIT) && (END >= addr);
251}
252
253// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
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. 向闪存写入数据。
常量原始数据封装类。 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:19
LibXR 命名空间
Definition ch32_can.hpp:14
闪存扇区描述 / Flash sector descriptor
uint32_t size
扇区大小(字节) / Sector size in bytes
uint32_t address
扇区起始地址 / Sector base address