diff --git a/firmware/cl-step-controller/platformio.ini b/firmware/cl-step-controller/platformio.ini index 63643599ff595899f2154abf38c7d4dba556c72e..50208f0cadb2e924ce3a661e45b5c88422dc71af 100644 --- a/firmware/cl-step-controller/platformio.ini +++ b/firmware/cl-step-controller/platformio.ini @@ -12,4 +12,3 @@ platform = atmelsam board = adafruit_feather_m4 framework = arduino -lib_deps = cmaglie/FlashStorage@^1.0.0 diff --git a/firmware/cl-step-controller/src/drivers/step_cl.cpp b/firmware/cl-step-controller/src/drivers/step_cl.cpp index 61b577b2c9ae6d2bf72e8c457a65ae81a55a6e5c..23f6c43553a47fcb4b8e816a2f7051ab07a508c3 100644 --- a/firmware/cl-step-controller/src/drivers/step_cl.cpp +++ b/firmware/cl-step-controller/src/drivers/step_cl.cpp @@ -13,6 +13,7 @@ is; no warranty is provided, and users accept all liability. */ #include "step_cl.h" +#include "../utils/FlashStorage.h" Step_CL* Step_CL::instance = 0; @@ -46,27 +47,72 @@ void Step_CL::init(void){ //lut = flash_lut.read(); } -FlashStorage(flash_store, float); +#define BYTES_PER_PAGE 512 +#define FLOATS_PER_PAGE 128 +#define PAGES_PER_BLOCK 16 // for 8192 bytes / block +#define LUT_SIZE 128 + +//const float __attribute__((__aligned__(BYTES_PER_PAGE))) lut[LUT_SIZE] = {}; +//const void* page_ptr; +//static float buffer[FLOATS_PER_PAGE]; +//static uint32_t bi; + +//FlashClass flashClass((const uint8_t*)lut, BYTES_PER_PAGE); // try w/ constructor values ? + +typedef struct { + float f[LUT_SIZE]; +} flts; + +flts inbuf; +uint32_t bi = 0; + +FlashStorage(flash_storage, flts); void flash_write_init(void){ } +void flash_write_page(void){ + sysError("writing"); + flash_storage.write(inbuf); + sysError("written"); + // sysError("unlocking block"); + // NVMCTRL->ADDR.reg = (uint32_t)((const uint8_t*)(lut)); + // NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_UR; + // while(NVMCTRL->STATUS.bit.READY == 0); + // sysError("erasing block"); + // //flashClass.erase((const uint8_t*)lut, 0); + // NVMCTRL->ADDR.reg = (uint32_t)((const uint8_t*)(lut)); + // NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_EB; + // // is it hung, or is there an error to catch ? + // // hung ! + // //while(NVMCTRL->STATUS.bit.READY == 0); + // sysError("writing page"); + // flashClass.write((const uint8_t*)lut, (const uint8_t*)buffer, BYTES_PER_PAGE); +} + void flash_write_value(float val){ - flash_store.write(val); + inbuf.f[bi ++] = val; + if(bi >= LUT_SIZE){ + flash_write_page(); + } } void Step_CL::print_table(void){ - for(uint16_t e = 0; e < 4; e ++){ - float ra = flash_store.read(); - sysError("e: " + String(e) + " ra: " + String(ra, 4)); + sysError("reading"); + flts read = flash_storage.read(); + for(uint16_t e = 0; e < LUT_SIZE; e ++){ + sysError(String(read.f[e])); delay(5); } } // the calib routine boolean Step_CL::calibrate(void){ - flash_write_value(100.0F); + flash_write_init(); + for(uint8_t i = 0; i < LUT_SIZE; i ++){ + flash_write_value(i * 1.1F); + } return true; // (1) first, build a table for 200 full steps w/ encoder averaged values at each step float phase_angle = 0.0F; @@ -215,7 +261,7 @@ boolean Step_CL::calibrate(void){ delay(10); } // ok, have the real angle (ra) at the encoder tick (e), now write it - flash_write_value(ra); // this just happens in order, we zeroe'd out global counters at the start + //flash_write_value(ra); // this just happens in order, we zeroe'd out global counters at the start } // end sweep thru 2^14 pts sysError("calib complete"); return true; // went OK diff --git a/firmware/cl-step-controller/src/drivers/step_cl.h b/firmware/cl-step-controller/src/drivers/step_cl.h index cdb40f64dd8575c33584d908c759719daca2ee83..b419de1255f03288d3dcc5959562bbde77e87b3c 100644 --- a/firmware/cl-step-controller/src/drivers/step_cl.h +++ b/firmware/cl-step-controller/src/drivers/step_cl.h @@ -20,8 +20,6 @@ is; no warranty is provided, and users accept all liability. #include "step_a4950.h" #include "enc_as5047.h" -#include "FlashStorage.h" - class Step_CL { private: static Step_CL* instance; @@ -38,6 +36,8 @@ class Step_CL { //step_cl_calib_table_t lut; // not even this works ?? too big ?? }; +extern const float lut[]; + extern Step_CL* step_cl; #endif \ No newline at end of file diff --git a/firmware/cl-step-controller/src/utils/FlashStorage.cpp b/firmware/cl-step-controller/src/utils/FlashStorage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63be02c78e0c890c2b189ae917445a6ea6db7960 --- /dev/null +++ b/firmware/cl-step-controller/src/utils/FlashStorage.cpp @@ -0,0 +1,149 @@ +/* + 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 +*/ + +#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), +#if defined(__SAMD51__) + ROW_SIZE(MAX_FLASH / 64), +#else + ROW_SIZE(PAGE_SIZE * 4), +#endif + 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; +} + +#if defined(__SAMD51__) +// Invalidate all CMCC cache entries if CMCC cache is enabled. +static void invalidate_CMCC_cache() +{ + if (CMCC->SR.bit.CSTS) { // CR -> SR + CMCC->CTRL.bit.CEN = 0; + while (CMCC->SR.bit.CSTS) {} + CMCC->MAINT0.bit.INVALL = 1; + CMCC->CTRL.bit.CEN = 1; + } +} +#endif + +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 +#if defined(__SAMD51__) + NVMCTRL->CTRLA.bit.WMODE = 0; + while (NVMCTRL->STATUS.bit.READY == 0) { } + // Disable NVMCTRL cache while writing, per SAMD51 errata. + bool original_CACHEDIS0 = NVMCTRL->CTRLA.bit.CACHEDIS0; + bool original_CACHEDIS1 = NVMCTRL->CTRLA.bit.CACHEDIS1; + NVMCTRL->CTRLA.bit.CACHEDIS0 = true; + NVMCTRL->CTRLA.bit.CACHEDIS1 = true; +#else + NVMCTRL->CTRLB.bit.MANW = 1; +#endif + + // Do writes in pages + while (size) { + // Execute "PBC" Page Buffer Clear +#if defined(__SAMD51__) + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.DONE == 0) { } +#else + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } +#endif + + // 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 +#if defined(__SAMD51__) + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_WP; + while (NVMCTRL->INTFLAG.bit.DONE == 0) { } + invalidate_CMCC_cache(); + // Restore original NVMCTRL cache settings. + NVMCTRL->CTRLA.bit.CACHEDIS0 = original_CACHEDIS0; + NVMCTRL->CTRLA.bit.CACHEDIS1 = original_CACHEDIS1; +#else + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } +#endif + } +} + +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) +{ +#if defined(__SAMD51__) + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr); + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_EB; + while (!NVMCTRL->INTFLAG.bit.DONE) { } + invalidate_CMCC_cache(); +#else + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; + while (!NVMCTRL->INTFLAG.bit.READY) { } +#endif +} + +void FlashClass::read(const volatile void *flash_ptr, void *data, uint32_t size) +{ + memcpy(data, (const void *)flash_ptr, size); +} + diff --git a/firmware/cl-step-controller/src/utils/FlashStorage.h b/firmware/cl-step-controller/src/utils/FlashStorage.h new file mode 100644 index 0000000000000000000000000000000000000000..7e1a64f40d6a7ecc4c6428581e00c78b9915fddf --- /dev/null +++ b/firmware/cl-step-controller/src/utils/FlashStorage.h @@ -0,0 +1,89 @@ +/* + 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 <Arduino.h> + +// Concatenate after macro expansion +#define PPCAT_NX(A, B) A ## B +#define PPCAT(A, B) PPCAT_NX(A, B) + +#if defined(__SAMD51__) + #define Flash(name, size) \ + __attribute__((__aligned__(8192))) \ + static const uint8_t PPCAT(_data,name)[(size+8191)/8192*8192] = { }; \ + FlashClass name(PPCAT(_data,name), size); + +#define FlashStorage(name, T) \ + __attribute__((__aligned__(8192))) \ + static const uint8_t PPCAT(_data,name)[(sizeof(T)+8191)/8192*8192] = { }; \ + FlashStorageClass<T> name(PPCAT(_data,name)); +#else + #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<T> name(PPCAT(_data,name)); +#endif + +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 T> +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/log/cl-step-control-log.md b/log/cl-step-control-log.md index 3aa6f4f5b0f45d5cecefce3e4c80be42b0a2b3b4..3812bc45222987c97f0aab91e54e7b3031ca6232 100644 --- a/log/cl-step-control-log.md +++ b/log/cl-step-control-log.md @@ -823,4 +823,53 @@ so that should be OK, I'm writing at 0x1... tho this program uses 42kb, but inde I don't know what is real anymore, the libraries failed me, the datasheet is opaque AF, I am writing somewhere I shouldn't, etc. Might be time to bring out the atmel studio guns. -Or the small guns: I'm going to try to get a minimum viable something up with this library. \ No newline at end of file +Or the small guns: I'm going to try to get a minimum viable something up with this library. + +Works like this: + +```cpp +FlashStorage(flash_store, float); + +void flash_write_init(void){ + +} + +void flash_write_value(float val){ + flash_store.write(val); +} + +void Step_CL::print_table(void){ + for(uint16_t e = 0; e < 4; e ++){ + float ra = flash_store.read(); + sysError("e: " + String(e) + " ra: " + String(ra, 4)); + delay(5); + } +} +``` + +So I can try doing batches of these... Seems like a full 'page' works, I wonder if anything > 512 bytes does as well, or crashes... breaks at 256 floats, but not at 129... + +So it seems that it should work, if I can get into the lower levels of this thing and increment pointers around. I'll try to do that first with just the 128 bytes that I know can work, and I'm pretty sure that's inside of one page. + +OK, trips at the erase. Takes *forever* to reload code once I cripple it like this. + +Oy, seems like I wrote it... then it dissappears after a reset, wth? That was to do with a volatile flag. + +I think this has to do with erase block / instead of erase page. I should learn more about that in the data sheet. + +Blocks are 16 pages: erase granularity is per block, write granularity is per page. One guess is that if the block / page are not aligned to a block, the EB command fails. Altho from 25.6.6.6 (fitting), it notes that any address within the block is valid for an erase block command. + +OK, trying to unlock the block beforehand. + +SO! Definitely hung on trying to erase a block. However, have had some evidence that this worked previously. + +It's 1230 - I'll think about this tomorrow. Maybe try taking the above single-float working example apart, see if you can code it up yourself, to understand what's up. + +## 2020 10 14 + +OK, today will bring this library into the local build and see about figuring what the heck it does, build the minimum example from scratch, and then see if I can scale that up to multiple blocks / tables. + +- pages are 512 bytes +- blocks are 16 pages + +This means a block is 8192, makes sense this is where flashstorage aligns itself. I need 8 blocks total for the full LUT. \ No newline at end of file