EEPROM emulation on internal flash for STM32F407 (#372)

* Added new Flash EEPROM emulation

# Conflicts:
#	platformio.ini
#	speeduino/board_stm32_official.ino
#	speeduino/init.ino
#	speeduino/src/SPIAsEEPROM/SPIAsEEPROM.cpp
#	speeduino/src/SPIAsEEPROM/SPIAsEEPROM.h

* changes to storage to make SPI flash work again

* cleanup
This commit is contained in:
Tjeerd 2020-05-06 07:22:48 +02:00 committed by GitHub
parent 8ac3717507
commit 1530bb892e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 797 additions and 250 deletions

View File

@ -68,9 +68,11 @@ framework = arduino
board = black_f407ve
;lib_deps = EEPROM
board_build.core = stm32
build_flags = -fpermissive -std=gnu++11 -UBOARD_NR_GPIO_PINS -DARDUINO_BLACK_F407VE -DCORE_STM32_OFFICIAL -DUSE_SPI_EEPROM=56 -DUSBCON -DUSBD_VID=0x0483 "-DUSB_MANUFACTURER=\"Unknown\"" "-DUSB_PRODUCT=\"BLACK_F407VE\"" -DHAL_PCD_MODULE_ENABLED -DUSBD_USE_CDC -DHAL_UART_MODULE_ENABLED
upload_protocol = stlink
build_flags = -fpermissive -std=gnu++11 -UBOARD_NR_GPIO_PINS -DARDUINO_BLACK_F407VE -DCORE_STM32_OFFICIAL -DENABLE_HWSERIAL2 -DENABLE_HWSERIAL3 -DUSBCON -DUSBD_VID=0x0483 "-DUSB_MANUFACTURER=\"Unknown\"" "-DUSB_PRODUCT=\"BLACK_F407VE\"" -DHAL_PCD_MODULE_ENABLED -DUSBD_USE_CDC -DHAL_UART_MODULE_ENABLED
;-DUSE_SPI_EEPROM=56
upload_protocol = dfu
debug_tool = stlink
monitor_speed = 115200
[env:bluepill_f103c8]
platform = ststm32

View File

@ -25,12 +25,10 @@
#define micros_safe() micros() //timer5 method is not used on anything but AVR, the micros_safe() macro is simply an alias for the normal micros()
#if defined(SRAM_AS_EEPROM)
#define EEPROM_LIB_H "src/BackupSram/BackupSramAsEEPROM.h"
#elif defined(USE_SPI_EEPROM)
#define EEPROM_LIB_H "src/SPIAsEEPROM/SPIAsEEPROM.h"
#elif defined(FRAM_AS_EEPROM) //https://github.com/VitorBoss/FRAM
#define EEPROM_LIB_H <Fram.h>
#else
#define EEPROM_LIB_H <EEPROM.h>
#define EEPROM_LIB_H "src/SPIAsEEPROM/SPIAsEEPROM.h"
#endif
#ifndef LED_BUILTIN

View File

@ -5,11 +5,6 @@
#include "idle.h"
#include "scheduler.h"
#include "HardwareTimer.h"
#ifdef USE_SPI_EEPROM
//We need to include and make a instance of the SPI flash EEPROM emulation if flag is set.
#include "src/SPIAsEEPROM/SPIAsEEPROM.h"
SPIAsEEPROM EEPROM;
#endif
void initBoard()
{

View File

@ -1,16 +1,15 @@
/* Speeduino SPIAsEEPROM Library v.1.0.0
* Copyright (C) 2019 by Tjeerd Hoogendijk
/* Speeduino SPIAsEEPROM Library v.2.0.4
* Copyright (C) 2020 by Tjeerd Hoogendijk
* Created by Tjeerd Hoogendijk - 21/09/2019
* Updated by Tjeerd Hoogendijk - 19/04/2020
*
* This file is part of the Speeduino project. This library is for
* Winbond SPI flash memory modules. In its current form it enables reading
* and writing individual bytes as if it where an AVR EEPROM. It uses some
* wear leveling (256x). When the begin() fuction is called for the first time
* it will "format" the flash chip.
* !!!!THIS DISTROYS ANY EXISTING DATA ON THE SPI FLASH!!!
* This file is part of the Speeduino project. This library started out for
* Winbond SPI flash memory modules. As of version 2.0 it also works with internal
* flash memory of the STM32F407. In its current form it enables reading
* and writing individual bytes as if it where an AVR EEPROM. When the begin()
* fuction is called for the first time it will "format" the flash chip.
* !!!!THIS DISTROYS ANY EXISTING DATA ON THE FLASH!!!!
*
* 1245184 bytes used of the SPI flash resulting in 4228 bytes of usable EEPROM
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@ -22,213 +21,425 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License v3.0
* along with the Arduino SPIMemory Library. If not, see
* along with the Speeduino SPIAsEEPROM Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
//#if defined(CORE_STM32_OFFICIAL) && defined(SPIFLASH_AS_EEPROM)
#if defined(USE_SPI_EEPROM)
#if defined(USE_SPI_EEPROM) | defined(STM32F407xx) | defined(STM32F103xB)
#include "SPIAsEEPROM.h"
#include "SPI.h"
//#include "globals.h"
SPIAsEEPROM::SPIAsEEPROM()
static EEPROM_Emulation_Config EmulatedEEPROMMconfig{
FLASH_SECTORS_USED,
FLASH_SECTOR_SIZE,
EEPROM_BYTES_PER_SECTOR,
EEPROM_FLASH_BASEADRESS
};
// EmulatedEEPROMMconfig.Flash_Sectors_Used = FLASH_SECTORS_USED;
FLASH_EEPROM_BaseClass::FLASH_EEPROM_BaseClass(EEPROM_Emulation_Config config)
{
//pinMode(PB0, OUTPUT);
magicbuf[0] = MAGICNUMBER1;
magicbuf[1] = MAGICNUMBER2;
magicbuf[2] = MAGICNUMBER3;
magicbuf[3] = 0x00;
//Class indicating if the emulated EEPROM flash is initialized
_EmulatedEEPROMAvailable=false;
}
uint8_t SPIAsEEPROM::begin(uint8_t pinSPIFlash_CS=6)
{
pinMode(pinSPIFlash_CS, OUTPUT);
SpiFlashAvialable = winbondSPIFlash.begin(_W25Q16,SPI, pinSPIFlash_CS);
uint8_t formatted = 0;
if(SpiFlashAvialable){
//check for magic numbers
formatted = 1;
uint8_t buf[MAGICNUMBER_OFFSET];
for(uint16_t i=0; i< FLASHSIZEUSED/SECTORSIZE; i++ ){
winbondSPIFlash.read(sectorNumber*SECTORSIZE, buf, sizeof(buf) - 1);
if((buf[0] != MAGICNUMBER1) | (buf[1] != MAGICNUMBER2) | (buf[2] != MAGICNUMBER3)){
//if one of the SECTORS has no magic numbers it is not formatted
formatted = 0;
}
}
//If not formatted format flash. This takes 10 seconds or more!
if(!formatted){
formatFlashForUse();
}
//Class variable storing number of ones counted in adres translation block
_nrOfOnes = 0;
//Class variable storing what sector we are working in.
_sectorFlash = 0;
//Class variable storing what flash address we are working in.
_addressFLASH = 0;
//Class bool indicating if the flash is initialized and available for use
_FlashAvailable=false;
//save configuration
_config = config;
_Flash_Size_Used = _config.Flash_Sectors_Used*_config.Flash_Sector_Size;
_Flash_Size_Per_EEPROM_Byte = _config.Flash_Sector_Size/(_config.EEPROM_Bytes_Per_Sector +1);
_Addres_Translation_Size = _Flash_Size_Per_EEPROM_Byte/8;
_EEPROM_Emulation_Size = _config.Flash_Sectors_Used*_config.EEPROM_Bytes_Per_Sector;
}
int8_t FLASH_EEPROM_BaseClass::initialize(bool flashavailable)
{
bool formatted = false;
_FlashAvailable = flashavailable;
_EmulatedEEPROMAvailable = false;
if(_FlashAvailable)
{
formatted = checkForMagicNumbers();
//If not formatted format flash. This takes 10 seconds or more!
if(!formatted){
clear();
//check if format succeeded
formatted = 1;
for(uint16_t i=0; i< FLASHSIZEUSED/SECTORSIZE; i++ ){
winbondSPIFlash.read(sectorNumber*SECTORSIZE, buf, sizeof(buf) - 1);
if((buf[0] != MAGICNUMBER1) | (buf[1] != MAGICNUMBER2) | (buf[2] != MAGICNUMBER3)){
formatted = 0;
}
}
formatted = checkForMagicNumbers();
}
if(formatted & SpiFlashAvialable){return true;}else{return false;}
}
int8_t SPIAsEEPROM::write(uint16_t addressEEPROM, uint8_t writeValue){
uint8_t ByteBuf[1];
if(formatted){_EmulatedEEPROMAvailable=true;}
}
return _EmulatedEEPROMAvailable;
}
//Check if adress is in the EEPROM space
if (addressEEPROM >= FLASHSIZEUSED/SECTORSIZE * (SECTORSIZE/FLASH_PAGESIZE - 2)){addressEEPROM = FLASHSIZEUSED/SECTORSIZE * (SECTORSIZE/FLASH_PAGESIZE - 2);}
byte FLASH_EEPROM_BaseClass::read(uint16_t addressEEPROM){
//version 0.1 does not check magic number
byte EEPROMbyte;
//Check if address is outside of the maximum. return zero if address is out of range.
if (addressEEPROM > _EEPROM_Emulation_Size){addressEEPROM = _EEPROM_Emulation_Size - 1; return 0;}
//Check at what flash sector the EEPROM byte information resides
_sectorFlash = addressEEPROM/_config.EEPROM_Bytes_Per_Sector;
//Check at what flash address the EEPROM byte information resides
_addressFLASH = (_sectorFlash*_config.Flash_Sector_Size) + ((addressEEPROM % _config.EEPROM_Bytes_Per_Sector) + 1) * _Flash_Size_Per_EEPROM_Byte;
//reset buffer to all 0xFF
for (uint32_t i = 0; i < _Flash_Size_Per_EEPROM_Byte; i++)
{
_ReadWriteBuffer[i] = 0xFF;
}
//read address translation part
readFlashBytes(_addressFLASH, _ReadWriteBuffer, _Addres_Translation_Size);
//calculate address of the valid data by couting the bits in the Address translation section
_nrOfOnes = count(_ReadWriteBuffer, _Addres_Translation_Size);
//Bring number of ones within specification of buffer size.
if(_nrOfOnes >=_Flash_Size_Per_EEPROM_Byte){_nrOfOnes =_Flash_Size_Per_EEPROM_Byte;}
//If it is the first read after clear (all ones still set), return 0xFF;
if (_nrOfOnes==_Flash_Size_Per_EEPROM_Byte){
EEPROMbyte = 0xFF;
}else{
byte tempBuf[1];
//read actual eeprom value of flash
readFlashBytes(_addressFLASH+_nrOfOnes, tempBuf, 1);
EEPROMbyte = tempBuf[0];
//make buffer correct, because write function expects a correct buffer.
_ReadWriteBuffer[_nrOfOnes] = EEPROMbyte;
}
return EEPROMbyte;
}
int8_t FLASH_EEPROM_BaseClass::write(uint16_t addressEEPROM, byte val){
//Check if address is outside of the maximum. limit to get inside maximum and return an error.
if (addressEEPROM > _EEPROM_Emulation_Size){addressEEPROM = _EEPROM_Emulation_Size - 1; return -1;}
//read the current value
uint8_t readValue = read(addressEEPROM);
//After reading the current byte all global variables containing inforamtion about the address are set correctly.
//After reading the current byte all global variables containing information about the address are set correctly.
//only write if value is changed.
if (readValue != writeValue){
//Check if buffer is full and an erase must be performed.
if (nrOfOnes < 1){
if (readValue != val){
//Check if section is full and an erase must be performed.
if (_nrOfOnes < _Addres_Translation_Size + 1){
//First read all the values in this sector that will get distroyed when erasing
uint8_t tempBuf[14];
for(uint8_t i = 0; i<14; i++){
tempBuf[i] = read((sectorNumber*14) + i);
byte tempBuf[_config.EEPROM_Bytes_Per_Sector];
for(uint16_t i = 0; i<_config.EEPROM_Bytes_Per_Sector; i++){
uint16_t TempEEPROMaddress = (_sectorFlash*_config.EEPROM_Bytes_Per_Sector) + i;
tempBuf[i] = read(TempEEPROMaddress);
}
//now erase the sector
writeMagicNumber(sectorNumber);
//Now erase the sector
eraseFlashSector(_sectorFlash*_config.Flash_Sector_Size, _config.Flash_Sector_Size);
//Write the magic numbers
writeMagicNumbers(_sectorFlash);
//write all the values back
for(uint8_t i=0; i<14; i++){
write((sectorNumber*14) + i, tempBuf[i]);
for(uint16_t i=0; i<_config.EEPROM_Bytes_Per_Sector; i++){
write((_sectorFlash*_config.EEPROM_Bytes_Per_Sector) + i, tempBuf[i]);
}
//also do not forget to write the new value!
write(addressEEPROM, writeValue);
return 0;
//Do not forget to write the new value!
write(addressEEPROM, val);
//Return we have writen a whole sector.
return 0xFF;
}
//determine the adress of the byte in the infoblock where one bit must be reset when writing new values
uint8_t RelativeAdressInInfoBlock = (nrOfOnes - 1)/8;
//determine the adress of the byte in the address translation section where one bit must be reset when writing new values
uint8_t AdressInAddressTranslation = (_nrOfOnes - 1)/8;
//determine value of the infoblock byte after writing one more time.
uint8_t ValueInInfoBlock = 0xFF << (8 - (nrOfOnes - 1 - ((RelativeAdressInInfoBlock) * 8)));
uint8_t ValueInAddressTranslation = 0xFF << (8 - (_nrOfOnes - 1 - ((AdressInAddressTranslation) * 8)));
//write the new value at the new location
ByteBuf[0] = writeValue;
winbondSPIFlash.WE();
winbondSPIFlash.writePage(dataFlashAddress - 1, ByteBuf, sizeof(ByteBuf));
while(winbondSPIFlash.busy());
//write the new adress translation value at the new location in buffer
_ReadWriteBuffer[AdressInAddressTranslation] = ValueInAddressTranslation;
//write where read can find the new value
ByteBuf[0] = ValueInInfoBlock;
winbondSPIFlash.WE();
winbondSPIFlash.writePage(infoFlashAddress + RelativeAdressInInfoBlock, ByteBuf, sizeof(ByteBuf));
while(winbondSPIFlash.busy());
//Write the new EEPROM value at the new location in the buffer.
_nrOfOnes--;
_ReadWriteBuffer[_nrOfOnes] = val;
//Write the buffer to the undelying flash storage.
// writeFlashBytes(_addressFLASH, _ReadWriteBuffer, _Flash_Size_Per_EEPROM_Byte);
return 0;
}else{
return 0;
}
}
//Write actual value part of the buffer to flash
byte tempBuffer[2];
_nrOfOnes &= ~(0x1); //align address with 2 byte (uint16_t) for write to flash for 32bit STM32 MCU
memcpy(&tempBuffer, &_ReadWriteBuffer[_nrOfOnes], sizeof(uint16_t));
writeFlashBytes(_addressFLASH +_nrOfOnes, tempBuffer, sizeof(uint16_t));
int8_t SPIAsEEPROM::update(uint16_t address, uint8_t val){
//a write function call is already an update.
write(address, val);
return 0;
}
uint8_t SPIAsEEPROM::writeMagicNumber(uint16_t sectorNumber){
//sector adress is for 0 to (FLASHSIZEUSED/SECTORSIZE -1)
//Function is used to write a magic number at the start of each Sector.
//This number can be used to identify if the flash is formated for use as EEPROM
if (sectorNumber>=FLASHSIZEUSED/SECTORSIZE){
sectorNumber = (FLASHSIZEUSED/SECTORSIZE - 1);
}
//First erase the sector (4KiB at the time)
winbondSPIFlash.WE();
winbondSPIFlash.eraseSector(sectorNumber*SECTORSIZE);
while(winbondSPIFlash.busy()); //if no spi flash present or accessible this hangs forever!
//Write the magic numbers at the start of the sector for identification.
winbondSPIFlash.WE();
winbondSPIFlash.writePage(sectorNumber*SECTORSIZE, magicbuf, MAGICNUMBER_OFFSET);
while(winbondSPIFlash.busy()); //if no spi flash present or accessible this hangs forever!
return 0;
}
uint8_t SPIAsEEPROM::formatFlashForUse(){
//Format the flash for use by erasing all sectors used and
//write the magic number at the start of each erased sector
for(uint16_t i = 0; i<FLASHSIZEUSED/SECTORSIZE; i++){
writeMagicNumber(i);
}
//Write address translation part of the buffer to flash
AdressInAddressTranslation &= ~(0x1); //align address with 2 byte for write to flash for 32bit STM32 MCU
memcpy(&tempBuffer, &_ReadWriteBuffer[AdressInAddressTranslation], sizeof(uint16_t));
writeFlashBytes(_addressFLASH+AdressInAddressTranslation, tempBuffer, sizeof(uint16_t));
return 1;
}
return 0;
}
uint8_t SPIAsEEPROM::read(uint16_t addressEEPROM){
//The infoblock is at the start of each sector
//The first two pages will be used for the infoblock
//The first 4 bytes of each page must have the magic number
//version 0.1 does not check magic number
if(!SpiFlashAvialable){
begin(USE_SPI_EEPROM);
}
uint8_t buf[INFOBYTES_PER_BYTE];
//Check if address is outside of the maximum. limit to get inside maximum and continue as normal.
//Should be changed so that it returns -1 (error)
if (addressEEPROM >= FLASHSIZEUSED/SECTORSIZE * (SECTORSIZE/FLASH_PAGESIZE - 2)){addressEEPROM = FLASHSIZEUSED/SECTORSIZE * (SECTORSIZE/FLASH_PAGESIZE - 2);}
//Check at what sector number the adress resides. 14 bytes per sector
sectorNumber = addressEEPROM/(SECTORSIZE/FLASH_PAGESIZE - 2);
//Check at what page number in the sector the adress can be found (16 pages per sector, 14 used)
pageNumber = addressEEPROM - (sectorNumber * ((SECTORSIZE/FLASH_PAGESIZE) - 2));
//The absulute adress of the infoblock of the byte in flash adress
infoFlashAddress = sectorNumber*SECTORSIZE + pageNumber * INFOBYTES_PER_BYTE + MAGICNUMBER_OFFSET;
//read the infoblock and put into the buffer
winbondSPIFlash.read(infoFlashAddress, buf, sizeof(buf));
while(winbondSPIFlash.busy()); //if no spi flash present or accessible this hangs forever!
//calculate actual flash address of the data
//Count de number of set bits in the infoblock
nrOfOnes = count(buf);
//Calulate the adress from all previous information.
dataFlashAddress = sectorNumber*SECTORSIZE + (pageNumber * FLASH_PAGESIZE) + INFOBYTESSECTOROFFSET + nrOfOnes - 1;
uint8_t ByteBuf[1];
//read the actual byte with information
winbondSPIFlash.read(dataFlashAddress, ByteBuf, sizeof(ByteBuf));
while(winbondSPIFlash.busy()); //if no spi flash present or accessible this hangs forever!
return ByteBuf[0];
int8_t FLASH_EEPROM_BaseClass::update(uint16_t addressEEPROM, uint8_t val){
return write(addressEEPROM, val);
}
uint16_t SPIAsEEPROM::count(uint8_t buf[FLASH_PAGESIZE/BITS_PER_BYTE]){
int16_t FLASH_EEPROM_BaseClass::clear(){
uint32_t i;
for(i=0; i< _config.Flash_Sectors_Used; i++ ){
eraseFlashSector(i*_config.Flash_Sector_Size, _config.Flash_Sector_Size);
writeMagicNumbers(i);
}
return i;
}
uint16_t FLASH_EEPROM_BaseClass::length(){ return _EEPROM_Emulation_Size; }
bool FLASH_EEPROM_BaseClass::checkForMagicNumbers(){
bool magicnumbers = true;
for(uint32_t i=0; i< _config.Flash_Sectors_Used; i++ ){
readFlashBytes(i*_config.Flash_Sector_Size, _ReadWriteBuffer, _Flash_Size_Per_EEPROM_Byte);
if((_ReadWriteBuffer[0] != MAGICNUMBER1) | (_ReadWriteBuffer[1] != MAGICNUMBER2) | (_ReadWriteBuffer[2] != MAGICNUMBER3) | (_ReadWriteBuffer[3] != EEPROM_VERSION)){magicnumbers=false;}
}
return magicnumbers;
}
int8_t FLASH_EEPROM_BaseClass::writeMagicNumbers(uint32_t sector){
_ReadWriteBuffer[0] = MAGICNUMBER1;
_ReadWriteBuffer[1] = MAGICNUMBER2;
_ReadWriteBuffer[2] = MAGICNUMBER3;
_ReadWriteBuffer[3] = EEPROM_VERSION;
writeFlashBytes(sector*_config.Flash_Sector_Size, _ReadWriteBuffer, MAGICNUMBER_OFFSET);
return true;
}
uint16_t FLASH_EEPROM_BaseClass::count(byte* buffer, uint32_t length){
byte tempBuffer[length];
memcpy(&tempBuffer, buffer, length);
uint16_t count=0;
for(uint8_t j=0; j < 32; j++)
for(uint8_t j=0; j < length; j++)
for(uint8_t i=0; i<8; i++){
if((buf[j] & 1) == 1){ //if current bit 1
if((tempBuffer[j] & 1) == 1){ //if current bit 1
count++;//increase count
}
buf[j]=buf[j]>>1;//right shift
tempBuffer[j]=tempBuffer[j]>>1;//right shift
}
return count;
}
//SPIAsEEPROM EEPROM;
int8_t FLASH_EEPROM_BaseClass::readFlashBytes(uint32_t address , byte* buffer, uint32_t length){return -1;}
int8_t FLASH_EEPROM_BaseClass::writeFlashBytes(uint32_t address, byte* buffer, uint32_t length){return -1;}
int8_t FLASH_EEPROM_BaseClass::eraseFlashSector(uint32_t address, uint32_t length){return -1;}
#endif
#if defined(USE_SPI_EEPROM)
SPI_EEPROM_Class::SPI_EEPROM_Class(EEPROM_Emulation_Config config):FLASH_EEPROM_BaseClass(config)
{
}
byte SPI_EEPROM_Class::read(uint16_t addressEEPROM){
//Check if emulated EEPROM is available if not yet start it first.
if(!_EmulatedEEPROMAvailable){
//22.5Mhz is highest it could get with this. But should be ~45Mhz :-(.
SPISettings settings(22500000, MSBFIRST, SPI_MODE0);
SPI.beginTransaction(settings);
begin(SPI, USE_SPI_EEPROM);
}
return FLASH_EEPROM_BaseClass::read(addressEEPROM);
}
int8_t SPI_EEPROM_Class::begin(SPIClass &_spi, uint8_t pinSPIFlash_CS=6){
pinMode(pinSPIFlash_CS, OUTPUT);
bool flashavailable;
flashavailable = winbondSPIFlash.begin(_W25Q16,_spi, pinSPIFlash_CS);
return FLASH_EEPROM_BaseClass::initialize(flashavailable);
}
int8_t SPI_EEPROM_Class::readFlashBytes(uint32_t address, byte *buf, uint32_t length){
while(winbondSPIFlash.busy());
return winbondSPIFlash.read(address+_config.EEPROM_Flash_BaseAddress, buf, length);
}
int8_t SPI_EEPROM_Class::writeFlashBytes(uint32_t address, byte *buf, uint32_t length){
winbondSPIFlash.setWriteEnable(true);
winbondSPIFlash.writePage(address+_config.EEPROM_Flash_BaseAddress, buf, length);
while(winbondSPIFlash.busy());
return 0;
}
int8_t SPI_EEPROM_Class::eraseFlashSector(uint32_t address, uint32_t length){
winbondSPIFlash.setWriteEnable(true);
winbondSPIFlash.eraseSector(address+_config.EEPROM_Flash_BaseAddress);
while(winbondSPIFlash.busy());
return 0;
}
//THIS IS NOT WORKING! FOR STM32F103 YOU CAN ONLY WRITE IN JUST ERASED HALFWORDS(UINT16_T). THE PHILISOPHY IS FLAWWED THERE.
// #elif defined(STM32F103xB)
// InternalSTM32F1_EEPROM_Class::InternalSTM32F1_EEPROM_Class(EEPROM_Emulation_Config config):FLASH_EEPROM_BaseClass(config)
// {
// }
// byte InternalSTM32F1_EEPROM_Class::read(uint16_t addressEEPROM){
// if(!_EmulatedEEPROMAvailable){
// FLASH_EEPROM_BaseClass::initialize(true);
// }
// return FLASH_EEPROM_BaseClass::read(addressEEPROM);
// }
// int8_t InternalSTM32F1_EEPROM_Class::readFlashBytes(uint32_t address, byte *buf, uint32_t length){
// memcpy(buf, (uint8_t *)(_config.EEPROM_Flash_BaseAddress + address), length);
// return 0;
// }
// int8_t InternalSTM32F1_EEPROM_Class::writeFlashBytes(uint32_t flashAddress, byte *buf, uint32_t length){
// {
// uint32_t translatedAddress = flashAddress+_config.EEPROM_Flash_BaseAddress;
// uint32_t data = 0;
// uint32_t countaddress = translatedAddress;
// HAL_FLASH_Unlock();
// while (countaddress < translatedAddress + length) {
// memcpy(&data, buf, sizeof(uint32_t));
// if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, countaddress, data) == HAL_OK) {
// countaddress += 4;
// offset += 4;
// } else {
// countaddress = translatedAddress + length + 1;
// }
// }
// }
// HAL_FLASH_Lock();
// return 0;
// }
// int8_t InternalSTM32F1_EEPROM_Class::eraseFlashSector(uint32_t address, uint32_t length){
// FLASH_EraseInitTypeDef EraseInitStruct;
// uint32_t pageError = 0;
// uint32_t realAddress = _config.EEPROM_Flash_BaseAddress+address;
// bool EraseSucceed=false;
// /* ERASING page */
// EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
// EraseInitStruct.Banks = 1;
// EraseInitStruct.PageAddress = realAddress;
// EraseInitStruct.NbPages = 1;
// HAL_FLASH_Unlock();
// if (HAL_FLASHEx_Erase(&EraseInitStruct, &pageError) == HAL_OK){EraseSucceed=true;}
// HAL_FLASH_Lock();
// return EraseSucceed;
// }
#elif defined(STM32F407xx)
InternalSTM32F4_EEPROM_Class::InternalSTM32F4_EEPROM_Class(EEPROM_Emulation_Config config) : FLASH_EEPROM_BaseClass(config)
{
}
byte InternalSTM32F4_EEPROM_Class::read(uint16_t addressEEPROM){
if(!_EmulatedEEPROMAvailable){
FLASH_EEPROM_BaseClass::initialize(true);
}
return FLASH_EEPROM_BaseClass::read(addressEEPROM);
}
int8_t InternalSTM32F4_EEPROM_Class::readFlashBytes(uint32_t address, byte *buf, uint32_t length){
memcpy(buf, (uint8_t *)(_config.EEPROM_Flash_BaseAddress + address), length);
return 0;
}
int8_t InternalSTM32F4_EEPROM_Class::writeFlashBytes(uint32_t flashAddress, byte *buf, uint32_t length){
{
uint32_t translatedAddress = flashAddress+_config.EEPROM_Flash_BaseAddress;
uint16_t data = 0;
uint32_t offset = 0;
uint32_t countaddress = translatedAddress;
HAL_FLASH_Unlock();
while (countaddress < translatedAddress + length) {
memcpy(&data, buf + offset, sizeof(uint16_t));
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, countaddress, data) == HAL_OK) {
countaddress += 2;
offset += 2;
} else {
countaddress = translatedAddress + length + 1;
}
}
}
HAL_FLASH_Lock();
return 0;
}
int8_t InternalSTM32F4_EEPROM_Class::eraseFlashSector(uint32_t address, uint32_t length){
FLASH_EraseInitTypeDef EraseInitStruct;
// uint32_t offset = 0;
uint32_t realAddress = _config.EEPROM_Flash_BaseAddress+address;
// uint32_t address_end = FLASH_BASE_ADDRESS + E2END;
bool EraseSucceed=false;
uint32_t SectorError = 0;
uint32_t _Sector = 11;
//Look in the datasheet for more information about flash sectors and sizes
//This is the correct sector allocation for the STM32F407 all types
if ((realAddress>=0x08000000UL)&(realAddress<=0x08003FFFUL)){_Sector = 0;}
if ((realAddress>=0x08004000UL)&(realAddress<=0x08007FFFUL)){_Sector = 1;}
if ((realAddress>=0x08008000UL)&(realAddress<=0x0800BFFFUL)){_Sector = 2;}
if ((realAddress>=0x0800C000UL)&(realAddress<=0x0800FFFFUL)){_Sector = 3;}
if ((realAddress>=0x08010000UL)&(realAddress<=0x0801FFFFUL)){_Sector = 4;}
if ((realAddress>=0x08020000UL)&(realAddress<=0x0803FFFFUL)){_Sector = 5;}
if ((realAddress>=0x08040000UL)&(realAddress<=0x0805FFFFUL)){_Sector = 6;}
if ((realAddress>=0x08050000UL)&(realAddress<=0x0807FFFFUL)){_Sector = 7;}
if ((realAddress>=0x08080000UL)&(realAddress<=0x0809FFFFUL)){_Sector = 8;}
if ((realAddress>=0x080A0000UL)&(realAddress<=0x080BFFFFUL)){_Sector = 9;}
if ((realAddress>=0x080C0000UL)&(realAddress<=0x080DFFFFUL)){_Sector = 10;}
if ((realAddress>=0x080E0000UL)&(realAddress<=0x080FFFFFUL)){_Sector = 11;}
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = _Sector;
EraseInitStruct.NbSectors = 1;
HAL_FLASH_Unlock();
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) == HAL_OK){EraseSucceed=true;}
HAL_FLASH_Lock();
return EraseSucceed;
}
#endif
#if defined(USE_SPI_EEPROM)
SPI_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#elif defined(STM32F407xx)
InternalSTM32F4_EEPROM_Class EEPROM(EmulatedEEPROMMconfig);
#endif
#endif

