]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/common/chibios/eeprom_stm32.c
STM32 EEPROM Emulation (#3741)
[qmk_firmware.git] / tmk_core / common / chibios / eeprom_stm32.c
1 /*
2  * This software is experimental and a work in progress.
3  * Under no circumstances should these files be used in relation to any critical system(s).
4  * Use of these files is at your own risk.
5  *
6  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
7  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
8  * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
9  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
11  * DEALINGS IN THE SOFTWARE.
12  *
13  * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and 
14  * https://github.com/leaflabs/libmaple
15  *
16  * Modifications for QMK and STM32F303 by Yiancar
17  */
18
19 #include "eeprom_stm32.h"
20
21     FLASH_Status EE_ErasePage(uint32_t);
22
23     uint16_t EE_CheckPage(uint32_t, uint16_t);
24     uint16_t EE_CheckErasePage(uint32_t, uint16_t);
25     uint16_t EE_Format(void);
26     uint32_t EE_FindValidPage(void);
27     uint16_t EE_GetVariablesCount(uint32_t, uint16_t);
28     uint16_t EE_PageTransfer(uint32_t, uint32_t, uint16_t);
29     uint16_t EE_VerifyPageFullWriteVariable(uint16_t, uint16_t);
30
31     uint32_t PageBase0 = EEPROM_PAGE0_BASE;
32     uint32_t PageBase1 = EEPROM_PAGE1_BASE;
33     uint32_t PageSize = EEPROM_PAGE_SIZE;
34     uint16_t Status = EEPROM_NOT_INIT;
35
36 // See http://www.st.com/web/en/resource/technical/document/application_note/CD00165693.pdf
37
38 /**
39   * @brief  Check page for blank
40   * @param  page base address
41   * @retval Success or error
42   *     EEPROM_BAD_FLASH:   page not empty after erase
43   *     EEPROM_OK:          page blank
44   */
45 uint16_t EE_CheckPage(uint32_t pageBase, uint16_t status)
46 {
47     uint32_t pageEnd = pageBase + (uint32_t)PageSize;
48
49     // Page Status not EEPROM_ERASED and not a "state"
50     if ((*(__IO uint16_t*)pageBase) != EEPROM_ERASED && (*(__IO uint16_t*)pageBase) != status)
51         return EEPROM_BAD_FLASH;
52     for(pageBase += 4; pageBase < pageEnd; pageBase += 4)
53         if ((*(__IO uint32_t*)pageBase) != 0xFFFFFFFF)  // Verify if slot is empty
54             return EEPROM_BAD_FLASH;
55     return EEPROM_OK;
56 }
57
58 /**
59   * @brief  Erase page with increment erase counter (page + 2)
60   * @param  page base address
61   * @retval Success or error
62   *         FLASH_COMPLETE: success erase
63   *         - Flash error code: on write Flash error
64   */
65 FLASH_Status EE_ErasePage(uint32_t pageBase)
66 {
67     FLASH_Status FlashStatus;
68     uint16_t data = (*(__IO uint16_t*)(pageBase));
69     if ((data == EEPROM_ERASED) || (data == EEPROM_VALID_PAGE) || (data == EEPROM_RECEIVE_DATA))
70         data = (*(__IO uint16_t*)(pageBase + 2)) + 1;
71     else
72         data = 0;
73
74     FlashStatus = FLASH_ErasePage(pageBase);
75     if (FlashStatus == FLASH_COMPLETE)
76         FlashStatus = FLASH_ProgramHalfWord(pageBase + 2, data);
77
78     return FlashStatus;
79 }
80
81 /**
82   * @brief  Check page for blank and erase it
83   * @param  page base address
84   * @retval Success or error
85   *         - Flash error code: on write Flash error
86   *         - EEPROM_BAD_FLASH: page not empty after erase
87   *         - EEPROM_OK:            page blank
88   */
89 uint16_t EE_CheckErasePage(uint32_t pageBase, uint16_t status)
90 {
91     uint16_t FlashStatus;
92     if (EE_CheckPage(pageBase, status) != EEPROM_OK)
93     {
94         FlashStatus = EE_ErasePage(pageBase);
95         if (FlashStatus != FLASH_COMPLETE)
96             return FlashStatus;
97         return EE_CheckPage(pageBase, status);
98     }
99     return EEPROM_OK;
100 }
101
102 /**
103   * @brief  Find valid Page for write or read operation
104   * @param  Page0: Page0 base address
105   *         Page1: Page1 base address
106   * @retval Valid page address (PAGE0 or PAGE1) or NULL in case of no valid page was found
107   */
108 uint32_t EE_FindValidPage(void)
109 {
110     uint16_t status0 = (*(__IO uint16_t*)PageBase0);        // Get Page0 actual status
111     uint16_t status1 = (*(__IO uint16_t*)PageBase1);        // Get Page1 actual status
112
113     if (status0 == EEPROM_VALID_PAGE && status1 == EEPROM_ERASED)
114         return PageBase0;
115     if (status1 == EEPROM_VALID_PAGE && status0 == EEPROM_ERASED)
116         return PageBase1;
117
118     return 0;
119 }
120
121 /**
122   * @brief  Calculate unique variables in EEPROM
123   * @param  start: address of first slot to check (page + 4)
124   * @param  end: page end address
125   * @param  address: 16 bit virtual address of the variable to excluse (or 0XFFFF)
126   * @retval count of variables
127   */
128 uint16_t EE_GetVariablesCount(uint32_t pageBase, uint16_t skipAddress)
129 {
130     uint16_t varAddress, nextAddress;
131     uint32_t idx;
132     uint32_t pageEnd = pageBase + (uint32_t)PageSize;
133     uint16_t count = 0;
134
135     for (pageBase += 6; pageBase < pageEnd; pageBase += 4)
136     {
137         varAddress = (*(__IO uint16_t*)pageBase);
138         if (varAddress == 0xFFFF || varAddress == skipAddress)
139             continue;
140
141         count++;
142         for(idx = pageBase + 4; idx < pageEnd; idx += 4)
143         {
144             nextAddress = (*(__IO uint16_t*)idx);
145             if (nextAddress == varAddress)
146             {
147                 count--;
148                 break;
149             }
150         }
151     }
152     return count;
153 }
154
155 /**
156   * @brief  Transfers last updated variables data from the full Page to an empty one.
157   * @param  newPage: new page base address
158   * @param  oldPage: old page base address
159   * @param  SkipAddress: 16 bit virtual address of the variable (or 0xFFFF)
160   * @retval Success or error status:
161   *           - FLASH_COMPLETE: on success
162   *           - EEPROM_OUT_SIZE: if valid new page is full
163   *           - Flash error code: on write Flash error
164   */
165 uint16_t EE_PageTransfer(uint32_t newPage, uint32_t oldPage, uint16_t SkipAddress)
166 {
167     uint32_t oldEnd, newEnd;
168     uint32_t oldIdx, newIdx, idx;
169     uint16_t address, data, found;
170     FLASH_Status FlashStatus;
171
172     // Transfer process: transfer variables from old to the new active page
173     newEnd = newPage + ((uint32_t)PageSize);
174
175     // Find first free element in new page
176     for (newIdx = newPage + 4; newIdx < newEnd; newIdx += 4)
177         if ((*(__IO uint32_t*)newIdx) == 0xFFFFFFFF)    // Verify if element
178             break;                                  //  contents are 0xFFFFFFFF
179     if (newIdx >= newEnd)
180         return EEPROM_OUT_SIZE;
181
182     oldEnd = oldPage + 4;
183     oldIdx = oldPage + (uint32_t)(PageSize - 2);
184
185     for (; oldIdx > oldEnd; oldIdx -= 4)
186     {
187         address = *(__IO uint16_t*)oldIdx;
188         if (address == 0xFFFF || address == SkipAddress)
189             continue;                       // it's means that power off after write data
190
191         found = 0;
192         for (idx = newPage + 6; idx < newIdx; idx += 4)
193             if ((*(__IO uint16_t*)(idx)) == address)
194             {
195                 found = 1;
196                 break;
197             }
198
199         if (found)
200             continue;
201
202         if (newIdx < newEnd)
203         {
204             data = (*(__IO uint16_t*)(oldIdx - 2));
205
206             FlashStatus = FLASH_ProgramHalfWord(newIdx, data);
207             if (FlashStatus != FLASH_COMPLETE)
208                 return FlashStatus;
209
210             FlashStatus = FLASH_ProgramHalfWord(newIdx + 2, address);
211             if (FlashStatus != FLASH_COMPLETE)
212                 return FlashStatus;
213
214             newIdx += 4;
215         }
216         else
217             return EEPROM_OUT_SIZE;
218     }
219
220     // Erase the old Page: Set old Page status to EEPROM_EEPROM_ERASED status
221     data = EE_CheckErasePage(oldPage, EEPROM_ERASED);
222     if (data != EEPROM_OK)
223         return data;
224
225     // Set new Page status
226     FlashStatus = FLASH_ProgramHalfWord(newPage, EEPROM_VALID_PAGE);
227     if (FlashStatus != FLASH_COMPLETE)
228         return FlashStatus;
229
230     return EEPROM_OK;
231 }
232
233 /**
234   * @brief  Verify if active page is full and Writes variable in EEPROM.
235   * @param  Address: 16 bit virtual address of the variable
236   * @param  Data: 16 bit data to be written as variable value
237   * @retval Success or error status:
238   *           - FLASH_COMPLETE: on success
239   *           - EEPROM_PAGE_FULL: if valid page is full (need page transfer)
240   *           - EEPROM_NO_VALID_PAGE: if no valid page was found
241   *           - EEPROM_OUT_SIZE: if EEPROM size exceeded
242   *           - Flash error code: on write Flash error
243   */
244 uint16_t EE_VerifyPageFullWriteVariable(uint16_t Address, uint16_t Data)
245 {
246     FLASH_Status FlashStatus;
247     uint32_t idx, pageBase, pageEnd, newPage;
248     uint16_t count;
249
250     // Get valid Page for write operation
251     pageBase = EE_FindValidPage();
252     if (pageBase == 0)
253         return  EEPROM_NO_VALID_PAGE;
254
255     // Get the valid Page end Address
256     pageEnd = pageBase + PageSize;          // Set end of page
257
258     for (idx = pageEnd - 2; idx > pageBase; idx -= 4)
259     {
260         if ((*(__IO uint16_t*)idx) == Address)      // Find last value for address
261         {
262             count = (*(__IO uint16_t*)(idx - 2));   // Read last data
263             if (count == Data)
264                 return EEPROM_OK;
265             if (count == 0xFFFF)
266             {
267                 FlashStatus = FLASH_ProgramHalfWord(idx - 2, Data); // Set variable data
268                 if (FlashStatus == FLASH_COMPLETE)
269                     return EEPROM_OK;
270             }
271             break;
272         }
273     }
274
275     // Check each active page address starting from begining
276     for (idx = pageBase + 4; idx < pageEnd; idx += 4)
277         if ((*(__IO uint32_t*)idx) == 0xFFFFFFFF)               // Verify if element 
278         {                                                   //  contents are 0xFFFFFFFF
279             FlashStatus = FLASH_ProgramHalfWord(idx, Data); // Set variable data
280             if (FlashStatus != FLASH_COMPLETE)
281                 return FlashStatus;
282             FlashStatus = FLASH_ProgramHalfWord(idx + 2, Address);  // Set variable virtual address
283             if (FlashStatus != FLASH_COMPLETE)
284                 return FlashStatus;
285             return EEPROM_OK;
286         }
287
288     // Empty slot not found, need page transfer
289     // Calculate unique variables in page
290     count = EE_GetVariablesCount(pageBase, Address) + 1;
291     if (count >= (PageSize / 4 - 1))
292         return EEPROM_OUT_SIZE;
293
294     if (pageBase == PageBase1)
295         newPage = PageBase0;        // New page address where variable will be moved to
296     else
297         newPage = PageBase1;
298
299     // Set the new Page status to RECEIVE_DATA status
300     FlashStatus = FLASH_ProgramHalfWord(newPage, EEPROM_RECEIVE_DATA);
301     if (FlashStatus != FLASH_COMPLETE)
302         return FlashStatus;
303
304     // Write the variable passed as parameter in the new active page
305     FlashStatus = FLASH_ProgramHalfWord(newPage + 4, Data);
306     if (FlashStatus != FLASH_COMPLETE)
307         return FlashStatus;
308
309     FlashStatus = FLASH_ProgramHalfWord(newPage + 6, Address);
310     if (FlashStatus != FLASH_COMPLETE)
311         return FlashStatus;
312
313     return EE_PageTransfer(newPage, pageBase, Address);
314 }
315
316 /*EEPROMClass::EEPROMClass(void)
317 {
318     PageBase0 = EEPROM_PAGE0_BASE;
319     PageBase1 = EEPROM_PAGE1_BASE;
320     PageSize = EEPROM_PAGE_SIZE;
321     Status = EEPROM_NOT_INIT;
322 }*/
323 /*
324 uint16_t EEPROM_init(uint32_t pageBase0, uint32_t pageBase1, uint32_t pageSize)
325 {
326     PageBase0 = pageBase0;
327     PageBase1 = pageBase1;
328     PageSize = pageSize;
329     return EEPROM_init();
330 }*/
331
332 uint16_t EEPROM_init(void)
333 {
334     uint16_t status0 = 6, status1 = 6;
335     FLASH_Status FlashStatus;
336
337     FLASH_Unlock();
338     Status = EEPROM_NO_VALID_PAGE;
339
340     status0 = (*(__IO uint16_t *)PageBase0);
341     status1 = (*(__IO uint16_t *)PageBase1);
342
343     switch (status0)
344     {
345 /*
346         Page0               Page1
347         -----               -----
348     EEPROM_ERASED       EEPROM_VALID_PAGE           Page1 valid, Page0 erased
349                         EEPROM_RECEIVE_DATA         Page1 need set to valid, Page0 erased
350                         EEPROM_ERASED               make EE_Format
351                         any                         Error: EEPROM_NO_VALID_PAGE
352 */
353     case EEPROM_ERASED:
354         if (status1 == EEPROM_VALID_PAGE)           // Page0 erased, Page1 valid
355             Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED);
356         else if (status1 == EEPROM_RECEIVE_DATA)    // Page0 erased, Page1 receive
357         {
358             FlashStatus = FLASH_ProgramHalfWord(PageBase1, EEPROM_VALID_PAGE);
359             if (FlashStatus != FLASH_COMPLETE)
360                 Status = FlashStatus;
361             else
362                 Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED);
363         }
364         else if (status1 == EEPROM_ERASED)          // Both in erased state so format EEPROM
365             Status = EEPROM_format();
366         break;
367 /*
368         Page0               Page1
369         -----               -----
370     EEPROM_RECEIVE_DATA EEPROM_VALID_PAGE           Transfer Page1 to Page0
371                         EEPROM_ERASED               Page0 need set to valid, Page1 erased
372                         any                         EEPROM_NO_VALID_PAGE
373 */
374     case EEPROM_RECEIVE_DATA:
375         if (status1 == EEPROM_VALID_PAGE)           // Page0 receive, Page1 valid
376             Status = EE_PageTransfer(PageBase0, PageBase1, 0xFFFF);
377         else if (status1 == EEPROM_ERASED)          // Page0 receive, Page1 erased
378         {
379             Status = EE_CheckErasePage(PageBase1, EEPROM_ERASED);
380             if (Status == EEPROM_OK)
381             {
382                 FlashStatus = FLASH_ProgramHalfWord(PageBase0, EEPROM_VALID_PAGE);
383                 if (FlashStatus != FLASH_COMPLETE)
384                     Status = FlashStatus;
385                 else
386                     Status = EEPROM_OK;
387             }
388         }
389         break;
390 /*
391         Page0               Page1
392         -----               -----
393     EEPROM_VALID_PAGE   EEPROM_VALID_PAGE           Error: EEPROM_NO_VALID_PAGE
394                         EEPROM_RECEIVE_DATA         Transfer Page0 to Page1
395                         any                         Page0 valid, Page1 erased
396 */
397     case EEPROM_VALID_PAGE:
398         if (status1 == EEPROM_VALID_PAGE)           // Both pages valid
399             Status = EEPROM_NO_VALID_PAGE;
400         else if (status1 == EEPROM_RECEIVE_DATA)
401             Status = EE_PageTransfer(PageBase1, PageBase0, 0xFFFF);
402         else
403             Status = EE_CheckErasePage(PageBase1, EEPROM_ERASED);
404         break;
405 /*
406         Page0               Page1
407         -----               -----
408         any             EEPROM_VALID_PAGE           Page1 valid, Page0 erased
409                         EEPROM_RECEIVE_DATA         Page1 valid, Page0 erased
410                         any                         EEPROM_NO_VALID_PAGE
411 */
412     default:
413         if (status1 == EEPROM_VALID_PAGE)
414             Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED);   // Check/Erase Page0
415         else if (status1 == EEPROM_RECEIVE_DATA)
416         {
417             FlashStatus = FLASH_ProgramHalfWord(PageBase1, EEPROM_VALID_PAGE);
418             if (FlashStatus != FLASH_COMPLETE)
419                 Status = FlashStatus;
420             else
421                 Status = EE_CheckErasePage(PageBase0, EEPROM_ERASED);
422         }
423         break;
424     }
425     return Status;
426 }
427
428 /**
429   * @brief  Erases PAGE0 and PAGE1 and writes EEPROM_VALID_PAGE / 0 header to PAGE0
430   * @param  PAGE0 and PAGE1 base addresses
431   * @retval Status of the last operation (Flash write or erase) done during EEPROM formating
432   */
433 uint16_t EEPROM_format(void)
434 {
435     uint16_t status;
436     FLASH_Status FlashStatus;
437
438     FLASH_Unlock();
439
440     // Erase Page0
441     status = EE_CheckErasePage(PageBase0, EEPROM_VALID_PAGE);
442     if (status != EEPROM_OK)
443         return status;
444     if ((*(__IO uint16_t*)PageBase0) == EEPROM_ERASED)
445     {
446         // Set Page0 as valid page: Write VALID_PAGE at Page0 base address
447         FlashStatus = FLASH_ProgramHalfWord(PageBase0, EEPROM_VALID_PAGE);
448         if (FlashStatus != FLASH_COMPLETE)
449             return FlashStatus;
450     }
451     // Erase Page1
452     return EE_CheckErasePage(PageBase1, EEPROM_ERASED);
453 }
454
455 /**
456   * @brief  Returns the erase counter for current page
457   * @param  Data: Global variable contains the read variable value
458   * @retval Success or error status:
459   *         - EEPROM_OK: if erases counter return.
460   *         - EEPROM_NO_VALID_PAGE: if no valid page was found.
461   */
462 uint16_t EEPROM_erases(uint16_t *Erases)
463 {
464     uint32_t pageBase;
465     if (Status != EEPROM_OK)
466         if (EEPROM_init() != EEPROM_OK)
467             return Status;
468
469     // Get active Page for read operation
470     pageBase = EE_FindValidPage();
471     if (pageBase == 0)
472         return  EEPROM_NO_VALID_PAGE;
473
474     *Erases = (*(__IO uint16_t*)pageBase+2);
475     return EEPROM_OK;
476 }
477
478 /**
479   * @brief  Returns the last stored variable data, if found,
480   *         which correspond to the passed virtual address
481   * @param  Address: Variable virtual address
482   * @retval Data for variable or EEPROM_DEFAULT_DATA, if any errors
483   */
484 /*
485 uint16_t EEPROM_read (uint16_t Address)
486 {
487     uint16_t data;
488     EEPROM_read(Address, &data);
489     return data;
490 }*/
491
492 /**
493   * @brief  Returns the last stored variable data, if found,
494   *         which correspond to the passed virtual address
495   * @param  Address: Variable virtual address
496   * @param  Data: Pointer to data variable
497   * @retval Success or error status:
498   *           - EEPROM_OK: if variable was found
499   *           - EEPROM_BAD_ADDRESS: if the variable was not found
500   *           - EEPROM_NO_VALID_PAGE: if no valid page was found.
501   */
502 uint16_t EEPROM_read(uint16_t Address, uint16_t *Data)
503 {
504     uint32_t pageBase, pageEnd;
505
506     // Set default data (empty EEPROM)
507     *Data = EEPROM_DEFAULT_DATA;
508
509     if (Status == EEPROM_NOT_INIT)
510         if (EEPROM_init() != EEPROM_OK)
511             return Status;
512
513     // Get active Page for read operation
514     pageBase = EE_FindValidPage();
515     if (pageBase == 0)
516         return  EEPROM_NO_VALID_PAGE;
517
518     // Get the valid Page end Address
519     pageEnd = pageBase + ((uint32_t)(PageSize - 2));
520     
521     // Check each active page address starting from end
522     for (pageBase += 6; pageEnd >= pageBase; pageEnd -= 4)
523         if ((*(__IO uint16_t*)pageEnd) == Address)      // Compare the read address with the virtual address
524         {
525             *Data = (*(__IO uint16_t*)(pageEnd - 2));       // Get content of Address-2 which is variable value
526             return EEPROM_OK;
527         }
528
529     // Return ReadStatus value: (0: variable exist, 1: variable doesn't exist)
530     return EEPROM_BAD_ADDRESS;
531 }
532
533 /**
534   * @brief  Writes/upadtes variable data in EEPROM.
535   * @param  VirtAddress: Variable virtual address
536   * @param  Data: 16 bit data to be written
537   * @retval Success or error status:
538   *         - FLASH_COMPLETE: on success
539   *         - EEPROM_BAD_ADDRESS: if address = 0xFFFF
540   *         - EEPROM_PAGE_FULL: if valid page is full
541   *         - EEPROM_NO_VALID_PAGE: if no valid page was found
542   *         - EEPROM_OUT_SIZE: if no empty EEPROM variables
543   *         - Flash error code: on write Flash error
544   */
545 uint16_t EEPROM_write(uint16_t Address, uint16_t Data)
546 {
547     if (Status == EEPROM_NOT_INIT)
548         if (EEPROM_init() != EEPROM_OK)
549             return Status;
550
551     if (Address == 0xFFFF)
552         return EEPROM_BAD_ADDRESS;
553
554     // Write the variable virtual address and value in the EEPROM
555     uint16_t status = EE_VerifyPageFullWriteVariable(Address, Data);
556     return status;
557 }
558
559 /**
560   * @brief  Writes/upadtes variable data in EEPROM.
561             The value is written only if differs from the one already saved at the same address.
562   * @param  VirtAddress: Variable virtual address
563   * @param  Data: 16 bit data to be written
564   * @retval Success or error status:
565   *         - EEPROM_SAME_VALUE: If new Data matches existing EEPROM Data
566   *         - FLASH_COMPLETE: on success
567   *         - EEPROM_BAD_ADDRESS: if address = 0xFFFF
568   *         - EEPROM_PAGE_FULL: if valid page is full
569   *         - EEPROM_NO_VALID_PAGE: if no valid page was found
570   *         - EEPROM_OUT_SIZE: if no empty EEPROM variables
571   *         - Flash error code: on write Flash error
572   */
573 uint16_t EEPROM_update(uint16_t Address, uint16_t Data)
574 {
575     uint16_t temp;
576     EEPROM_read(Address, &temp);
577     if (Address == Data)
578         return EEPROM_SAME_VALUE;
579     else
580         return EEPROM_write(Address, Data);
581 }
582
583 /**
584   * @brief  Return number of variable
585   * @retval Number of variables
586   */
587 uint16_t EEPROM_count(uint16_t *Count)
588 {
589     if (Status == EEPROM_NOT_INIT)
590         if (EEPROM_init() != EEPROM_OK)
591             return Status;
592
593     // Get valid Page for write operation
594     uint32_t pageBase = EE_FindValidPage();
595     if (pageBase == 0)
596         return EEPROM_NO_VALID_PAGE;    // No valid page, return max. numbers
597
598     *Count = EE_GetVariablesCount(pageBase, 0xFFFF);
599     return EEPROM_OK;
600 }
601
602 uint16_t EEPROM_maxcount(void)
603 {
604     return ((PageSize / 4)-1);
605 }
606
607
608 uint8_t eeprom_read_byte (const uint8_t *Address)
609 {
610     const uint16_t p = (const uint32_t) Address;
611     uint16_t temp;
612     EEPROM_read(p, &temp);
613     return (uint8_t) temp;
614 }
615
616 void eeprom_write_byte (uint8_t *Address, uint8_t Value)
617 {
618     uint16_t p = (uint32_t) Address;
619     EEPROM_write(p, (uint16_t) Value);
620 }
621
622 void eeprom_update_byte (uint8_t *Address, uint8_t Value)
623 {
624     uint16_t p = (uint32_t) Address;
625     EEPROM_update(p, (uint16_t) Value);
626 }
627
628 uint16_t eeprom_read_word (const uint16_t *Address)
629 {
630     const uint16_t p = (const uint32_t) Address;
631     uint16_t temp;
632     EEPROM_read(p, &temp);
633     return temp;
634 }
635
636 void eeprom_write_word (uint16_t *Address, uint16_t Value)
637 {
638     uint16_t p = (uint32_t) Address;
639     EEPROM_write(p, Value);
640 }
641
642 void eeprom_update_word (uint16_t *Address, uint16_t Value)
643 {
644     uint16_t p = (uint32_t) Address;
645     EEPROM_update(p, Value);
646 }
647
648 uint32_t eeprom_read_dword (const uint32_t *Address)
649 {
650     const uint16_t p = (const uint32_t) Address;
651     uint16_t temp1, temp2;
652     EEPROM_read(p, &temp1);
653     EEPROM_read(p + 1, &temp2);
654     return temp1 | (temp2 << 16);
655 }
656
657 void eeprom_write_dword (uint32_t *Address, uint32_t Value)
658 {
659     uint16_t temp = (uint16_t) Value;
660     uint16_t p = (uint32_t) Address;
661     EEPROM_write(p, temp);
662     temp = (uint16_t) (Value >> 16);
663     EEPROM_write(p + 1, temp);
664 }
665
666 void eeprom_update_dword (uint32_t *Address, uint32_t Value)
667 {
668     uint16_t temp = (uint16_t) Value;
669     uint16_t p = (uint32_t) Address;
670     EEPROM_update(p, temp);
671     temp = (uint16_t) (Value >> 16);
672     EEPROM_update(p + 1, temp);
673 }