qmk

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.z3bra.org/qmk.git
Log | Files | Refs | Submodules | LICENSE

eeprom_stm32.c (8230B)


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