]> git.sur5r.net Git - freertos/blob
2ba657176595c52549f35f7d23a4c7d72aa1bc5d
[freertos] /
1 /*******************************************************************************\r
2  * (c) Copyright 2011-2013 Microsemi SoC Products Group.  All rights reserved.\r
3  *\r
4  * This source file contains SmartFusion2 eNVM driver code.\r
5  *\r
6  * SVN $Revision: 5316 $\r
7  * SVN $Date: 2013-03-24 12:33:15 +0000 (Sun, 24 Mar 2013) $\r
8  */\r
9 \r
10 #include "../../CMSIS/m2sxxx.h"\r
11 #include "../../CMSIS/mss_assert.h"\r
12 #include "../../CMSIS/system_m2sxxx.h"\r
13 #include "mss_nvm.h"\r
14 \r
15 #ifdef __cplusplus\r
16 extern "C" {\r
17 #endif\r
18 \r
19 /**************************************************************************/\r
20 /* Preprocessor definitions                                               */\r
21 /**************************************************************************/\r
22 /*     eNVM command codes       */\r
23 #define PROG_ADS       0x08000000u  /* One shot program with data in WD */\r
24 #define VERIFY_ADS     0x10000000u  /* One shot verification with data in WD */\r
25 #define USER_UNLOCK    0x13000000u  /* User unlock */\r
26 \r
27 #define BITS_PER_PAGE  1024u                   /* Number of bits per page */\r
28 #define BYTES_PER_PAGE (BITS_PER_PAGE / 8u)    /* Number of bytes per page */\r
29 \r
30 #define NVM_OFFSET_SIGNIFICANT_BITS     0x0007FFFFu\r
31 #define NVM1_BOTTOM_OFFSET              0x00040000u\r
32 #define NVM1_TOP_OFFSET                 0x0007FFFFu\r
33 \r
34 #define NVM_BASE_ADDRESS                0x60000000u\r
35 \r
36 #define PAGE_ADDR_MASK                  0xFFFFFF80u\r
37 \r
38 #define BLOCK1_FIRST_WORD_OFFSET        0x00010000u\r
39 \r
40 #define WD_WORD_SIZE        32u\r
41 \r
42 #define NB_OF_BYTES_IN_A_WORD           4u\r
43 \r
44 #define WRITE_ERROR_MASK    (MSS_NVM_VERIFY_FAIL | \\r
45                              MSS_NVM_EVERIFY_FAIL | \\r
46                              MSS_NVM_WVERIFY_FAIL | \\r
47                              MSS_NVM_PEFAIL_LOCK | \\r
48                              MSS_NVM_WRCNT_OVER | \\r
49                              MSS_NVM_WR_DENIED)\r
50 \r
51 /*******************************************************************************\r
52  * Combined status definitions\r
53  * Below definitions should be used to decoded the bit encoded status returned \r
54  * by the function MSS_NVM_get_status().\r
55  */\r
56 #define MSS_NVM_BUSY_B              (1u)        /* NVM is performing an internal operation */\r
57 #define MSS_NVM_VERIFY_FAIL         ((uint32_t)1 << 1u)     /* NVM verify operation failed */\r
58 #define MSS_NVM_EVERIFY_FAIL        ((uint32_t)1 << 2u)     /* NVM erase verify operation failed */\r
59 #define MSS_NVM_WVERIFY_FAIL        ((uint32_t)1 << 3u)     /* NVM write verify operation failed */\r
60 #define MSS_NVM_PEFAIL_LOCK         ((uint32_t)1 << 4u)     /* NVM program / erase operation failed due to page lock */\r
61 #define MSS_NVM_WRCNT_OVER          ((uint32_t)1 << 5u)     /* NVM write count overflowed */\r
62 #define MSS_NVM_WR_DENIED           ((uint32_t)1 << 18u)    /* NVM write is denied due to protection */\r
63 \r
64 /*******************************************************************************\r
65  * \r
66  */\r
67 #define NVM_BLOCK_0     0u\r
68 #define NVM_BLOCK_1     1u\r
69 \r
70 /*******************************************************************************\r
71  * \r
72  */\r
73 #define MAX_512K_OFFSET     0x00080000u\r
74 \r
75 /**************************************************************************/\r
76 /* Global data definitions                                                */\r
77 /**************************************************************************/\r
78 /**************************************************************************//**\r
79  * Look-up table for NVM blocks.\r
80  */\r
81 static NVM_TypeDef * const g_nvm[] = \r
82 {\r
83     ENVM_1 ,\r
84     ENVM_2\r
85 };\r
86 \r
87 static NVM32_TypeDef * const g_nvm32[] =\r
88 {\r
89     (NVM32_TypeDef *)ENVM1_BASE ,\r
90     (NVM32_TypeDef *)ENVM2_BASE\r
91 };\r
92 \r
93 /**************************************************************************/\r
94 /* Private function declarations                                          */\r
95 /**************************************************************************/\r
96 static nvm_status_t request_nvm_access\r
97 (\r
98     uint32_t nvm_block_id\r
99 );\r
100 \r
101 static nvm_status_t get_ctrl_access\r
102 (\r
103     uint32_t nvm_offset,\r
104     uint32_t  length\r
105 );\r
106 \r
107 static void release_ctrl_access(void);\r
108 \r
109 static uint32_t get_remaining_page_length\r
110 (\r
111     uint32_t offset,\r
112     uint32_t  length\r
113 );\r
114 \r
115 static void fill_wd_buffer\r
116 (\r
117     const uint8_t * p_data,\r
118     uint32_t  length,\r
119     uint32_t block,\r
120     uint32_t offset\r
121 );\r
122 \r
123 static uint32_t \r
124 write_nvm\r
125 (\r
126     uint32_t addr,\r
127     const uint8_t * pidata,\r
128     uint32_t  length,\r
129     uint32_t  lock_page,\r
130     uint32_t * p_status\r
131 );\r
132 \r
133 static uint32_t \r
134 wait_nvm_ready\r
135 (\r
136     uint32_t block\r
137 );\r
138 \r
139 static nvm_status_t get_error_code(uint32_t nvm_hw_status);\r
140 \r
141 /**************************************************************************/\r
142 /* Public function definitions                                            */\r
143 /**************************************************************************/\r
144 \r
145 /**************************************************************************//**\r
146  * See mss_nvm.h for details of how to use this function.\r
147  */\r
148 nvm_status_t \r
149 NVM_write\r
150 (\r
151     uint32_t start_addr,\r
152     const uint8_t * pidata,\r
153     uint32_t  length,\r
154     uint32_t  lock_page\r
155 )\r
156 {\r
157     nvm_status_t status;\r
158     uint32_t nvm_offset;\r
159     uint32_t device_version;\r
160     \r
161     /*\r
162      * Prevent pages being locked for silicon versions which do not allow\r
163      * locked pages to be unlocked.\r
164      */\r
165     device_version = SYSREG->DEVICE_VERSION;\r
166     if((0x0000F802u == device_version) || (0x0001F802u == device_version))\r
167     {\r
168         lock_page = NVM_DO_NOT_LOCK_PAGE;\r
169     }\r
170     \r
171     /* Ignore upper address bits to ignore remapping setting. */\r
172     nvm_offset = start_addr & NVM_OFFSET_SIGNIFICANT_BITS;  /* Ignore remapping. */\r
173     \r
174     /* Check against attempt to write data larger than eNVM. */\r
175     ASSERT((nvm_offset + length) < MAX_512K_OFFSET);\r
176     if((nvm_offset + length) < MAX_512K_OFFSET)\r
177     {\r
178         /* Gain exclusive access to eNVM controller */\r
179         status = get_ctrl_access(nvm_offset, length);\r
180 \r
181         /* Write eNVM one page at a time. */\r
182         if(NVM_SUCCESS == status)\r
183         {\r
184             uint32_t remaining_length = length;\r
185             \r
186             while((remaining_length > 0u) && (NVM_SUCCESS == status))\r
187             {\r
188                 uint32_t length_written;\r
189                 uint32_t nvm_hw_status = 0u;\r
190                 \r
191                 length_written = write_nvm(start_addr + (length - remaining_length), \r
192                                            &pidata[length - remaining_length],\r
193                                            remaining_length,\r
194                                            lock_page,\r
195                                            &nvm_hw_status);\r
196                 \r
197                 if(0u == length_written)\r
198                 {\r
199                     status = get_error_code(nvm_hw_status);\r
200                 }\r
201                 else if(remaining_length > length_written)\r
202                 {\r
203                     remaining_length -= length_written;\r
204                 }\r
205                 else\r
206                 {\r
207                     remaining_length = 0u;\r
208                 }\r
209             }\r
210             \r
211             /* Release eNVM controllers so that other masters can gain access to it. */\r
212             release_ctrl_access();\r
213         }\r
214     }\r
215     else\r
216     {\r
217         status = NVM_INVALID_PARAMETER;\r
218     }\r
219 \r
220     return status;\r
221 }\r
222 \r
223 /**************************************************************************//**\r
224   Generate error code based on NVM status value.\r
225   \r
226   The hardware nvm status passed as parameter is expected to be masked using the\r
227   following mask:\r
228                 (MSS_NVM_VERIFY_FAIL | \\r
229                  MSS_NVM_EVERIFY_FAIL | \\r
230                  MSS_NVM_WVERIFY_FAIL | \\r
231                  MSS_NVM_PEFAIL_LOCK | \\r
232                  MSS_NVM_WRCNT_OVER | \\r
233                  MSS_NVM_WR_DENIED)\r
234   \r
235  */\r
236 static nvm_status_t get_error_code(uint32_t nvm_hw_status)\r
237 {\r
238     nvm_status_t status;\r
239     if(nvm_hw_status & MSS_NVM_WR_DENIED)\r
240     {\r
241         status = NVM_PROTECTION_ERROR;\r
242     }\r
243     else if(nvm_hw_status & MSS_NVM_WRCNT_OVER)\r
244     {\r
245         status = NVM_WRITE_THRESHOLD_ERROR;\r
246     }\r
247     else if(nvm_hw_status & MSS_NVM_PEFAIL_LOCK)\r
248     {\r
249         status = NVM_PAGE_LOCK_ERROR;\r
250     }\r
251     else\r
252     {\r
253         status = NVM_VERIFY_FAILURE;\r
254     }\r
255     \r
256     return status;\r
257 }\r
258 \r
259 /**************************************************************************//**\r
260  * See mss_nvm.h for details of how to use this function.\r
261  */\r
262 nvm_status_t\r
263 NVM_unlock\r
264 (\r
265     uint32_t start_addr,\r
266     uint32_t length\r
267 )\r
268 {\r
269     nvm_status_t status;\r
270     uint32_t nvm_offset;\r
271     uint32_t first_page;\r
272     uint32_t last_page;\r
273     uint32_t current_page;\r
274     uint32_t current_offset;\r
275     \r
276     /* Ignore upper address bits to ignore remapping setting. */\r
277     nvm_offset = start_addr & NVM_OFFSET_SIGNIFICANT_BITS;  /* Ignore remapping. */\r
278     \r
279     /* Check against attempt to write data larger than eNVM. */\r
280     ASSERT((nvm_offset + length) < MAX_512K_OFFSET);\r
281     if((nvm_offset + length) < MAX_512K_OFFSET)\r
282     {\r
283         current_offset = nvm_offset;\r
284         \r
285         first_page = nvm_offset / BYTES_PER_PAGE;\r
286         last_page = (nvm_offset + length) / BYTES_PER_PAGE;\r
287 \r
288         /* Gain exclusive access to eNVM controller */\r
289         status = get_ctrl_access(nvm_offset, length);\r
290 \r
291         /* Unlock eNVM one page at a time. */\r
292         if(NVM_SUCCESS == status)\r
293         {\r
294             uint32_t block;\r
295             uint32_t inc;\r
296             uint32_t first_word;\r
297             uint32_t word_offset;\r
298             uint32_t * p_nvm32;\r
299             uint32_t errors;\r
300             \r
301             p_nvm32 = (uint32_t *)NVM_BASE_ADDRESS;\r
302             \r
303             first_word = nvm_offset / 4u;\r
304             word_offset = first_word;\r
305             \r
306             for(current_page = first_page;\r
307                 (current_page <= last_page) && (NVM_SUCCESS == status);\r
308                 ++current_page)\r
309             {\r
310                 uint32_t ctrl_status;\r
311             \r
312                 if(word_offset >= BLOCK1_FIRST_WORD_OFFSET)\r
313                 {\r
314                     block = NVM_BLOCK_1;\r
315                 }\r
316                 else\r
317                 {\r
318                     block = NVM_BLOCK_0;\r
319                 }\r
320                 \r
321                 for(inc = 0u; inc < WD_WORD_SIZE; ++inc)\r
322                 {\r
323                     g_nvm32[block]->WD[inc] = p_nvm32[word_offset];\r
324                     ++word_offset;\r
325                 }\r
326                 \r
327                 g_nvm[block]->PAGE_LOCK = NVM_DO_NOT_LOCK_PAGE;\r
328                 g_nvm[block]->CMD = USER_UNLOCK;\r
329 \r
330                 /* Issue program command */\r
331                 g_nvm[block]->CMD = PROG_ADS | (current_offset & PAGE_ADDR_MASK);\r
332                 current_offset += BYTES_PER_PAGE;\r
333                 \r
334                 /* Wait for NVM to become ready. */\r
335                 ctrl_status = wait_nvm_ready(block);\r
336 \r
337                 /* Check for errors. */\r
338                 errors = ctrl_status & WRITE_ERROR_MASK;\r
339                 if(errors)\r
340                 {\r
341                     uint32_t nvm_hw_status;\r
342                     nvm_hw_status = g_nvm[block]->STATUS;\r
343                     status = get_error_code(nvm_hw_status);\r
344                 }\r
345             }\r
346             \r
347             /* Release eNVM controllers so that other masters can gain access to it. */\r
348             release_ctrl_access();\r
349         }\r
350     }\r
351     else\r
352     {\r
353         status = NVM_INVALID_PARAMETER;\r
354     }\r
355     \r
356     return status;\r
357 }\r
358 \r
359 /**************************************************************************/\r
360 /* Private function definitions                                            */\r
361 /**************************************************************************/\r
362 \r
363 /**************************************************************************//**\r
364  * \r
365  */\r
366 #define ACCESS_REQUEST_TIMEOUT      0x00800000u\r
367 #define REQUEST_NVM_ACCESS          0x01u\r
368 #define CORTEX_M3_ACCESS_GRANTED    0x05u\r
369 \r
370 static uint8_t g_envm_ctrl_locks = 0x00u;\r
371 \r
372 static nvm_status_t\r
373 request_nvm_access\r
374 (\r
375     uint32_t nvm_block_id\r
376 )\r
377 {\r
378     nvm_status_t status = NVM_SUCCESS;\r
379     volatile uint32_t timeout_counter;\r
380     uint32_t access;\r
381     \r
382     /*\r
383      * Use the SystemCoreClock frequency to compute a delay counter value giving\r
384      * us a delay in the 500ms range. This is a very approximate delay.\r
385      */\r
386     timeout_counter = SystemCoreClock / 16u;\r
387     \r
388     /*\r
389      * Gain access to eNVM controller.\r
390      */\r
391     do {\r
392         g_nvm[nvm_block_id]->REQ_ACCESS = REQUEST_NVM_ACCESS;\r
393         access = g_nvm[nvm_block_id]->REQ_ACCESS;\r
394         if(access != CORTEX_M3_ACCESS_GRANTED)\r
395         {\r
396             /*\r
397              * Time out if another AHB master locked access to eNVM to prevent\r
398              * the Cortex-M3 from locking up on eNVM write if some other part\r
399              * of the system fails from releasing the eNVM.\r
400              */\r
401             --timeout_counter;\r
402             if(0u == timeout_counter)\r
403             {\r
404                 status = NVM_IN_USE_BY_OTHER_MASTER;\r
405             }\r
406         }\r
407     } while((access != CORTEX_M3_ACCESS_GRANTED) && (NVM_SUCCESS == status));\r
408     \r
409     /*\r
410      * Mark controller as locked if successful so that it will be unlocked by a\r
411      * call to release_ctrl_access.\r
412      */\r
413     if(NVM_SUCCESS == status)\r
414     {\r
415         g_envm_ctrl_locks |= (uint8_t)((uint32_t)0x01 << nvm_block_id);\r
416     }\r
417     \r
418     return status;\r
419 }\r
420 \r
421 \r
422 /**************************************************************************//**\r
423  * \r
424  */\r
425 static nvm_status_t\r
426 get_ctrl_access\r
427 (\r
428     uint32_t nvm_offset,\r
429     uint32_t  length\r
430 )\r
431 {\r
432     nvm_status_t access_req_status;\r
433     \r
434     /*\r
435      * Gain access to eNVM controller(s).\r
436      */\r
437     if(nvm_offset < NVM1_BOTTOM_OFFSET)\r
438     {\r
439         access_req_status = request_nvm_access(NVM_BLOCK_0);\r
440         if(NVM_SUCCESS == access_req_status)\r
441         {\r
442             uint32_t last_offset;\r
443             last_offset = nvm_offset + length;\r
444             if(last_offset >= NVM1_BOTTOM_OFFSET)\r
445             {\r
446                 access_req_status = request_nvm_access(NVM_BLOCK_1);\r
447                 if(NVM_IN_USE_BY_OTHER_MASTER == access_req_status)\r
448                 {\r
449                     release_ctrl_access();\r
450                 }\r
451             }\r
452         }\r
453     }\r
454     else\r
455     {\r
456         access_req_status = request_nvm_access(NVM_BLOCK_1);\r
457     }\r
458     \r
459     return access_req_status;\r
460 }\r
461 \r
462 /**************************************************************************//**\r
463  * Release access to eNVM controllers.\r
464  */\r
465 #define NVM_BLOCK_0_LOCK_MASK   0x01u\r
466 #define NVM_BLOCK_1_LOCK_MASK   0x02u\r
467 \r
468 static void release_ctrl_access(void)\r
469 {\r
470     uint8_t block_locked;\r
471     \r
472     block_locked = g_envm_ctrl_locks & NVM_BLOCK_0_LOCK_MASK;\r
473     if(block_locked)\r
474     {\r
475         g_nvm[NVM_BLOCK_0]->REQ_ACCESS = 0x00u;\r
476         g_envm_ctrl_locks &= ~NVM_BLOCK_0_LOCK_MASK;\r
477     }\r
478     \r
479     block_locked = g_envm_ctrl_locks & NVM_BLOCK_1_LOCK_MASK;\r
480     if(block_locked)\r
481     {\r
482         g_nvm[NVM_BLOCK_1]->REQ_ACCESS = 0x00u;\r
483         g_envm_ctrl_locks &= ~NVM_BLOCK_1_LOCK_MASK;\r
484     }\r
485 }\r
486 \r
487 /**************************************************************************//**\r
488  * \r
489  */\r
490 static uint32_t wait_nvm_ready(uint32_t block) \r
491 {\r
492     volatile uint32_t ctrl_status;\r
493     uint32_t ctrl_ready;\r
494     uint32_t inc;\r
495     \r
496     /*\r
497      * Wait for NVM to become ready.\r
498      * We must ensure that we can read the ready bit set to 1 twice before we\r
499      * can assume that the other status bits are valid. See SmartFusion2 errata.\r
500      */\r
501     for(inc = 0u; inc < 2u; ++inc)\r
502     {\r
503         do {\r
504             ctrl_status = g_nvm[block]->STATUS;\r
505             ctrl_ready = ctrl_status  & MSS_NVM_BUSY_B;\r
506         } while(0u == ctrl_ready);\r
507     }\r
508     \r
509     return ctrl_status;\r
510 }\r
511 \r
512 /**************************************************************************//**\r
513   Write as much data as will fit into the eNVM page corresponding to the\r
514   address "addr" passed as parameter. Return the number of bytes written into\r
515   the page.\r
516   In case of error, return the content of the eNVM controller status register\r
517   into the 32-bit word pointed to by p_status.\r
518  */\r
519 static uint32_t \r
520 write_nvm\r
521 (\r
522     uint32_t addr,\r
523     const uint8_t * pidata,\r
524     uint32_t  length,\r
525     uint32_t  lock_page,\r
526     uint32_t * p_status\r
527 )\r
528 {\r
529     uint32_t length_written;\r
530     uint32_t offset;\r
531     \r
532     *p_status = 0u;\r
533     \r
534     offset = addr & NVM_OFFSET_SIGNIFICANT_BITS;  /* Ignore remapping. */\r
535 \r
536     ASSERT(offset <= NVM1_TOP_OFFSET);\r
537     \r
538     /* Adjust length to fit within one page. */\r
539     length_written = get_remaining_page_length(offset, length);\r
540     \r
541     if(offset <= NVM1_TOP_OFFSET)\r
542     {\r
543         uint32_t block;\r
544         volatile uint32_t ctrl_status;\r
545         uint32_t errors;\r
546         \r
547         if(offset < NVM1_BOTTOM_OFFSET)\r
548         {\r
549             block = NVM_BLOCK_0;\r
550         }\r
551         else\r
552         {\r
553             block = NVM_BLOCK_1;\r
554             offset = offset - NVM1_BOTTOM_OFFSET;\r
555         }\r
556         \r
557         fill_wd_buffer(pidata, length_written, block, offset);\r
558 \r
559         /* Set requested locking option. */\r
560         g_nvm[block]->PAGE_LOCK = lock_page;\r
561         \r
562         /* Issue program command */\r
563         g_nvm[block]->CMD = PROG_ADS | (offset & PAGE_ADDR_MASK);\r
564         \r
565         /* Wait for NVM to become ready. */\r
566         ctrl_status = wait_nvm_ready(block);\r
567 \r
568         /* Check for errors. */\r
569         errors = ctrl_status & WRITE_ERROR_MASK;\r
570         if(errors)\r
571         {\r
572             /* Signal that an error occured by returning 0 a a number of bytes written. */\r
573             length_written = 0u;\r
574             *p_status = g_nvm[block]->STATUS;\r
575         }\r
576         else\r
577         {\r
578             /* Perform a verify. */\r
579             g_nvm[block]->CMD = VERIFY_ADS | (offset & PAGE_ADDR_MASK);\r
580             /* Wait for NVM to become ready. */\r
581             ctrl_status = wait_nvm_ready(block);\r
582 \r
583             /* Check for errors. */\r
584             errors = ctrl_status & WRITE_ERROR_MASK;\r
585             if(errors)\r
586             {\r
587                 /* Signal that an error occured by returning 0 a a number of bytes written. */\r
588                 length_written = 0u;\r
589                 *p_status = g_nvm[block]->STATUS;\r
590             }\r
591         }\r
592     }\r
593     \r
594     return length_written;\r
595 }\r
596 \r
597 /*******************************************************************************\r
598   Return the number of bytes between the offset location and the end of the page\r
599   containing the first offset location. This tells us how many actual bytes can\r
600   be programmed with a single ProgramADS command.\r
601   This also tells us if we are programming a full page. If the return value is\r
602   equal to BYTES_PER_PAGE then we will be pragramming an entire NVM page.\r
603   Alternatively, this function returning a value other than BYTES_PER_PAGE\r
604   indicates that the WD[] buffer will have to be seeded with the existing\r
605   content of the eNVM before copying the data to program to eNVM into the WD[]\r
606   buffer.\r
607  */\r
608 static uint32_t get_remaining_page_length\r
609 (\r
610     uint32_t offset,\r
611     uint32_t  length\r
612 )\r
613 {\r
614     uint32_t start_page_plus_one;\r
615     uint32_t last_page;\r
616     \r
617     start_page_plus_one = (offset / BYTES_PER_PAGE) + 1u;\r
618     last_page = (offset + length) / BYTES_PER_PAGE;\r
619     if(last_page >= start_page_plus_one)\r
620     {\r
621         length = BYTES_PER_PAGE - (offset % BYTES_PER_PAGE);\r
622     }\r
623     \r
624     return length;\r
625 }\r
626 \r
627 /**************************************************************************//**\r
628  * \r
629  */\r
630 static void fill_wd_buffer\r
631 (\r
632     const uint8_t * p_data,\r
633     uint32_t  length,\r
634     uint32_t block,\r
635     uint32_t offset\r
636 )\r
637 {\r
638     uint32_t inc;\r
639     uint32_t wd_offset;\r
640     \r
641     if(length != BYTES_PER_PAGE)\r
642     {\r
643         uint32_t * p_nvm32;\r
644         uint32_t nb_non_written_words;\r
645         uint32_t first_non_written_word;\r
646         /* \r
647          * Fill beginning of WD[] with current content of NVM page that must not\r
648          * be overwritten.\r
649          */\r
650         p_nvm32 = (uint32_t *)((NVM_BASE_ADDRESS + offset) & PAGE_ADDR_MASK);\r
651         nb_non_written_words = (offset % BYTES_PER_PAGE) / NB_OF_BYTES_IN_A_WORD;\r
652         if((offset % NB_OF_BYTES_IN_A_WORD) > 0u)\r
653         {\r
654             ++nb_non_written_words;\r
655         }\r
656         for(inc = 0u; (inc < WD_WORD_SIZE) && (inc < nb_non_written_words); ++inc)\r
657         {\r
658             g_nvm32[block]->WD[inc] = p_nvm32[inc];\r
659         }\r
660         \r
661         /*\r
662          * Fill end of WD[] with current content of NVM page that must not be\r
663          * overwritten.\r
664          */\r
665         first_non_written_word = ((offset + length) % BYTES_PER_PAGE) / NB_OF_BYTES_IN_A_WORD;\r
666         nb_non_written_words = (BYTES_PER_PAGE / NB_OF_BYTES_IN_A_WORD) - first_non_written_word;\r
667         \r
668         for(inc = 0u; inc < nb_non_written_words; ++inc)\r
669         {\r
670             g_nvm32[block]->WD[first_non_written_word + inc] = p_nvm32[first_non_written_word + inc];\r
671         }\r
672     }\r
673     \r
674     /*\r
675      * Fill WD[] with data requested to be written into NVM.\r
676      */\r
677     wd_offset = offset % BYTES_PER_PAGE;\r
678     for(inc = 0u; inc < length; ++inc)\r
679     {\r
680         g_nvm[block]->WD[wd_offset + inc] = p_data[inc];\r
681     }\r
682 }\r
683 \r
684 #ifdef __cplusplus\r
685 }\r
686 #endif\r
687 \r
688 /******************************** END OF FILE ******************************/\r
689 \r
690 \r
691 \r
692 \r
693 \r
694 \r