From 314736dd701cffc81677afd28a41a3e59b7df7f7 Mon Sep 17 00:00:00 2001
From: Jake Read <jake.read@cba.mit.edu>
Date: Wed, 14 Oct 2020 18:26:59 -0400
Subject: [PATCH] 50khz up

---
 .../src/drivers/enc_as5047.cpp                |  1 -
 .../src/drivers/step_a4950.cpp                | 11 +---
 .../src/drivers/step_cl.cpp                   | 64 +++++++++++--------
 .../cl-step-controller/src/drivers/step_cl.h  |  5 +-
 firmware/cl-step-controller/src/main.cpp      | 18 ++++--
 .../cl-step-controller/src/utils/clamp.cpp    |  9 +++
 firmware/cl-step-controller/src/utils/clamp.h |  6 ++
 .../src/utils/clocks_d51_module.cpp           | 34 ++++++++++
 .../src/utils/clocks_d51_module.h             |  1 +
 log/cl-step-control-log.md                    | 10 ++-
 10 files changed, 115 insertions(+), 44 deletions(-)
 create mode 100644 firmware/cl-step-controller/src/utils/clamp.cpp
 create mode 100644 firmware/cl-step-controller/src/utils/clamp.h

diff --git a/firmware/cl-step-controller/src/drivers/enc_as5047.cpp b/firmware/cl-step-controller/src/drivers/enc_as5047.cpp
index ad377c8..2d1adf0 100644
--- a/firmware/cl-step-controller/src/drivers/enc_as5047.cpp
+++ b/firmware/cl-step-controller/src/drivers/enc_as5047.cpp
@@ -146,7 +146,6 @@ void ENC_AS5047::rxcISR(void){
 }
 
 void SERCOM4_2_Handler(void){
-    DEBUG1PIN_TOGGLE;
     enc_as5047->rxcISR();
 }
 
diff --git a/firmware/cl-step-controller/src/drivers/step_a4950.cpp b/firmware/cl-step-controller/src/drivers/step_a4950.cpp
index 421601f..9f2cee4 100644
--- a/firmware/cl-step-controller/src/drivers/step_a4950.cpp
+++ b/firmware/cl-step-controller/src/drivers/step_a4950.cpp
@@ -13,8 +13,7 @@ is; no warranty is provided, and users accept all liability.
 */
 
 #include "step_a4950.h"
-//#include "ucbus_drop.h"
-
+#include "../utils/clamp.h"
 
 // sine, 0-8190, 4095 center / 'zero', 256 steps 
 #define LUT_LENGTH 1024 
@@ -99,14 +98,6 @@ STEP_A4950* stepper_hw = STEP_A4950::getInstance();
 
 STEP_A4950::STEP_A4950() {}
 