View File

@ -1,16 +1,15 @@
/* Speeduino SPIAsEEPROM Library v.1.0.0
* Copyright (C) 2019 by Tjeerd Hoogendijk
/* Speeduino SPIAsEEPROM Library v.2.0.4
* Copyright (C) 2020 by Tjeerd Hoogendijk
* Created by Tjeerd Hoogendijk - 21/09/2019
* Updated by Tjeerd Hoogendijk - 19/04/2020
*
* This file is part of the Speeduino project. This library is for
* Winbond SPI flash memory modules. In its current form it enables reading
* and writing individual bytes as if it where an AVR EEPROM. It uses some
* wear leveling (256x). When the begin() fuction is called for the first time
* it will "format" the flash chip.
* !!!!THIS DISTROYS ANY EXISTING DATA ON THE SPI FLASH!!!
*
* 1757184 bytes used of the SPI flash resulting in 6006 bytes of usable EEPROM
*
* This file is part of the Speeduino project. This library started out for
* Winbond SPI flash memory modules. As of version 2.0 it also works with internal
* flash memory of the STM32F407. In its current form it enables reading
* and writing individual bytes as if it where an AVR EEPROM. When the begin()
* fuction is called for the first time it will "format" the flash chip.
* !!!!THIS DISTROYS ANY EXISTING DATA ON THE FLASH!!!!
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@ -22,63 +21,409 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License v3.0
* along with the Arduino SPIMemory Library. If not, see
* along with the Speeduino SPIAsEEPROM Library. If not, see
* <http://www.gnu.org/licenses/>.
*
* ----------------- Explanation of the EEPROM emulation -------------------
* This explanation is written for novice flash users. If you already know
* about the details of programming flash memmory and EEPROM emulation in
* flash skip this part.
*
* The important thing to rember for prgramming flash
* 1. It has a limitted number of ERASE cycles. usually ~10k
* 2. When erased all bits in flash are set so all flash is 0xFF
* 3. An erase can only be done per flash sector of size X (X=4k or 128k or...)
* 4. Writing to flash can be done unlimited amounts of times, but
* you can only write bits from 1 to 0, never from 0 to 1.
*
* This library makes use of the fact it can reset bits but not set bits in
* flash. It uses X amount of bits for each emulated EEPROM byte that is
* available. For example 512kb of internal flash get 8188 of usable EEPROM bytes.
* The benefit of this is you can write X times more to the EMULATED eeprom than
* writing directly to flash without wearing it down.
*
-------------------------------- IMPLEMENTATION ----------------------------
*
* For every EEPROM byte there are Y amount of flash bytes available. Every write
* to the same EEPROM address writes the new value to a +1 location in flash. Until
* the the buffer of Y locations is full. Than a erase is performed and the whole
* cycle starts again.
*
* To know the location of the last written value there is an address translation part
* for each emulated EEPROM address. For every write one of the bits in the address
* translation part is reset. So when reading the emulated EEPROM it first reads the
* address translation part in flash. The number of ones tells the read function where
* it can find the current byte of that emulated EEPROM address.
*
* Each flash memmory is devided into erasable sectors. This is a property of the flash
* used. You can find the value in the datasheet of the chip. It is FLASH_SECTOR_SIZE macro
* See table 1. The first sector used is offset by the EEPROM_FLASH_BASEADRESS. The last sector
* is determiend by the FLASH_SECTORS_USED macro.
*
* table 1: Each flash memory
* +-------------------------+----------------------+-------------------+-------------------------------------------------------------+
* | Flash Address | Flash sector address | Size | Explanation |
* +-------------------------+----------------------+-------------------+-------------------------------------------------------------+
* | EEPROM_FLASH_BASEADRESS | Flash Sector[0] | FLASH_SECTOR_SIZE | "Start address of EEPROM emulation in flash" |
* | 0000XXXXX | Flash Sector[1] | FLASH_SECTOR_SIZE | "Stores "EEPROM_BYTES_PER_SECTOR" bytes of emulated EEPROM" |
* | 0000XXXXX | Flash Sector[2] | FLASH_SECTOR_SIZE | "Stores "EEPROM_BYTES_PER_SECTOR" bytes of emulated EEPROM" |
* | 0000XXXXX | ....... | ......... | .......... |
* | 0000XXXXX | Flash Sector[X] | FLASH_SECTOR_SIZE | "Last Flash sector[FLASH_SECTORS_USED -1] |
* +-------------------------+----------------------+-------------------+-------------------------------------------------------------+
*
* Each sector is devided into equaly sized sections of FLASH_SECTOR_SIZE/(EEPROM_BYTES_PER_SECTOR+1)
* The first section is used to store some identifiable numbers to show the sector is used
* for EEPROM emulation. Every following section is used to store emulated EEPROM data per address.
* See table 2
*
* table 2: Each flash sector
* +--------------------------+---------------------+-------------------------------------------------+-------------------------------------------------------------------------+
* | Flash Address in sector | EEPROM address | Size | Explanation |
* +--------------------------+---------------------+-------------------------------------------------+-------------------------------------------------------------------------+
* | 000000000 | Magic numbers | FLASH_SECTOR_SIZE/(EEPROM_BYTES_PER_SECTOR + 1) | "Magic numbers and EEPROM version at the start of each flash sector" |
* | 0000XXXXX | Emulated EEPROM [0] | FLASH_SECTOR_SIZE/(EEPROM_BYTES_PER_SECTOR + 1) | "EEPROM section[0], Address translation and value of eeprom address[0]" |
* | 0000XXXXX | Emulated EEPROM [1] | FLASH_SECTOR_SIZE/(EEPROM_BYTES_PER_SECTOR + 1) | "EEPROM section[1], Address translation and value of eeprom address[1]" |
* | 0000XXXXX | ....... | ......... | .......... |
* | 0000XXXXX | Emulated EEPROM [X] | FLASH_SECTOR_SIZE/(EEPROM_BYTES_PER_SECTOR + 1) | "Last EEPROM section[EEPROM_BYTES_PER_SECTOR -1] |
* +--------------------------+---------------------+-------------------------------------------------+-------------------------------------------------------------------------+
*
* Each section that is used for EEPROM emulation starts with the address translation part. This has minimum
* of Y bits to store the address translation. The rest is used for historic EEPROM written data for each EEPROM
* address. See
*
* table 3: Each section in the flash sector
* +---------------------------+---------------------+---------------------------------------------------+------------------------------------------------------------------------------------------------------------+
* | Address in sector section | Description | Size | Explanation |
* +---------------------------+---------------------+---------------------------------------------------+------------------------------------------------------------------------------------------------------------+
* | 00000000X | Address translation | FLASH_SECTOR_SIZE/(EEPROM_BYTES_PER_SECTOR + 1)/8 | "Number of ones translates to address at what location the latest value is, a one is reset for each write" |
* | 000000X+1 | Emulated EEPROM [Y] | 1 | "EEPROM value for the last write to emulated EEPROM at address Y. After this erase of flash sector" |
* | 000000X+2 | Emulated EEPROM [Y] | 1 | "Emulated EEPROM address Y byte write [last-1]" |
* | 000000X+3 | ....... | ......... | .......... |
* | 0000XXXXX | Emulated EEPROM [Y] | 1 | "Location of a EEPROM value for the first write to emulated EEPROM at address Y" |
* +---------------------------+---------------------+---------------------------------------------------+------------------------------------------------------------------------------------------------------------+
*/
#ifndef SPI_AS_EEPROM_H
#define SPI_AS_EEPROM_H
#ifndef FLASH_AS_EEPROM_h
#define FLASH_AS_EEPROM_h
#include <Arduino.h>
#include "winbondflash.h"
#include <SPI.h>
//#if defined(CORE_STM32_OFFICIAL) && defined(SPIFLASH_AS_EEPROM)
#if defined(USE_SPI_EEPROM)
//windbond W25Q16 SPI flash EEPROM emulation
#define FLASH_SECTORS_USED 255UL //This can be any number from 1 to many.
#define FLASH_SECTOR_SIZE 4096UL //Flash sector size this is determined by the physical device. This is the smallest block that can be erased at one time
#define EEPROM_BYTES_PER_SECTOR 31 //(FLASH_SECTOR_SIZE/EEPROM_BYTES_PER_SECTOR+1) Must be integer number and aligned with page size of flash used. For windbond align with 256bytes.
#define EEPROM_FLASH_BASEADRESS 0x00100000UL //address to start from can be zero or any other place in flash. make sure EEPROM_FLASH_BASEADRESS+FLASH_SIZE_USED is not over end of flash
#elif defined(STM32F407xx)
#include "stm32_def.h"
//Internal flash STM32F407 EEPROM emulation
#define FLASH_SECTORS_USED 4UL //This can be any number from 1 to many.
#define FLASH_SECTOR_SIZE 131072UL //Flash sector size this is determined by the physical device. This is the smallest block that can be erased at one time
#define EEPROM_BYTES_PER_SECTOR 2047UL //(FLASH_SECTOR_SIZE/EEPROM_BYTES_PER_SECTOR+1) Must be integer number and aligned with page size of flash used.
#define EEPROM_FLASH_BASEADRESS 0x08080000UL //address to start from can be zero or any other place in flash. make sure EEPROM_FLASH_BASEADRESS+FLASH_SIZE_USED is not over end of flash
#elif defined(STM32F103xB)
#include "stm32_def.h"
//Internal flash STM32F407 EEPROM emulation
#define FLASH_SECTORS_USED 9UL //This can be any number from 1 to many.
#define FLASH_SECTOR_SIZE 1024UL //Flash sector size this is determined by the physical device. This is the smallest block that can be erased at one time
#define EEPROM_BYTES_PER_SECTOR 127UL //(FLASH_SECTOR_SIZE/EEPROM_BYTES_PER_SECTOR+1) Must be integer number and aligned with page size of flash used.
#define EEPROM_FLASH_BASEADRESS 0x801D400UL //address to start from can be zero or any other place in flash. make sure EEPROM_FLASH_BASEADRESS+FLASH_SIZE_USED is not over end of flash
#endif
#define MAGICNUMBER1 0xC0
#define MAGICNUMBER2 0xFF
#define MAGICNUMBER3 0xEE
#define EEPROM_VERSION 204 //V2.0.4
#define MAGICNUMBER_OFFSET 4
#define FLASHSIZEUSED 1757184 //must be a multiple of sectorsize //1757184 = 6006 bytes of EEPROM
#define BYTESPERSECTOR 14
#define SECTORSIZE 4096
#define INFOBYTESSECTOROFFSET 512
#define FLASH_PAGESIZE 256
#define MAGICNUMBER1 0xC0
#define MAGICNUMBER2 0xFF
#define MAGICNUMBER3 0xEE
#define MAGICNUMBER_OFFSET 4
#define BITS_PER_BYTE 8
//Need one bit per byte to determine location actual data
//256bits/8 so 32 bytes
#define INFOBYTES_PER_BYTE FLASH_PAGESIZE/BITS_PER_BYTE
typedef struct {
uint32_t Flash_Sectors_Used;
uint32_t Flash_Sector_Size;
uint32_t EEPROM_Bytes_Per_Sector;
uint32_t EEPROM_Flash_BaseAddress;
} EEPROM_Emulation_Config;
#include <stdint.h>
#include <SPI.h>
#include "winbondflash.h"
class SPIAsEEPROM {
private:
winbondFlashSPI winbondSPIFlash;
uint8_t SpiFlashAvialable = 0;
uint8_t ReadOutBuffer[BYTESPERSECTOR];
uint8_t magicbuf[4];
uint16_t sectorNumber;
uint16_t pageNumber;
uint16_t nrOfOnes;
uint32_t dataFlashAddress;
uint32_t infoFlashAddress;
uint8_t writeMagicNumber(uint16_t sectorNumber);
uint16_t count(uint8_t buf[FLASH_PAGESIZE/BITS_PER_BYTE]);
uint8_t pinSPIFlash_CS;
//Base class for flash read and write. SPI and internal flash inherrit from this class.
class FLASH_EEPROM_BaseClass
{
public:
SPIAsEEPROM();
uint8_t begin(uint8_t pinSPIFlash_CS);
uint8_t formatFlashForUse();
uint8_t read(uint16_t addressEEPROM);
int8_t write(uint16_t addressEEPROM, uint8_t val);
int8_t update(uint16_t address, uint8_t val);
FLASH_EEPROM_BaseClass(EEPROM_Emulation_Config);
/**
* Initialize emulated EEPROM in flash
* @param flashavailable
* @return succes
*/
int8_t initialize(bool);
/**
* Read an eeprom cell
* @param address
* @return value
*/
byte read(uint16_t);
/**
* Write value to an eeprom cell
* @param address
* @param value
*/
int8_t write(uint16_t, byte);
/**
* Update a eeprom cell
* @param address
* @param value
* @return number of bytes written to flash
*/
int8_t update(uint16_t, uint8_t);
/**
* Clear emulated eeprom sector
* @return sectorsCleared
*/
int16_t clear();
/**
* Calculates emulated eeprom length in bytes
* @return eeprom length in bytes
*/
uint16_t length();
//Class variable indicating if the emulated EEPROM flash is initialized
bool _EmulatedEEPROMAvailable=false;
//Class variable storing number of ones counted in adres translation block
uint32_t _nrOfOnes = 0;
//Class variable storing what sector we are working in.
uint32_t _sectorFlash = 0;
//Class variable storing what flash address we are working in.
uint32_t _addressFLASH = 0;
//Class bool indicating if the flash is initialized and available for use
bool _FlashAvailable=false;
//Readwrite buffer used for flash access through the class.
byte _ReadWriteBuffer[128]; //make sure the FLASH_SECTOR_SIZE/EEPROM_BYTES_PER_SECTOR+1 < 128. Else increase this number.
EEPROM_Emulation_Config _config;
uint32_t _Flash_Size_Used;
uint32_t _Flash_Size_Per_EEPROM_Byte;
uint32_t _Addres_Translation_Size;
uint32_t _EEPROM_Emulation_Size;
private:
/**
* Checking for magic numbers on flash if numbers are there no erase is needed else do erase. True if magic numbers are there.
* @return Succes.
*/
bool checkForMagicNumbers();
/**
* After an erase of a flash sector. New magic numbers must be written to that sector for use.
* @param Sector
* @return Succes.
*/
int8_t writeMagicNumbers(uint32_t);
/**
* For adress translation we need to know the first non 1 bit in the address translation block.
* Read the buffer until length and count the numbers of ones in that buffer part. return the count
* @param Buffer
* @param Length
* @return Count.
*/
uint16_t count(byte*, uint32_t);
//************************************************* START Implement for actual flash used ****************************************
/**
* Read bytes from the flash storage
* @param address
* @param buffer
* @param length
* @return succes
*/
virtual int8_t readFlashBytes(uint32_t , byte*, uint32_t);
/**
* Write bytes to the flash storage
* @param address
* @param buffer
* @param length
* @return succes
*/
virtual int8_t writeFlashBytes(uint32_t, byte*, uint32_t);
/**
* Erase a flash sector. Adress determines the flash sector to erase.
* length is specified in number of bytes. if number of bytes > sector size, more than one sector is erased
* @param address
* @param length
* @return succes
*/
virtual int8_t eraseFlashSector(uint32_t, uint32_t);
//************************************************* END Implement for actual flash used ****************************************
};
extern SPIAsEEPROM EEPROM;
//SPI flash class for SPI flash EEPROM emulation. Inherrit most from the base class.
class SPI_EEPROM_Class : public FLASH_EEPROM_BaseClass
{
#endif
public:
SPI_EEPROM_Class(EEPROM_Emulation_Config);
/**
* begin emulated EEPROM in flash
* @param Chip_select_pin
* @param SPI_Instance
* @return succes
*/
int8_t begin(SPIClass&, uint8_t);
/**
* Read an eeprom cell
* @param address
* @return value
*/
byte read(uint16_t);
/**
* Read bytes from the flash storage
* @param address
* @param buffer
* @param length
* @return succes
*/
int8_t readFlashBytes(uint32_t , byte*, uint32_t);
/**
* Write bytes to the flash storage
* @param address
* @param buffer
* @param length
* @return succes
*/
int8_t writeFlashBytes(uint32_t, byte*, uint32_t);
/**
* Erase a flash sector. Adress determines the flash sector to erase.
* length is specified in number of bytes. if number of bytes > sector size, more than one sector is erased
* @param address
* @param length
* @return succes
*/
int8_t eraseFlashSector(uint32_t, uint32_t);
//winbond flash class instance for interacting with the spi flash chip
winbondFlashSPI winbondSPIFlash;
};
//Internal flash class for flash EEPROM emulation. Inherrit most from the base class.
//Internal flash of the STM32F407VE6 is listed as 512kb total. But in reality is 1024kb
//The last 512kb flash is used for the EEPROM emulation
class InternalSTM32F4_EEPROM_Class : public FLASH_EEPROM_BaseClass
{
public:
InternalSTM32F4_EEPROM_Class(EEPROM_Emulation_Config);
/**
* Read an eeprom cell
* @param address
* @return value
*/
byte read(uint16_t);
/**
* Read bytes from the flash storage
* @param address
* @param buffer
* @param length
* @return succes
*/
int8_t readFlashBytes(uint32_t , byte*, uint32_t);
/**
* Write bytes to the flash storage
* @param address
* @param buffer
* @param length
* @return succes
*/
int8_t writeFlashBytes(uint32_t, byte*, uint32_t);
/**
* Erase a flash sector. Adress determines the flash sector to erase.
* length is specified in number of bytes. if number of bytes > sector size, more than one sector is erased
* @param address
* @param length
* @return succes
*/
int8_t eraseFlashSector(uint32_t, uint32_t);
};
// class InternalSTM32F1_EEPROM_Class : public FLASH_EEPROM_BaseClass
// {
// public:
// InternalSTM32F1_EEPROM_Class(EEPROM_Emulation_Config);
// /**
// * Read an eeprom cell
// * @param address
// * @return value
// */
// byte read(uint16_t);
// /**
// * Read bytes from the flash storage
// * @param address
// * @param buffer
// * @param length
// * @return succes
// */
// int8_t readFlashBytes(uint32_t , byte*, uint32_t);
// /**
// * Write bytes to the flash storage
// * @param address
// * @param buffer
// * @param length
// * @return succes
// */
// int8_t writeFlashBytes(uint32_t, byte*, uint32_t);
// /**
// * Erase a flash sector. Adress determines the flash sector to erase.
// * length is specified in number of bytes. if number of bytes > sector size, more than one sector is erased
// * @param address
// * @param length
// * @return succes
// */
// int8_t eraseFlashSector(uint32_t, uint32_t);
// };
#if defined(USE_SPI_EEPROM)
extern SPI_EEPROM_Class EEPROM;
#elif defined(STM32F407xx)
extern InternalSTM32F4_EEPROM_Class EEPROM;
#endif
#endif

View File

@ -5,9 +5,6 @@
latest version available on http://code.google.com/p/winbondflash
*/
#include <Arduino.h>
#include <SPI.h>
#include <errno.h>
#include "winbondflash.h"
//COMMANDS
@ -349,16 +346,10 @@ void winbondFlashClass::eraseResume()
bool winbondFlashSPI::begin(partNumber _partno,SPIClass &_spi,uint8_t _nss)
{
//spi = _spi;
nss = _nss;
// pinMode(MISO,INPUT_PULLUP);
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV2);
SPI.setDataMode(SPI_MODE0);
spi_port = &_spi;
deselect();
// Serial.println("SPI OK");
//Serial.println("SPI OK");
return winbondFlashClass::begin(_partno);
}
@ -366,7 +357,7 @@ bool winbondFlashSPI::begin(partNumber _partno,SPIClass &_spi,uint8_t _nss)
void winbondFlashSPI::end()
{
winbondFlashClass::end();
SPI.end();
// spi_port->end();
}

