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