LCM — CH32V003 Light Control Module
Light Control Module, I2C slave
Loading...
Searching...
No Matches
user_data.c
Go to the documentation of this file.
1/********************************** (C) COPYRIGHT *******************************
2 * File Name : user_data.c
3 * Description : Доступ к 64-байтной странице User Option Bytes CH32V003.
4 *
5 * Карта страницы 0x1FFFF800 (64 байта):
6 *
7 * Смещ. Содержимое (официально)
8 * +0x00 RDPR + nRDPR
9 * +0x04 USER + nUSER
10 * +0x08 Data0 + nData0 ← user_data[0]
11 * +0x0C Data1 + nData1 ← user_data[1]
12 * +0x10 WRPR0 + nWRPR0
13 * +0x14 WRPR1 + nWRPR1
14 * +0x18 Reserved (48 байт) ← user_data[2…25] (по 2 байта на каждый data-байт)
15 *
16 * Запись: только erase всей страницы + program halfword (низкий байт = данные).
17 *********************************************************************************/
18
19#include "user_data.h"
20#include "ch32v00x_conf.h"
21
22/*
23 * Карта 16-битных слов (halfword) страницы option bytes, если смотреть
24 * на неё как на массив uint16_t ob[0..31] (64 байта / 2). Используется
25 * в UserData_LoadFromFlash()/UserData_Commit() ниже — там же и хранится
26 * актуальная нумерация индексов, здесь только сводка для навигации:
27 *
28 * ob[0] = RDPR + ~RDPR (защита чтения) — служебное, не трогаем
29 * ob[1] = USER + ~USER (конфиг. биты MCU) — служебное, не трогаем
30 * ob[2] = Data0 + ~Data0 → s_user_cache[0] — официальный пользовательский байт
31 * ob[3] = Data1 + ~Data1 → s_user_cache[1] — официальный пользовательский байт
32 * ob[4] = WRPR0 + ~WRPR0 (защита записи flash) — служебное, не трогаем
33 * ob[5] = WRPR1 + ~WRPR1 — служебное, не трогаем
34 * ob[6..7] = «Reserved» (WRPR2/3 по имени регистра, не используются
35 * аппаратно на CH32V003) — не проверяются на чтении, но
36 * бережно копируются как снимок при Commit (см. hold32[3]),
37 * чтобы случайно не занулить их при erase всей страницы.
38 * ob[8..31] = расширенная пользовательская область (USER_DATA_OFF_EXT_BASE
39 * … USER_DATA_CAPACITY-1) → s_user_cache[2..25].
40 *
41 * Во всех «данных» halfword старший байт — побитовая инверсия младшего
42 * (see UserData_VerifyHalfword) — так аппаратура/программатор проверяют
43 * целостность содержимого без отдельной контрольной суммы.
44 */
45
46/* Индекс первой свободной halfword в OB после WRPR1 (байтовое смещение 0x18). */
47#define USER_DATA_OB_HALFWORD_BASE 8U
48
49/* Локальные биты управления flash (как в ch32v00x_flash.c). */
50#define USER_DATA_CR_OPTPG_Set ((uint32_t)0x00000010)
51#define USER_DATA_CR_OPTPG_Reset ((uint32_t)0xFFFFFFEF)
52#define USER_DATA_CR_OPTER_Set ((uint32_t)0x00000020)
53#define USER_DATA_CR_OPTER_Reset ((uint32_t)0xFFFFFFDF)
54#define USER_DATA_CR_STRT_Set ((uint32_t)0x00000040)
55#define USER_DATA_CR_LOCK_Set ((uint32_t)0x00000080)
56#define USER_DATA_FLASH_KEY1 ((uint32_t)0x45670123)
57#define USER_DATA_FLASH_KEY2 ((uint32_t)0xCDEF89AB)
58
60static uint8_t s_dirty;
61
62/*********************************************************************
63 * @fn UserData_FlashWait
64 *
65 * @brief Дождаться завершения текущей операции flash и проверить её
66 * результат.
67 *
68 * @details Вызывается после КАЖДОЙ операции со страницей option bytes
69 * (erase, program halfword) — по спецификации периферии flash
70 * CH32V003 запись в CTLR (STRT/OPTPG/OPTER) только запускает
71 * операцию, а её фактическое выполнение асинхронно относительно
72 * шины: пока не снят бит BSY в STATR, содержимое затрагиваемой
73 * области не определено. Занимает от единиц до нескольких
74 * миллисекунд — вызывающий код (UserData_Commit) не должен
75 * работать из ISR.
76 *
77 * WRPRTERR (Write Protection Error) означает попытку записи в
78 * защищённую область — для option bytes практически не должно
79 * происходить, но проверяется на случай отсутствия разблокировки
80 * (см. UserData_UnlockFlash) или порчи регистров защиты. EOP
81 * (End Of Programming) — штатный флаг успешного завершения,
82 * просто сбрасывается, чтобы не «протух» до следующей проверки.
83 *
84 * @return USER_DATA_OK — операция завершилась штатно (EOP, без WRPRTERR);
85 * USER_DATA_ERR_FLASH — обнаружен WRPRTERR.
86 */
88{
89 while (FLASH_GetFlagStatus(FLASH_FLAG_BSY) != RESET) {
90 }
91
92 if (FLASH_GetFlagStatus(FLASH_FLAG_WRPRTERR) != RESET) {
93 FLASH_ClearFlag(FLASH_FLAG_WRPRTERR);
95 }
96
97 if (FLASH_GetFlagStatus(FLASH_FLAG_EOP) != RESET) {
98 FLASH_ClearFlag(FLASH_FLAG_EOP);
99 }
100
101 return USER_DATA_OK;
102}
103
104/*********************************************************************
105 * @fn UserData_UnlockFlash
106 *
107 * @brief Разблокировка основной flash и отдельно option bytes.
108 *
109 * @details Два независимых замка: FLASH_Unlock() (стандартная функция
110 * SPL, снимает LOCK через KEYR/FKEYR) открывает основную flash-
111 * память, а запись в OBKEYR фиксированной парой ключей KEY1/KEY2
112 * отдельно разблокирует именно страницу option bytes (OPTWRE в
113 * CTLR). Без второго шага биты OPTPG/OPTER в UserData_Commit()
114 * не будут иметь эффекта, хотя основная flash уже разблокирована.
115 */
116static void UserData_UnlockFlash(void)
117{
118 FLASH_Unlock();
119 FLASH->OBKEYR = USER_DATA_FLASH_KEY1;
120 FLASH->OBKEYR = USER_DATA_FLASH_KEY2;
121}
122
123/*********************************************************************
124 * @fn UserData_LockFlash
125 *
126 * @brief Заблокировать flash после программирования option bytes.
127 *
128 * @details Установка бита LOCK в CTLR блокирует ОБА замка, снятых в
129 * UserData_UnlockFlash() (основную flash и option bytes) —
130 * отдельного «lock» для OBKEYR не требуется.
131 */
132static void UserData_LockFlash(void)
133{
134 FLASH->CTLR |= USER_DATA_CR_LOCK_Set;
135}
136
137/*********************************************************************
138 * @fn UserData_VerifyHalfword
139 *
140 * @brief Проверить целостность одной 16-битной ячейки option bytes.
141 *
142 * @param hw — прочитанное из option page 16-битное слово (младший
143 * байт — данные, старший — ожидаемая инверсия данных).
144 *
145 * @details В option bytes CH32V003 каждый байт данных аппаратно дублируется
146 * инвертированным байтом-«напарником» в том же 16-битном слове —
147 * так исключается ложное считывание при частичном сбое ячейки
148 * (без этого отдельного бита чётности/CRC на этой странице нет).
149 * Два допустимых состояния: полностью стёртая ячейка (0xFFFF —
150 * инверсия 0xFF тоже 0xFF, совпадение случайное, но проверяется
151 * отдельно первым условием) или корректно запрограммированная
152 * (data ^ inv == 0xFF). Любое другое сочетание — повреждение
153 * (например, прерванная запись при потере питания).
154 *
155 * @return USER_DATA_OK — ячейка цела (стёрта или корректно записана);
156 * USER_DATA_ERR_FLASH — data/~data не согласованы.
157 */
159{
160 uint8_t data = (uint8_t)hw;
161 uint8_t inv = (uint8_t)(hw >> 8);
162
163 if (data == 0xFFU && inv == 0xFFU) {
164 return USER_DATA_OK;
165 }
166 if ((uint8_t)(data ^ inv) == 0xFFU) {
167 return USER_DATA_OK;
168 }
169 return USER_DATA_ERR_FLASH;
170}
171
172/*********************************************************************
173 * @fn UserData_CacheFillErased
174 *
175 * @brief Заполнить RAM-кэш значением 0xFF (логически стёртое состояние).
176 *
177 * @details 0xFF выбрано не произвольно: это то же значение, которое
178 * физически имеет каждая ячейка flash сразу после erase (см.
179 * UserData_VerifyHalfword) — так поведение «данные повреждены/
180 * отсутствуют» в RAM-кэше неотличимо от «страница только что
181 * стёрта», и вызывающий код (LCM_LoadConfig) может использовать
182 * общую проверку magic-байта для обоих случаев.
183 */
185{
186 uint8_t i;
187
188 for (i = 0U; i < USER_DATA_CAPACITY; i++) {
189 s_user_cache[i] = 0xFFU;
190 }
191}
192
193/*********************************************************************
194 * @fn UserData_LoadFromFlash
195 *
196 * @brief Считать пользовательские байты из option page в s_user_cache.
197 *
198 * @details Из каждой 16-битной ячейки в кэш берётся только младший байт
199 * (старший — контрольная инверсия, см. UserData_VerifyHalfword).
200 * Перед копированием ЛЮБОГО байта в кэш сначала проверяются
201 * служебные ячейки ob[0]/ob[1] (RDPR/USER) и ob[4]/ob[5]
202 * (WRPR0/WRPR1, см. карту в начале файла) — если повреждена
203 * хотя бы одна из них, всей странице нельзя доверять (например,
204 * питание пропало в середине предыдущего Commit), и функция
205 * прерывается ДО того, как начнёт заполнять s_user_cache —
206 * вызывающий UserData_Init() в этом случае откатится на
207 * UserData_CacheFillErased() и вернёт ошибку целиком, не
208 * оставляя кэш в частично заполненном состоянии.
209 *
210 * ob[6]/ob[7] («Reserved») сознательно не проверяются — они не
211 * используются приложением, их integrity не влияет на данные
212 * LCM; порядок проверок оставляет их «как есть» на аппаратном
213 * уровне без дополнительных требований.
214 *
215 * Data0/Data1 (ob[2]/ob[3]) и расширенная область (ob[8…31])
216 * проверяются и копируются по одному байту — при первой же
217 * повреждённой ячейке функция также прерывается сразу, без
218 * попытки восстановить оставшиеся байты.
219 */
221{
222 const uint16_t *ob = (const uint16_t *)USER_DATA_FLASH_BASE;
224 uint8_t i;
225
226 /* Служебные ячейки: RDPR/USER (защита чтения, конфигурация MCU) */
227 st = UserData_VerifyHalfword(ob[0]);
228 if (st != USER_DATA_OK) {
229 return st;
230 }
231 st = UserData_VerifyHalfword(ob[1]);
232 if (st != USER_DATA_OK) {
233 return st;
234 }
235 /* Служебные ячейки: WRPR0/WRPR1 (защита записи flash по секторам) */
236 st = UserData_VerifyHalfword(ob[4]);
237 if (st != USER_DATA_OK) {
238 return st;
239 }
240 st = UserData_VerifyHalfword(ob[5]);
241 if (st != USER_DATA_OK) {
242 return st;
243 }
244
245 /* Официальные пользовательские байты Data0/Data1 → s_user_cache[0..1] */
246 st = UserData_VerifyHalfword(ob[2]);
247 if (st != USER_DATA_OK) {
248 return st;
249 }
250 s_user_cache[0] = (uint8_t)ob[2];
251
252 st = UserData_VerifyHalfword(ob[3]);
253 if (st != USER_DATA_OK) {
254 return st;
255 }
256 s_user_cache[1] = (uint8_t)ob[3];
257
258 /* Расширенная область (Reserved, ob[8…31]) → s_user_cache[2..25] */
259 for (i = USER_DATA_OFF_EXT_BASE; i < USER_DATA_CAPACITY; i++) {
260 uint16_t hw = ob[USER_DATA_OB_HALFWORD_BASE + (i - USER_DATA_OFF_EXT_BASE)];
261
263 if (st != USER_DATA_OK) {
264 return st;
265 }
266 s_user_cache[i] = (uint8_t)hw;
267 }
268
269 return USER_DATA_OK;
270}
271
272/*********************************************************************
273 * @fn UserData_ProgramHalfwordRaw
274 *
275 * @brief Записать готовое 16-битное слово целиком (для служебных
276 * ячеек: RDPR, USER, WRPR0/1, Reserved WRPR2/3).
277 *
278 * @param addr — адрес halfword в option page (после erase — 0xFFFF).
279 * @param value — оба байта уже подготовлены вызывающим кодом (см.
280 * снимок hold[] в UserData_Commit — там value — это старое
281 * значение data+~data, считанное ДО erase, чтобы восстановить
282 * служебные биты «как было»).
283 *
284 * @details В отличие от UserData_ProgramUserByte(), сюда передаётся
285 * именно 16-битное значение (не 8-битный «полезный» байт) —
286 * используется, когда старший байт слова не является простой
287 * инверсией младшего в терминах бизнес-логики приложения (для
288 * RDPR/USER/WRPR это пара регистр+его собственная аппаратная
289 * инверсия, формируемая контроллером при исходной записи).
290 */
291static UserData_Status UserData_ProgramHalfwordRaw(volatile uint16_t *addr, uint16_t value)
292{
293 *addr = value;
294 return UserData_FlashWait();
295}
296
297/*********************************************************************
298 * @fn UserData_ProgramUserByte
299 *
300 * @brief Записать один пользовательский байт (Data0/Data1 или байт
301 * расширенной области).
302 *
303 * @param addr — адрес halfword в option page.
304 * @param data — «полезный» байт (0…255), который должен получить
305 * пользователь при последующем чтении.
306 *
307 * @details Пишется только младший байт значения (старший = 0x00 в
308 * записываемом uint16_t) — контроллер flash CH32V003 сам
309 * подставляет побитовую инверсию data в старший байт слова при
310 * программировании option bytes (аппаратная особенность именно
311 * этой страницы, в отличие от «сырых» служебных ячеек через
312 * UserData_ProgramHalfwordRaw). Результат затем можно проверить
313 * через UserData_VerifyHalfword().
314 */
315static UserData_Status UserData_ProgramUserByte(volatile uint16_t *addr, uint8_t data)
316{
317 *addr = (uint16_t)data;
318 return UserData_FlashWait();
319}
320
321/*********************************************************************
322 * @fn UserData_Commit
323 *
324 * @brief Сохранить s_user_cache в flash с сохранением служебных option bytes.
325 *
326 * @details Единственный способ изменить option bytes на CH32V003 —
327 * стереть страницу ЦЕЛИКОМ (нет операции «стереть один байт»),
328 * поэтому нельзя просто перезаписать только Data0/Data1 и
329 * расширенную область: это уничтожило бы RDPR/USER/WRPR* —
330 * защиту чтения/записи и системные настройки MCU. Алгоритм:
331 *
332 * 1) Снимок (hold[]) — читаем ТЕКУЩЕЕ содержимое всех 8 служебных
333 * halfword (ob[0..7], см. карту в начале файла) ДО erase,
334 * чтобы потом записать их обратно «как было». Пользовательские
335 * Data0/Data1 (hold32[1]) собираются не из flash, а из
336 * s_user_cache — так одной и той же процедурой восстановления
337 * (см. шаг 3) применяется и новое пользовательское значение.
338 * 2) Erase всей 64-байтной страницы (OPTER+STRT). После этого
339 * ВСЕ 32 halfword читаются как 0xFFFF, независимо от того,
340 * что было раньше.
341 * 3) Program — сначала восстанавливаем 8 служебных halfword из
342 * снимка (обычный OPTPG, «сырые» значения), затем поверх
343 * расширенной области пишем НЕ-0xFF байты из s_user_cache
344 * через UserData_ProgramUserByte(). Байты со значением 0xFF
345 * пропускаются намеренно — сразу после erase они и так 0xFF
346 * (лишняя операция записи не нужна и лишь расходует ресурс
347 * цикла P/E flash).
348 *
349 * При ошибке на любом шаге после erase (WRPRTERR/EOP-фейл)
350 * функция сразу прерывается и возвращает ошибку — страница
351 * может остаться частично восстановленной (это ограничение
352 * самого железа: erase уже не откатить). s_dirty сбрасывается
353 * в 0 только при полном успехе.
354 */
356{
357 volatile uint16_t *ob = (volatile uint16_t *)USER_DATA_FLASH_BASE;
358 uint16_t hold[8];
359 uint32_t *hold32 = (uint32_t *)hold;
360 const uint32_t *ob32 = (const uint32_t *)USER_DATA_FLASH_BASE;
362 uint8_t i;
363
364 if (!s_dirty) {
365 return USER_DATA_OK;
366 }
367
368 /* Снимок служебных полей до стирания страницы (побайтно как uint32,
369 т.к. ob32[k] покрывает пару halfword ob[2k]/ob[2k+1] — см. карту). */
370 hold32[0] = ob32[0]; /* RDPR, USER */
371 hold32[1] = (uint32_t)s_user_cache[0] | ((uint32_t)s_user_cache[1] << 16); /* Data0, Data1 — новое значение из кэша */
372 hold32[2] = ob32[2]; /* WRPR0, WRPR1 */
373 hold32[3] = ob32[3]; /* Reserved WRPR2, WRPR3 */
374
376
377 /* Стирание всей 64-байтной user option page (одной операцией —
378 частичное стирание аппаратно не поддерживается). */
379 FLASH->CTLR |= USER_DATA_CR_OPTER_Set;
380 FLASH->CTLR |= USER_DATA_CR_STRT_Set;
381 st = UserData_FlashWait();
382 if (st != USER_DATA_OK) {
383 FLASH->CTLR &= USER_DATA_CR_OPTER_Reset;
385 return st;
386 }
387 FLASH->CTLR &= USER_DATA_CR_OPTER_Reset;
388
389 /* Восстановление 8 служебных halfword (ob[0..7]) из снимка hold[] —
390 без этого шага MCU лишится настроек RDPR/USER/WRPR* после erase. */
391 FLASH->CTLR |= USER_DATA_CR_OPTPG_Set;
392 for (i = 0; i < 8U; i++) {
393 st = UserData_ProgramHalfwordRaw(&ob[i], hold[i]);
394 if (st != USER_DATA_OK) {
395 FLASH->CTLR &= USER_DATA_CR_OPTPG_Reset;
397 return st;
398 }
399 }
400
401 /* Расширенная пользовательская область (байты 2…25): пишем только
402 непустые значения — 0xFF после erase уже установлен аппаратно. */
403 for (i = USER_DATA_OFF_EXT_BASE; i < USER_DATA_CAPACITY; i++) {
404 if (s_user_cache[i] != 0xFFU) {
407 s_user_cache[i]);
408 if (st != USER_DATA_OK) {
409 FLASH->CTLR &= USER_DATA_CR_OPTPG_Reset;
411 return st;
412 }
413 }
414 }
415
416 FLASH->CTLR &= USER_DATA_CR_OPTPG_Reset;
418
419 s_dirty = 0U;
420 return USER_DATA_OK;
421}
422
423/*********************************************************************
424 * @fn UserData_Init
425 *
426 * @brief Загрузить содержимое option bytes в RAM-кэш при старте.
427 *
428 * @details Проверка BSY ПЕРЕД чтением — защита от редкого случая,
429 * когда предыдущая операция flash (например, зависшая после
430 * сброса питания в середине программирования) ещё не завершена;
431 * в этом состоянии содержимое страницы недостоверно, поэтому
432 * UserData_LoadFromFlash() даже не вызывается. И здесь, и при
433 * ошибке чтения кэш откатывается на «всё 0xFF» — вызывающий код
434 * (LCM_LoadConfig) распознаёт это как «нет валидной конфигурации»
435 * и применяет заводские значения по несовпадению magic-байта.
436 */
438{
440
441 if (FLASH_GetFlagStatus(FLASH_FLAG_BSY) != RESET) {
443 s_dirty = 0U;
444 return USER_DATA_ERR_BUSY;
445 }
446
448 if (st != USER_DATA_OK) {
450 s_dirty = 0U;
451 return st;
452 }
453
454 s_dirty = 0U;
455 return USER_DATA_OK;
456}
457
458uint8_t UserData_Capacity(void)
459{
460 return USER_DATA_CAPACITY;
461}
462
463/*********************************************************************
464 * @fn UserData_CheckRange
465 *
466 * @brief Проверить корректность пары (offset, len) относительно
467 * логического массива RAM-кэша.
468 *
469 * @details len == 0 считается ошибкой параметра (а не «нулевой операцией
470 * без эффекта») — вызывающий код почти всегда ожидает реального
471 * чтения/записи хотя бы одного байта, а len == 0 чаще всего
472 * признак ошибки в вызывающем коде. Сложение offset+len ведётся
473 * в uint16_t, чтобы избежать переполнения uint8_t при offset,
474 * близком к 255 (даже если такой offset для 26-байтного кэша
475 * заведомо некорректен).
476 */
477static UserData_Status UserData_CheckRange(uint8_t offset, uint8_t len)
478{
479 if (len == 0U) {
480 return USER_DATA_ERR_PARAM;
481 }
482 if ((uint16_t)offset + (uint16_t)len > USER_DATA_CAPACITY) {
483 return USER_DATA_ERR_RANGE;
484 }
485 return USER_DATA_OK;
486}
487
488UserData_Status UserData_Read(uint8_t offset, uint8_t *buf, uint8_t len)
489{
491 uint8_t i;
492
493 if (buf == NULL) {
494 return USER_DATA_ERR_PARAM;
495 }
496
497 st = UserData_CheckRange(offset, len);
498 if (st != USER_DATA_OK) {
499 return st;
500 }
501
502 for (i = 0; i < len; i++) {
503 buf[i] = s_user_cache[offset + i];
504 }
505
506 return USER_DATA_OK;
507}
508
509UserData_Status UserData_Write(uint8_t offset, const uint8_t *buf, uint8_t len)
510{
512 uint8_t i;
513
514 if (buf == NULL) {
515 return USER_DATA_ERR_PARAM;
516 }
517
518 st = UserData_CheckRange(offset, len);
519 if (st != USER_DATA_OK) {
520 return st;
521 }
522
523 for (i = 0; i < len; i++) {
524 s_user_cache[offset + i] = buf[i];
525 }
526
527 s_dirty = 1U;
528 return USER_DATA_OK;
529}
530
531UserData_Status UserData_ReadByte(uint8_t offset, uint8_t *value)
532{
533 if (value == NULL) {
534 return USER_DATA_ERR_PARAM;
535 }
536 return UserData_Read(offset, value, 1U);
537}
538
539UserData_Status UserData_WriteByte(uint8_t offset, uint8_t value)
540{
541 return UserData_Write(offset, &value, 1U);
542}
543
544UserData_Status UserData_Fill(uint8_t offset, uint8_t len, uint8_t value)
545{
547 uint8_t i;
548
549 st = UserData_CheckRange(offset, len);
550 if (st != USER_DATA_OK) {
551 return st;
552 }
553
554 for (i = 0; i < len; i++) {
555 s_user_cache[offset + i] = value;
556 }
557
558 s_dirty = 1U;
559 return USER_DATA_OK;
560}
561
563{
564 return UserData_Fill(0U, USER_DATA_CAPACITY, 0xFFU);
565}
566
567uint8_t UserData_IsDirty(void)
568{
569 return s_dirty;
570}
571
572uint8_t *UserData_Buffer(void)
573{
574 return s_user_cache;
575}
576
577const uint8_t *UserData_ConstBuffer(void)
578{
579 return s_user_cache;
580}
581
583{
584 uint8_t i;
585
586 if (page == NULL) {
587 return USER_DATA_ERR_PARAM;
588 }
589
590 for (i = 0; i < USER_DATA_FLASH_PAGE_SIZE; i++) {
591 page[i] = *(volatile uint8_t *)(USER_DATA_FLASH_BASE + i);
592 }
593
594 return USER_DATA_OK;
595}
UserData_Status UserData_Write(uint8_t offset, const uint8_t *buf, uint8_t len)
Definition user_data.c:509
uint8_t UserData_Capacity(void)
Definition user_data.c:458
UserData_Status UserData_Commit(void)
Definition user_data.c:355
uint8_t * UserData_Buffer(void)
Definition user_data.c:572
static void UserData_LockFlash(void)
Definition user_data.c:132
UserData_Status UserData_Init(void)
Definition user_data.c:437
static void UserData_CacheFillErased(void)
Definition user_data.c:184
static UserData_Status UserData_LoadFromFlash(void)
Definition user_data.c:220
#define USER_DATA_CR_LOCK_Set
Definition user_data.c:55
#define USER_DATA_FLASH_KEY2
Definition user_data.c:57
static uint8_t s_dirty
Definition user_data.c:60
static UserData_Status UserData_FlashWait(void)
Definition user_data.c:87
UserData_Status UserData_Fill(uint8_t offset, uint8_t len, uint8_t value)
Definition user_data.c:544
static void UserData_UnlockFlash(void)
Definition user_data.c:116
UserData_Status UserData_Erase(void)
Definition user_data.c:562
static UserData_Status UserData_VerifyHalfword(uint16_t hw)
Definition user_data.c:158
uint8_t UserData_IsDirty(void)
Definition user_data.c:567
#define USER_DATA_CR_OPTER_Set
Definition user_data.c:52
static uint8_t s_user_cache[USER_DATA_CAPACITY]
Definition user_data.c:59
UserData_Status UserData_ReadByte(uint8_t offset, uint8_t *value)
Definition user_data.c:531
UserData_Status UserData_Read(uint8_t offset, uint8_t *buf, uint8_t len)
Definition user_data.c:488
#define USER_DATA_CR_OPTER_Reset
Definition user_data.c:53
#define USER_DATA_CR_OPTPG_Reset
Definition user_data.c:51
static UserData_Status UserData_ProgramUserByte(volatile uint16_t *addr, uint8_t data)
Definition user_data.c:315
#define USER_DATA_CR_STRT_Set
Definition user_data.c:54
UserData_Status UserData_WriteByte(uint8_t offset, uint8_t value)
Definition user_data.c:539
#define USER_DATA_FLASH_KEY1
Definition user_data.c:56
#define USER_DATA_OB_HALFWORD_BASE
Definition user_data.c:47
#define USER_DATA_CR_OPTPG_Set
Definition user_data.c:50
const uint8_t * UserData_ConstBuffer(void)
Definition user_data.c:577
UserData_Status UserData_ReadFlashPageRaw(uint8_t *page)
Definition user_data.c:582
static UserData_Status UserData_ProgramHalfwordRaw(volatile uint16_t *addr, uint16_t value)
Definition user_data.c:291
static UserData_Status UserData_CheckRange(uint8_t offset, uint8_t len)
Definition user_data.c:477
#define USER_DATA_FLASH_PAGE_SIZE
Definition user_data.h:34
#define USER_DATA_FLASH_BASE
Definition user_data.h:31
#define USER_DATA_OFF_EXT_BASE
Definition user_data.h:42
UserData_Status
Definition user_data.h:44
@ USER_DATA_ERR_PARAM
Definition user_data.h:46
@ USER_DATA_OK
Definition user_data.h:45
@ USER_DATA_ERR_BUSY
Definition user_data.h:49
@ USER_DATA_ERR_RANGE
Definition user_data.h:47
@ USER_DATA_ERR_FLASH
Definition user_data.h:48
#define USER_DATA_CAPACITY
Definition user_data.h:37