From 750d486276c74780742797507ac3969a34da1ead Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Thu, 17 Jan 2019 20:47:19 +1100 Subject: [PATCH] VERY rough initial work on modular boards layout --- .gitignore | 1 + platformio.ini | 12 ++- speeduino/comms.ino | 4 +- speeduino/globals.h | 3 + speeduino/init.ino | 14 +-- speeduino/speeduino.ino | 1 + speeduino/src/FastCRC/FastCRC_tables.h | 2 +- speeduino/src/FlashStorage/FlashAsEEPROM.cpp | 75 ++++++++++++++ speeduino/src/FlashStorage/FlashAsEEPROM.h | 87 ++++++++++++++++ speeduino/src/FlashStorage/FlashStorage.cpp | 102 +++++++++++++++++++ speeduino/src/FlashStorage/FlashStorage.h | 77 ++++++++++++++ speeduino/src/boards/avr2560.h | 0 speeduino/storage.h | 9 ++ speeduino/storage.ino | 12 +++ speeduino/updates.ino | 15 ++- 15 files changed, 400 insertions(+), 14 deletions(-) create mode 100755 speeduino/src/FlashStorage/FlashAsEEPROM.cpp create mode 100755 speeduino/src/FlashStorage/FlashAsEEPROM.h create mode 100755 speeduino/src/FlashStorage/FlashStorage.cpp create mode 100755 speeduino/src/FlashStorage/FlashStorage.h create mode 100644 speeduino/src/boards/avr2560.h diff --git a/.gitignore b/.gitignore index d38966be..4dd3f6d5 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ reference/hardware/v0.4/gerbers/Archive.zip .vscode/c_cpp_properties.json .vscode/launch.json .vscode/.browse.c_cpp.db* +speeduino/src/boards/samd21.h diff --git a/platformio.ini b/platformio.ini index ec7a5469..3524a22f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -44,7 +44,17 @@ framework = arduino board = bluepill_f103c8 lib_deps = EEPROM ;build_flags = -fpermissive -std=gnu++11 -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,-Map,output.map -build_flags = -fpermissive -std=gnu++11 -Os +build_flags = -fpermissive -std=gnu++11 -Os + +;SAMD21 +[env:samd21] +platform = atmelsam +framework = arduino +board = zeroUSB +lib_deps = EEPROM +build_flags = -fpermissive -std=gnu++11 +upload_protocol = sam-ba + ;Support for the stm32f407 doesn't look ready in platformio yet ;[env:genericSTM32F407VE] diff --git a/speeduino/comms.ino b/speeduino/comms.ino index 8bf72ab9..c0ad455e 100644 --- a/speeduino/comms.ino +++ b/speeduino/comms.ino @@ -11,7 +11,6 @@ A full copy of the license may be found in the projects root directory #include "maths.h" #include "utils.h" #include "decoders.h" -#include /* Processes the data on the serial buffer. @@ -1406,7 +1405,8 @@ void receiveCalibration(byte tableID) //From TS3.x onwards, the EEPROM must be written here as TS restarts immediately after the process completes which is before the EEPROM write completes int y = EEPROM_START + (x / 2); - EEPROM.update(y, (byte)tempValue); + //EEPROM.update(y, (byte)tempValue); + storeCalibrationValue(y, (byte)tempValue); every2nd = false; #if defined(CORE_STM32) diff --git a/speeduino/globals.h b/speeduino/globals.h index 5962f1a5..b2e8021b 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -51,6 +51,9 @@ #define portOutputRegister(port) (volatile byte *)( &(port->regs->ODR) ) #define portInputRegister(port) (volatile byte *)( &(port->regs->IDR) ) #endif +#elif defined(__SAMD21G18A__) + #define BOARD_H "src/boards/samd21.h" + #define CORE_SAMD21 #else #error Incorrect board selected. Please select the correct board (Usually Mega 2560) and upload again #endif diff --git a/speeduino/init.ino b/speeduino/init.ino index 437665ec..574e1aa5 100644 --- a/speeduino/init.ino +++ b/speeduino/init.ino @@ -13,7 +13,6 @@ #include "decoders.h" #include "corrections.h" #include "idle.h" -#include void initialiseAll() { @@ -155,8 +154,9 @@ void initialiseAll() //barometric reading can be taken from either an external sensor if enabled, or simply by using the initial MAP value if ( configPage6.useExtBaro != 0 ) { - readBaro(); - EEPROM.update(EEPROM_LAST_BARO, currentStatus.baro); + readBaro(); + //EEPROM.update(EEPROM_LAST_BARO, currentStatus.baro); + storeLastBaro(currentStatus.baro); } else { @@ -168,13 +168,15 @@ void initialiseAll() if ((currentStatus.MAP >= BARO_MIN) && (currentStatus.MAP <= BARO_MAX)) //Check if engine isn't running { currentStatus.baro = currentStatus.MAP; - EEPROM.update(EEPROM_LAST_BARO, currentStatus.baro); + //EEPROM.update(EEPROM_LAST_BARO, currentStatus.baro); + storeLastBaro(currentStatus.baro); } else { //Attempt to use the last known good baro reading from EEPROM - if ((EEPROM.read(EEPROM_LAST_BARO) >= BARO_MIN) && (EEPROM.read(EEPROM_LAST_BARO) <= BARO_MAX)) //Make sure it's not invalid (Possible on first run etc) - { currentStatus.baro = EEPROM.read(EEPROM_LAST_BARO); } //last baro correction + //if (EEPROM.read(EEPROM_LAST_BARO) >= BARO_MIN) && (EEPROM.read(EEPROM_LAST_BARO) <= BARO_MAX)) //Make sure it's not invalid (Possible on first run etc) + if ((readLastBaro() >= BARO_MIN) && (readLastBaro() <= BARO_MAX)) //Make sure it's not invalid (Possible on first run etc) + { currentStatus.baro = readLastBaro(); } //last baro correction else { currentStatus.baro = 100; } //Final fall back position. } } diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 6e9b1a91..ddd6feb2 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "storage.h" #include "crankMaths.h" #include "init.h" +#include BOARD_H //Note that this is not a real file, it is defined in globals.h. #if defined (CORE_TEENSY) #include #endif diff --git a/speeduino/src/FastCRC/FastCRC_tables.h b/speeduino/src/FastCRC/FastCRC_tables.h index 1d5142f5..c0d32c11 100755 --- a/speeduino/src/FastCRC/FastCRC_tables.h +++ b/speeduino/src/FastCRC/FastCRC_tables.h @@ -31,7 +31,7 @@ #define FastCRC_tables #include "inttypes.h" -#if defined(__AVR__) || defined(STM32_MCU_SERIES) || defined(ARDUINO_ARCH_STM32) || defined(_VARIANT_ARDUINO_STM32_) +#if defined(__AVR__) || defined(STM32_MCU_SERIES) || defined(ARDUINO_ARCH_STM32) || defined(_VARIANT_ARDUINO_STM32_) || defined(__SAMD21G18A__) #include #else #include diff --git a/speeduino/src/FlashStorage/FlashAsEEPROM.cpp b/speeduino/src/FlashStorage/FlashAsEEPROM.cpp new file mode 100755 index 00000000..92676ce7 --- /dev/null +++ b/speeduino/src/FlashStorage/FlashAsEEPROM.cpp @@ -0,0 +1,75 @@ +/* + EEPROM like API that uses Arduino Zero's flash memory. + Written by A. Christian + + Copyright (c) 2015-2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#if defined(CORE_SAMD21) +#include "FlashAsEEPROM.h" + +FlashStorage(eeprom_storage, EEPROM_EMULATION); + +EEPROMClass::EEPROMClass(void) : _initialized(false), _dirty(false) { + // Empty +} + +uint8_t EEPROMClass::read(int address) +{ + if (!_initialized) init(); + return _eeprom.data[address]; +} + +void EEPROMClass::update(int address, uint8_t value) +{ + if (!_initialized) init(); + if (_eeprom.data[address] != value) { + _dirty = true; + _eeprom.data[address] = value; + } +} + +void EEPROMClass::write(int address, uint8_t value) +{ + update(address, value); +} + +void EEPROMClass::init() +{ + _eeprom = eeprom_storage.read(); + if (!_eeprom.valid) { + memset(_eeprom.data, 0xFF, EEPROM_EMULATION_SIZE); + } + _initialized = true; +} + +bool EEPROMClass::isValid() +{ + if (!_initialized) init(); + return _eeprom.valid; +} + +void EEPROMClass::commit() +{ + if (!_initialized) init(); + if (_dirty) { + _eeprom.valid = true; + eeprom_storage.write(_eeprom); + } +} + +EEPROMClass EEPROM; +#endif \ No newline at end of file diff --git a/speeduino/src/FlashStorage/FlashAsEEPROM.h b/speeduino/src/FlashStorage/FlashAsEEPROM.h new file mode 100755 index 00000000..8ea3a913 --- /dev/null +++ b/speeduino/src/FlashStorage/FlashAsEEPROM.h @@ -0,0 +1,87 @@ +/* + EEPROM like API that uses Arduino Zero's flash memory. + Written by A. Christian + + Copyright (c) 2015-2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef FLASH_AS_EEPROM_h +#define FLASH_AS_EEPROM_h + +#include "FlashStorage.h" + +#ifndef EEPROM_EMULATION_SIZE +#define EEPROM_EMULATION_SIZE 1024 +#endif + +typedef struct { + byte data[EEPROM_EMULATION_SIZE]; + boolean valid; +} EEPROM_EMULATION; + + +class EEPROMClass { + + public: + EEPROMClass(void); + + /** + * Read an eeprom cell + * @param index + * @return value + */ + uint8_t read(int); + + /** + * Write value to an eeprom cell + * @param index + * @param value + */ + void write(int, uint8_t); + + /** + * Update a eeprom cell + * @param index + * @param value + */ + void update(int, uint8_t); + + /** + * Check whether the eeprom data is valid + * @return true, if eeprom data is valid (has been written at least once), false if not + */ + bool isValid(); + + /** + * Write previously made eeprom changes to the underlying flash storage + * Use this with care: Each and every commit will harm the flash and reduce it's lifetime (like with every flash memory) + */ + void commit(); + + uint16_t length() { return EEPROM_EMULATION_SIZE; } + + private: + void init(); + + bool _initialized; + EEPROM_EMULATION _eeprom; + bool _dirty; +}; + +extern EEPROMClass EEPROM; + +#endif diff --git a/speeduino/src/FlashStorage/FlashStorage.cpp b/speeduino/src/FlashStorage/FlashStorage.cpp new file mode 100755 index 00000000..0a6986b0 --- /dev/null +++ b/speeduino/src/FlashStorage/FlashStorage.cpp @@ -0,0 +1,102 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Written by Cristian Maglie + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#if defined(CORE_SAMD21) +#include "FlashStorage.h" + +static const uint32_t pageSizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024 }; + +FlashClass::FlashClass(const void *flash_addr, uint32_t size) : + PAGE_SIZE(pageSizes[NVMCTRL->PARAM.bit.PSZ]), + PAGES(NVMCTRL->PARAM.bit.NVMP), + MAX_FLASH(PAGE_SIZE * PAGES), + ROW_SIZE(PAGE_SIZE * 4), + flash_address((volatile void *)flash_addr), + flash_size(size) +{ +} + +static inline uint32_t read_unaligned_uint32(const void *data) +{ + union { + uint32_t u32; + uint8_t u8[4]; + } res; + const uint8_t *d = (const uint8_t *)data; + res.u8[0] = d[0]; + res.u8[1] = d[1]; + res.u8[2] = d[2]; + res.u8[3] = d[3]; + return res.u32; +} + +void FlashClass::write(const volatile void *flash_ptr, const void *data, uint32_t size) +{ + // Calculate data boundaries + size = (size + 3) / 4; + volatile uint32_t *dst_addr = (volatile uint32_t *)flash_ptr; + const uint8_t *src_addr = (uint8_t *)data; + + // Disable automatic page write + NVMCTRL->CTRLB.bit.MANW = 1; + + // Do writes in pages + while (size) { + // Execute "PBC" Page Buffer Clear + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + + // Fill page buffer + uint32_t i; + for (i=0; i<(PAGE_SIZE/4) && size; i++) { + *dst_addr = read_unaligned_uint32(src_addr); + src_addr += 4; + dst_addr++; + size--; + } + + // Execute "WP" Write Page + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + } +} + +void FlashClass::erase(const volatile void *flash_ptr, uint32_t size) +{ + const uint8_t *ptr = (const uint8_t *)flash_ptr; + while (size > ROW_SIZE) { + erase(ptr); + ptr += ROW_SIZE; + size -= ROW_SIZE; + } + erase(ptr); +} + +void FlashClass::erase(const volatile void *flash_ptr) +{ + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; + while (!NVMCTRL->INTFLAG.bit.READY) { } +} + +void FlashClass::read(const volatile void *flash_ptr, void *data, uint32_t size) +{ + memcpy(data, (const void *)flash_ptr, size); +} + +#endif \ No newline at end of file diff --git a/speeduino/src/FlashStorage/FlashStorage.h b/speeduino/src/FlashStorage/FlashStorage.h new file mode 100755 index 00000000..77bb492e --- /dev/null +++ b/speeduino/src/FlashStorage/FlashStorage.h @@ -0,0 +1,77 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + Written by Cristian Maglie + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include + +// Concatenate after macro expansion +#define PPCAT_NX(A, B) A ## B +#define PPCAT(A, B) PPCAT_NX(A, B) + +#define Flash(name, size) \ + __attribute__((__aligned__(256))) \ + static const uint8_t PPCAT(_data,name)[(size+255)/256*256] = { }; \ + FlashClass name(PPCAT(_data,name), size); + +#define FlashStorage(name, T) \ + __attribute__((__aligned__(256))) \ + static const uint8_t PPCAT(_data,name)[(sizeof(T)+255)/256*256] = { }; \ + FlashStorageClass name(PPCAT(_data,name)); + +class FlashClass { +public: + FlashClass(const void *flash_addr = NULL, uint32_t size = 0); + + void write(const void *data) { write(flash_address, data, flash_size); } + void erase() { erase(flash_address, flash_size); } + void read(void *data) { read(flash_address, data, flash_size); } + + void write(const volatile void *flash_ptr, const void *data, uint32_t size); + void erase(const volatile void *flash_ptr, uint32_t size); + void read(const volatile void *flash_ptr, void *data, uint32_t size); + +private: + void erase(const volatile void *flash_ptr); + + const uint32_t PAGE_SIZE, PAGES, MAX_FLASH, ROW_SIZE; + const volatile void *flash_address; + const uint32_t flash_size; +}; + +template +class FlashStorageClass { +public: + FlashStorageClass(const void *flash_addr) : flash(flash_addr, sizeof(T)) { }; + + // Write data into flash memory. + // Compiler is able to optimize parameter copy. + inline void write(T data) { flash.erase(); flash.write(&data); } + + // Read data from flash into variable. + inline void read(T *data) { flash.read(data); } + + // Overloaded version of read. + // Compiler is able to optimize copy-on-return. + inline T read() { T data; read(&data); return data; } + +private: + FlashClass flash; +}; + diff --git a/speeduino/src/boards/avr2560.h b/speeduino/src/boards/avr2560.h new file mode 100644 index 00000000..e69de29b diff --git a/speeduino/storage.h b/speeduino/storage.h index 87edef5c..c0f8368e 100644 --- a/speeduino/storage.h +++ b/speeduino/storage.h @@ -1,12 +1,21 @@ #ifndef STORAGE_H #define STORAGE_H +#include "globals.h" + void writeAllConfig(); void writeConfig(byte); void loadConfig(); void loadCalibration(); void writeCalibration(); +//These are utility functions that prevent other files from having to use EEPROM.h directly +byte readLastBaro(); +void storeLastBaro(byte); +void storeCalibrationValue(byte, byte); +byte readEEPROMVersion(); +void storeEEPROMVersion(byte); + #if defined(CORE_STM32) || defined(CORE_TEENSY) #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 diff --git a/speeduino/storage.ino b/speeduino/storage.ino index 43bf91a5..d7f1ae53 100644 --- a/speeduino/storage.ino +++ b/speeduino/storage.ino @@ -8,7 +8,11 @@ A full copy of the license may be found in the projects root directory #include "globals.h" #include "table.h" #include "comms.h" +#if defined(CORE_SAMD21) + #include "src/FlashStorage/FlashAsEEPROM.h" +#else #include +#endif void writeAllConfig() { @@ -643,3 +647,11 @@ void writeCalibration() } } + +// Utility functions. +// By having these in this file, it prevents other files from calling EEPROM functions directly. This is useful due to differences in the EEPROM libraries on different devces +byte readLastBaro() { return EEPROM.read(EEPROM_LAST_BARO); } +void storeLastBaro(byte newValue) { EEPROM.update(EEPROM_LAST_BARO, newValue); } +void storeCalibrationValue(byte location, byte value) { EEPROM.update(location, value); } //This is essentially just an abstraction for EEPROM.update() +byte readEEPROMVersion() { return EEPROM.read(EEPROM_DATA_VERSION); } +void storeEEPROMVersion(byte newVersion) { EEPROM.update(EEPROM_DATA_VERSION, newVersion); } \ No newline at end of file diff --git a/speeduino/updates.ino b/speeduino/updates.ino index 7a0007f0..6873f21f 100644 --- a/speeduino/updates.ino +++ b/speeduino/updates.ino @@ -4,9 +4,13 @@ * It also can be used for setting good values when there are viarables that move locations in the ini * When a user skips multiple firmware versions at a time, this will roll through the updates 1 at a time */ -#include #include "globals.h" #include "storage.h" +#if defined(CORE_SAMD21) + #include "src/FlashStorage/FlashAsEEPROM.h" +#else +#include +#endif void doUpdates() { @@ -23,7 +27,8 @@ void doUpdates() } } writeAllConfig(); - EEPROM.write(EEPROM_DATA_VERSION, 3); + //EEPROM.write(EEPROM_DATA_VERSION, 3); + storeEEPROMVersion(3); } //June 2017 required the forced addition of some CAN values to avoid weird errors if(EEPROM.read(EEPROM_DATA_VERSION) == 3) @@ -36,7 +41,8 @@ void doUpdates() if(configPage4.sparkDur == 255) { configPage4.sparkDur = 10; } writeAllConfig(); - EEPROM.write(EEPROM_DATA_VERSION, 4); + //EEPROM.write(EEPROM_DATA_VERSION, 4); + storeEEPROMVersion(4); } //July 2017 adds a cranking enrichment curve in place of the single value. This converts that single value to the curve if(EEPROM.read(EEPROM_DATA_VERSION) == 4) @@ -53,7 +59,8 @@ void doUpdates() configPage10.crankingEnrichValues[3] = 100 + configPage2.crankingPct; writeAllConfig(); - EEPROM.write(EEPROM_DATA_VERSION, 5); + //EEPROM.write(EEPROM_DATA_VERSION, 5); + storeEEPROMVersion(5); } //September 2017 had a major change to increase the minimum table size to 128. This required multiple pieces of data being moved around if(EEPROM.read(EEPROM_DATA_VERSION) == 5)