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