Contiki 3.x
nvm.h
Go to the documentation of this file.
1 /** @file hal/micro/cortexm3/nvm.h
2  * @brief Cortex-M3 Non-Volatile Memory data storage system.
3  * See @ref nvm for documentation.
4  *
5  * The functions in this file return an ::StStatus value.
6  * See error-def.h for definitions of all ::StStatus return values.
7  *
8  * See hal/micro/cortexm3/nvm.h for source code.
9  *
10  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved. -->
11  */
12 
13 /**
14  * @addtogroup stm32w-cpu
15  * @{ */
16 
17 /** @defgroup nvm Cortex-M3 Non-Volatile Memory data storage system.
18  *
19  * This header defines the API for NVM data storage. This header also
20  * describes the algorithm behind the NVM data storage system with notes
21  * on algorithm behavior.
22  *
23  * See hal/micro/cortexm3/nvm.h for source code.
24  *
25  * @note The algorithm description uses "page" to indicate an area of memory
26  * that is a multiple of physical flash pages. There are two pages: LEFT
27  * and RIGHT. The term "flash page" is used to refer to a page of
28  * physical flash.
29  *
30  * NVM data storage works by alternating between two pages: LEFT and RIGHT.
31  * The basic algorithm is driven by a call to halCommonSaveToNvm(). It will:
32  * - erase the inactive page
33  * - write the new data to the inactive page
34  * - copy existing data from the active page to the inactive page
35  * - mark the inactive page as the new active page
36  * - mark the old active page as the new inactive page
37  * To accomplish alternating between two pages and knowing which page has the
38  * valid set of data, the algorithm uses 4 bytes of mgmt data that exists
39  * at the top of both LEFT and RIGHT (the term "mgmt" is shorthand referring to
40  * the management data). The management data is comprised of a Valid marker,
41  * an Active marker, a Dead marker, and a Spare byte. Viewing the
42  * management data as a single 32 bit quantity yields:
43  * - Valid is mgmt[0]
44  * - Active is mgmt[1]
45  * - Dead is mgmt[2]
46  * - Spare is mgmt[3]
47  * The algorithm is based on a simple, circular state machine. The following
48  * discussion details all of the possible mgmt bytes and the states they
49  * correspond to. The "Reads from" line indicates which page a call to
50  * halCommonReadFromNvm() will read from (an 'x' page will stuff the read
51  * data with 0xFF). The vertical "erase" and "write" words indicate the
52  * flash altering actions taken between those states. Invalid mgmt bytes
53  * is equivalent to erased mgmt bytes (state 0) and will trigger an
54  * erase of both LEFT and RIGHT. State 3 and state 7 are the only exit
55  * states. When the algorithm is run, regardless of starting state, it
56  * will advance to the next exit state. This means if the "Read from"
57  * is LEFT then the state machine will advance until state 7 and then exit.
58  * If "Read from" is RIGHT, then the state machine will advance until
59  * state 3 and then exit.
60  *
61  * @code
62  * Starting from erased or invalid mgmt, write to LEFT
63  * State # 0 0 1 2 3
64  * Reads from: x x e w L L L
65  * Valid xx|xx FF|FF r r 00|FF 00|FF 00|00
66  * Active xx|xx FF|FF a i 00|FF 00|FF 00|00
67  * Dead xx|xx FF|FF s t FF|FF FF|00 FF|00
68  * Spare xx|xx FF|FF e e FF|FF FF|FF FF|FF
69  *
70  *
71  * Starting from LEFT page, transition to RIGHT page:
72  * State # 3 4 5 6 7
73  * Reads from: L e L w R R R
74  * Valid 00|00 r 00|FF r 00|00 00|00 00|00
75  * Active 00|00 a 00|FF i 00|FF 00|FF 00|00
76  * Dead FF|00 s FF|FF t FF|FF 00|FF 00|FF
77  * Spare FF|FF e FF|FF e FF|FF FF|FF FF|FF
78  *
79  *
80  * Starting from RIGHT page, transition to LEFT page:
81  * State # 7 8 9 10 3
82  * Reads from: R e R w L L L
83  * Valid 00|00 r FF|00 r 00|00 00|00 00|00
84  * Active 00|00 a FF|00 i FF|00 FF|00 00|00
85  * Dead 00|FF s FF|FF t FF|FF FF|00 FF|00
86  * Spare FF|FF e FF|FF e FF|FF FF|FF FF|FF
87  * @endcode
88  *
89  * Based on the 10 possible states, there are 5 valid 32bit mgmt words:
90  * - 0xFFFFFFFF
91  * - 0xFFFFFF00
92  * - 0xFFFF0000
93  * - 0xFF000000
94  * - 0xFF00FFFF
95  * The algorithm determines the current state by using these 5 mgmt words
96  * with the 10 possible combinations of LEFT mgmt and RIGHT mgmt.
97  *
98  * Detailed State Description:
99  * - State 0:
100  * In this state the mgmt bytes do not conform to any of the other states
101  * and therefore the entire NVM system, both the LEFT and RIGHT, is
102  * invalid. Invalid could be as simple as both LEFT and RIGHT are erased
103  * or as complex as serious memory corruption or a bug caused bad data to
104  * be written to the NVM. By using a small set of very strict, precise,
105  * valid states (versus other management systems such as a simple counter),
106  * the algorithm/data gains some protection against not only corruption, but
107  * also executing the NVM algorithm on a chip that previously did not
108  * have the NVM system running on it.
109  * - State 1, 4, 8
110  * In these states, mgmt is saying that one page is valid and active, while
111  * the other page is erased. This tells the algorithm which page to read
112  * from and indicates that the other page has already been erased.
113  * - State 2
114  * This state is only necessary for transitioning from state 0. From state
115  * 0, the goal is to arrive at state 3. Ideally, the RIGHT mgmt would
116  * be written with 0xFF000000, but the flash library only permits 16 bit
117  * writes. If a reset were to occur in the middle of this section of the
118  * algorithm, we want to ensure that the mgmt is left in a known state,
119  * state 2, so that the algorithm could continue from where it got
120  * interrupted.
121  * - State 5, 9
122  * These states indicate that the other page has just become valid because
123  * the new data has just been written. Once at these states, reading
124  * from the NVM will now pull data from the other page.
125  * - State 6, 10
126  * These states indicate that the old page is now dead and not in use.
127  * While the algorithm already knows to read from the new page, the Dead
128  * mgmt byte is primarily used to indicate that the other page needs to
129  * be erased. Conceptually, the Dead byte can also be considered a type
130  * of "garbage collection" flag indicating the old page needs to be
131  * destroyed and has not yet been erased.
132  * - State 3, 7
133  * These states are the final exit points of the circular state machine.
134  * Once at these states, the current page is marked Valid and Active and
135  * the old page is marked as Dead. The algorithm knows which page to
136  * read from and which page needs to be erased on the next write to the NVM.
137  *
138  *
139  * Notes on algorithm behavior:
140  * - Refer to nvm-def.h for a list of offset/length that define the data
141  * stored in NVM storage space.
142  * - All writes to flash are 16bit granularity and therefore the internal
143  * flash writes cast the data to uint16_t. Length is also required to be
144  * a multiple of 16bits.
145  * - Flash page erase uses a granularity of a single flash page. The size
146  * of a flash page depends on the chip and is defined in memmap.h with
147  * the define MFB_PAGE_SIZE_B.
148  * - Erasing will only occur when halCommonSaveToNvm() is called.
149  * - Erasing will always occur when halCommonSaveToNvm() is called unless the
150  * page intended to be erased is already entirely 0xFFFF.
151  * - When reading and management is invalid, the read will return 0xFF for data.
152  * - Calling halCommonSaveToNvm() while in any state is always valid and the
153  * new data will be written to flash.
154  * - halCommonSaveToNvm() will always advance the state machine to 3 or 7.
155  * - When writing and management is invalid, both LEFT and RIGHT will be erased
156  * and the new data will be written to LEFT.
157  * - Writing causes the new data being passed into halCommonSaveToNvm() to be
158  * written to flash. The data already existing in the currently valid page
159  * will be copied over to the new page.
160  * - Reading or writing to an offset equal to or greater than NVM_DATA_SIZE_B is
161  * illegal and will cause an assert.
162  * - Offset and length must always be multiples of 16bits. If not, both a read
163  * and a write will trigger an assert.
164  * - Offset and length must be supplied in bytes.
165  * - All data in NVM storage must exist above the mgmt bytes, denoted by
166  * NVM_MGMT_SIZE_B.
167  * - The bottom 64 bytes of NVM storage are allocated to radio calibration
168  * values. These 64 bytes *must* exist for the radio to function.
169  * - There is no error checking beyond checking for 16bit alignment. This
170  * means it is possible to use data offset and size combinations that
171  * exceed NVM storage space or overlap with other data. Be careful!
172  *@{
173  */
174 
175 
176 #ifndef NVM_H_
177 #define NVM_H_
178 
179 //Pull in the MFB_ definitions.
181 //Pull in nvm-def.h so any code including nvm.h has access to the
182 //offsets and sizes defining the NVM data.
184 //Necessary to define StStatus and codes.
185 #include "error.h"
186 
187 
188 /**
189  * @brief Copy the NVM data from flash into the provided RAM location.
190  * It is illegal for the offset to be greater than NVM_DATA_SIZE_B.
191  *
192  * @param data A (RAM) pointer to where the data should be copied.
193  *
194  * @param offset The location from which the data should be copied. Must be
195  * 16bit aligned.
196  *
197  * @param length The length of the data in bytes. Must be 16bit aligned.
198  *
199  * @return An StStatus value indicating the success of the function.
200  * - ST_SUCCESS if the read completed cleanly.
201  * - ST_ERR_FATAL if the NVM storage management indicated an invalid
202  * state. The function will return entirely 0xFF in the data parameter.
203  */
204 StStatus halCommonReadFromNvm(void *data, uint32_t offset, uint16_t length);
205 
206 /**
207  * @brief Return the address of the token in NVM
208  *
209  * @param offset The location offset from which the address should be returned
210  *
211  *
212  * @return The address requested
213  */
214 uint16_t *halCommonGetAddressFromNvm(uint32_t offset);
215 
216 /**
217  * @brief Write the NVM data from the provided location RAM into flash.
218  * It is illegal for the offset to be greater than NVM_DATA_SIZE_B.
219  *
220  * @param data A (RAM) pointer from where the data should be taken.
221  *
222  * @param offset The location to which the data should be written. Must be
223  * 16bit aligned.
224  *
225  * @param length The length of the data in bytes. Must be 16bit aligned.
226  *
227  * @return An StStatus value indicating the success of the function.
228  * - ST_SUCCESS if the write completed cleanly.
229  * - Any other status value is an error code generated by the low level
230  * flash erase and write API. Refer to flash.h for details.
231  */
232 StStatus halCommonWriteToNvm(const void *data, uint32_t offset, uint16_t length);
233 
234 /**
235  * @brief Define the number of physical flash pages that comprise a NVM page.
236  * Since NVM_DATA_SIZE_B must be a multiple of MFB_PAGE_SIZE_B, increasing the
237  * size of NVM storage should be done by modifying this define.
238  *
239  * @note The total flash area consumed by NVM storage is double this value.
240  * This is due to the fact that there are two NVM pages, LEFT and RIGHT,
241  * which the algorithm alternates between.
242  */
243 #define NVM_FLASH_PAGE_COUNT (1)
244 
245 /**
246  * @brief Define the total size of a NVM page, in bytes. This must be a
247  * multiple of the memory map define MFB_PAGE_SIZE_B. Note that 4 bytes of
248  * the total size of an NVM page are dedicated to page management.
249  *
250  * @note <b>DO NOT EDIT THIS DEFINE. Instead, edit NVM_FLASH_PAGE_COUNT.</b>
251  */
252 #define NVM_DATA_SIZE_B (MFB_PAGE_SIZE_B*NVM_FLASH_PAGE_COUNT)
253 #if ((NVM_DATA_SIZE_B%MFB_PAGE_SIZE_B) != 0)
254  #error Illegal NVM data storage size. NVM_DATA_SIZE_B must be a multiple of MFB_PAGE_SIZE_B.
255 #endif
256 
257 /**
258  * @brief Define the absolute address of the LEFT page. LEFT page storage
259  * is defined by nvmStorageLeft[NVM_DATA_SIZE_B] and placed by the linker
260  * using the segment "NVM".
261  */
262 #define NVM_LEFT_PAGE ((uint32_t)nvmStorageLeft)
263 
264 /**
265  * @brief Define the absolute address of the RIGHT page. RIGHT page storage
266  * is defined by nvmStorageRight[NVM_DATA_SIZE_B] and placed by the linker
267  * using the segment "NVM".
268  */
269 #define NVM_RIGHT_PAGE ((uint32_t)nvmStorageRight)
270 
271 /**
272  * @brief Define the number of bytes that comprise the NVM management bytes.
273  * All data must begin at an offset above the management bytes.
274  *
275  * @note This value <b>must not change</b>.
276  */
277 #define NVM_MGMT_SIZE_B (4)
278 
279 /** @} END addtogroup */
280 /** @} */
281 
282 #endif // NVM_H_
283 
STM32W108 series memory map definitions used by the full hal.
StStatus halCommonReadFromNvm(void *data, uint32_t offset, uint16_t length)
Copy the NVM data from flash into the provided RAM location.
Definition: nvm.c:98
StStatus halCommonWriteToNvm(const void *data, uint32_t offset, uint16_t length)
Write the NVM data from the provided location RAM into flash.
Definition: nvm.c:280
Data definitions for the Cortex-M3 Non-Volatile Memory data storage system.
uint16_t * halCommonGetAddressFromNvm(uint32_t offset)
Return the address of the token in NVM.
Definition: nvm.c:158
uint8_t StStatus
Return type for St functions.
Definition: error.h:18