/* * Copyright (C) 2013 Uwe Bonnes * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ * */ #include #include #include #include #include #include #include #if defined(MCU_STM32L1) #include #else #warning "STM32 family has no L1 compatible FLASH/EEPROM" #endif #define ERASED_PATTERN_32 0 #define FLASH_PEKEY1 0x89abcdef #define FLASH_PEKEY2 0x02030405 #if defined (STM32L1XX_MDP) #define STM32L1_EEPROM_SIZE ( 8 << 10) #elif defined (STM32L1XX_HD) #define STM32L1_EEPROM_SIZE ( 8 << 10) #else #define STM32L1_EEPROM_SIZE ( 4 << 10) #endif #define STM32L1_EEPROM_BASE 0x08080000 /*! * \brief Read data from EEPROM at specific address * * \param address EEPROM address that start to write data, it must be * in range 0..STM32L1_EEPROM_SIZE * \param buff buffer to place the read data in * \param size number of bytes to be read * * \return none */ int Stm32l1_EepromRead(uint16_t addr, void* buff, size_t size) { uint32_t ee_addr; if ((uint32_t)addr + size > STM32L1_EEPROM_SIZE ) return FLASH_BOUNDARY; ee_addr = STM32L1_EEPROM_BASE + addr; while((ee_addr & 3) && size) { *(uint8_t*)buff = *(uint8_t*)ee_addr; buff++; ee_addr++; size--; } while(size > 3) { *(uint32_t*)buff = *(uint32_t*)ee_addr; buff += 4; ee_addr += 4; size -= 4; } while(size) { *(uint8_t*)buff = *(uint8_t*)ee_addr; buff++; ee_addr++; size--; } return FLASH_COMPLETE; } /*! * \brief Write data to EEPROM at specific address * * \param address EEPROM address that start to write data, it must be * in range 0..STM32L1_EEPROM_SIZE * \param buff buffer that contain data that will be written to buffer * \param size number of bytes to be written * * \return FLASH_STARUS */ int Stm32l1_EepromWrite(uint16_t addr, const void* buff, size_t size) { uint32_t ee_addr; int rs; if (size == 0) return FLASH_COMPLETE; if ((uint32_t)addr + size > STM32L1_EEPROM_SIZE ) return FLASH_BOUNDARY; ee_addr = STM32L1_EEPROM_BASE + addr; if (FLASH->PECR & FLASH_PECR_PELOCK) { FLASH->PEKEYR = FLASH_PEKEY1; FLASH->PEKEYR = FLASH_PEKEY2; if (FLASH->PECR & FLASH_PECR_PELOCK) return FLASH_ERROR_PG; } if (ee_addr & 1) { uint8_t data = *(uint8_t *)buff; if (data != *(uint8_t *)ee_addr) { if (*(uint8_t *)ee_addr != (uint8_t)ERASED_PATTERN_32) FLASH->PECR = FLASH_PECR_FTDW; else FLASH->PECR = 0; *(uint8_t *)ee_addr = data; } buff ++; ee_addr ++; size --; } if ((ee_addr & 2) && (size > 1)) { uint16_t data = *(uint16_t *)buff; if (data != *(uint16_t *)ee_addr) { if (*(uint16_t *)ee_addr != (uint16_t)ERASED_PATTERN_32) FLASH->PECR = FLASH_PECR_FTDW; else FLASH->PECR = 0; *(uint16_t *)ee_addr = data; } buff += 2; ee_addr += 2; size -= 2; } while (size > 3) { uint32_t data = *(uint32_t *)buff; if (data != *(uint32_t *)ee_addr) { if (*(uint32_t *)ee_addr != ERASED_PATTERN_32) FLASH->PECR = FLASH_PECR_FTDW; else FLASH->PECR = 0; *(uint32_t *)ee_addr = data; } buff += 4; ee_addr += 4; size -= 4; } if (size > 1) { uint16_t data = *(uint16_t *)buff; if (data != *(uint16_t *)ee_addr) { if (*(uint16_t *)ee_addr != (uint16_t)ERASED_PATTERN_32) FLASH->PECR = FLASH_PECR_FTDW; else FLASH->PECR = 0; *(uint16_t *)ee_addr = data; } buff += 2; ee_addr += 2; size -= 2; } if (size) { uint8_t data = *(uint8_t *)buff; if (data != *(uint8_t *)ee_addr) { if (*(uint8_t *)ee_addr != (uint8_t)ERASED_PATTERN_32) FLASH->PECR = FLASH_PECR_FTDW; else FLASH->PECR = 0; *(uint8_t *)ee_addr = data; } } rs = FLASH_COMPLETE; FLASH->PECR = FLASH_PECR_PELOCK; return rs; }