-void clamp(float *val, float min, float max){
-    if(*val < min){
-        *val = min;
-    } else if (*val > max){
-        *val = max;
-    }
-}
-
 void STEP_A4950::init(boolean invert, float cscale){
     // all of 'em, outputs 
     AIN1_PORT.DIRSET.reg = AIN1_BM;
diff --git a/firmware/cl-step-controller/src/drivers/step_cl.cpp b/firmware/cl-step-controller/src/drivers/step_cl.cpp
index 4ec2736..a3e65e4 100644
--- a/firmware/cl-step-controller/src/drivers/step_cl.cpp
+++ b/firmware/cl-step-controller/src/drivers/step_cl.cpp
@@ -14,6 +14,7 @@ is; no warranty is provided, and users accept all liability.
 
 #include "step_cl.h"
 #include "../utils/FlashStorage.h"
+#include "../utils/clamp.h"
 
 Step_CL* Step_CL::instance = 0;
 
@@ -26,11 +27,6 @@ Step_CL* Step_CL::getInstance(void){
 
 Step_CL* step_cl = Step_CL::getInstance();
 
-// https://github.com/cmaglie/FlashStorage
-// flash LUT
-// FlashStorage(flash_lut, step_cl_calib_table_t);
-// float __attribute__((__aligned__(256))) lut[16384];
-
 Step_CL::Step_CL(void){}
 
 #define CALIB_CSCALE 0.4F
@@ -43,34 +39,32 @@ Step_CL::Step_CL(void){}
 void Step_CL::init(void){
     stepper_hw->init(false, 0.4);
     enc_as5047->init();
-    // this lut == stored lut 
-    //lut = flash_lut.read();
+    _tc = 0; // torque command -> 0; 
 }
 
-// #define BYTES_PER_PAGE 512 
-// #define FLOATS_PER_PAGE 128
-// #define PAGES_PER_BLOCK 16 // for 8192 bytes / block 
-
-//const float __attribute__((__aligned__(BYTES_PER_PAGE))) lut[LUT_SIZE] = {}; 
-//const void* page_ptr; 
+// LUT / flash work 
+/*
+the D51J19 flash is organized into *pages* of 512bytes, 
+and *blocks* of 16 pages (8192 bytes)
+write granularity is to the page, erase granularity is per block 
+we must erase flash before writing to it: this is how flash hardware works 
+to do flash storage of this monster table, we declare a const LUT array
+const keyword will cause the compiler to put it in flash mem, 
+and so we point the helper class at that void* (the head of the array) to start, 
+and increment that void* thru the array in blocks, when our buffer is full
+*/
 
 #define BYTES_PER_BLOCK 8192
 #define FLOATS_PER_BLOCK 2048
 
-const float __attribute__((__aligned__(8192))) lut[16834] = {};
-FlashClass flashClass((const uint8_t*)lut);
-
-// write mechanics
-const void* block_ptr;
-
-// write buffer 
-static float buffer[FLOATS_PER_BLOCK];
+const float __attribute__((__aligned__(8192))) lut[16834] = {}; // the actual LUT: const means it gets allocated to flash 
+FlashClass flashClass((const uint8_t*)lut); // helper class (lib) // https://github.com/cmaglie/FlashStorage
+const void* block_ptr; // void* to section-of-lut for write 
+static float buffer[FLOATS_PER_BLOCK]; // one full block (16 pages) of flash mem, buffered 
 
 uint32_t bfi = 0; // buffer indice 
 uint32_t bli = 0; // block indice 
 
-//FlashStorage(flash_storage, flts);
-
 void flash_write_init(void){
     block_ptr = (const uint8_t*) lut;
     bfi = 0;
@@ -91,7 +85,7 @@ void flash_write_value(float val){
         flash_write_page();
         bfi = 0;
         bli ++;
-        block_ptr = ((const uint8_t *)(&(lut[bli * FLOATS_PER_BLOCK])));
+        block_ptr = ((const uint8_t *)(&(lut[bli * FLOATS_PER_BLOCK]))); 
     }
 }
 
@@ -99,11 +93,31 @@ void Step_CL::print_table(void){
     sysError("reading from lut");
     for(uint32_t i = 0; i < ENCODER_COUNTS; i ++){
         float ra = lut[i];
-        sysError(String(ra));
+        sysError("real angle at enc " + String(i) + ": " + String(ra));
         delay(5);
     }
 }
 
+// set twerks 
+// tc: -1 : 1
+void Step_CL::set_torque(float tc){
+    clamp(&tc, -1.0F, 1.0F);
+    _tc = tc;
+}
+
+// the control loop 
+void Step_CL::run_torque_loop(void){
+    // ok, first we read the encoder 
+    enc_as5047->trigger_read();
+    // this kicks off the party, proceeds below
+}
+
+void ENC_AS5047::on_read_complete(uint16_t result){
+    float ra = lut[result];
+    // debug loop completion 
+    DEBUG1PIN_OFF;
+}
+
 // the calib routine 
 boolean Step_CL::calibrate(void){
     // (1) first, build a table for 200 full steps w/ encoder averaged values at each step 
diff --git a/firmware/cl-step-controller/src/drivers/step_cl.h b/firmware/cl-step-controller/src/drivers/step_cl.h
index b419de1..2b0b083 100644
--- a/firmware/cl-step-controller/src/drivers/step_cl.h
+++ b/firmware/cl-step-controller/src/drivers/step_cl.h
@@ -24,13 +24,16 @@ class Step_CL {
     private:
         static Step_CL* instance;
         float calib_readings[201];
+        float _tc;
 
     public:
         Step_CL();
         static Step_CL* getInstance(void);
         void init(void);
-        boolean calibrate(void);
         void print_table(void);
+        void set_torque(float tc);
+        void run_torque_loop(void);
+        boolean calibrate(void);
         //float __attribute__((__aligned__(256))) lut[16384]; // nor does this ! 
         //float lut[16384]; // nor does this work 
         //step_cl_calib_table_t lut; // not even this works ?? too big ?? 
diff --git a/firmware/cl-step-controller/src/main.cpp b/firmware/cl-step-controller/src/main.cpp
index 272f937..e9bcfae 100644
--- a/firmware/cl-step-controller/src/main.cpp
+++ b/firmware/cl-step-controller/src/main.cpp
@@ -54,6 +54,8 @@ void setup() {
   ucBusDrop->init(false, BUS_DROP);
   // cl controller 
   step_cl->init();
+  // start ctrl timer for 100khz loop, 
+  d51_clock_boss->start_50kHz_ticker_tc0();
 }
 
 uint8_t bChPck[64];
@@ -69,11 +71,18 @@ volatile boolean setBlock = false;
 
 uint16_t tick = 0;
 
+void TC0_Handler(void){
+  TC0->COUNT32.INTFLAG.bit.MC0 = 1;
+  TC0->COUNT32.INTFLAG.bit.MC1 = 1;
+  DEBUG1PIN_ON;
+  step_cl->run_torque_loop();
+}
+
+// async loop 
 void loop() {
-  DEBUG1PIN_TOGGLE;
   osap->loop();
   stepper_hw->dacRefresh();
-
+  /*
   tick++;
   if(tick > 500){
     tick = 0;
@@ -82,6 +91,7 @@ void loop() {
     uint16_t reading = 0b0011111111111111 & enc_as5047->get_reading();
     //sysError(String(reading));
   }
+  */
   // do packet B grab / handle 
   /*
   if(ucBusDrop->ctr_b()){
@@ -125,10 +135,6 @@ void loop() {
   */
 } // end loop 
 
-void ENC_AS5047::on_read_complete(uint16_t pos){
-  // do work 
-}
-
 void OSAP::handleAppPacket(uint8_t *pck, uint16_t pl, uint16_t ptr, uint16_t segsize, VPort* vp, uint16_t vpi, uint8_t pwp){
   // track end of header, to reply with 
   uint16_t replyPtr = ptr;
diff --git a/firmware/cl-step-controller/src/utils/clamp.cpp b/firmware/cl-step-controller/src/utils/clamp.cpp
new file mode 100644
index 0000000..3238c8b
--- /dev/null
+++ b/firmware/cl-step-controller/src/utils/clamp.cpp
@@ -0,0 +1,9 @@
+#include "clamp.h"
+
+void clamp(float *val, float min, float max){
+    if(*val < min){
+        *val = min;
+    } else if (*val > max){
+        *val = max;
+    }
+}
\ No newline at end of file
diff --git a/firmware/cl-step-controller/src/utils/clamp.h b/firmware/cl-step-controller/src/utils/clamp.h
new file mode 100644
index 0000000..0e18f65
--- /dev/null
+++ b/firmware/cl-step-controller/src/utils/clamp.h
@@ -0,0 +1,6 @@
+#ifndef CLAMP_H_
+#define CLAMP_H_ 
+
+void clamp(float *val, float min, float max);
+
+#endif 
\ No newline at end of file
diff --git a/firmware/cl-step-controller/src/utils/clocks_d51_module.cpp b/firmware/cl-step-controller/src/utils/clocks_d51_module.cpp
index 317c403..de2bbe8 100644
--- a/firmware/cl-step-controller/src/utils/clocks_d51_module.cpp
+++ b/firmware/cl-step-controller/src/utils/clocks_d51_module.cpp
@@ -80,6 +80,40 @@ void D51_Clock_Boss::start_100kHz_ticker_tc0(void){
     NVIC_EnableIRQ(TC0_IRQn);
 }
 
+void D51_Clock_Boss::start_50kHz_ticker_tc0(void){
+    setup_16mhz_xtal();
+    // ok
+    TC0->COUNT32.CTRLA.bit.ENABLE = 0;
+    TC1->COUNT32.CTRLA.bit.ENABLE = 0;
+    // unmask clocks
+    MCLK->APBAMASK.reg |= MCLK_APBAMASK_TC0 | MCLK_APBAMASK_TC1;
+    // ok, clock to these channels...
+    GCLK->PCHCTRL[TC0_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(d51_clock_boss->mhz_xtal_gclk_num);
+    GCLK->PCHCTRL[TC1_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(d51_clock_boss->mhz_xtal_gclk_num);
+    // turn them ooon...
+    TC0->COUNT32.CTRLA.reg = TC_CTRLA_MODE_COUNT32 | TC_CTRLA_PRESCSYNC_PRESC | TC_CTRLA_PRESCALER_DIV2 | TC_CTRLA_CAPTEN0;
+    TC1->COUNT32.CTRLA.reg = TC_CTRLA_MODE_COUNT32 | TC_CTRLA_PRESCSYNC_PRESC | TC_CTRLA_PRESCALER_DIV2 | TC_CTRLA_CAPTEN0;
+    // going to set this up to count at some time, we will tune
+    // that freq. with
+    TC0->COUNT32.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ;
+    TC1->COUNT32.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ;
+    // allow interrupt to trigger on this event (overflow)
+    TC0->COUNT32.INTENSET.bit.MC0 = 1;
+    TC0->COUNT32.INTENSET.bit.MC1 = 1;
+    // set the period,
+    while (TC0->COUNT32.SYNCBUSY.bit.CC0);
+    TC0->COUNT32.CC[0].reg = 160;  // at DIV2, 240 for 10us ('realtime') (with
+                                    // DFLL), 80 for 10us (with XTAL 16MHZ)
+                                    // 400 for 50us, 
+    // enable, sync for enable write
+    while (TC0->COUNT32.SYNCBUSY.bit.ENABLE);
+    TC0->COUNT32.CTRLA.bit.ENABLE = 1;
+    while (TC0->COUNT32.SYNCBUSY.bit.ENABLE);
+    TC1->COUNT32.CTRLA.bit.ENABLE = 1;
+    // enable the IRQ
+    NVIC_EnableIRQ(TC0_IRQn);
+}
+
 void D51_Clock_Boss::start_100kHz_ticker_tc2(void){
     setup_16mhz_xtal();
     // ok
diff --git a/firmware/cl-step-controller/src/utils/clocks_d51_module.h b/firmware/cl-step-controller/src/utils/clocks_d51_module.h
index 084141e..2e0fcd8 100644
--- a/firmware/cl-step-controller/src/utils/clocks_d51_module.h
+++ b/firmware/cl-step-controller/src/utils/clocks_d51_module.h
@@ -35,6 +35,7 @@ class D51_Clock_Boss {
         // builds 100kHz clock on TC0 or TC2
         // todo: tell these fns a frequency, 
         void start_100kHz_ticker_tc0(void); 
+        void start_50kHz_ticker_tc0(void);
         void start_100kHz_ticker_tc2(void);
 };
 
diff --git a/log/cl-step-control-log.md b/log/cl-step-control-log.md
index 168c8c2..3cc14d8 100644
--- a/log/cl-step-control-log.md
+++ b/log/cl-step-control-log.md
@@ -964,4 +964,12 @@ boolean Step_CL::calibrate(void){
 
 So I think now I'll carry on actually running the calibration, then see if I can send a 'torque' command down / operate a control loop. 
 
-Great, this calibrates, so now I can roll a tiny control loop, yeah? 
\ No newline at end of file
+Great, this calibrates, so now I can roll a tiny control loop, yeah? 
+
+### Rolling a Loop
+
+First up, I'm hanging this thing up when I try to run it in an interrupt: might need to make some volatile vars. 
+
+Ah - no, this is probably because I am running the control loop in an interrupt, but the var is never returning because that happens in *another* interrupt. 
+
+OK, have 50khz of this going on, now I need to apply some twerk vector and see if I can poke it around. 
\ No newline at end of file
-- 
GitLab