eeprom_stm32.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 http://engsta.com/stm32-flash-memory-eeprom-emulator/ by
  14. * Artur F.
  15. *
  16. * Modifications for QMK and STM32F303 by Yiancar
  17. */
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include "eeprom_stm32.h"
  21. /*****************************************************************************
  22. * Allows to use the internal flash to store non volatile data. To initialize
  23. * the functionality use the EEPROM_Init() function. Be sure that by reprogramming
  24. * of the controller just affected pages will be deleted. In other case the non
  25. * volatile data will be lost.
  26. ******************************************************************************/
  27. /* Private macro -------------------------------------------------------------*/
  28. /* Private variables ---------------------------------------------------------*/
  29. /* Functions -----------------------------------------------------------------*/
  30. uint8_t DataBuf[FEE_PAGE_SIZE];
  31. /*****************************************************************************
  32. * Delete Flash Space used for user Data, deletes the whole space between
  33. * RW_PAGE_BASE_ADDRESS and the last uC Flash Page
  34. ******************************************************************************/
  35. uint16_t EEPROM_Init(void) {
  36. // unlock flash
  37. FLASH_Unlock();
  38. // Clear Flags
  39. //FLASH_ClearFlag(FLASH_SR_EOP|FLASH_SR_PGERR|FLASH_SR_WRPERR);
  40. return FEE_DENSITY_BYTES;
  41. }
  42. /*****************************************************************************
  43. * Erase the whole reserved Flash Space used for user Data
  44. ******************************************************************************/
  45. void EEPROM_Erase (void) {
  46. int page_num = 0;
  47. // delete all pages from specified start page to the last page
  48. do {
  49. FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE));
  50. page_num++;
  51. } while (page_num < FEE_DENSITY_PAGES);
  52. }
  53. /*****************************************************************************
  54. * Writes once data byte to flash on specified address. If a byte is already
  55. * written, the whole page must be copied to a buffer, the byte changed and
  56. * the manipulated buffer written after PageErase.
  57. *******************************************************************************/
  58. uint16_t EEPROM_WriteDataByte (uint16_t Address, uint8_t DataByte) {
  59. FLASH_Status FlashStatus = FLASH_COMPLETE;
  60. uint32_t page;
  61. int i;
  62. // exit if desired address is above the limit (e.G. under 2048 Bytes for 4 pages)
  63. if (Address > FEE_DENSITY_BYTES) {
  64. return 0;
  65. }
  66. // calculate which page is affected (Pagenum1/Pagenum2...PagenumN)
  67. page = FEE_ADDR_OFFSET(Address) / FEE_PAGE_SIZE;
  68. // if current data is 0xFF, the byte is empty, just overwrite with the new one
  69. if ((*(__IO uint16_t*)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address))) == FEE_EMPTY_WORD) {
  70. FlashStatus = FLASH_ProgramHalfWord(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address), (uint16_t)(0x00FF & DataByte));
  71. } else {
  72. // Copy Page to a buffer
  73. memcpy(DataBuf, (uint8_t*)FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE), FEE_PAGE_SIZE); // !!! Calculate base address for the desired page
  74. // check if new data is differ to current data, return if not, proceed if yes
  75. if (DataByte == *(__IO uint8_t*)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address))) {
  76. return 0;
  77. }
  78. // manipulate desired data byte in temp data array if new byte is differ to the current
  79. DataBuf[FEE_ADDR_OFFSET(Address) % FEE_PAGE_SIZE] = DataByte;
  80. //Erase Page
  81. FlashStatus = FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE));
  82. // Write new data (whole page) to flash if data has been changed
  83. for(i = 0; i < (FEE_PAGE_SIZE / 2); i++) {
  84. if ((__IO uint16_t)(0xFF00 | DataBuf[FEE_ADDR_OFFSET(i)]) != 0xFFFF) {
  85. FlashStatus = FLASH_ProgramHalfWord((FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE)) + (i * 2), (uint16_t)(0xFF00 | DataBuf[FEE_ADDR_OFFSET(i)]));
  86. }
  87. }
  88. }
  89. return FlashStatus;
  90. }
  91. /*****************************************************************************
  92. * Read once data byte from a specified address.
  93. *******************************************************************************/
  94. uint8_t EEPROM_ReadDataByte (uint16_t Address) {
  95. uint8_t DataByte = 0xFF;
  96. // Get Byte from specified address
  97. DataByte = (*(__IO uint8_t*)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address)));
  98. return DataByte;
  99. }
  100. /*****************************************************************************
  101. * Wrap library in AVR style functions.
  102. *******************************************************************************/
  103. uint8_t eeprom_read_byte (const uint8_t *Address)
  104. {
  105. const uint16_t p = (const uint32_t) Address;
  106. return EEPROM_ReadDataByte(p);
  107. }
  108. void eeprom_write_byte (uint8_t *Address, uint8_t Value)
  109. {
  110. uint16_t p = (uint32_t) Address;
  111. EEPROM_WriteDataByte(p, Value);
  112. }
  113. void eeprom_update_byte (uint8_t *Address, uint8_t Value)
  114. {
  115. uint16_t p = (uint32_t) Address;
  116. EEPROM_WriteDataByte(p, Value);
  117. }
  118. uint16_t eeprom_read_word (const uint16_t *Address)
  119. {
  120. const uint16_t p = (const uint32_t) Address;
  121. return EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p+1) << 8);
  122. }
  123. void eeprom_write_word (uint16_t *Address, uint16_t Value)
  124. {
  125. uint16_t p = (uint32_t) Address;
  126. EEPROM_WriteDataByte(p, (uint8_t) Value);
  127. EEPROM_WriteDataByte(p + 1, (uint8_t) (Value >> 8));
  128. }
  129. void eeprom_update_word (uint16_t *Address, uint16_t Value)
  130. {
  131. uint16_t p = (uint32_t) Address;
  132. EEPROM_WriteDataByte(p, (uint8_t) Value);
  133. EEPROM_WriteDataByte(p + 1, (uint8_t) (Value >> 8));
  134. }
  135. uint32_t eeprom_read_dword (const uint32_t *Address)
  136. {
  137. const uint16_t p = (const uint32_t) Address;
  138. return EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p+1) << 8)
  139. | (EEPROM_ReadDataByte(p+2) << 16) | (EEPROM_ReadDataByte(p+3) << 24);
  140. }
  141. void eeprom_write_dword (uint32_t *Address, uint32_t Value)
  142. {
  143. uint16_t p = (const uint32_t) Address;
  144. EEPROM_WriteDataByte(p, (uint8_t) Value);
  145. EEPROM_WriteDataByte(p+1, (uint8_t) (Value >> 8));
  146. EEPROM_WriteDataByte(p+2, (uint8_t) (Value >> 16));
  147. EEPROM_WriteDataByte(p+3, (uint8_t) (Value >> 24));
  148. }
  149. void eeprom_update_dword (uint32_t *Address, uint32_t Value)
  150. {
  151. uint16_t p = (const uint32_t) Address;
  152. uint32_t existingValue = EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p+1) << 8)
  153. | (EEPROM_ReadDataByte(p+2) << 16) | (EEPROM_ReadDataByte(p+3) << 24);
  154. if(Value != existingValue){
  155. EEPROM_WriteDataByte(p, (uint8_t) Value);
  156. EEPROM_WriteDataByte(p+1, (uint8_t) (Value >> 8));
  157. EEPROM_WriteDataByte(p+2, (uint8_t) (Value >> 16));
  158. EEPROM_WriteDataByte(p+3, (uint8_t) (Value >> 24));
  159. }
  160. }
  161. void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
  162. const uint8_t *p = (const uint8_t *)addr;
  163. uint8_t *dest = (uint8_t *)buf;
  164. while (len--) {
  165. *dest++ = eeprom_read_byte(p++);
  166. }
  167. }
  168. void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
  169. uint8_t *p = (uint8_t *)addr;
  170. const uint8_t *src = (const uint8_t *)buf;
  171. while (len--) {
  172. eeprom_write_byte(p++, *src++);
  173. }
  174. }
  175. void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
  176. uint8_t *p = (uint8_t *)addr;
  177. const uint8_t *src = (const uint8_t *)buf;
  178. while (len--) {
  179. eeprom_write_byte(p++, *src++);
  180. }
  181. }