1 /**
2 ******************************************************************************
3 * @file EEPROM_Emul/Core/eeprom_emul.c
4 * @author MCD Application Team
5 * @brief This file provides all the EEPROM emulation firmware functions.
6 @verbatim
7 ==============================================================================
8 ##### How to use this driver #####
9 ==============================================================================
10 [..]
11 This driver provides functions to initialize EEPROM emulation, to read and
12 write EEPROM variables, and to cleanup FLASH pages used by EEPROM emulation.
13
14 (#) EEPROM emulation initialization functions:
15 (++) Format the FLASH pages used by EEPROM emulation using EE_Format().
16 This function is optionally used, it can be called the very first
17 time EEPROM emulation is used, to prepare FLASH pages for EEPROM
18 emulation with empty EEPROM variables. It can also be called at
19 any time, to flush all EEPROM variables.
20 (++) Initialize EEPROM emulation, and restore the FLASH pages used by
21 EEPROM emulation to a known good state in case of power loss
22 using EE_Init(). It must be performed at system start up.
23
24 (#) EEPROM variables access functions:
25 (++) Write EEPROM variable using EE_WriteVariableXbits() functions
26 A Clean Up request can be raised as return parameter in case
27 FLASH pages used by EEPROM emulation, are full.
28 (++) Read EEPROM variable using EE_ReadVariableXbits() functions
29
30 (#) Clean up functions of FLASH pages, used by EEPROM emulation:
31 (++) There Two modes of erasing:
32 (+++) Polling mode using EE_CleanUp() function
33 (+++) Interrupt mode using EE_CleanUp_IT() function
34 (++) Callback function called when the clean up operation in interrupt
35 mode, is finished: EE_EndOfCleanup_UserCallback()
36
37 @endverbatim
38 ******************************************************************************
39 * @attention
40 *
41 * <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
42 * All rights reserved.</center></h2>
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted, provided that the following conditions are met:
46 *
47 * 1. Redistribution of source code must retain the above copyright notice,
48 * this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright notice,
50 * this list of conditions and the following disclaimer in the documentation
51 * and/or other materials provided with the distribution.
52 * 3. Neither the name of STMicroelectronics nor the names of other
53 * contributors to this software may be used to endorse or promote products
54 * derived from this software without specific written permission.
55 * 4. This software, including modifications and/or derivative works of this
56 * software, must execute solely and exclusively on microcontroller or
57 * microprocessor devices manufactured by or for STMicroelectronics.
58 * 5. Redistribution and use of this software other than as permitted under
59 * this license is void and will automatically terminate your rights under
60 * this license.
61 *
62 * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
63 * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
64 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
65 * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
66 * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
67 * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
68 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
69 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
70 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
71 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
72 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
73 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
74 *
75 ******************************************************************************
76 */
77
78 /* Includes ------------------------------------------------------------------*/
79 #include "eeprom_emul.h"
80
81 /** @defgroup EEPROM_Emulation EEPROM_Emulation
82 * @{
83 */
84
85 /* Private typedef -----------------------------------------------------------*/
86 /** @defgroup EEPROM_Private_Structures EEPROM Private Structures
87 * @{
88 */
89
90 /**
91 * @brief EE Find Type structure definition.
92 */
93 /* Type of find requested :
94 READ --> page in active state
95 WRITE --> page in receive state or active state
96 ERASE --> page in erased state */
97 typedef enum {
98 FIND_READ_PAGE,
99 FIND_WRITE_PAGE,
100 FIND_ERASE_PAGE
101 } EE_Find_type;
102
103 /**
104 * @brief EE State Type structure definition.
105 */
106 /* Type of state requested :
107 ERASED --> page is erased
108 RECEIVE --> page used during data transfer when no more space available in the system
109 ACTIVE --> page contains valid data and is not full
110 VALID --> page contains valid data and is full
111 ERASING --> page used during transfer, should be erased after transfer
112 INVALID --> page invalid state */
113 typedef enum {
114 STATE_PAGE_ERASED,
115 STATE_PAGE_RECEIVE,
116 STATE_PAGE_ACTIVE,
117 STATE_PAGE_VALID,
118 STATE_PAGE_ERASING,
119 STATE_PAGE_INVALID
120 } EE_State_type;
121
122 /**
123 * @brief EE Transfer Type structure definition.
124 */
125 /* Definition of the different type of page transfer
126 NORMAL -> copy data page source to page destination
127 RECOVER -> resume page transfer that has been interrupted */
128 typedef enum {
129 EE_TRANSFER_NORMAL,
130 EE_TRANSFER_RECOVER
131 } EE_Transfer_type;
132
133 /**
134 * @brief EE State Reliability structure definition.
135 */
136 /* Reliability of page state:
137 RELIABLE -> header of page is not corrupted, state is reliable
138 CORRUPTED -> header of page is corrupted, state is corrupted */
139 typedef enum {
140 STATE_RELIABLE,
141 STATE_CORRUPTED
142 } EE_State_Reliability;
143
144 /**
145 * @}
146 */
147
148 /* Private variables ---------------------------------------------------------*/
149 /** @defgroup EEPROM_Private_Variables EEPROM Private Variables
150 * @{
151 */
152
153 /* Global variables used to store eeprom status */
154 uint16_t* puhVirtAdd = NULL; /*!< Pointer to Virtual addresses Table defined by user */
155 uint16_t uhNbWrittenElements = 0U; /*!< Nb of elements written in valid and active pages */
156 uint8_t ubCurrentActivePage = 0U; /*!< Current active page (can be active or receive state) */
157 uint32_t uwAddressNextWrite = PAGE_HEADER_SIZE; /*!< Initialize write position just after page header */
158
159 /**
160 * @}
161 */
162
163 /* Private function prototypes -----------------------------------------------*/
164 /** @defgroup EEPROM_Private_Functions EEPROM Private Functions
165 * @{
166 */
167
168 static EE_Status ReadVariable(uint16_t VirtAddress, EE_DATA_TYPE* pData);
169 static EE_Status WriteVariable(uint16_t VirtAddress, EE_DATA_TYPE Data);
170 static EE_Status VerifyPageFullyErased(uint32_t Address, uint32_t PageSize);
171 static uint32_t FindPage(EE_Find_type Operation);
172 static EE_Status PagesTransfer(uint16_t VirtAddress, EE_DATA_TYPE Data, EE_Transfer_type type);
173 static EE_Status VerifyPagesFullWriteVariable(uint16_t VirtAddress, EE_DATA_TYPE Data);
174 static EE_Status SetPageState(uint32_t Page, EE_State_type State);
175 static EE_State_type GetPageState(uint32_t Address);
176 #if defined(RECOVERY_TEST)
177 static void VerifyStateReset(uint32_t TriggerState);
178 #endif
179 void ConfigureCrc(void);
180 uint16_t CalculateCrc(EE_DATA_TYPE Data, uint16_t VirtAddress);
181
182 /**
183 * @}
184 */
185
186 /* Exported functions -------------------------------------------------------*/
187 /** @addtogroup EEPROM_Exported_Functions
188 * @{
189 */
190
191 /**
192 * @brief Restore the pages to a known good state in case of power loss.
193 * If a page is in RECEIVE state, resume transfer.
194 * Then if some pages are ERASING state, erase these pages.
195 * @param VirtAddTab Table of virtual addresses defined by user.
196 * 0xFFFF value is prohibited as virtual address.
197 * @param EraseType: Type of erase to apply on page requiring to be erased.
198 * This parameter can be one of the following values:
199 * @arg @ref EE_FORCED_ERASE pages to erase are erased unconditionnally
200 * @arg @ref EE_CONDITIONAL_ERASE pages to erase are erased only if not fully erased
201 * @retval EE_Status
202 * - EE_OK in case of success
203 * - EE error code in case of error
204 */
EE_Init(uint16_t * VirtAddTab,EE_Erase_type EraseType)205 EE_Status EE_Init(uint16_t* VirtAddTab, EE_Erase_type EraseType)
206 {
207 EE_State_type pagestatus = STATE_PAGE_INVALID;
208 uint32_t page = 0U, pageaddress = 0U, varidx = 0U,
209 nbactivepage = 0U, nbactivereceivepage = 0U, nbvalidpage = 0U,
210 lastvalidpage = 0U, firstvalidpage = 0U,
211 recoverytransfer = 0U;
212 EE_ELEMENT_TYPE addressvalue = 0U;
213 EE_State_Reliability pagestate = STATE_RELIABLE;
214 EE_Status status = EE_OK;
215
216 /* Check if the configuration is 128-bits bank or 2*64-bits bank */
217 if (CheckBankConfig() != EE_OK)
218 {
219 return EE_INVALID_BANK_CFG;
220 }
221
222 /***************************************************************************/
223 /* Step 0: Check parameters validity and perform initial configuration */
224 /***************************************************************************/
225 /* Configure CRC peripheral for eeprom emulation usage */
226 ConfigureCrc();
227
228 /* Check validity of Table of Virtual addresses */
229 if (VirtAddTab == NULL)
230 {
231 return EE_INVALID_VIRTUALADDRESS;
232 }
233
234 /* Store Table of Virtual addressess */
235 puhVirtAdd = VirtAddTab;
236
237 /* Check the variables definitions: 0x0000 and 0xFFFF value are prohibited */
238 for (varidx = 0U; varidx < NB_OF_VARIABLES; varidx++)
239 {
240 if ((puhVirtAdd[varidx] == 0x0000U) || (puhVirtAdd[varidx] == 0xFFFFU))
241 {
242 return EE_INVALID_VIRTUALADDRESS;
243 }
244 }
245
246 /***************************************************************************/
247 /* Step 1: Read all lines of the flash pages of eeprom emulation to */
248 /* delete corrupted lines detectable through NMI */
249 /***************************************************************************/
250 for (page = START_PAGE; page < (START_PAGE + PAGES_NUMBER); page++)
251 {
252 pageaddress = PAGE_ADDRESS(page);
253 for (varidx = 0U; varidx < PAGE_SIZE; varidx += EE_ELEMENT_SIZE)
254 {
255 addressvalue = (*(__IO EE_ELEMENT_TYPE*)(pageaddress + varidx));
256 }
257 }
258
259 /***************************************************************************/
260 /* Step 2: Handle case of reset during transfer with no receive page */
261 /* present, by setting missing receive page state */
262 /***************************************************************************/
263 /* Check if no active page and no receive page present */
264 /* Browse all pages */
265 for (page = START_PAGE; page < (START_PAGE + PAGES_NUMBER); page++)
266 {
267 pageaddress = PAGE_ADDRESS(page);
268 pagestatus = GetPageState(pageaddress);
269
270 /* Search for active and receive page */
271 if ((pagestatus == STATE_PAGE_ACTIVE) || (pagestatus == STATE_PAGE_RECEIVE))
272 {
273 nbactivereceivepage++;
274 }
275 /* Keep index of first valid page, and last valid page */
276 else if (pagestatus == STATE_PAGE_VALID)
277 {
278 if (nbvalidpage == 0U)
279 {
280 firstvalidpage = page;
281 }
282 lastvalidpage = page;
283 nbvalidpage++;
284 }
285 }
286
287 /* Check if no active and no receive page have been detected */
288 if (nbactivereceivepage == 0U)
289 {
290 /* Check if valid pages have been detected */
291 if (nbvalidpage > 0U)
292 {
293 /* Check state of page just before first valid page.
294 If it is erasing page, then page after last valid page shall be set
295 to receiving state */
296 if (GetPageState(PAGE_ADDRESS(PREVIOUS_PAGE(firstvalidpage))) == STATE_PAGE_ERASING)
297 {
298 if (SetPageState(FOLLOWING_PAGE(lastvalidpage), STATE_PAGE_RECEIVE) != EE_OK)
299 {
300 return EE_WRITE_ERROR;
301 }
302 }
303 }
304 /* Format flash pages used for eeprom emulation in case no active, no receive, no valid pages are found */
305 else
306 {
307 return EE_Format(EE_FORCED_ERASE);
308 }
309 }
310
311 /*********************************************************************/
312 /* Step 3: Handle case of reset during transfer, by performing */
313 /* transfer recovery */
314 /*********************************************************************/
315 /* Browse all pages */
316 for (page = START_PAGE; page < (START_PAGE + PAGES_NUMBER); page++)
317 {
318 pageaddress = PAGE_ADDRESS(page);
319 pagestatus = GetPageState(pageaddress);
320
321 /* Check if there is receive page, meaning transfer has been interrupted */
322 if (pagestatus == STATE_PAGE_RECEIVE)
323 {
324 /* Verify that receive page is a true one, not a corrupted page state */
325 /* Check if page is not the first page of a bloc */
326 if ((page != START_PAGE) && (page != (uint32_t)(START_PAGE + (PAGES_NUMBER / 2U))))
327 {
328 /* Check that previous page is valid state */
329 if (GetPageState(PAGE_ADDRESS(PREVIOUS_PAGE(page))) == STATE_PAGE_VALID)
330 {
331 /* The receive page is a true receive page */
332 pagestate = STATE_RELIABLE;
333 }
334 else /* Previous page is not valid state */
335 {
336 /* The receive page is false receive page due to header corruption */
337 pagestate = STATE_CORRUPTED;
338 }
339 }
340 else /* The receive page is the first page of a bloc */
341 {
342 /* Check that following page is erased state */
343 if (GetPageState(PAGE_ADDRESS(FOLLOWING_PAGE(page))) == STATE_PAGE_ERASED)
344 {
345 /* The receive page is a true receive page */
346 pagestate = STATE_RELIABLE;
347 }
348 else /* Following page is not erased state */
349 {
350 /* The receive page is false receive page due to header corruption */
351 pagestate = STATE_CORRUPTED;
352 }
353 }
354
355 /* If the receive page is a true receive page, resume pages transfer */
356 if (pagestate == STATE_RELIABLE)
357 {
358 /* Initialize current active page */
359 ubCurrentActivePage = page;
360
361 /* Resume the interrupted page transfer, using dummy new data */
362 if (PagesTransfer(0U, 0U, EE_TRANSFER_RECOVER) != EE_CLEANUP_REQUIRED)
363 {
364 return EE_TRANSFER_ERROR;
365 }
366
367 /* Memorize transfer recovery occured */
368 recoverytransfer = 1U;
369
370 /* transfer recovery is done, then stop searching receive page */
371 break;
372 }
373 }
374 }
375
376 /*********************************************************************/
377 /* Step 4: Verify presence of one unique active page */
378 /* If more than one active page, raise error */
379 /* If no active page present, set missing active page */
380 /*********************************************************************/
381 /* Browse all pages to search for active pages */
382 nbactivepage = 0U;
383 for (page = START_PAGE; page < (START_PAGE + PAGES_NUMBER); page++)
384 {
385 pageaddress = PAGE_ADDRESS(page);
386 pagestatus = GetPageState(pageaddress);
387
388 /* Search for active page */
389 if (pagestatus == STATE_PAGE_ACTIVE)
390 {
391 /* Verify that active page is a true one, not a corrupted page state */
392 /* Check if page is not the first page of a bloc */
393 if ((page != START_PAGE) && (page != (uint32_t)(START_PAGE + (PAGES_NUMBER / 2U))))
394 {
395 /* Check that previous page is valid state */
396 if (GetPageState(PAGE_ADDRESS(PREVIOUS_PAGE(page))) == STATE_PAGE_VALID)
397 {
398 /* The active page is a true active page */
399 pagestate = STATE_RELIABLE;
400 }
401 else /* Previous page is not valid state */
402 {
403 /* The active page is false active page due to header corruption */
404 pagestate = STATE_CORRUPTED;
405 }
406 }
407 else /* The active page is the first page of a bloc */
408 {
409 /* Check that following page is erased state */
410 if (GetPageState(PAGE_ADDRESS(FOLLOWING_PAGE(page))) == STATE_PAGE_ERASED)
411 {
412 /* The active page is a true active page */
413 pagestate = STATE_RELIABLE;
414 }
415 else /* Following page is not erased state */
416 {
417 /* The active page is false active page due to header corruption */
418 pagestate = STATE_CORRUPTED;
419 }
420 }
421
422 /* If the active page is a true active page, initialize global variables */
423 if (pagestate == STATE_RELIABLE)
424 {
425 if (nbactivepage == 0U)
426 {
427 ubCurrentActivePage = page;
428 nbactivepage++;
429 }
430 else
431 {
432 /* Error: More than one reliable active page is present */
433 return EE_INVALID_PAGE_SEQUENCE;
434 }
435 }
436 }
437 /* Keep index of last valid page, will be required in case no active page is found */
438 else if (pagestatus == STATE_PAGE_VALID)
439 {
440 lastvalidpage = page;
441 }
442 }
443
444 /* In case no active page is found, set page after last valid page to active state */
445 if (nbactivepage == 0U)
446 {
447 ubCurrentActivePage = FOLLOWING_PAGE(lastvalidpage);
448 if (SetPageState(ubCurrentActivePage, STATE_PAGE_ACTIVE) != EE_OK)
449 {
450 return EE_WRITE_ERROR;
451 }
452 }
453
454 /*********************************************************************/
455 /* Step 5: Initialize eeprom emulation global variables relative */
456 /* to active page */
457 /*********************************************************************/
458 /* Initialize global variables, with elements detected in active page */
459 uhNbWrittenElements = 0U;
460 uwAddressNextWrite = PAGE_HEADER_SIZE;
461
462 for (varidx = PAGE_HEADER_SIZE; varidx < PAGE_SIZE; varidx += EE_ELEMENT_SIZE)
463 {
464 /* Check elements present in active page */
465 addressvalue = (*(__IO EE_ELEMENT_TYPE*)(PAGE_ADDRESS(ubCurrentActivePage) + varidx));
466 if (addressvalue != EE_MASK_FULL)
467 {
468 /* Then increment uhNbWrittenElements and uwAddressNextWrite */
469 uhNbWrittenElements++;
470 uwAddressNextWrite += EE_ELEMENT_SIZE;
471 }
472 else /* no more element in the page */
473 {
474 break;
475 }
476 }
477
478 /*********************************************************************/
479 /* Step 6: Finalize eeprom emulation global variables relative */
480 /* to valid pages, and check consistency of pages sequence */
481 /*********************************************************************/
482 /* Check consistency of pages sequence: one active page, optionnally some valid pages before */
483 /* Update global variable uhNbWrittenElements if valid pages are found */
484 page = ubCurrentActivePage;
485 firstvalidpage = ubCurrentActivePage;
486 while ((page != START_PAGE) && (page != (uint32_t)(START_PAGE + (PAGES_NUMBER / 2U))))
487 {
488 /* Decrement page index among circular pages list */
489 page = PREVIOUS_PAGE(page);
490 pagestatus = GetPageState(PAGE_ADDRESS(page));
491
492 /* Check if page is valid state */
493 if (pagestatus == STATE_PAGE_VALID)
494 {
495 /* Update uhNbWrittenElements with number of elements in full page */
496 uhNbWrittenElements += NB_MAX_ELEMENTS_BY_PAGE;
497
498 /* Keep index of first valid page */
499 firstvalidpage = page;
500 }
501 else
502 {
503 /* Error: Pages sequence is not consistent */
504 return EE_INVALID_PAGE_SEQUENCE;
505 }
506 }
507
508 /*********************************************************************/
509 /* Step 7: Ensure empty pages are erased */
510 /*********************************************************************/
511 /* Ensure all pages after active page, until first valid page, are erased */
512 page = FOLLOWING_PAGE(ubCurrentActivePage);
513 pageaddress = PAGE_ADDRESS(page);
514
515 while (page != firstvalidpage)
516 {
517 /* Check if page erase has to be forced unconditionally (default case) */
518 if (EraseType == EE_FORCED_ERASE)
519 {
520 /* Force page erase independently of its content */
521 if (PageErase(page, 1U) != EE_OK)
522 {
523 return EE_ERASE_ERROR;
524 }
525 }
526 else /* EraseType == EE_CONDITIONAL_ERASE */
527 {
528 /* Check if page is fully erased */
529 if (VerifyPageFullyErased(pageaddress, PAGE_SIZE) == EE_PAGE_NOTERASED)
530 {
531 /* Erase pages if not fully erased */
532 if (PageErase(page, 1U) != EE_OK)
533 {
534 return EE_ERASE_ERROR;
535 }
536 }
537 }
538
539 /* Increment page index among circular pages list, to get first page to erased */
540 page = FOLLOWING_PAGE(page);
541 pageaddress = PAGE_ADDRESS(page);
542 }
543
544 /*********************************************************************/
545 /* Step 8: Perform dummy write '0' to get rid of potential */
546 /* instability of line value 0xFFFFFFFF consecutive to a */
547 /* reset during write here */
548 /* Only needed if recovery transfer did not occured */
549 /*********************************************************************/
550 if (recoverytransfer == 0U)
551 {
552 status = VerifyPagesFullWriteVariable(0U, 0U);
553
554 /* The dummy write can be skipped in case pages are full
555 because in this case potential instability can not happen */
556 if ((status != EE_OK) && (status != EE_PAGE_FULL))
557 {
558 return EE_WRITE_ERROR;
559 }
560 }
561
562 return EE_OK;
563 }
564
565 /**
566 * @brief Erases all flash pages of eeprom emulation, and set first page
567 * header as ACTIVE.
568 * @note This function can be called the very first time eeprom emulation is
569 * used, to prepare flash pages for eeprom emulation with empty eeprom
570 variables. It can also be called at any time, to flush all eeprom
571 * variables.
572 * @param EraseType: Type of erase to apply on page requiring to be erased.
573 * This parameter can be one of the following values:
574 * @arg @ref EE_FORCED_ERASE pages to erase are erased unconditionnally
575 * @arg @ref EE_CONDITIONAL_ERASE pages to erase are erased only if not fully erased
576 * @retval EE_Status
577 * - EE_OK: on success
578 * - EE error code: if an error occurs
579 */
EE_Format(EE_Erase_type EraseType)580 EE_Status EE_Format(EE_Erase_type EraseType)
581 {
582 uint32_t page = 0U;
583
584 /* Check if the configuration is 128-bits bank or 2*64-bits bank */
585 if (CheckBankConfig() != EE_OK)
586 {
587 return EE_INVALID_BANK_CFG;
588 }
589
590 /* Erase All Pages */
591 for (page = START_PAGE; page < (START_PAGE + PAGES_NUMBER); page++)
592 {
593 /* Check if page erase has to be forced unconditionally (default case) */
594 if (EraseType == EE_FORCED_ERASE)
595 {
596 /* Force page erase independently of its content */
597 if (PageErase(page, 1U) != EE_OK)
598 {
599 return EE_ERASE_ERROR;
600 }
601 }
602 else /* EraseType == EE_CONDITIONAL_ERASE */
603 {
604 /* Check if Page is not yet fully erased */
605 if (VerifyPageFullyErased(PAGE_ADDRESS(page), PAGE_SIZE) == EE_PAGE_NOTERASED)
606 {
607 /* Erase the page */
608 /* If Erase operation was failed, a Flash error code is returned */
609 if (PageErase(page, 1U) != EE_OK)
610 {
611 return EE_ERASE_ERROR;
612 }
613 }
614 }
615 }
616
617 /* Set first Page in Active State */
618 /* If program operation was failed, a Flash error code is returned */
619 if (SetPageState(START_PAGE, STATE_PAGE_ACTIVE) != EE_OK)
620 {
621 return EE_WRITE_ERROR;
622 }
623
624 /* Reset global variables */
625 uhNbWrittenElements = (uint16_t)0U;
626 ubCurrentActivePage = START_PAGE;
627 uwAddressNextWrite = PAGE_HEADER_SIZE; /* Initialize write position just after page header */
628
629 return EE_OK;
630 }
631
632 #if defined(EE_ACCESS_32BITS)
633 /**
634 * @brief Returns the last stored variable data, if found, which correspond to
635 * the passed virtual address
636 * @param VirtAddress Variable virtual address
637 * @param pData Variable containing the 32bits read variable value
638 * @retval EE_Status
639 * - EE_OK: if variable was found
640 * - EE error code: if an error occurs
641 */
EE_ReadVariable32bits(uint16_t VirtAddress,uint32_t * pData)642 EE_Status EE_ReadVariable32bits(uint16_t VirtAddress, uint32_t* pData)
643 {
644 EE_DATA_TYPE datatmp = 0U;
645 EE_Status status = EE_OK;
646
647 /* Read variable of size EE_DATA_TYPE, then cast it to 32bits */
648 status = ReadVariable(VirtAddress, &datatmp);
649 *pData = (uint32_t) datatmp;
650
651 return status;
652 }
653 #endif
654
655 /**
656 * @brief Returns the last stored variable data, if found, which correspond to
657 * the passed virtual address
658 * @param VirtAddress Variable virtual address
659 * @param pData Variable containing the 16bits read variable value
660 * @retval EE_Status
661 * - EE_OK: if variable was found
662 * - EE error code: if an error occurs
663 */
EE_ReadVariable16bits(uint16_t VirtAddress,uint16_t * pData)664 EE_Status EE_ReadVariable16bits(uint16_t VirtAddress, uint16_t* pData)
665 {
666 EE_DATA_TYPE datatmp = 0U;
667 EE_Status status = EE_OK;
668
669 /* Read variable of size EE_DATA_TYPE, then cast it to 16bits */
670 status = ReadVariable(VirtAddress, &datatmp);
671 *pData = (uint16_t) datatmp;
672
673 return status;
674 }
675
676 /**
677 * @brief Returns the last stored variable data, if found, which correspond to
678 * the passed virtual address
679 * @param VirtAddress Variable virtual address
680 * @param pData Variable containing the 8bits read variable value
681 * @retval EE_Status
682 * - EE_OK: if variable was found
683 * - EE error code: if an error occurs
684 */
EE_ReadVariable8bits(uint16_t VirtAddress,uint8_t * pData)685 EE_Status EE_ReadVariable8bits(uint16_t VirtAddress, uint8_t* pData)
686 {
687 EE_DATA_TYPE datatmp = 0U;
688 EE_Status status = EE_OK;
689
690 /* Read variable of size EE_DATA_TYPE, then cast it to 8bits */
691 status = ReadVariable(VirtAddress, &datatmp);
692 *pData = (uint8_t) datatmp;
693
694 return status;
695 }
696
697 #if defined(EE_ACCESS_32BITS)
698 /**
699 * @brief Writes/updates variable data in EEPROM.
700 * Trig internal Pages transfer if half of the pages are full.
701 * @warning This function is not reentrant
702 * @param VirtAddress Variable virtual address
703 * @param Data 32bits data to be written
704 * @retval EE_Status
705 * - EE_OK: on success
706 * - EE_CLEANUP_REQUIRED: success and user has to trig flash pages cleanup
707 * - EE error code: if an error occurs
708 */
EE_WriteVariable32bits(uint16_t VirtAddress,uint32_t Data)709 EE_Status EE_WriteVariable32bits(uint16_t VirtAddress, uint32_t Data)
710 {
711 return WriteVariable(VirtAddress, (EE_DATA_TYPE) Data);
712 }
713 #endif
714
715 /**
716 * @brief Writes/updates variable data in EEPROM.
717 * Trig internal Pages transfer if half of the pages are full.
718 * @warning This function is not reentrant
719 * @param VirtAddress Variable virtual address
720 * @param Data 16bits data to be written
721 * @retval EE_Status
722 * - EE_OK: on success
723 * - EE_CLEANUP_REQUIRED: success and user has to trig flash pages cleanup
724 * - EE error code: if an error occurs
725 */
EE_WriteVariable16bits(uint16_t VirtAddress,uint16_t Data)726 EE_Status EE_WriteVariable16bits(uint16_t VirtAddress, uint16_t Data)
727 {
728 return WriteVariable(VirtAddress, (EE_DATA_TYPE) Data);
729 }
730
731 /**
732 * @brief Writes/updates variable data in EEPROM.
733 * Trig internal Pages transfer if half of the pages are full.
734 * @warning This function is not reentrant
735 * @param VirtAddress Variable virtual address
736 * @param Data 8bits data to be written
737 * @retval EE_Status
738 * - EE_OK: on success
739 * - EE_CLEANUP_REQUIRED: success and user has to trig flash pages cleanup
740 * - EE error code: if an error occurs
741 */
EE_WriteVariable8bits(uint16_t VirtAddress,uint8_t Data)742 EE_Status EE_WriteVariable8bits(uint16_t VirtAddress, uint8_t Data)
743 {
744 return WriteVariable(VirtAddress, (EE_DATA_TYPE) Data);
745 }
746
747 /**
748 * @brief Erase group of pages which are erasing state, in polling mode.
749 * Could be either first half or second half of total pages number.
750 * @note This function should be called when EE_WriteVariableXXbits has
751 * returned EE_CLEANUP_REQUIRED status (and only in that case)
752 * @retval EE_Status
753 * - EE_OK: in case of success
754 * - EE error code: if an error occurs
755 */
EE_CleanUp(void)756 EE_Status EE_CleanUp(void)
757 {
758 uint32_t firstpage = 0U, page = 0U;
759 uint32_t firstpageaddress = 0U, pageaddress = 0U;
760 EE_State_type firstpagestatus = STATE_PAGE_INVALID, pagestatus = STATE_PAGE_INVALID;
761
762 /* Check first half and second half page group */
763 for (firstpage = START_PAGE; firstpage < (START_PAGE + PAGES_NUMBER); firstpage += (PAGES_NUMBER / 2U))
764 {
765 /* Check status of first page of the group */
766 firstpageaddress = PAGE_ADDRESS(firstpage);
767 firstpagestatus = GetPageState(firstpageaddress);
768
769 /* If first page of the group is erasing state, check that all other pages
770 of the group are also erasing state */
771 if (firstpagestatus == STATE_PAGE_ERASING)
772 {
773 for (page = (firstpage + 1U); page < (firstpage + (PAGES_NUMBER / 2U)); page++)
774 {
775 pageaddress = PAGE_ADDRESS(page);
776 pagestatus = GetPageState(pageaddress);
777
778 /* If page is not erasing, return error */
779 if (pagestatus != STATE_PAGE_ERASING)
780 {
781 return EE_ERROR_NOERASING_PAGE;
782 }
783 }
784
785 /* Erase all the pages of the group */
786 /* If erase operation fails, a Flash error code is returned */
787 if (PageErase(firstpage, PAGES_NUMBER / 2U) != EE_OK)
788 {
789 return EE_ERASE_ERROR;
790 }
791 else
792 {
793 return EE_OK;
794 }
795 }
796 }
797
798 /* Error if no erasing pages group is found */
799 return EE_ERROR_NOERASING_PAGE;
800 }
801
802 /**
803 * @brief Erase group of pages which are erasing state, in IT mode.
804 * Could be either first half or second half of total pages number.
805 * @note This function should be called when EE_WriteVariableXXbits has
806 * returned EE_CLEANUP_REQUIRED status (and only in that case)
807 * @retval EE_Status
808 * - EE_OK: in case of success
809 * - EE error code: if an error occurs
810 */
EE_CleanUp_IT(void)811 EE_Status EE_CleanUp_IT(void)
812 {
813 uint32_t firstpage = 0U, page = 0U;
814 uint32_t firstpageaddress = 0U, pageaddress = 0U;
815 EE_State_type firstpagestatus = STATE_PAGE_INVALID, pagestatus = STATE_PAGE_INVALID;
816
817 /* Check first half and second half page group */
818 for (firstpage = START_PAGE; firstpage < (START_PAGE + PAGES_NUMBER); firstpage += (PAGES_NUMBER / 2U))
819 {
820 /* Check status of first page of the group */
821 firstpageaddress = PAGE_ADDRESS(firstpage);
822 firstpagestatus = GetPageState(firstpageaddress);
823
824 /* If first page of the group is erasing state, check that all other pages
825 of the group are also erasing state */
826 if (firstpagestatus == STATE_PAGE_ERASING)
827 {
828 for (page = (firstpage + 1U); page < (firstpage + (PAGES_NUMBER / 2U)); page++)
829 {
830 pageaddress = PAGE_ADDRESS(page);
831 pagestatus = GetPageState(pageaddress);
832
833 /* If page is not erasing, return error */
834 if (pagestatus != STATE_PAGE_ERASING)
835 {
836 return EE_ERROR_NOERASING_PAGE;
837 }
838 }
839
840 /* Erase all the pages of the group */
841 /* If erase operation fails, a Flash error code is returned */
842 if (PageErase_IT(firstpage, PAGES_NUMBER / 2U) != EE_OK)
843 {
844 return EE_ERASE_ERROR;
845 }
846 else
847 {
848 return EE_OK;
849 }
850 }
851 }
852
853 /* Error if no erasing pages group is found */
854 return EE_ERROR_NOERASING_PAGE;
855 }
856
857 /**
858 * @brief Delete corrupted Flash address, can be called under NMI.
859 * @param Address Address of the FLASH Memory to delete
860 * @retval EE_Status
861 * - EE_OK: on success
862 * - EE error code: if an error occurs
863 */
EE_DeleteCorruptedFlashAddress(uint32_t Address)864 EE_Status EE_DeleteCorruptedFlashAddress(uint32_t Address)
865 {
866 return DeleteCorruptedFlashAddress(Address);
867 }
868
869 /**
870 * @brief Clean Up end of operation interrupt callback.
871 * @retval None
872 */
EE_EndOfCleanup_UserCallback(void)873 __weak void EE_EndOfCleanup_UserCallback(void)
874 {
875 /* NOTE : This function should not be modified, when the callback is needed,
876 the EE_EndOfCleanup_UserCallback could be implemented in the user file
877 */
878 }
879
880 /**
881 * @}
882 */
883
884 /* Private functions ---------------------------------------------------------*/
885 /** @addtogroup EEPROM_Private_Functions
886 * @{
887 */
888
889 /**
890 * @brief Returns the last stored variable data, if found, which correspond to
891 * the passed virtual address
892 * @param VirtAddress Variable virtual address
893 * @param pData Variable containing the EE_DATA_TYPE read variable value
894 * @retval EE_Status
895 * - EE_OK: if variable was found
896 * - EE error code: if an error occurs
897 */
ReadVariable(uint16_t VirtAddress,EE_DATA_TYPE * pData)898 static EE_Status ReadVariable(uint16_t VirtAddress, EE_DATA_TYPE* pData)
899 {
900 EE_ELEMENT_TYPE addressvalue = 0U;
901 uint32_t page = 0U, pageaddress = 0U, counter = 0U, crc = 0U;
902 EE_State_type pagestate = STATE_PAGE_INVALID;
903
904 /* Get active Page for read operation */
905 page = FindPage(FIND_READ_PAGE);
906
907 /* Check if there is no active page */
908 if (page == EE_NO_PAGE_FOUND)
909 {
910 return EE_ERROR_NOACTIVE_PAGE;
911 }
912 pageaddress = PAGE_ADDRESS(page);
913 pagestate = GetPageState(pageaddress);
914
915 /* Search variable in active page and valid pages until erased page is found
916 or in erasing pages until erased page is found */
917 while ((pagestate == STATE_PAGE_ACTIVE) || (pagestate == STATE_PAGE_VALID) || (pagestate == STATE_PAGE_ERASING))
918 {
919 /* Set counter index to last element position in the page */
920 counter = PAGE_SIZE - EE_ELEMENT_SIZE;
921
922 /* Check each page address starting from end */
923 while (counter >= PAGE_HEADER_SIZE)
924 {
925 /* Get the current location content to be compared with virtual address */
926 addressvalue = (*(__IO EE_ELEMENT_TYPE*)(pageaddress + counter));
927 if (addressvalue != EE_PAGESTAT_ERASED)
928 {
929 /* Compare the read address with the virtual address */
930 if (EE_VIRTUALADDRESS_VALUE(addressvalue) == VirtAddress)
931 {
932 /* Calculate crc of variable data and virtual address */
933 crc = CalculateCrc(EE_DATA_VALUE(addressvalue), EE_VIRTUALADDRESS_VALUE(addressvalue));
934
935 /* if crc verification pass, data is correct and is returned.
936 if crc verification fails, data is corrupted and has to be skip */
937 if (crc == EE_CRC_VALUE(addressvalue))
938 {
939 /* Get content of variable value */
940 *pData = EE_DATA_VALUE(addressvalue);
941
942 return EE_OK;
943 }
944 }
945 }
946 /* Next address location */
947 counter -= EE_ELEMENT_SIZE;
948 }
949
950 /* Decrement page index circularly, among pages allocated to eeprom emulation */
951 page = PREVIOUS_PAGE(page);
952 pageaddress = PAGE_ADDRESS(page);
953 pagestate = GetPageState(pageaddress);
954 }
955
956 /* Variable is not found */
957 return EE_NO_DATA;
958 }
959
960 /**
961 * @brief Writes/updates variable data in EEPROM
962 * Trig internal Pages transfer if half of the pages are full
963 * @param VirtAddress Variable virtual address
964 * @param Data EE_DATA_TYPE data to be written
965 * @retval EE_Status
966 * - EE_OK: on success, without page transfer
967 * - EE_CLEANUP_REQUIRED: on success, with page transfer occured
968 * - EE error code: if an error occurs
969 */
WriteVariable(uint16_t VirtAddress,EE_DATA_TYPE Data)970 static EE_Status WriteVariable(uint16_t VirtAddress, EE_DATA_TYPE Data)
971 {
972 EE_Status status = EE_OK;
973
974 /* Write the variable virtual address and value in the EEPROM, if not full */
975 status = VerifyPagesFullWriteVariable(VirtAddress, Data);
976 if (status == EE_PAGE_FULL)
977 {
978 /* In case the EEPROM pages are full, perform Pages transfer */
979 return PagesTransfer(VirtAddress, Data, EE_TRANSFER_NORMAL);
980 }
981
982 /* Return last operation status */
983 return status;
984 }
985
986 /**
987 * @brief Verify if specified page is fully erased.
988 * @param Address page address
989 * @param PageSize page size
990 * @retval EE_Status
991 * - EE_PAGE_NOTERASED : if Page not erased
992 * - EE_PAGE_ERASED : if Page erased
993 */
VerifyPageFullyErased(uint32_t Address,uint32_t PageSize)994 static EE_Status VerifyPageFullyErased(uint32_t Address, uint32_t PageSize)
995 {
996 EE_Status readstatus = EE_PAGE_ERASED;
997 uint32_t counter = 0U;
998
999 /* Check each element in the page */
1000 while (counter < PageSize)
1001 {
1002 /* Compare the read address with the virtual address */
1003 if ((*(__IO EE_ELEMENT_TYPE*)(Address+counter)) != EE_PAGESTAT_ERASED)
1004 {
1005 /* In case one element is not erased, reset readstatus flag */
1006 readstatus = EE_PAGE_NOTERASED;
1007 }
1008 /* Next address location */
1009 counter = counter + EE_ELEMENT_SIZE;
1010 }
1011
1012 /* Return readstatus value */
1013 return readstatus;
1014 }
1015
1016 /**
1017 * @brief Find suitable page for read/write/erase operation.
1018 * It also update pages state if current page is full.
1019 * And it force cleanup if all pages are full.
1020 * @param Operation Type of page to be requested.
1021 * This parameter can be one of the following values:
1022 * @arg @ref FIND_READ_PAGE return the active page index
1023 * @arg @ref FIND_WRITE_PAGE return the write page index
1024 * @arg @ref FIND_ERASE_PAGE return the erase page index
1025 * @retval Page_Index
1026 * - Page Index: on success
1027 * - @ref EE_NO_PAGE_FOUND : if an error occurs
1028 */
FindPage(EE_Find_type Operation)1029 static uint32_t FindPage(EE_Find_type Operation)
1030 {
1031 EE_State_type currentpagestatus = STATE_PAGE_INVALID, followingpagestatus = STATE_PAGE_INVALID;
1032 uint32_t currentpage = 0U, followingpage = 0U, previouspage = 0U;
1033
1034 /* Get currentpage status */
1035 currentpage = ubCurrentActivePage;
1036 currentpagestatus = GetPageState(PAGE_ADDRESS(currentpage));
1037
1038 /* Get followingpage status */
1039 followingpage = FOLLOWING_PAGE(currentpage);
1040 followingpagestatus = GetPageState(PAGE_ADDRESS(followingpage));
1041
1042 /* Get previouspage status */
1043 previouspage = PREVIOUS_PAGE(currentpage);
1044
1045 /* Write, read or erase operation */
1046 switch (Operation)
1047 {
1048 case FIND_WRITE_PAGE: /* ---- Write operation ---- */
1049 /* Normal operation, no page transfer on going */
1050 if (currentpagestatus == STATE_PAGE_ACTIVE)
1051 {
1052 /* Check if active page is not full */
1053 if (uwAddressNextWrite < PAGE_SIZE)
1054 {
1055 /* Return current Active page */
1056 return currentpage;
1057 }
1058 else
1059 /* No more space in current active page */
1060 {
1061 /* Check if following page is erasing state */
1062 if (followingpagestatus == STATE_PAGE_ERASING)
1063 {
1064 /* Force Cleanup, as not yet performed by user */
1065 if (EE_CleanUp() != EE_OK)
1066 {
1067 return EE_NO_PAGE_FOUND;
1068 }
1069 }
1070
1071 /* Set current active page in valid state */
1072 if (SetPageState(currentpage, STATE_PAGE_VALID) != EE_OK)
1073 {
1074 return EE_NO_PAGE_FOUND;
1075 }
1076
1077 #if defined(RECOVERY_TEST)
1078 VerifyStateReset(8U);
1079 #endif
1080
1081 /* Set following page as active */
1082 if (SetPageState(followingpage, STATE_PAGE_ACTIVE) != EE_OK)
1083 {
1084 return EE_NO_PAGE_FOUND;
1085 }
1086 uwAddressNextWrite = PAGE_HEADER_SIZE; /* Skip page header */
1087 return followingpage; /* Following page is now active one */
1088 }
1089 }
1090 /* Transfer is on going, page receiving data */
1091 else
1092 {
1093 if (currentpagestatus == STATE_PAGE_RECEIVE)
1094 {
1095 /* Check if receive page is not full */
1096 if (uwAddressNextWrite < PAGE_SIZE)
1097 {
1098 /* Return current receive page */
1099 return currentpage;
1100 }
1101 else
1102 /* No more space in current receive page */
1103 {
1104 /* Check if following page is erasing state */
1105 if (followingpagestatus == STATE_PAGE_ERASING)
1106 {
1107 /* Force Cleanup, as not yet performed by user */
1108 if (EE_CleanUp() != EE_OK)
1109 {
1110 return EE_NO_PAGE_FOUND;
1111 }
1112 }
1113
1114 /* Set current receive page in valid state */
1115 if (SetPageState(currentpage, STATE_PAGE_VALID) != EE_OK)
1116 {
1117 return EE_NO_PAGE_FOUND;
1118 }
1119
1120 /* Set following page as receive */
1121 if (SetPageState(followingpage, STATE_PAGE_RECEIVE) != EE_OK)
1122 {
1123 return EE_NO_PAGE_FOUND;
1124 }
1125 uwAddressNextWrite = PAGE_HEADER_SIZE; /* Skip page header */
1126 return followingpage; /* Following page is now active one */
1127 }
1128 }
1129 else
1130 {
1131 return EE_NO_PAGE_FOUND; /* No active Page */
1132 }
1133 }
1134
1135 case FIND_READ_PAGE: /* ---- Read operation ---- */
1136 if (currentpagestatus == STATE_PAGE_ACTIVE)
1137 {
1138 return currentpage;
1139 }
1140 else
1141 {
1142 if (currentpagestatus == STATE_PAGE_RECEIVE)
1143 {
1144 return previouspage;
1145 }
1146 else
1147 {
1148 return EE_NO_PAGE_FOUND; /* No active Page */
1149 }
1150 }
1151
1152 case FIND_ERASE_PAGE: /* ---- Return the erased page */
1153 if (followingpagestatus == STATE_PAGE_ERASED)
1154 {
1155 return followingpage;
1156 }
1157 else
1158 {
1159 return EE_NO_PAGE_FOUND; /* No erased Page */
1160 }
1161
1162 default:
1163 ;
1164 }
1165
1166 return EE_NO_PAGE_FOUND;
1167 }
1168
1169 /**
1170 * @brief Writes a new variable data in fresh new page in case of normal
1171 * transfer, and transfers last updated elements from full pages to
1172 * empty pages in any cases.
1173 * @param VirtAddress 16 bit virtual address of the new variable data
1174 * @param Data @ref EE_DATA_TYPE data value of the new variable data
1175 * @param Type Type of transfer.
1176 * This parameter can be one of the EE_Transfer_type enum values.
1177 * @arg @ref EE_TRANSFER_NORMAL Pages transfer during normal processing
1178 * @arg @ref EE_TRANSFER_RECOVER Recovering pages transfer at Init
1179 * @retval EE_Status
1180 * - EE_CLEANUP_REQUIRED: on success
1181 * - EE error code: if an error occurs
1182 */
PagesTransfer(uint16_t VirtAddress,EE_DATA_TYPE Data,EE_Transfer_type Type)1183 static EE_Status PagesTransfer(uint16_t VirtAddress, EE_DATA_TYPE Data, EE_Transfer_type Type)
1184 {
1185 EE_State_type pagestatus = STATE_PAGE_INVALID;
1186 uint32_t pageaddress = 0U;
1187 uint32_t page = 0U;
1188 uint32_t varidx = 0U;
1189 EE_ELEMENT_TYPE addressvalue = 0U;
1190 EE_Status status = EE_OK;
1191 EE_DATA_TYPE DataValue = 0U;
1192
1193 /* Get receive Page for transfer operation */
1194 page = FindPage((Type == EE_TRANSFER_NORMAL?FIND_ERASE_PAGE:FIND_WRITE_PAGE));
1195 if (page == EE_NO_PAGE_FOUND)
1196 {
1197 return EE_ERROR_NOERASE_PAGE;
1198 }
1199
1200 /* Reinitialize number of data written in the pages, and current active page */
1201 uhNbWrittenElements = 0U;
1202 ubCurrentActivePage = page;
1203 uwAddressNextWrite = PAGE_HEADER_SIZE;
1204
1205 /* Mark the erased page at receive state in case of normal transfer */
1206 /* It is already the case in recover transfer case */
1207 /* If program operation was failed, a Flash error code is returned */
1208 if (Type == EE_TRANSFER_NORMAL)
1209 {
1210 if (SetPageState(page, STATE_PAGE_RECEIVE) != EE_OK)
1211 {
1212 return EE_WRITE_ERROR;
1213 }
1214 }
1215
1216 #if defined(RECOVERY_TEST)
1217 if (Type == EE_TRANSFER_NORMAL)
1218 {
1219 VerifyStateReset(1U);
1220 }
1221 #endif
1222
1223 /* Set the previous active page and all previous valid pages to erasing state */
1224 /* In case of recover transfer, some of these pages may already be marked erasing */
1225 page = PREVIOUS_PAGE(page);
1226 pageaddress = PAGE_ADDRESS(page);
1227 pagestatus = GetPageState(pageaddress);
1228
1229 if ((pagestatus == STATE_PAGE_ACTIVE) || (pagestatus == STATE_PAGE_ERASING))
1230 {
1231 /* Set active page to erasing */
1232 if (pagestatus == STATE_PAGE_ACTIVE)
1233 {
1234 if (SetPageState(page, STATE_PAGE_ERASING) != EE_OK)
1235 {
1236 return EE_WRITE_ERROR;
1237 }
1238 }
1239
1240 #if defined(RECOVERY_TEST)
1241 if (Type == EE_TRANSFER_NORMAL)
1242 {
1243 VerifyStateReset(2U);
1244 }
1245 #endif
1246
1247 /* Inspect the previous pages to set all valid pages to erasing state */
1248 /* In case of recover, some valid pages may be already erasing state */
1249 page = PREVIOUS_PAGE(page);
1250 pageaddress = PAGE_ADDRESS(page);
1251 pagestatus = GetPageState(pageaddress);
1252
1253 while ((pagestatus == STATE_PAGE_VALID) || (pagestatus == STATE_PAGE_ERASING))
1254 {
1255 /* Set valid page to erasing */
1256 if (pagestatus == STATE_PAGE_VALID)
1257 {
1258 if (SetPageState(page, STATE_PAGE_ERASING) != EE_OK)
1259 {
1260 return EE_WRITE_ERROR;
1261 }
1262 }
1263
1264 #if defined(RECOVERY_TEST)
1265 if (Type == EE_TRANSFER_NORMAL)
1266 {
1267 VerifyStateReset(3U);
1268 }
1269 #endif
1270
1271 /* decrement page index */
1272 page = PREVIOUS_PAGE(page);
1273 pageaddress = PAGE_ADDRESS(page);
1274 pagestatus = GetPageState(pageaddress);
1275 }
1276 }
1277 else
1278 {
1279 if ((Type == EE_TRANSFER_RECOVER) && (pagestatus == STATE_PAGE_VALID))
1280 {
1281 /* This can happen in case of recover transfer. It indicates that previous */
1282 /* transfer goes far enough to fill a complete receive page at least */
1283 /* (valid state). Then erasing state marking was already completed */
1284 }
1285 else
1286 {
1287 /* Inconsistent previous page state */
1288 return EE_INVALID_PAGE_SEQUENCE;
1289 }
1290 }
1291
1292 #if defined(RECOVERY_TEST)
1293 if (Type == EE_TRANSFER_NORMAL)
1294 {
1295 VerifyStateReset(4U);
1296 }
1297 #endif
1298
1299 /* In case of recover transfer, transfer must be resumed where it has been stopped */
1300 /* Update global variables to reflect current transfer status */
1301 if (Type == EE_TRANSFER_RECOVER)
1302 {
1303 /* Count number of elements already transferred in current receive page */
1304 for (varidx = PAGE_HEADER_SIZE; varidx < PAGE_SIZE; varidx += EE_ELEMENT_SIZE)
1305 {
1306 /* Get next element in receive page */
1307 addressvalue = (*(__IO EE_ELEMENT_TYPE*)(PAGE_ADDRESS(ubCurrentActivePage) + varidx));
1308
1309 /* Check if element is valid */
1310 if (addressvalue != EE_PAGESTAT_ERASED)
1311 {
1312 /* Update global variables accordingly */
1313 uhNbWrittenElements++;
1314 uwAddressNextWrite += EE_ELEMENT_SIZE;
1315 }
1316 else
1317 {
1318 break;
1319 }
1320 }
1321
1322 /* Count number of elements already transferred in previous valid pages */
1323 page = ubCurrentActivePage;
1324 for (varidx = 0U; varidx < PAGES_NUMBER; varidx++)
1325 {
1326 /* Decrement page index among circular pages list */
1327 page = PREVIOUS_PAGE(page);
1328 pagestatus = GetPageState(PAGE_ADDRESS(page));
1329
1330 /* Check if page is valid state */
1331 if (pagestatus == STATE_PAGE_VALID)
1332 {
1333 /* Update uhNbWrittenElements with number of elements in page */
1334 uhNbWrittenElements += NB_MAX_ELEMENTS_BY_PAGE;
1335 }
1336 else
1337 {
1338 break;
1339 }
1340 }
1341 }
1342
1343 /* Write the variable passed as parameter in the new active page */
1344 /* If program operation was failed, a Flash error code is returned */
1345 if (VerifyPagesFullWriteVariable(VirtAddress, Data) != EE_OK)
1346 {
1347 return EE_WRITE_ERROR;
1348 }
1349
1350 #if defined(RECOVERY_TEST)
1351 if (Type == EE_TRANSFER_NORMAL)
1352 {
1353 VerifyStateReset(5U);
1354 }
1355 #endif
1356
1357 /* Transfer process: transfer variables from old to the new active page */
1358 /* First element in receive page can be any one, the following elements are */
1359 /* ordered from the beginning. */
1360 /* In case of recovery, Pre-Last element in receive page could be */
1361 /* corrupted if reset occured during write of this element, */
1362 /* and last element is dummy value that we have just written. */
1363 /* Transfer shall then resume from (uhNbWrittenElements-3) variable index */
1364 for (varidx = (uhNbWrittenElements >= 3U?uhNbWrittenElements-3U:0U); varidx < NB_OF_VARIABLES; varidx++)
1365 {
1366 /* Check each variable except the one passed as parameter */
1367 if (puhVirtAdd[varidx] != VirtAddress)
1368 {
1369 /* Read the last variable updates */
1370 status = ReadVariable(puhVirtAdd[varidx], &DataValue);
1371 if (status == EE_OK)
1372 {
1373 /* In case variable corresponding to the virtual address was found */
1374 /* Transfer the variable to the new active page */
1375 /* If program operation was failed, a Flash error code is returned */
1376 status = VerifyPagesFullWriteVariable(puhVirtAdd[varidx], DataValue);
1377 if (status != EE_OK)
1378 {
1379 return status;
1380 }
1381 }
1382 else
1383 {
1384 if (status != EE_NO_DATA)
1385 {
1386 /* In case variable is not found , do nothing */
1387 /* Any other status is error code occurs during variable read */
1388 return status;
1389 }
1390 }
1391 }
1392 }
1393
1394 #if defined(RECOVERY_TEST)
1395 if (Type == EE_TRANSFER_NORMAL)
1396 {
1397 VerifyStateReset(6U);
1398 }
1399 #endif
1400
1401 /* Transfer is now done, mark the receive state page as active */
1402 if (SetPageState(ubCurrentActivePage, STATE_PAGE_ACTIVE) != EE_OK)
1403 {
1404 return EE_WRITE_ERROR;
1405 }
1406
1407 #if defined(RECOVERY_TEST)
1408 if (Type == EE_TRANSFER_NORMAL)
1409 {
1410 VerifyStateReset(7U);
1411 }
1412 #endif
1413
1414 /* Return last operation flash status */
1415 return EE_CLEANUP_REQUIRED;
1416 }
1417
1418 /**
1419 * @brief Verify if pages are full
1420 * then if not the case, writes variable in EEPROM.
1421 * @param VirtAddress 16 bit virtual address of the variable
1422 * @param Data @ref EE_DATA_TYPE data to be written as variable value
1423 * @retval EE_Status
1424 * - EE_OK: on success
1425 * - EE_FULL: if half pages are full
1426 * - EE error code: if an error occurs
1427 */
VerifyPagesFullWriteVariable(uint16_t VirtAddress,EE_DATA_TYPE Data)1428 static EE_Status VerifyPagesFullWriteVariable(uint16_t VirtAddress, EE_DATA_TYPE Data)
1429 {
1430 uint32_t crc = 0U;
1431
1432 /* Check if pages are full, i.e. max number of written elements achieved */
1433 if (uhNbWrittenElements >= NB_MAX_WRITTEN_ELEMENTS)
1434 {
1435 return EE_PAGE_FULL;
1436 }
1437
1438 /* Get active Page for write operation */
1439 uint32_t activepage = FindPage(FIND_WRITE_PAGE);
1440 uint32_t activepageaddress = 0U;
1441
1442 /* Check if there is no active page */
1443 if (activepage == EE_NO_PAGE_FOUND)
1444 {
1445 return EE_ERROR_NOACTIVE_PAGE;
1446 }
1447
1448 activepageaddress = PAGE_ADDRESS(activepage);
1449
1450 /* Force crc to 0 in case of Data/VirtAddress are 0*/
1451 if ((Data == 0U) && (VirtAddress == 0U))
1452 {
1453 crc = 0U;
1454 }
1455 else
1456 {
1457 /* Calculate crc of variable data and virtual address */
1458 crc = CalculateCrc(Data, VirtAddress);
1459 }
1460
1461 /* Program variable data + virtual address + crc */
1462 /* If program operation was failed, a Flash error code is returned */
1463 if (EE_FLASH_PROGRAM(activepageaddress+uwAddressNextWrite, EE_ELEMENT_VALUE(VirtAddress,Data,crc)) != HAL_OK)
1464 {
1465 return EE_WRITE_ERROR;
1466 }
1467
1468 #if defined(RECOVERY_TEST)
1469 uint32_t index = 0U;
1470
1471 /* Write variable values in backup registers 0 to 30 */
1472 for (index = 0U; index < 31U; index++)
1473 {
1474 if (puhVirtAdd[index] == VirtAddress)
1475 {
1476 LL_RTC_BAK_SetRegister(RTC, index, Data);
1477 }
1478 }
1479 #endif
1480
1481 /* Increment global variables relative to write operation done*/
1482 uwAddressNextWrite += EE_ELEMENT_SIZE;
1483 uhNbWrittenElements++;
1484
1485 return EE_OK;
1486 }
1487
1488 /**
1489 * @brief Set page state in page header
1490 * @param Page Index of the page
1491 * @param State State of the page
1492 * @retval EE_Status
1493 * - EE_OK: on success
1494 * - EE error code: if an error occurs
1495 */
SetPageState(uint32_t Page,EE_State_type State)1496 static EE_Status SetPageState(uint32_t Page, EE_State_type State)
1497 {
1498 uint32_t header1 = 0U, header2 = 0U, header3 = 0U, header4 = 0U;
1499
1500 header1 = PAGE_ADDRESS(Page);
1501 header2 = PAGE_ADDRESS(Page) + EE_ELEMENT_SIZE;
1502 header3 = PAGE_ADDRESS(Page) + (EE_ELEMENT_SIZE*2U);
1503 header4 = PAGE_ADDRESS(Page) + (EE_ELEMENT_SIZE*3U);
1504
1505 switch(State)
1506 {
1507 case STATE_PAGE_RECEIVE:
1508 {
1509 /* Set new Page status to STATE_PAGE_RECEIVE status */
1510 if (EE_FLASH_PROGRAM(header1, EE_PAGESTAT_RECEIVE) != HAL_OK)
1511 {
1512 return EE_WRITE_ERROR;
1513 }
1514 ubCurrentActivePage = Page;
1515 }
1516 break;
1517 case STATE_PAGE_ACTIVE:
1518 {
1519 /* Set new Page status to STATE_PAGE_ACTIVE status */
1520 if (EE_FLASH_PROGRAM(header2, EE_PAGESTAT_ACTIVE) != HAL_OK)
1521 {
1522 return EE_WRITE_ERROR;
1523 }
1524 ubCurrentActivePage = Page;
1525 }
1526 break;
1527 case STATE_PAGE_VALID:
1528 {
1529 /* Set new Page status to STATE_PAGE_VALID status */
1530 if (EE_FLASH_PROGRAM(header3, EE_PAGESTAT_VALID) != HAL_OK)
1531 {
1532 return EE_WRITE_ERROR;
1533 }
1534 }
1535 break;
1536 case STATE_PAGE_ERASING:
1537 {
1538 /* Set new Page status to STATE_PAGE_ERASING status */
1539 if (EE_FLASH_PROGRAM(header4, EE_PAGESTAT_ERASING) != HAL_OK)
1540 {
1541 return EE_WRITE_ERROR;
1542 }
1543 }
1544 break;
1545 default:
1546 break;
1547 }
1548
1549 /* Return last operation flash status */
1550 return EE_OK;
1551 }
1552
1553 /**
1554 * @brief Get page state in page header
1555 * @param Address Address of the FLASH Memory page
1556 * @retval State State of the page
1557 */
GetPageState(uint32_t Address)1558 static EE_State_type GetPageState(uint32_t Address)
1559 {
1560 EE_ELEMENT_TYPE status1 = 0U, status2 = 0U, status3 = 0U, status4 = 0U;
1561
1562 /* Get page state information from page header (3 first elements) */
1563 status1 = (*(__IO EE_ELEMENT_TYPE*)Address);
1564 status2 = (*(__IO EE_ELEMENT_TYPE*)(Address + EE_ELEMENT_SIZE));
1565 status3 = (*(__IO EE_ELEMENT_TYPE*)(Address + (EE_ELEMENT_SIZE*2U)));
1566 status4 = (*(__IO EE_ELEMENT_TYPE*)(Address + (EE_ELEMENT_SIZE*3U)));
1567
1568 /* Return erasing status, if element4 is not EE_PAGESTAT_ERASED value */
1569 if (status4 != EE_PAGESTAT_ERASED)
1570 {
1571 return STATE_PAGE_ERASING;
1572 }
1573
1574 /* Return valid status, if element3 is not EE_PAGESTAT_ERASED value */
1575 if (status3 != EE_PAGESTAT_ERASED)
1576 {
1577 return STATE_PAGE_VALID;
1578 }
1579
1580 /* Return active status, if element2 is not EE_PAGESTAT_ERASED value */
1581 if (status2 != EE_PAGESTAT_ERASED)
1582 {
1583 return STATE_PAGE_ACTIVE;
1584 }
1585
1586 /* Return receive status, if element1 is not EE_PAGESTAT_ERASED value */
1587 if (status1 != EE_PAGESTAT_ERASED)
1588 {
1589 return STATE_PAGE_RECEIVE;
1590 }
1591
1592 /* Return erased status, if 4 first elements are EE_PAGESTAT_ERASED value */
1593 return STATE_PAGE_ERASED;
1594 }
1595
1596 #if defined(RECOVERY_TEST)
1597 /**
1598 * @brief Check reset state in backup registers, then increment
1599 * it and reset system if it fits trigger value
1600 * @param TriggerState Value of state triggering system reset
1601 * @retval None
1602 */
VerifyStateReset(uint32_t TriggerState)1603 static void VerifyStateReset(uint32_t TriggerState)
1604 {
1605 uint32_t state = 0U;
1606
1607 /* Read state in backup registers N�31 */
1608 state = LL_RTC_BAK_GetRegister(RTC, 31U);
1609
1610 /* Trig System Reset, if state reach trigger state */
1611 if (state == TriggerState)
1612 {
1613 /* Increment state */
1614 state++;
1615
1616 /* Save state in backup register N�31 */
1617 LL_RTC_BAK_SetRegister(RTC, 31U, state);
1618
1619 /* System Reset */
1620 HAL_NVIC_SystemReset();
1621 }
1622 }
1623 #endif
1624
1625 /**
1626 * @brief This function configures CRC Instance.
1627 * @note This function is used to :
1628 * -1- Enable peripheral clock for CRC.
1629 * -2- Configure CRC functional parameters.
1630 * @note Peripheral configuration is minimal configuration from reset values.
1631 * Thus, some useless LL unitary functions calls below are provided as
1632 * commented examples - setting is default configuration from reset.
1633 * @param None
1634 * @retval None
1635 */
ConfigureCrc(void)1636 void ConfigureCrc(void)
1637 {
1638 /* (1) Enable peripheral clock for CRC */
1639 LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_CRC);
1640
1641 /* (2) Configure CRC functional parameters */
1642
1643 /* Configure CRC calculation unit with user defined polynomial */
1644 LL_CRC_SetPolynomialCoef(CRC, CRC_POLYNOMIAL_VALUE);
1645 LL_CRC_SetPolynomialSize(CRC, CRC_POLYNOMIAL_LENGTH);
1646
1647 /* Initialize default CRC initial value */
1648 /* Reset value is LL_CRC_DEFAULT_CRC_INITVALUE */
1649 /* LL_CRC_SetInitialData(CRC, LL_CRC_DEFAULT_CRC_INITVALUE);*/
1650
1651 /* Set input data inversion mode : No inversion*/
1652 /* Reset value is LL_CRC_INDATA_REVERSE_NONE */
1653 /* LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_NONE); */
1654
1655 /* Set output data inversion mode : No inversion */
1656 /* Reset value is LL_CRC_OUTDATA_REVERSE_NONE */
1657 /* LL_CRC_SetOutputDataReverseMode(CRC, LL_CRC_OUTDATA_REVERSE_NONE); */
1658 }
1659
1660 /**
1661 * @brief This function performs CRC calculation on Data and Virtual Address.
1662 * @param Data value of the eeprom variable.
1663 * @param VirtAddress address of the eeprom variable.
1664 * @retval 16-bit CRC value computed on Data and Virtual Address.
1665 */
CalculateCrc(EE_DATA_TYPE Data,uint16_t VirtAddress)1666 uint16_t CalculateCrc(EE_DATA_TYPE Data, uint16_t VirtAddress)
1667 {
1668 /* Reset CRC calculation unit */
1669 LL_CRC_ResetCRCCalculationUnit(CRC);
1670
1671 /* Feed Data and Virtual Address */
1672 LL_CRC_FeedData32(CRC, Data);
1673 LL_CRC_FeedData16(CRC, VirtAddress);
1674
1675 /* Return computed CRC value */
1676 return(LL_CRC_ReadData16(CRC));
1677 }
1678
1679 /**
1680 * @}
1681 */
1682
1683 /**
1684 * @}
1685 */
1686
1687 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
1688