diff --git a/platformio.ini b/platformio.ini index 415746fa..715dff8d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -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 diff --git a/speeduino/board_stm32_official.h b/speeduino/board_stm32_official.h index 67b81093..18dbf61b 100644 --- a/speeduino/board_stm32_official.h +++ b/speeduino/board_stm32_official.h @@ -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 #else - #define EEPROM_LIB_H + #define EEPROM_LIB_H "src/SPIAsEEPROM/SPIAsEEPROM.h" #endif #ifndef LED_BUILTIN diff --git a/speeduino/board_stm32_official.ino b/speeduino/board_stm32_official.ino index b93a761e..dc9fcdd5 100644 --- a/speeduino/board_stm32_official.ino +++ b/speeduino/board_stm32_official.ino @@ -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() { diff --git a/speeduino/src/SPIAsEEPROM/SPIAsEEPROM.cpp b/speeduino/src/SPIAsEEPROM/SPIAsEEPROM.cpp index c85e6d0c..6f7ed89c 100644 --- a/speeduino/src/SPIAsEEPROM/SPIAsEEPROM.cpp +++ b/speeduino/src/SPIAsEEPROM/SPIAsEEPROM.cpp @@ -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 * . */ -//#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 * (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 \ No newline at end of file diff --git a/speeduino/src/SPIAsEEPROM/SPIAsEEPROM.h b/speeduino/src/SPIAsEEPROM/SPIAsEEPROM.h index 220b00c7..65658d1a 100644 --- a/speeduino/src/SPIAsEEPROM/SPIAsEEPROM.h +++ b/speeduino/src/SPIAsEEPROM/SPIAsEEPROM.h @@ -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 * . + * + * ----------------- 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 +#include "winbondflash.h" +#include -//#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 -#include -#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 diff --git a/speeduino/src/SPIAsEEPROM/winbondflash.cpp b/speeduino/src/SPIAsEEPROM/winbondflash.cpp index ebc13a3d..7fed4cff 100644 --- a/speeduino/src/SPIAsEEPROM/winbondflash.cpp +++ b/speeduino/src/SPIAsEEPROM/winbondflash.cpp @@ -5,9 +5,6 @@ latest version available on http://code.google.com/p/winbondflash */ -#include -#include -#include #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(); } diff --git a/speeduino/src/SPIAsEEPROM/winbondflash.h b/speeduino/src/SPIAsEEPROM/winbondflash.h index 0fda28b9..7bba0d4c 100644 --- a/speeduino/src/SPIAsEEPROM/winbondflash.h +++ b/speeduino/src/SPIAsEEPROM/winbondflash.h @@ -10,10 +10,15 @@ #include #include +#include +#include //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; } diff --git a/speeduino/storage.h b/speeduino/storage.h index 472b13f2..d6af7577 100644 --- a/speeduino/storage.h +++ b/speeduino/storage.h @@ -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)