source: trunk/firmware/SES/Drivers/EEPROM/eeprom_emul.c@ 1

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