View File

@ -10,10 +10,15 @@
#include <inttypes.h>
#include <SPI.h>
#include <Arduino.h>
#include <errno.h>
//W25Q64 = 256_bytes_per_page * 16_pages_per_sector * 16_sectors_per_block * 128_blocks_per_chip
//= 256b*16*16*128 = 8Mbyte = 64MBits
//W25Q16 = 256_bytes_per_page * 16_pages_per_sector * 16_sectors_per_block * 32_blocks_per_chip
//= 256b*16*16*32 = 2Mbyte = 16MBits
#define _W25Q80 winbondFlashClass::W25Q80
#define _W25Q16 winbondFlashClass::W25Q16
#define _W25Q32 winbondFlashClass::W25Q32
@ -81,13 +86,13 @@ protected:
class winbondFlashSPI: public winbondFlashClass {
private:
uint8_t nss;
// SPIClass spi;
SPIClass *spi_port;
inline void select() {
digitalWrite(nss,LOW);
}
inline uint8_t transfer(uint8_t x) {
byte y = SPI.transfer(x);
byte y = spi_port->transfer(x);
return y;
}

View File

@ -18,7 +18,7 @@ void storeEEPROMVersion(byte);
void storePageCRC32(byte, uint32_t);
uint32_t readPageCRC32(byte);
#if defined(CORE_STM32) || defined(CORE_TEENSY)
#if defined(CORE_STM32) || defined(CORE_TEENSY) & !defined(USE_SPI_EEPROM)
#define EEPROM_MAX_WRITE_BLOCK 64 //The maximum number of write operations that will be performed in one go. If we try to write to the EEPROM too fast (Each write takes ~3ms) then the rest of the system can hang)
#else
#define EEPROM_MAX_WRITE_BLOCK 30 //The maximum number of write operations that will be performed in one go. If we try to write to the EEPROM too fast (Each write takes ~3ms) then the rest of the system can hang)