NHS31xx storage - Maximizing storage for equisized samples
storage.h
Go to the documentation of this file.
1 /*
2  * Copyright 2016-2020 NXP
3  * This software is owned or controlled by NXP and may only be used strictly
4  * in accordance with the applicable license terms. By expressly accepting
5  * such terms or by downloading, installing, activating and/or otherwise using
6  * the software, you are agreeing that you have read, and that you agree to
7  * comply with and are bound by, such license terms. If you do not agree to
8  * be bound by the applicable license terms, then you may not retain, install,
9  * activate or otherwise use the software.
10  */
11 
12 #ifndef __STORAGE_H_
13 #define __STORAGE_H_
14 
15 /**
16  * @defgroup MODS_NSS_STORAGE storage: NVM Storage module
17  * @ingroup MODS_NSS
18  * The storage module allows an application to store samples <strong> all of identical size</strong> in non-volatile
19  * memories EEPROM and FLASH.
20  *
21  * It will:
22  * - abstract away where and how the samples are stored
23  * - provide an easy interface via which samples can be written to and read from
24  * - utilize all bits, placing all samples back to back, maximizing storage capacity
25  * - minimize FLASH program operations, thereby avoiding the time penalty, voltage drop and current consumption that
26  * comes with every FLASH program operation
27  * - move data from EEPROM to FLASH automatically whenever necessary to make sure the newest data is always in EEPROM
28  * - allow application-specific compression of the data just before moving data from EEPROM to FLASH
29  * - allow application-specific decompression of the data before they are read out again
30  * - recover its full state based on the contents of the non-volatile memory alone
31  *
32  * The storage module will use general purpose registers, EEPROM and FLASH to store bits of data. The usage of the
33  * three types of memories is prioritized. When a new sample is to be stored:
34  * - first an attempt is made to store it in the general purpose registers ("cached").
35  * - when this is not possible, the storage module tries to store it (together with all the cached samples) in EEPROM
36  * @n After moving data to EEPROM, the general purpose registers are re-used.
37  * - only when a sufficient amount of samples are stored in EEPROM, all the data is moved to FLASH.
38  * @n After moving data to FLASH, the EEPROM is re-used.
39  * .
40  * Writing samples always means appending them to the already written samples; it is not possible to edit the already
41  * written stream of bits.
42  * When reading out, the user can control the starting read position using a sequence number. It is automatically
43  * deduced where the corresponding sample is written, whether it is compressed, and what needs to be done to be able to
44  * return the requested sample(s).
45  *
46  * @par Hardening
47  * The storage module provides a ready-made solution to maximize storage of samples in persistent memory. It can:
48  * - store more than 10.000 samples without hitting the write endurance limit of both EEPROM and FLASH
49  * - recover state from unexpected resets
50  * - recover all or most of the samples in case of data corruption (this may occur when the battery is degraded and
51  * can no longer supply the minimum voltage when the load increases during a write operation in EEPROM or FLASH)
52  * .
53  * It is not possible to fully recover data under all circumstances. The storage module guarantees that only the last
54  * few samples may get lost. The number is dependent on the number of the reserved general purpose registers and the
55  * size of a sample, both of which (and more) can be tweaked using diversity settings.
56  *
57  *
58  * @par Diversity
59  * This module supports diversity settings. Some settings define the type and size of the sample. Others define the
60  * EEPROM and FLASH regions placed under control of this module. The rest of the settings control the behavior of the
61  * module. Check @ref MODS_NSS_STORAGE_DFT for all diversity settings.
62  * @n
63  * It is expected that each application that requires this module includes it and configures the diversity settings of
64  * the module according to its specific needs.
65  *
66  * @par Memory Requirements
67  * The storage module requires a large chunk of SRAM, called its workarea - see #STORAGE_WORKAREA and
68  * #STORAGE_WORKAREA_SIZE. This is used for two purposes:
69  * - When storing samples, and a move from EEPROM to FLASH is required, the assigned compress callback - see
70  * #STORAGE_COMPRESS_CB - is given a pointer inside this SRAM memory. The output is then stored in FLASH.
71  * - When reading samples from FLASH, the assigned decompress callback - see #STORAGE_DECOMPRESS_CB - is called as
72  * little as possible: its output is cached in the work area to speed up subsequent reads.
73  * .
74  * If two operations in your code require such a big chunk of memory, you can overlap them if they don't have to
75  * operate concurrently. Diversity setting #STORAGE_WORKAREA can be used for this.
76  *
77  * @par How to use the module
78  * -# Define the best diversity settings for your application or accept the default ones.
79  * -# Initialize the EEPROM driver and the storage module, in that order.
80  * -# Read and write samples as necessary, in any order or quantity that is required for your use case.
81  * -# De-initialize the storage module and the EEPROM driver, in that order.
82  * .
83  *
84  * @par Example
85  * @snippet storage_mod_example_1.c storage_mod_example_1
86  *
87  * @warning These functions are not re-entrant. Calling these functions from multiple threads or in an interrupt is
88  * highly discouraged.
89  * @warning The storage module requires the exclusive use of @em at @em least @em one register in the always-on domain
90  * (see #STORAGE_FIRST_ALON_REGISTER). Under no circumstance may the reserved registers be touched from outside the
91  * storage module.
92  * @warning Although the storage module is able to recover after a power loss or going to Power-off, it is slow in doing
93  * so. The slow recovery time only occurs once as long as no changes to the NVM are made (e.g. by calling
94  * #Storage_Write).
95  * @{
96  */
97 
98 #include "board.h"
99 #include "storage_dft.h"
100 
101 /* ------------------------------------------------------------------------- */
102 
103 /**
104  * Whenever data is about to be moved from EEPROM to FLASH, the application is notified via a callback of this
105  * prototype. It then has a chance to compress the data before it is written to FLASH.
106  * The application is in charge of:
107  * - reading the data from EEPROM using @c eepromByteOffset as starting point,
108  * - compressing exactly @c bitCount bits,
109  * - storing the end result in @c out and
110  * - returning the size of the data written in @c pOut, expressed in @b bits.
111  * @param eepromByteOffset The absolute offset in bytes to the EEPROM where the first sample is stored.
112  * @param bitCount An exact total of #STORAGE_BLOCK_SIZE_IN_SAMPLES samples are stored. They are
113  * packed together, i.e. without any padding bits. This argument will @b always equal
114  * @c #STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BITS.
115  * @param pOut A pointer to SRAM where the compressed data must be stored in. The buffer has a size of
116  * @c #STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BYTES bytes.
117  * @return The size of the compressed data @b in @b bits. When @c 0 is returned, or a value bigger than or equal to
118  * @c #STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BITS, the uncompressed data will be stored instead, and the corresponding
119  * decompression callback of type #pStorage_DecompressCb_t will not be called when reading out the data later.
120  * @warning It is @b not allowed to call any function of this module during the lifetime of the callback.
121  * @see STORAGE_COMPRESS_CB
122  */
123 typedef int (*pStorage_CompressCb_t)(int eepromByteOffset, int bitCount, void * pOut);
124 
125 /**
126  * Whenever data is read from FLASH, the application is notified via a callback of this prototype. It then has a chance
127  * to decompress the data before it is used to fulfill the read request #Storage_Read.
128  * The application is in charge of:
129  * - reading the data from FLASH using @c data as starting point,
130  * - decompressing one block of compressed data stored from that point with size @c bitCount,
131  * - storing the end result - #STORAGE_BLOCK_SIZE_IN_SAMPLES samples - in @c out. The samples @b must be written
132  * packed together, i.e. without any padding bits.
133  * @param pData The absolute byte address to FLASH memory where the start of the (compressed) data block is found.
134  * @param bitCount The size in bits of the (compressed) data block.
135  * @param pOut A pointer to SRAM where the compressed data must be stored in. The buffer has a size of
136  * @c #STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BYTES bytes.
137  * @return The number of bits written to in @c pOut.
138  * If @c #STORAGE_UNCOMPRESSED_BLOCK_SIZE_IN_BITS is returned, the operation is assumed to be
139  * successful and the decompressed samples are now available. @c Any other value indicates a decompression failure:
140  * the samples stored in that block can @b not be retrieved any more, and the call to #Storage_Read which initiated
141  * this callback will fail.
142  * @warning It is @b not allowed to call any function of this module during the lifetime of the callback.
143  * @see STORAGE_DECOMPRESS_CB
144  */
145 typedef int (*pStorage_DecompressCb_t)(const uint8_t * pData, int bitCount, void * pOut);
146 
147 /* ------------------------------------------------------------------------- */
148 
149 /**
150  * This function must be the first function to call in this module after going to deep power down or power-off power
151  * save mode. Not calling this function will result at best in random data being written and read, and possibly generate
152  * hard faults.
153  * @pre The value written in #STORAGE_FIRST_ALON_REGISTER and beyond is either exactly what was stored after leaving
154  * #Storage_DeInit, or equal to @c 0.
155  * @pre EEPROM is initialized and is ready to be used.
156  * @post When this function returns, #Storage_Seek still needs to be called before being able to read samples. This is
157  * also required when reading from the start of the memory, i.e. when reading the oldest stored sample referred to as
158  * index 0.
159  * @warning This function can run for a long time before completion when it is forced to scan the assigned EEPROM
160  * region to recover the data that is stored in EEPROM and/or FLASH. The time spent is depending on both the assigned
161  * EEPROM region and the number of samples stored in EEPROM: the longer the region, the more time spent; the more
162  * samples stored in EEPROM, the less time spent recovering. Under worst case conditions using a system clock of
163  * 0.5 MHz, this may last more than 10 msec.
164  * This penalty only occurs under these combined conditions:
165  * - the IC went to power-off, losing all information stored in the register #STORAGE_FIRST_ALON_REGISTER and beyond.
166  * - data was added to the storage module after leaving a previous power-off mode
167  * .
168  */
169 void Storage_Init(void);
170 
171 /**
172  * This function must be the last function to call in this module before going to deep power down or power-off power
173  * save mode.
174  * @pre EEPROM is still initialized and ready to be used.
175  * @post Possibly, an EEPROM flush was necessary, but that has finished when this function returns.
176  * @warning Loss of power before or during this call may result in loss of some or all of the newly added samples.
177  */
178 void Storage_DeInit(void);
179 
180 /**
181  * @return The total number of samples currently stored, in EEPROM and FLASH combined.
182  */
183 int Storage_GetCount(void);
184 
185 /**
186  * Resets the storage module to a pristine state.
187  * @param checkFlash The contents in FLASH must have been erased before it can be written to. An erase operation is
188  * costly and time-consuming and is preferably avoided.
189  * - When @c true is given, @b all words of the FLASH memory assigned for sample storage are checked.
190  * If one checked word does not contain the erased value (@c 0xFFFFFFFF), all FLASH memory is erased. This
191  * can possibly take up to 3 erase cycles. Aligning #STORAGE_FLASH_FIRST_PAGE and #STORAGE_FLASH_LAST_PAGE to
192  * sector boundaries can reduce this to the minimum of 1 erase cycle.
193  * - When @c false is given, FLASH memory is not checked and not erased.
194  * .
195  * @note Provide @c true as argument for @c checkFlash when the intention is to store new samples afterwards.
196  */
197 void Storage_Reset(bool checkFlash);
198 
199 /**
200  * Stores @c n samples.
201  * @pre EEPROM is initialized
202  * @param pSamples Pointer to the start of the array where to copy the samples from. For each element of the array,
203  * only the #STORAGE_BITSIZE LSBits are copied.
204  * @param n The size of the array @c pSamples points to, in number of #STORAGE_TYPE elements.
205  * @return The number of samples written. This value may be @c 0 or any number of samples less than or equal to @c n.
206  * @note When a value less than @c n is returned, at least one of these errors occurred:
207  * - There is insufficient storage capacity
208  * - Compressing of samples was necessary during the call, but that operation yielded an error.
209  * .
210  * @note A prior call to #Storage_Seek is @b not required, as writing will always @b append the new samples.
211  * @post A later call to #Storage_DeInit is necessary to ensure the data can survive Deep power down state.
212  * @warning Data is not guaranteed to be stored in EEPROM or FLASH: reset can lose some of the last samples written.
213  */
214 int Storage_Write(STORAGE_TYPE * pSamples, int n);
215 
216 /**
217  * Determines which sample is read out next in a future call to #Storage_Read. This call is
218  * required to be called once before calling #Storage_Read one or multiple times.
219  * @param n Must be a positive number. A value of @c 0 indicates the oldest sample, which was written first.
220  * @return @c true when the sought for sequence number was found; @c false otherwise.
221  * @post the next call to #Storage_Read will either return at least one sample - the value
222  * which was stored as the @c n-th sample - or fail - when less than @c n samples are being stored at the time of
223  * calling this function.
224  * @note After initialization, the default sequence number is @em not @c 0. First, a call to this function is required
225  * before #Storage_Read can retrieve samples.
226  */
227 bool Storage_Seek(int n);
228 
229 /**
230  * Reads @c n samples from persistent storage, starting from the sequence number set in #Storage_Seek.
231  * @pre EEPROM is initialized
232  * @pre A prior successful call to #Storage_Seek is required before this function can succeed.
233  * @note Multiple reads can be issued after calling #Storage_Seek once, each time fetching samples in sequence.
234  * @param [out] pSamples : Pointer to an array of @n elements, where the read samples are copied to. Upon successful
235  * completion, each element will contain one sample, where only the #STORAGE_BITSIZE LSBits are used per
236  * element; the remainder MSBits are set to 0.
237  * @param n : The size of the array @c samples points to, in number of #STORAGE_TYPE elements.
238  * @return The number of samples read. This value may be @c 0 or any number of samples less than @c n.
239  * The remainder of the elements with a higher index may have been written to, but must be ignored.
240  * @note When a value less than @c n is returned, at least one of these errors occurred:
241  * - There was no prior successful call to #Storage_Seek
242  * - Decompressing of samples was necessary during the call, but that operation yielded an error.
243  * - There are no more samples stored.
244  */
245 int Storage_Read(STORAGE_TYPE * pSamples, int n);
246 
247 /**
248  * @cond STORAGE_DOC
249  * @mainpage storage: NVM Storage module
250  * @copydoc MODS_NSS_STORAGE
251  * @endcond
252  */
253 #endif /** @} */
int Storage_Read(STORAGE_TYPE *pSamples, int n)
Definition: storage.c:1750
bool Storage_Seek(int n)
Definition: storage.c:1681
void Storage_DeInit(void)
Definition: storage.c:1505
void Storage_Init(void)
Definition: storage.c:1425
int Storage_GetCount(void)
Definition: storage.c:1530
void Storage_Reset(bool checkFlash)
Definition: storage.c:1535
int Storage_Write(STORAGE_TYPE *pSamples, int n)
Definition: storage.c:1619
#define STORAGE_TYPE
Definition: storage_dft.h:264
int(* pStorage_CompressCb_t)(int eepromByteOffset, int bitCount, void *pOut)
Definition: storage.h:123
int(* pStorage_DecompressCb_t)(const uint8_t *pData, int bitCount, void *pOut)
Definition: storage.h:145