diff --git a/.gitmodules b/.gitmodules
index cfd187deaa33bef6903824d987cd63ba74ab17bc..0bb89b4c4cdf3b1c089eab64733f5bbe9fbf80f1 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -28,3 +28,6 @@
 [submodule "firmware/axl-stepper/src/osape_arduino"]
 	path = firmware/axl-stepper/src/osape_arduino
 	url = https://github.com/jakeread/osape_arduino.git
+[submodule "firmware/axl-stepper/src/utils_samd51"]
+	path = firmware/axl-stepper/src/utils_samd51
+	url = https://github.com/jakeread/utils_samd51.git
diff --git a/firmware/axl-stepper/src/axl b/firmware/axl-stepper/src/axl
index 79ca7181653d7e8c567cf026e7cc882a5c410feb..c874b7afa9102ae3e5c150e444b01703c7143303 160000
--- a/firmware/axl-stepper/src/axl
+++ b/firmware/axl-stepper/src/axl
@@ -1 +1 @@
-Subproject commit 79ca7181653d7e8c567cf026e7cc882a5c410feb
+Subproject commit c874b7afa9102ae3e5c150e444b01703c7143303
diff --git a/firmware/axl-stepper/src/drivers/dacs.cpp b/firmware/axl-stepper/src/drivers/dacs.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b9dbf277cb341d4d1c36240456da9fd240eaa5c1
--- /dev/null
+++ b/firmware/axl-stepper/src/drivers/dacs.cpp
@@ -0,0 +1,122 @@
+/*
+osap/drivers/dacs.cpp
+
+dacs on the d51
+
+Jake Read at the Center for Bits and Atoms
+(c) Massachusetts Institute of Technology 2019
+
+This work may be reproduced, modified, distributed, performed, and
+displayed for any purpose, but must acknowledge the squidworks and ponyo
+projects. Copyright is retained and must be preserved. The work is provided as
+is; no warranty is provided, and users accept all liability.
+*/
+
+#include "dacs.h"
+//#include "ucbus_drop.h"
+
+DACs* DACs::instance = 0;
+
+DACs* DACs::getInstance(void){
+    if(instance == 0){
+        instance = new DACs();
+    }
+    return instance;
+}
+
+DACs* dacs = DACs::getInstance();
+
+DACs::DACs() {}
+
+void DACs::init(){
+    /*
+    // the below code was an attempt to scrape from 
+    // scrape https://github.com/adafruit/ArduinoCore-samd/blob/master/cores/arduino/startup.c (clock)
+    // scrape https://github.com/adafruit/ArduinoCore-samd/blob/master/cores/arduino/wiring.c (peripheral clock)
+    // scrape https://github.com/adafruit/ArduinoCore-samd/blob/master/cores/arduino/wiring_analog.c
+    // to setup the DAC 'from scratch' - of course it occurred to me later that this 
+    // setup already happens in arduino's boot. so I omitted this and just used 
+    // the messy per-analogWrite-call config below, and wrote small write-to-dac functions 
+    // to operate under the assumption that this init happens once.
+
+    // ... 
+    // put the pins on the peripheral,
+    // DAC0 is PA02, Peripheral B
+    // DAC1 is PA05, Peripheral B
+    //PORT->Group[0].DIRSET.reg = (uint32_t)(1 << 2);
+    //PORT->Group[0].DIRCLR.reg = (uint32_t)(1 << 2);
+    PORT->Group[0].PINCFG[2].bit.PMUXEN = 1;
+    PORT->Group[0].PMUX[2 >> 1].reg |= PORT_PMUX_PMUXE(1);
+    //PORT->Group[0].DIRSET.reg = (uint32_t)(1 << 5);
+    //PORT->Group[0].DIRCLR.reg = (uint32_t)(1 << 5);
+    PORT->Group[0].PINCFG[5].bit.PMUXEN = 1;
+    PORT->Group[0].PMUX[5 >> 1].reg |= PORT_PMUX_PMUXO(1);
+
+    // unmask the DAC peripheral
+    MCLK->APBDMASK.bit.DAC_ = 1;
+
+    // DAC needs a clock, 
+    GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_12M].reg = GCLK_GENCTRL_SRC_DFLL | 
+        GCLK_GENCTRL_IDC | 
+        GCLK_GENCTRL_DIV(4) |
+        GCLK_GENCTRL_GENEN;
+    while(GCLK->SYNCBUSY.reg & GENERIC_CLOCK_GENERATOR_12M_SYNC);
+    // feed that clock to the DAC,
+    GCLK->PCHCTRL[DAC_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(GENERIC_CLOCK_GENERATOR_12M_SYNC);
+    while(GCLK->PCHCTRL[DAC_GCLK_ID].bit.CHEN == 0);
+    
+    // software reset the DAC 
+    while(DAC->SYNCBUSY.bit.SWRST == 1);
+    DAC->CTRLA.bit.SWRST = 1;
+    while(DAC->SYNCBUSY.bit.SWRST == 1);
+    // and finally the DAC itself, 
+    while(DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
+    DAC->CTRLA.bit.ENABLE = 0;
+    // enable both channels 
+    while(DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
+    DAC->DACCTRL[0].reg = DAC_DACCTRL_ENABLE | DAC_DACCTRL_REFRESH(2);
+    while(DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
+    DAC->DACCTRL[1].reg = DAC_DACCTRL_ENABLE | DAC_DACCTRL_REFRESH(2);
+    // voltage out, and select vref
+    DAC->CTRLB.reg = DAC_CTRLB_REFSEL_VDDANA;
+    // re-enable dac 
+    while(DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
+    DAC->CTRLA.bit.ENABLE = 1;
+    // await up, 
+    while(!DAC->STATUS.bit.READY0);
+    while(!DAC->STATUS.bit.READY1);
+    */
+   while(DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
+   DAC->CTRLA.bit.ENABLE = 0;
+   while(DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
+   DAC->DACCTRL[0].bit.ENABLE = 1;
+   DAC->DACCTRL[1].bit.ENABLE = 1;
+   while(DAC->SYNCBUSY.bit.ENABLE || DAC->SYNCBUSY.bit.SWRST);
+   DAC->CTRLA.bit.ENABLE = 1;
+   while(!DAC->STATUS.bit.READY0);
+   while(!DAC->STATUS.bit.READY1);
+}
+
+// 0 - 4095
+void DACs::writeDac0(uint16_t val){
+    //analogWrite(A0, val);
+    while(DAC->SYNCBUSY.bit.DATA0);
+    DAC->DATA[0].reg = val;//DAC_DATA_DATA(val);
+    currentVal0 = val;
+}
+
+void DACs::writeDac1(uint16_t val){
+    //analogWrite(A1, val);
+    while(DAC->SYNCBUSY.bit.DATA1);
+    DAC->DATA[1].reg = val;//DAC_DATA_DATA(val);
+    currentVal1 = val;
+}
+
+void DACs::refresh(void){
+    writeDac0(currentVal0);
+    writeDac1(currentVal1);
+    uint32_t now = micros();
+    if(now > lastRefresh + 1000){
+        lastRefresh = now;
+    }
+}
diff --git a/firmware/axl-stepper/src/drivers/dacs.h b/firmware/axl-stepper/src/drivers/dacs.h
new file mode 100644
index 0000000000000000000000000000000000000000..9aba2d9a8a422560702ea4cc0dcecd697c0dae09
--- /dev/null
+++ b/firmware/axl-stepper/src/drivers/dacs.h
@@ -0,0 +1,54 @@
+/*
+osap/drivers/dacs.h
+
+dacs on the d51
+
+Jake Read at the Center for Bits and Atoms
+(c) Massachusetts Institute of Technology 2019
+
+This work may be reproduced, modified, distributed, performed, and
+displayed for any purpose, but must acknowledge the squidworks and ponyo
+projects. Copyright is retained and must be preserved. The work is provided as
+is; no warranty is provided, and users accept all liability.
+*/
+
+#ifndef DACS_H_
+#define DACS_H_
+
+#include <arduino.h>
+
+#include "indicators.h"
+
+// scrape https://github.com/adafruit/ArduinoCore-samd/blob/master/cores/arduino/wiring_analog.c
+// scrape https://github.com/adafruit/ArduinoCore-samd/blob/master/cores/arduino/startup.c (clock)
+// scrape https://github.com/adafruit/ArduinoCore-samd/blob/master/cores/arduino/wiring.c (peripheral clock)
+// DAC0 is on PA02
+// DAC1 is on PA05
+
+// NOTE: the DAC must be refreshed manually to maintain voltage.
+// there does appear to be a refresh register in DACCTRL band, 
+// but it does *not* seem to work... 
+
+#define GENERIC_CLOCK_GENERATOR_12M       (4u)
+#define GENERIC_CLOCK_GENERATOR_12M_SYNC   GCLK_SYNCBUSY_GENCTRL4
+
+class DACs {
+   private:
+    // is driver, is singleton, 
+    static DACs* instance;
+    volatile uint16_t currentVal0 = 0;
+    volatile uint16_t currentVal1 = 0;
+    volatile uint32_t lastRefresh = 0;
+
+   public:
+    DACs();
+    static DACs* getInstance(void);
+    void init(void);
+    void writeDac0(uint16_t val);
+    void writeDac1(uint16_t val);
+    void refresh(void);
+};
+
+extern DACs* dacs;
+
+#endif
\ No newline at end of file
diff --git a/firmware/axl-stepper/src/drivers/peripheral_nums.h b/firmware/axl-stepper/src/drivers/peripheral_nums.h
new file mode 100644
index 0000000000000000000000000000000000000000..eed9f188afacfb0da271d43603f833f61ec61191
--- /dev/null
+++ b/firmware/axl-stepper/src/drivers/peripheral_nums.h
@@ -0,0 +1,18 @@
+#ifndef PERIPHERAL_NUMS_H_
+#define PERIPHERAL_NUMS_H_
+
+#define PERIPHERAL_A 0
+#define PERIPHERAL_B 1
+#define PERIPHERAL_C 2
+#define PERIPHERAL_D 3
+#define PERIPHERAL_E 4
+#define PERIPHERAL_F 5
+#define PERIPHERAL_G 6
+#define PERIPHERAL_H 7
+#define PERIPHERAL_I 8
+#define PERIPHERAL_K 9
+#define PERIPHERAL_L 10
+#define PERIPHERAL_M 11
+#define PERIPHERAL_N 12
+
+#endif 
\ No newline at end of file
diff --git a/firmware/axl-stepper/src/drivers/step_a4950.cpp b/firmware/axl-stepper/src/drivers/step_a4950.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..440e5a8678dd941ce5280e5a8104661e94c09d7b
--- /dev/null
+++ b/firmware/axl-stepper/src/drivers/step_a4950.cpp
@@ -0,0 +1,214 @@
+/*
+osap/drivers/step_a4950.cpp
+
+stepper code for two A4950s
+
+Jake Read at the Center for Bits and Atoms
+(c) Massachusetts Institute of Technology 2019
+
+This work may be reproduced, modified, distributed, performed, and
+displayed for any purpose, but must acknowledge the squidworks and ponyo
+projects. Copyright is retained and must be preserved. The work is provided as
+is; no warranty is provided, and users accept all liability.
+*/
+
+#include "step_a4950.h"
+//#include "ucbus_drop.h"
+
+// sine, 0-8190, 4095 center / 'zero', 256 steps 
+uint16_t LUT_8190[256] = {
+    4095,4195,4296,4396,4496,4596,4696,4795,4894,4992,
+    5090,5187,5284,5380,5475,5569,5662,5754,5846,5936,
+    6025,6113,6200,6286,6370,6453,6534,6614,6693,6770,
+    6845,6919,6991,7061,7129,7196,7260,7323,7384,7443,
+    7500,7555,7607,7658,7706,7753,7797,7839,7878,7916,
+    7951,7983,8014,8042,8067,8091,8111,8130,8146,8159,
+    8170,8179,8185,8189,8190,8189,8185,8179,8170,8159,
+    8146,8130,8111,8091,8067,8042,8014,7983,7951,7916,
+    7878,7839,7797,7753,7706,7658,7607,7555,7500,7443,
+    7384,7323,7260,7196,7129,7061,6991,6919,6845,6770,
+    6693,6614,6534,6453,6370,6286,6200,6113,6025,5936,
+    5846,5754,5662,5569,5475,5380,5284,5187,5090,4992,
+    4894,4795,4696,4596,4496,4396,4296,4195,4095,3995,
+    3894,3794,3694,3594,3494,3395,3296,3198,3100,3003,
+    2906,2810,2715,2621,2528,2436,2344,2254,2165,2077,
+    1990,1904,1820,1737,1656,1576,1497,1420,1345,1271,
+    1199,1129,1061,994,930,867,806,747,690,635,
+    583,532,484,437,393,351,312,274,239,207,
+    176,148,123,99,79,60,44,31,20,11,
+    5,1,0,1,5,11,20,31,44,60,
+    79,99,123,148,176,207,239,274,312,351,
+    393,437,484,532,583,635,690,747,806,867,
+    930,994,1061,1129,1199,1271,1345,1420,1497,1576,
+    1656,1737,1820,1904,1990,2077,2165,2254,2344,2436,
+    2528,2621,2715,2810,2906,3003,3100,3198,3296,3395,
+    3494,3594,3694,3794,3894,3995
+};
+
+// sine, 0-1022 (511 center / 'zero'), 256 steps 
+uint16_t LUT_1022[256] = {
+    511,524,536,549,561,574,586,598,611,623,635,647,659,671,683,695,
+    707,718,729,741,752,763,774,784,795,805,815,825,835,845,854,863,
+    872,881,890,898,906,914,921,929,936,943,949,956,962,967,973,978,
+    983,988,992,996,1000,1003,1007,1010,1012,1014,1016,1018,1020,1021,1021,1022,
+    1022,1022,1021,1021,1020,1018,1016,1014,1012,1010,1007,1003,1000,996,992,988,
+    983,978,973,967,962,956,949,943,936,929,921,914,906,898,890,881,
+    872,863,854,845,835,825,815,805,795,784,774,763,752,741,729,718,
+    707,695,683,671,659,647,635,623,611,598,586,574,561,549,536,524,
+    511,498,486,473,461,448,436,424,411,399,387,375,363,351,339,327,
+    315,304,293,281,270,259,248,238,227,217,207,197,187,177,168,159,
+    150,141,132,124,116,108,101,93,86,79,73,66,60,55,49,44,
+    39,34,30,26,22,19,15,12,10,8,6,4,2,1,1,0,
+    0,0,1,1,2,4,6,8,10,12,15,19,22,26,30,34,
+    39,44,49,55,60,66,73,79,86,93,101,108,116,124,132,141,
+    150,159,168,177,187,197,207,217,227,238,248,259,270,281,293,304,
+    315,327,339,351,363,375,387,399,411,424,436,448,461,473,486,498,
+};
+
+uint16_t dacLUT[256];
+
+STEP_A4950* STEP_A4950::instance = 0;
+
+STEP_A4950* STEP_A4950::getInstance(void){
+    if(instance == 0){
+        instance = new STEP_A4950();
+    }
+    return instance;
+}
+
+STEP_A4950* stepper_hw = STEP_A4950::getInstance();
+
+STEP_A4950::STEP_A4950() {}
+
+void STEP_A4950::init(boolean invert, float cscale){
+    // all of 'em, outputs 
+    AIN1_PORT.DIRSET.reg = AIN1_BM;
+    AIN2_PORT.DIRSET.reg = AIN2_BM;
+    BIN1_PORT.DIRSET.reg = BIN1_BM;
+    BIN2_PORT.DIRSET.reg = BIN2_BM;
+    // floating cscale 
+    if(cscale < 0){
+        _cscale = 0;
+    } else if (cscale > 1){
+        _cscale = 1;
+    } else {
+        _cscale = cscale;
+    }
+    // write a rectified LUT for writing to DACs
+    for(uint16_t i = 0; i < 256; i ++){
+        if(LUT_8190[i] > 4095){
+            dacLUT[i] = LUT_8190[i] - 4095;
+        } else if (LUT_8190[i] < 4095){
+            dacLUT[i] = abs(4095 - LUT_8190[i]);
+        } else {
+            dacLUT[i] = 0;
+        }
+    }
+    // invert direction / not 
+    _dir_invert = invert;
+    // start the DAAAC
+    dacs->init();
+    // start condition, 
+    step();
+}
+
+// sequence like
+// S: 1 2 3 4 5 6 7 8 
+// A: ^ ^ ^ x v v v x
+// B: ^ x v v v x ^ ^
+void STEP_A4950::step(void){
+    // increment: wrapping comes for free with uint8_t, bless 
+    if(_dir){
+        if(_dir_invert){
+            _aStep -= _microstep_count;
+            _bStep -= _microstep_count;
+        } else {
+            _aStep += _microstep_count;
+            _bStep += _microstep_count;
+        }
+    } else {
+        if(_dir_invert){
+            _aStep += _microstep_count;
+            _bStep += _microstep_count;
+        } else {
+            _aStep -= _microstep_count;
+            _bStep -= _microstep_count;
+        }
+    }
+    // a phase, 
+    if(LUT_8190[_aStep] > 4095){
+        A_UP;
+    } else if (LUT_8190[_aStep] < 4095){
+        A_DOWN;
+    } else {
+        A_OFF;
+    }
+    // a DAC 
+    // so that we can easily rewrite currents on the fly. will extend to servoing, yeah 
+    dacs->writeDac0(dacLUT[_aStep] * _cscale);
+    // b phase, 
+    if(LUT_8190[_bStep] > 4095){
+        B_UP;
+    } else if (LUT_8190[_bStep] < 4095){
+        B_DOWN;
+    } else {
+        B_OFF;
+    }
+    // b DAC
+    dacs->writeDac1(dacLUT[_bStep] * _cscale);
+}
+
+void STEP_A4950::dir(boolean val){
+    _dir = val;
+}
+
+boolean STEP_A4950::getDir(void){
+    return _dir;
+}
+
+void STEP_A4950::setMicrostep(uint8_t microstep){
+    switch(microstep){
+        case 64:
+            _microstep_count = MICROSTEP_64_COUNT;
+            break;
+        case 32:
+            _microstep_count = MICROSTEP_32_COUNT;
+            break;
+        case 16:
+            _microstep_count = MICROSTEP_16_COUNT;
+            break;
+        case 8:
+            _microstep_count = MICROSTEP_8_COUNT;
+            break;
+        case 4: 
+            _microstep_count = MICROSTEP_4_COUNT;
+            break;
+        case 1:
+            _microstep_count = MICROSTEP_1_COUNT;
+            break;
+        default:
+            _microstep_count = MICROSTEP_1_COUNT;
+            break;
+    }
+}
+
+void STEP_A4950::setCurrent(float cscale){
+    if(cscale > 1){
+        _cscale = 1;
+    } else if(cscale < 0){
+        _cscale = 0;
+    } else {
+        _cscale = cscale;
+    }
+    // do DAC re-writes 
+    dacs->writeDac0(dacLUT[_aStep] * _cscale);
+    dacs->writeDac1(dacLUT[_bStep] * _cscale);
+}
+
+void STEP_A4950::setInversion(boolean inv){
+    _dir_invert = inv;
+}
+
+void STEP_A4950::dacRefresh(void){
+    dacs->refresh();
+}
diff --git a/firmware/axl-stepper/src/drivers/step_a4950.h b/firmware/axl-stepper/src/drivers/step_a4950.h
new file mode 100644
index 0000000000000000000000000000000000000000..fb19f2f12c2d651dbf52826d16f6f3fb311b4b9c
--- /dev/null
+++ b/firmware/axl-stepper/src/drivers/step_a4950.h
@@ -0,0 +1,114 @@
+/*
+osap/drivers/step_a4950.h
+
+stepper code for two A4950s
+
+Jake Read at the Center for Bits and Atoms
+(c) Massachusetts Institute of Technology 2019
+
+This work may be reproduced, modified, distributed, performed, and
+displayed for any purpose, but must acknowledge the squidworks and ponyo
+projects. Copyright is retained and must be preserved. The work is provided as
+is; no warranty is provided, and users accept all liability.
+*/
+
+#ifndef STEP_A4950_H_
+#define STEP_A4950_H_
+
+#include <Arduino.h>
+
+#include "dacs.h"
+#include "indicators.h"
+
+// C_SCALE 
+// 1: DACs go 0->512 (of 4096, peak current is 1.6A at 4096): 0.2A
+// 2: DACs go 0->1024,
+// ...
+// 8: DACs go full width 
+//#define C_SCALE 8 // on init 
+// MICROSTEP_COUNT 
+// 1:   do 1 tick of 256 table, for full resolution, this is 64 'microsteps'
+// 2:   32 microsteps
+// 4:   16 microsteps
+// 8:   8 microsteps
+// 16:  4 microsteps
+// 32:  2 microsteps (half steps)
+// 64:  full steps 
+#define MICROSTEP_COUNT 1
+
+#define MICROSTEP_64_COUNT 1
+#define MICROSTEP_32_COUNT 2
+#define MICROSTEP_16_COUNT 4
+#define MICROSTEP_8_COUNT 8 
+#define MICROSTEP_4_COUNT 16
+#define MICROSTEP_2_COUNT 32
+#define MICROSTEP_1_COUNT 64 
+
+// AIN1 PB06
+// AIN2 PA04 
+// BIN1 PA07 
+// BIN2 PA06 
+#define AIN1_PIN 6
+#define AIN1_PORT PORT->Group[1]
+#define AIN1_BM (uint32_t)(1 << AIN1_PIN)
+#define AIN2_PIN 4 
+#define AIN2_PORT PORT->Group[0]
+#define AIN2_BM (uint32_t)(1 << AIN2_PIN)
+#define BIN1_PIN 7 
+#define BIN1_PORT PORT->Group[0]
+#define BIN1_BM (uint32_t)(1 << BIN1_PIN)
+#define BIN2_PIN 6 
+#define BIN2_PORT PORT->Group[0] 
+#define BIN2_BM (uint32_t)(1 << BIN2_PIN)
+
+// handles
+#define AIN1_HI AIN1_PORT.OUTSET.reg = AIN1_BM
+#define AIN1_LO AIN1_PORT.OUTCLR.reg = AIN1_BM
+#define AIN2_HI AIN2_PORT.OUTSET.reg = AIN2_BM
+#define AIN2_LO AIN2_PORT.OUTCLR.reg = AIN2_BM 
+#define BIN1_HI BIN1_PORT.OUTSET.reg = BIN1_BM
+#define BIN1_LO BIN1_PORT.OUTCLR.reg = BIN1_BM
+#define BIN2_HI BIN2_PORT.OUTSET.reg = BIN2_BM
+#define BIN2_LO BIN2_PORT.OUTCLR.reg = BIN2_BM
+
+// set a phase up or down direction
+// transition low first, avoid brake condition for however many ns 
+#define A_UP AIN2_LO; AIN1_HI
+#define A_OFF AIN2_LO; AIN1_LO
+#define A_DOWN AIN1_LO; AIN2_HI
+#define B_UP BIN2_LO; BIN1_HI 
+#define B_OFF BIN2_LO; BIN1_LO
+#define B_DOWN BIN1_LO; BIN2_HI
+
+class STEP_A4950 {
+   private:
+    // is driver, is singleton, 
+    static STEP_A4950* instance;
+    volatile uint8_t _aStep = 0;    // 0 of 256 micros, 
+    volatile uint8_t _bStep = 63;   // of the same table, startup 90' out of phase 
+    volatile boolean _dir = false;
+    boolean _dir_invert = false;
+    uint8_t _microstep_count = 1;
+    // try single scalar
+    float _cscale = 0.1;
+
+   public:
+    STEP_A4950();
+    static STEP_A4950* getInstance(void);
+    // do like 
+    void init(boolean invert, float cscale);
+    void step(void);
+    void dir(boolean val);
+    boolean getDir(void);
+    // microstep setting 
+    void setMicrostep(uint8_t microstep);
+    // current settings 
+    void setCurrent(float cscale);
+    void setInversion(boolean inv);
+    // for the dacs 
+    void dacRefresh(void);
+};
+
+extern STEP_A4950* stepper_hw;
+
+#endif
\ No newline at end of file
diff --git a/firmware/axl-stepper/src/indicators.h b/firmware/axl-stepper/src/indicators.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d7452112ea3debaa5eb0b8128a73a66e150f953
--- /dev/null
+++ b/firmware/axl-stepper/src/indicators.h
@@ -0,0 +1,59 @@
+// indicators for the macrofab-d 
+#define CLKLIGHT_PIN 27
+#define CLKLIGHT_PORT PORT->Group[0]
+#define ERRLIGHT_PIN 8
+#define ERRLIGHT_PORT PORT->Group[1]
+
+// PB05, is DIP1 
+#define DEBUG1PIN_PIN 5
+#define DEBUG1PIN_PORT PORT->Group[1]
+// PA23, is limit 
+//#define DEBUG1PIN_PIN 23 
+//#define DEBUG1PIN_PORT PORT->Group[0]
+// PB04, is DIP2 
+#define DEBUG2PIN_PIN 4
+#define DEBUG2PIN_PORT PORT->Group[1]
+// NOT setup 
+#define DEBUG3PIN_PIN 13 
+#define DEBUG3PIN_PORT PORT->Group[1]
+#define DEBUG4PIN_PIN 14
+#define DEBUG4PIN_PORT PORT->Group[1]
+
+// PA27
+#define CLKLIGHT_BM (uint32_t)(1 << CLKLIGHT_PIN)
+#define CLKLIGHT_ON CLKLIGHT_PORT.OUTCLR.reg = CLKLIGHT_BM
+#define CLKLIGHT_OFF CLKLIGHT_PORT.OUTSET.reg = CLKLIGHT_BM
+#define CLKLIGHT_TOGGLE CLKLIGHT_PORT.OUTTGL.reg = CLKLIGHT_BM
+#define CLKLIGHT_SETUP CLKLIGHT_PORT.DIRSET.reg = CLKLIGHT_BM; CLKLIGHT_OFF
+
+// PB08 
+#define ERRLIGHT_BM (uint32_t)(1 << ERRLIGHT_PIN)
+#define ERRLIGHT_ON ERRLIGHT_PORT.OUTCLR.reg = ERRLIGHT_BM
+#define ERRLIGHT_OFF ERRLIGHT_PORT.OUTSET.reg = ERRLIGHT_BM
+#define ERRLIGHT_TOGGLE ERRLIGHT_PORT.OUTTGL.reg = ERRLIGHT_BM
+#define ERRLIGHT_SETUP ERRLIGHT_PORT.DIRSET.reg = ERRLIGHT_BM; ERRLIGHT_OFF
+
+// the limit: turn off as input if using as output 
+#define DEBUG1PIN_BM (uint32_t)(1 << DEBUG1PIN_PIN)
+#define DEBUG1PIN_ON DEBUG1PIN_PORT.OUTSET.reg = DEBUG1PIN_BM
+#define DEBUG1PIN_OFF DEBUG1PIN_PORT.OUTCLR.reg = DEBUG1PIN_BM
+#define DEBUG1PIN_TOGGLE DEBUG1PIN_PORT.OUTTGL.reg = DEBUG1PIN_BM
+#define DEBUG1PIN_SETUP DEBUG1PIN_PORT.DIRSET.reg = DEBUG1PIN_BM; DEBUG1PIN_OFF
+
+#define DEBUG2PIN_BM (uint32_t)(1 << DEBUG2PIN_PIN)
+#define DEBUG2PIN_ON DEBUG2PIN_PORT.OUTSET.reg = DEBUG2PIN_BM
+#define DEBUG2PIN_OFF DEBUG2PIN_PORT.OUTCLR.reg = DEBUG2PIN_BM
+#define DEBUG2PIN_TOGGLE DEBUG2PIN_PORT.OUTTGL.reg = DEBUG2PIN_BM
+#define DEBUG2PIN_SETUP DEBUG2PIN_PORT.DIRSET.reg = DEBUG2PIN_BM; DEBUG2PIN_OFF
+
+#define DEBUG3PIN_BM (uint32_t)(1 << DEBUG3PIN_PIN)
+#define DEBUG3PIN_ON DEBUG3PIN_PORT.OUTSET.reg = DEBUG3PIN_BM
+#define DEBUG3PIN_OFF DEBUG3PIN_PORT.OUTCLR.reg = DEBUG3PIN_BM
+#define DEBUG3PIN_TOGGLE DEBUG3PIN_PORT.OUTTGL.reg = DEBUG3PIN_BM
+#define DEBUG3PIN_SETUP DEBUG3PIN_PORT.DIRSET.reg = DEBUG3PIN_BM; DEBUG3PIN_OFF
+
+#define DEBUG4PIN_BM (uint32_t)(1 << DEBUG4PIN_PIN)
+#define DEBUG4PIN_ON DEBUG4PIN_PORT.OUTSET.reg = DEBUG4PIN_BM
+#define DEBUG4PIN_OFF DEBUG4PIN_PORT.OUTCLR.reg = DEBUG4PIN_BM
+#define DEBUG4PIN_TOGGLE DEBUG4PIN_PORT.OUTTGL.reg = DEBUG4PIN_BM
+#define DEBUG4PIN_SETUP DEBUG4PIN_PORT.DIRSET.reg = DEBUG4PIN_BM; DEBUG4PIN_OFF
\ No newline at end of file
diff --git a/firmware/axl-stepper/src/main.cpp b/firmware/axl-stepper/src/main.cpp
index 58b344c5757478d990bb23dd41243135880fb2f5..460f8bac738574457eb4ba0a7b4fb85dfb61d80f 100644
--- a/firmware/axl-stepper/src/main.cpp
+++ b/firmware/axl-stepper/src/main.cpp
@@ -1,9 +1,135 @@
 #include <Arduino.h>
+#include "indicators.h"
+
+#include "drivers/step_a4950.h"
+#include "axl/axl.h"
+#include "axl/axl_config.h"
+#include "utils_samd51/clock_utils.h"
+
+#include "osape/core/osap.h"
+#include "osape/core/ts.h"
+#include "osape/vertices/endpoint.h"
+#include "osape_arduino/vp_arduinoSerial.h"
+
+OSAP osap("hmc-motor");
+
+VPort_ArduinoSerial vpUSBSerial(&osap, "arduinoUSBSerial", &Serial);
+
+// -------------------------------------------------------- 2: States
+
+EP_ONDATA_RESPONSES onStateData(uint8_t* data, uint16_t len){
+  // we have accel, rate, posn data, 
+  dofs targ;
+  uint16_t rptr = 0;
+  uint8_t mode = data[rptr];
+  if(mode == AXL_MODE_ACCEL){
+    // read from 1st block of ndof 
+    /*
+    rptr = 1;
+    for(uint8_t a = 0; a < AXL_NUM_DOF; a ++){
+      targ.axis[a] = ts_readFloat32(data, &rptr);
+    }
+    axl_setAccelTarget(targ);
+    */
+  } else if (mode == AXL_MODE_VELOCITY){
+    //axl_setVelocityTarget(rate.f);
+    rptr = 1 + AXL_NUM_DOF * 4 * 1;
+    for(uint8_t a = 0; a < AXL_NUM_DOF; a ++){
+      targ.axis[a] = ts_readFloat32(data, &rptr);
+    }
+    axl_setVelocityTarget(targ);
+  } else if (mode == AXL_MODE_POSITION){
+    rptr = 1 + AXL_NUM_DOF * 4 * 2;
+    for(uint8_t a = 0; a < AXL_NUM_DOF; a ++){
+      targ.axis[a] = ts_readFloat32(data, &rptr);
+    }
+    axl_setPositionTarget(targ);  
+  } else {
+    // no / bad mode set, noop 
+    OSAP::error("bad set-states request to axl, no / bad mode info", MEDIUM);
+  }
+  // chunk_float32 acc = { .bytes = { data[0], data[1], data[2], data[3] } };
+  // chunk_float32 rate = { .bytes = { data[4], data[5], data[6], data[7] } };
+  // chunk_float32 posn = { .bytes = { data[8], data[9], data[10], data[11] } };
+  // we 'reject' this i.e. we don't write these data into the endpoint,
+  // since we routinely update it w/ actual states (not requests) 
+  return EP_ONDATA_REJECT;
+}
+
+Endpoint statesEP(&osap, "states", onStateData);
+
+void updateStatesEP(void){
+  uint8_t numBytes = AXL_NUM_DOF * 4 * 3 + 1;
+  uint8_t stash[numBytes]; uint16_t wptr = 0;
+  stash[wptr ++] = axl_getMode();
+  dofs temp = axl_getPositions();
+  for(uint8_t a = 0; a < AXL_NUM_DOF; a ++){
+    ts_writeFloat32(temp.axis[a], stash, &wptr);
+  }
+  temp = axl_getVelocities();
+  for(uint8_t a = 0; a < AXL_NUM_DOF; a ++){
+    ts_writeFloat32(temp.axis[a], stash, &wptr);
+  }
+  temp = axl_getAccelerations();
+  for(uint8_t a = 0; a < AXL_NUM_DOF; a ++){
+    ts_writeFloat32(temp.axis[a], stash, &wptr);
+  }
+  statesEP.write(stash, numBytes);
+}
+
 
 void setup() {
-  // put your setup code here, to run once:
+  CLKLIGHT_SETUP;
+  ERRLIGHT_SETUP;
+  DEBUG1PIN_SETUP;
+  DEBUG2PIN_SETUP;
+  // port begin 
+  vpUSBSerial.begin();
+  // setup stepper machine 
+  stepper_hw->init(false, 0.35F);
+  stepper_hw->setMicrostep(4);
+  // setup controller
+  axl_setup();
+  // ticker begin:
+  d51ClockUtils->start_ticker_a(AXL_TICKER_INTERVAL_US);
 }
 
+uint32_t lastBlink = 0;
+uint32_t blinkInterval = 50; // ms 
+
 void loop() {
-  // put your main code here, to run repeatedly:
+  osap.loop();
+  stepper_hw->dacRefresh();
+  if(lastBlink + blinkInterval < millis()){
+    lastBlink = millis();
+    CLKLIGHT_TOGGLE;
+    updateStatesEP();
+  }
+}
+
+uint8_t axisPick = 0;
+float spu = 100.0F;
+
+volatile float stepRatchet = 0.0F;
+void axl_onPositionDelta(uint8_t axis, float delta){
+  if(axis != axisPick) return;
+  stepRatchet += delta * spu;
+  if(stepRatchet >= 1.0F){
+    stepper_hw->dir(true);
+    stepper_hw->step();
+    stepRatchet -= 1.0F;
+  } else if (stepRatchet <= -1.0F){
+    stepper_hw->dir(false);
+    stepper_hw->step();
+    stepRatchet += 1.0F;
+  }
+}
+
+void TC0_Handler(void){
+  DEBUG1PIN_ON;
+  TC0->COUNT32.INTFLAG.bit.MC0 = 1;
+  TC0->COUNT32.INTFLAG.bit.MC1 = 1;
+  // run the loop, 
+  axl_integrator();
+  DEBUG1PIN_OFF;
 }
\ No newline at end of file
diff --git a/firmware/axl-stepper/src/osap_config.h b/firmware/axl-stepper/src/osap_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..a0efe77035e1e3e5e37a72cd5e7d9bdc6d129dc8
--- /dev/null
+++ b/firmware/axl-stepper/src/osap_config.h
@@ -0,0 +1,31 @@
+/*
+osap_config.h
+
+config options for an osap-embedded build 
+
+Jake Read at the Center for Bits and Atoms
+(c) Massachusetts Institute of Technology 2022
+
+This work may be reproduced, modified, distributed, performed, and
+displayed for any purpose, but must acknowledge the osap project.
+Copyright is retained and must be preserved. The work is provided as is;
+no warranty is provided, and users accept all liability.
+*/
+
+#ifndef OSAP_CONFIG_H_
+#define OSAP_CONFIG_H_
+
+// size of vertex stacks, lenght, then count,
+#define VT_SLOTSIZE 256
+#define VT_STACKSIZE 3  // must be >= 2 for ringbuffer operation 
+#define VT_MAXCHILDREN 16
+#define VT_MAXITEMSPERTURN 8
+
+// max # of endpoints that could be spawned here,
+#define MAX_CONTEXT_ENDPOINTS 64
+
+// count of routes each endpoint can have, 
+#define ENDPOINT_MAX_ROUTES 4
+#define ENDPOINT_ROUTE_MAX_LEN 64 
+
+#endif 
\ No newline at end of file
diff --git a/firmware/axl-stepper/src/osape b/firmware/axl-stepper/src/osape
index d413d255cdccd7b4ae9f3467ab2c2a9a84b9abb8..4f5c37e60669b7357b29cba0b842014cdda23161 160000
--- a/firmware/axl-stepper/src/osape
+++ b/firmware/axl-stepper/src/osape
@@ -1 +1 @@
-Subproject commit d413d255cdccd7b4ae9f3467ab2c2a9a84b9abb8
+Subproject commit 4f5c37e60669b7357b29cba0b842014cdda23161
diff --git a/firmware/axl-stepper/src/ucbus_config.h b/firmware/axl-stepper/src/ucbus_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b84fba6edf04a4d5ad1fc9fd5a11bfee67d08f6
--- /dev/null
+++ b/firmware/axl-stepper/src/ucbus_config.h
@@ -0,0 +1,29 @@
+/*
+ucbus_confi.h
+
+config options for an ucbus instance 
+
+Jake Read at the Center for Bits and Atoms
+(c) Massachusetts Institute of Technology 2022
+
+This work may be reproduced, modified, distributed, performed, and
+displayed for any purpose, but must acknowledge the osap project.
+Copyright is retained and must be preserved. The work is provided as is;
+no warranty is provided, and users accept all liability.
+*/
+
+#ifndef UCBUS_CONFIG_H_
+#define UCBUS_CONFIG_H_
+
+#define UCBUS_MAX_DROPS 32 
+//#define UCBUS_IS_DROP 
+#define UCBUS_IS_HEAD 
+
+#define UCBUS_BAUD 2 
+
+#define UCBUS_IS_D51
+// #define UCBUS_IS_D21
+
+#define UCBUS_ON_OSAP 
+
+#endif 
\ No newline at end of file
diff --git a/firmware/axl-stepper/src/utils_samd51 b/firmware/axl-stepper/src/utils_samd51
new file mode 160000
index 0000000000000000000000000000000000000000..d77c3a9993a908c52ef53efd69d407be3c288e7e
--- /dev/null
+++ b/firmware/axl-stepper/src/utils_samd51
@@ -0,0 +1 @@
+Subproject commit d77c3a9993a908c52ef53efd69d407be3c288e7e