Modified Motor Driver Firmware to include Flash + Thermal

Dependencies:   FastPWM3 mbed-dev-STM-lean

Files at this revision

API Documentation at this revision

Comitter:
benkatz
Date:
Fri Apr 13 13:50:54 2018 +0000
Parent:
36:d88fd41f60a6
Child:
38:67e4e1453a4b
Commit message:
always samples position sensor

Changed in this revision

Config/current_controller_config.h Show annotated file Show diff for this revision Revisions of this file
Config/hw_config.h Show annotated file Show diff for this revision Revisions of this file
Config/motor_config.h Show annotated file Show diff for this revision Revisions of this file
Config/user_config.h Show annotated file Show diff for this revision Revisions of this file
FOC/foc.cpp Show annotated file Show diff for this revision Revisions of this file
FOC/foc.h Show annotated file Show diff for this revision Revisions of this file
PositionSensor/PositionSensor.cpp Show annotated file Show diff for this revision Revisions of this file
PositionSensor/PositionSensor.h Show annotated file Show diff for this revision Revisions of this file
hw_setup.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-dev.lib Show annotated file Show diff for this revision Revisions of this file
structs.h Show annotated file Show diff for this revision Revisions of this file
--- a/Config/current_controller_config.h	Fri Mar 02 15:24:00 2018 +0000
+++ b/Config/current_controller_config.h	Fri Apr 13 13:50:54 2018 +0000
@@ -1,6 +1,7 @@
 #ifndef CURRENT_CONTROLLER_CONFIG_H
 #define CURRENT_CONTROLLER_CONFIG_H
 
+// Current controller///
 #define K_D .05f                     // Volts/Amp
 #define K_Q .05f                     // Volts/Amp
 #define K_SCALE 0.0001f            // K_loop/Loop BW (Hz) 0.0042
@@ -13,6 +14,11 @@
 
 #define I_MAX 40.0f
 
+//Observer//
+#define DT 0.000025f
+#define K_O 0.02f
+
+
 
 
 #endif
--- a/Config/hw_config.h	Fri Mar 02 15:24:00 2018 +0000
+++ b/Config/hw_config.h	Fri Apr 13 13:50:54 2018 +0000
@@ -5,10 +5,13 @@
 #define PIN_V PA_9
 #define PIN_W PA_8
 #define ENABLE_PIN PA_11        // Enable gate drive pin
+#define LED         PC_5        // LED Pin
 #define I_SCALE 0.02014160156f  // Amps per A/D Count
+#define V_SCALE 0.00884f        // Bus volts per A/D Count
 #define DTC_MAX 0.95f          // Max phase duty cycle
 #define DTC_MIN 0.05f          // Min phase duty cycle
 #define PWM_ARR 0x8CA           /// timer autoreload value
 
 
+
 #endif
--- a/Config/motor_config.h	Fri Mar 02 15:24:00 2018 +0000
+++ b/Config/motor_config.h	Fri Apr 13 13:50:54 2018 +0000
@@ -4,12 +4,11 @@
 #define R_PHASE 0.105f          //Ohms
 #define L_D 0.00003f            //Henries
 #define L_Q 0.00003f            //Henries
-#define KT .075f                 //N-m per peak phase amp (= RMS amps/1.5)
+#define KT .075f                 //N-m per peak phase amp, = WB*NPP*3/2
 #define NPP 21                  //Number of pole pairs
 #define GR 6.0f                 //Gear ratio
-#define KT_OUT 0.45f            //Effective output torque constatnt
-
-#define WB KT/NPP               //Webers.  
+#define KT_OUT 0.45f            //KT*GR
+#define WB 0.0024f               //Webers.  
 
 
 
--- a/Config/user_config.h	Fri Mar 02 15:24:00 2018 +0000
+++ b/Config/user_config.h	Fri Apr 13 13:50:54 2018 +0000
@@ -16,7 +16,8 @@
 #define CAN_ID                  __int_reg[1]                                    // CAN bus ID
 #define CAN_MASTER              __int_reg[2]                                    // CAN bus "master" ID
 #define CAN_TIMEOUT             __int_reg[3]                                    // CAN bus timeout period
-#define ENCODER_LUT             __int_reg[4]                                    // Encoder offset LUT - 128 elements long
+#define ENCODER_LUT             __int_reg[5]                                    // Encoder offset LUT - 128 elements long
+
 
 
 extern float __float_reg[];
--- a/FOC/foc.cpp	Fri Mar 02 15:24:00 2018 +0000
+++ b/FOC/foc.cpp	Fri Apr 13 13:50:54 2018 +0000
@@ -1,8 +1,5 @@
-#include "user_config.h"
-#include "hw_config.h"
+
 #include "foc.h"
-
-#include "FastMath.h"
 using namespace FastMath;
 
 
@@ -10,10 +7,12 @@
     /// Inverse DQ0 Transform ///
     ///Phase current amplitude = lengh of dq vector///
     ///i.e. iq = 1, id = 0, peak phase current of 1///
-
-    *a = d*cosf(theta) - q*sinf(theta);
-    *b = d*cosf(theta - (2.0f*PI/3.0f)) - q*sinf(theta - (2.0f*PI/3.0f));
-    *c =  d*cosf(theta + (2.0f*PI/3.0f)) - q*sinf(theta +(2.0f*PI/3.0f));
+    float cf = FastCos(theta);
+    float sf = FastSin(theta);
+    
+    *a = cf*d - sf*q;                // Faster Inverse DQ0 transform
+    *b = (0.86602540378f*sf-.5f*cf)*d - (-0.86602540378f*cf-.5f*sf)*q;
+    *c = (-0.86602540378f*sf-.5f*cf)*d - (0.86602540378f*cf-.5f*sf)*q;
     }
     
     
@@ -22,11 +21,12 @@
     ///Phase current amplitude = lengh of dq vector///
     ///i.e. iq = 1, id = 0, peak phase current of 1///
     
-    //float cos = cosf(theta);
-    //float sin = sinf(theta);
+    float cf = FastCos(theta);
+    float sf = FastSin(theta);
     
-    *d = (2.0f/3.0f)*(a*cosf(theta) + b*cosf(theta - (2.0f*PI/3.0f)) + c*cosf(theta + (2.0f*PI/3.0f)));
-    *q = (2.0f/3.0f)*(-a*sinf(theta) - b*sinf(theta - (2.0f*PI/3.0f)) - c*sinf(theta + (2.0f*PI/3.0f)));
+    *d = 0.6666667f*(cf*a + (0.86602540378f*sf-.5f*cf)*b + (-0.86602540378f*sf-.5f*cf)*c);   ///Faster DQ0 Transform
+    *q = 0.6666667f*(-sf*a - (-0.86602540378f*cf-.5f*sf)*b - (0.86602540378f*cf-.5f*sf)*c);
+       
     }
     
 void svm(float v_bus, float u, float v, float w, float *dtc_u, float *dtc_v, float *dtc_w){
@@ -65,6 +65,7 @@
     controller->i_q_ref = 0;
     controller->i_d = 0;
     controller->i_q = 0;
+    controller->i_q_filt = 0;
     controller->q_int = 0;
     controller->d_int = 0;
     controller->v_q = 0;
@@ -72,9 +73,12 @@
     }
 
 
-void commutate(ControllerStruct *controller, GPIOStruct *gpio, float theta){
+void commutate(ControllerStruct *controller, ObserverStruct *observer, GPIOStruct *gpio, float theta){
+       /// Observer Prediction ///
+       observer->i_d_est += DT*(observer->i_d_dot);
+       observer->i_q_est += DT*(observer->i_q_dot);
+       
        /// Commutation Loop ///
-       
        controller->loop_count ++;   
        if(PHASE_ORDER){                                                                          // Check current sensor ordering
            controller->i_b = I_SCALE*(float)(controller->adc2_raw - controller->adc2_offset);    // Calculate phase currents from ADC readings
@@ -91,15 +95,31 @@
        //dq0(controller->theta_elec, controller->i_a, controller->i_b, controller->i_c, &controller->i_d, &controller->i_q);    //dq0 transform on currents
        controller->i_d = 0.6666667f*(c*controller->i_a + (0.86602540378f*s-.5f*c)*controller->i_b + (-0.86602540378f*s-.5f*c)*controller->i_c);   ///Faster DQ0 Transform
        controller->i_q = 0.6666667f*(-s*controller->i_a - (-0.86602540378f*c-.5f*s)*controller->i_b - (0.86602540378f*c-.5f*s)*controller->i_c);
-        controller->i_q_filt = .95f*controller->i_q_filt + .05f*controller->i_q;
-        float s_cog = sinf(12.0f*theta);
-       float cogging_current =-0.33f*s_cog + .25f*s;
+        
+        controller->i_q_filt = 0.95f*controller->i_q_filt + 0.05f*controller->i_q;
+        observer->i_d_m = controller->i_d;
+        observer->i_q_m = controller->i_q;
+        
+        observer->e_d = observer->i_d_m - observer->i_d_est;
+        observer->e_q = observer->i_q_m - observer->i_q_est;
+        observer->e_d_int += observer->e_d;
+        observer->e_q_int += observer->e_q;
+        
+        observer->i_d_est +=  K_O*observer->e_d + .001f*observer->e_d_int;
+        observer->i_q_est += K_O*observer->e_q + .001f*observer->e_q_int;
+        
+        
+        //float s_cog = sinf(12.0f*theta);
+        
+        //float cogging_current =-0.33f*s_cog + .25f*s;
        
        /// PI Controller ///
        float i_d_error = controller->i_d_ref - controller->i_d;
-       float i_q_error = controller->i_q_ref - controller->i_q + cogging_current;
-       float v_d_ff = 2.0f*(2*controller->i_d_ref*R_PHASE);   //feed-forward voltage
-       float v_q_ff =  controller->dtheta_elec*WB*1.73205081f;
+       float i_q_error = controller->i_q_ref - controller->i_q ;// + cogging_current;
+       
+       float v_d_ff = 2.0f*(controller->i_d_ref*R_PHASE - controller->dtheta_elec*L_Q*controller->i_q_ref);   //feed-forward voltages
+       float v_q_ff =  2.0f*(controller->i_q_ref*R_PHASE  + controller->dtheta_elec*(L_D*controller->i_d_ref + WB));
+       
        controller->d_int += i_d_error;   
        controller->q_int += i_q_error;
        
@@ -116,7 +136,7 @@
        //controller->v_d = v_d_ff;
        //controller->v_q = v_q_ff; 
        
-       limit_norm(&controller->v_d, &controller->v_q, 1.2f*controller->v_bus);       // Normalize voltage vector to lie within curcle of radius v_bus
+       limit_norm(&controller->v_d, &controller->v_q, 1.0f*controller->v_bus);       // Normalize voltage vector to lie within curcle of radius v_bus
        //abc(controller->theta_elec, controller->v_d, controller->v_q, &controller->v_u, &controller->v_v, &controller->v_w); //inverse dq0 transform on voltages
     
         controller->v_u = c*controller->v_d - s*controller->v_q;                // Faster Inverse DQ0 transform
@@ -124,6 +144,8 @@
         controller->v_w = (-0.86602540378f*s-.5f*c)*controller->v_d - (0.86602540378f*c-.5f*s)*controller->v_q;
        svm(controller->v_bus, controller->v_u, controller->v_v, controller->v_w, &controller->dtc_u, &controller->dtc_v, &controller->dtc_w); //space vector modulation
 
+       observer->i_d_dot = 0.5f*(controller->v_d - 2.0f*(observer->i_d_est*R_PHASE - controller->dtheta_elec*L_Q*observer->i_q_est))/L_D;   //feed-forward voltage
+       observer->i_q_dot =  0.5f*(controller->v_q - 2.0f*(observer->i_q_est*R_PHASE  + controller->dtheta_elec*(L_D*observer->i_d_est + WB)))/L_Q;
        
        if(PHASE_ORDER){                                                         // Check which phase order to use, 
             TIM1->CCR3 = (PWM_ARR)*(1.0f-controller->dtc_u);                        // Write duty cycles
@@ -156,7 +178,7 @@
     float torque_ref = controller->kp*(controller->p_des - controller->theta_mech) + controller->t_ff + controller->kd*(controller->v_des - controller->dtheta_mech);
     //float torque_ref = -.1*(controller->p_des - controller->theta_mech);
     controller->i_q_ref = torque_ref/KT_OUT;    
-    controller->i_d_ref = 0;
+    controller->i_d_ref = 0.0f;
     }
 
 
--- a/FOC/foc.h	Fri Mar 02 15:24:00 2018 +0000
+++ b/FOC/foc.h	Fri Apr 13 13:50:54 2018 +0000
@@ -9,12 +9,14 @@
 #include "math_ops.h"
 #include "motor_config.h"
 #include "current_controller_config.h"
+#include "FastMath.h"
+#include "user_config.h"
 
 void abc(float theta, float d, float q, float *a, float *b, float *c);
 void dq0(float theta, float a, float b, float c, float *d, float *q);
 void svm(float v_bus, float u, float v, float w, float *dtc_u, float *dtc_v, float *dtc_w);
 void zero_current(int *offset_1, int *offset_2);
 void reset_foc(ControllerStruct *controller);
-void commutate(ControllerStruct *controller, GPIOStruct *gpio, float theta);
+void commutate(ControllerStruct *controller, ObserverStruct *observer, GPIOStruct *gpio, float theta);
 void torque_control(ControllerStruct *controller);
 #endif
--- a/PositionSensor/PositionSensor.cpp	Fri Mar 02 15:24:00 2018 +0000
+++ b/PositionSensor/PositionSensor.cpp	Fri Apr 13 13:50:54 2018 +0000
@@ -13,10 +13,11 @@
     spi = new SPI(PC_12, PC_11, PC_10);
     spi->format(16, 1);                                                          // mbed v>127 breaks 16-bit spi, so transaction is broken into 2 8-bit words
     spi->frequency(25000000);
+    
     cs = new DigitalOut(PA_15);
     cs->write(1);
     readAngleCmd = 0xffff;   
-    MechOffset = 0;
+    MechOffset = offset;
     modPosition = 0;
     oldModPosition = 0;
     oldVel = 0;
@@ -24,10 +25,10 @@
     }
     
 void PositionSensorAM5147::Sample(){
-    cs->write(0);
+    GPIOA->ODR &= ~(1 << 15);
     raw = spi->write(readAngleCmd);
     raw &= 0x3FFF;                                                              //Extract last 14 bits
-    cs->write(1);
+    GPIOA->ODR |= (1 << 15);
     int off_1 = offset_lut[raw>>7];
     int off_2 = offset_lut[((raw>>7)+1)%128];
     int off_interp = off_1 + ((off_2 - off_1)*(raw - ((raw>>7)<<7))>>7);        // Interpolate between lookup table entries
@@ -84,6 +85,10 @@
     return ElecPosition;
     }
 
+float PositionSensorAM5147::GetElecVelocity(){
+    return ElecVelocity;
+    }
+
 float PositionSensorAM5147::GetMechVelocity(){
     return MechVelocity;
     }
@@ -98,6 +103,9 @@
 void PositionSensorAM5147::SetElecOffset(float offset){
     ElecOffset = offset;
     }
+void PositionSensorAM5147::SetMechOffset(float offset){
+    MechOffset = offset;
+    }
 
 int PositionSensorAM5147::GetCPR(){
     return _CPR;
@@ -109,6 +117,7 @@
     }
     
 
+
 PositionSensorEncoder::PositionSensorEncoder(int CPR, float offset, int ppairs) {
     _ppairs = ppairs;
     _CPR = CPR;
--- a/PositionSensor/PositionSensor.h	Fri Mar 02 15:24:00 2018 +0000
+++ b/PositionSensor/PositionSensor.h	Fri Apr 13 13:50:54 2018 +0000
@@ -47,9 +47,11 @@
     virtual float GetMechPosition();
     virtual float GetElecPosition();
     virtual float GetMechVelocity();
+    virtual float GetElecVelocity();
     virtual int GetRawPosition();
     virtual void ZeroPosition();
     virtual void SetElecOffset(float offset);
+    virtual void SetMechOffset(float offset);
     virtual int GetCPR(void);
     virtual void WriteLUT(int new_lut[128]);
 private:
--- a/hw_setup.cpp	Fri Mar 02 15:24:00 2018 +0000
+++ b/hw_setup.cpp	Fri Apr 13 13:50:54 2018 +0000
@@ -33,7 +33,6 @@
     //PWM Setup
 
     TIM1->PSC = 0x0;                                            // no prescaler, timer counts up in sync with the peripheral clock
-    //TIM1->ARR = 0x1194; // 20 khz
     TIM1->ARR = PWM_ARR;                                          // set auto reload, 40 khz
     TIM1->CCER |= ~(TIM_CCER_CC1NP);                            // Interupt when low side is on.
     TIM1->CR1 |= TIM_CR1_CEN;                                   // enable TIM1
@@ -41,17 +40,29 @@
     }
 
 void Init_ADC(void){
-        // ADC Setup
+    // ADC Setup
+     RCC->APB2ENR |= RCC_APB2ENR_ADC3EN;                        // clock for ADC3
      RCC->APB2ENR |= RCC_APB2ENR_ADC2EN;                        // clock for ADC2
      RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;                        // clock for ADC1
-    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;                        // Enable clock for GPIOC
      
-     ADC->CCR = 0x00000006;                                     // Regular simultaneous mode only
+     RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;                        // Enable clock for GPIOC
+     RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;                        // Enable clock for GPIOA
+    
+     ADC->CCR = 0x00000016;                                     // Regular simultaneous mode only
      ADC1->CR2 |= ADC_CR2_ADON;//0x00000001;                    // ADC1 ON
-     ADC1->SQR3 = 0x000000A;                                    // use PC_0 as input
-     ADC2->CR2 |= ADC_CR2_ADON;//0x00000001;                    // ADC1 ON
-     ADC2->SQR3 = 0x0000000B;                                   // use PC_1 as input
+     ADC1->SQR3 = 0x000000A;                                    // use PC_0 as input- ADC1_IN0
+     ADC2->CR2 |= ADC_CR2_ADON;//0x00000001;                    // ADC2 ON
+     ADC2->SQR3 = 0x0000000B;                                   // use PC_1 as input - ADC2_IN11
+     ADC3->CR2 |= ADC_CR2_ADON;                                 // ADC3 ON
+     ADC3->SQR3 = 0x00000000;                                   // use PA_0, - ADC3_IN0
      GPIOC->MODER |= 0x0000000f;                                // Alternate function, PC_0, PC_1 are analog inputs 
+     GPIOA->MODER |= 0x3;                                       // PA_0 as analog input
+     
+     ADC1->SMPR1 |= 0x1;                                        // 15 cycles on CH_10, 0b 001
+     ADC2->SMPR1 |= 0x8;                                        // 15 cycles on CH_11, 0b 0001 000
+     ADC3->SMPR2 |= 0x1;                                        // 15 cycles on CH_0, 0b 001;
+
+
 
     }
 
@@ -64,6 +75,7 @@
 void Init_All_HW(GPIOStruct *gpio){
     Init_PWM(gpio);
     Init_ADC();
+    gpio->led = new DigitalOut(LED);
     //Init_DAC();
     
     }
\ No newline at end of file
--- a/main.cpp	Fri Mar 02 15:24:00 2018 +0000
+++ b/main.cpp	Fri Apr 13 13:50:54 2018 +0000
@@ -10,7 +10,7 @@
 #define SETUP_MODE 4
 #define ENCODER_MODE 5
 
-#define VERSION_NUM "1.2"
+#define VERSION_NUM "1.4"
 
 
 float __float_reg[64];                                                          // Floats stored in flash
@@ -31,14 +31,14 @@
 #include "user_config.h"
 #include "PreferenceWriter.h"
 
+
  
 PreferenceWriter prefs(6);
 
 GPIOStruct gpio;
 ControllerStruct controller;
 COMStruct com;
-VelocityEstimatorStruct velocity;
-
+ObserverStruct observer;
 
 //using namespace CANnucleo;
 
@@ -50,10 +50,10 @@
 Serial pc(PA_2, PA_3);
 
 PositionSensorAM5147 spi(16384, 0.0, NPP);  
-PositionSensorEncoder encoder(4096, 0, NPP); 
+//PositionSensorEncoder encoder(4096, 0, NPP); 
 
 
-DigitalOut toggle(PA_0);
+DigitalOut toggle(PC_8);
 
 volatile int count = 0;
 volatile int state = REST_MODE;
@@ -61,8 +61,8 @@
 
  #define P_MIN -12.5f
  #define P_MAX 12.5f
- #define V_MIN -30.0f
- #define V_MAX 30.0f
+ #define V_MIN -45.0f
+ #define V_MAX 45.0f
  #define KP_MIN 0.0f
  #define KP_MAX 500.0f
  #define KD_MIN 0.0f
@@ -122,20 +122,15 @@
         controller->kp = uint_to_float(kp_int, KP_MIN, KP_MAX, 12);
         controller->kd = uint_to_float(kd_int, KD_MIN, KD_MAX, 12);
         controller->t_ff = uint_to_float(t_int, T_MIN, T_MAX, 12);
-    
-    
     //printf("Received   ");
     //printf("%.3f  %.3f  %.3f  %.3f  %.3f   %.3f", controller->p_des, controller->v_des, controller->kp, controller->kd, controller->t_ff, controller->i_q_ref);
     //printf("\n\r");
-    
-    
     }
 
 void onMsgReceived() {
     //msgAvailable = true;
     //printf("%.3f   %.3f   %.3f\n\r", controller.theta_mech, controller.dtheta_mech, controller.i_q);
     can.read(rxMsg);  
-    
     if((rxMsg.id == CAN_ID)){
         controller.timeout = 0;
         if(((rxMsg.data[0]==0xFF) & (rxMsg.data[1]==0xFF) & (rxMsg.data[2]==0xFF) & (rxMsg.data[3]==0xFF) & (rxMsg.data[4]==0xFF) & (rxMsg.data[5]==0xFF) & (rxMsg.data[6]==0xFF) & (rxMsg.data[7]==0xFC))){
@@ -145,16 +140,16 @@
         else if(((rxMsg.data[0]==0xFF) & (rxMsg.data[1]==0xFF) & (rxMsg.data[2]==0xFF) & (rxMsg.data[3]==0xFF) * (rxMsg.data[4]==0xFF) & (rxMsg.data[5]==0xFF) & (rxMsg.data[6]==0xFF) & (rxMsg.data[7]==0xFD))){
             state = REST_MODE;
             state_change = 1;
-            GPIOC->ODR &= !(1 << 5); 
+            gpio.led->write(0);; 
             }
         else if(((rxMsg.data[0]==0xFF) & (rxMsg.data[1]==0xFF) & (rxMsg.data[2]==0xFF) & (rxMsg.data[3]==0xFF) * (rxMsg.data[4]==0xFF) & (rxMsg.data[5]==0xFF) & (rxMsg.data[6]==0xFF) & (rxMsg.data[7]==0xFE))){
             spi.ZeroPosition();
             }
         else if(state == MOTOR_MODE){
             unpack_cmd(rxMsg, &controller);
-            pack_reply(&txMsg, controller.theta_mech, controller.dtheta_mech, controller.i_q_filt*KT_OUT);
-            can.write(txMsg);
             }
+        pack_reply(&txMsg, controller.theta_mech, controller.dtheta_mech, controller.i_q_filt*KT_OUT);
+        can.write(txMsg);
         }
     
 }
@@ -166,9 +161,11 @@
     printf(" c - Calibrate Encoder\n\r");
     printf(" s - Setup\n\r");
     printf(" e - Display Encoder\n\r");
+    printf(" z - Set Zero Position\n\r");
     printf(" esc - Exit to Menu\n\r");
     state_change = 0;
     gpio.enable->write(0);
+    gpio.led->write(0);
     }
 
 void enter_setup_state(void){
@@ -184,32 +181,30 @@
     }
     
 void enter_torque_mode(void){
+    controller.ovp_flag = 0;
     gpio.enable->write(1);                                                      // Enable gate drive
     reset_foc(&controller);                                                     // Tesets integrators, and other control loop parameters
     wait(.001);
     controller.i_d_ref = 0;
     controller.i_q_ref = 0;                                                     // Current Setpoints
-    GPIOC->ODR |= (1 << 5);                                                     // Turn on status LED
+    gpio.led->write(1);                                                     // Turn on status LED
     state_change = 0;
     printf("\n\r Entering Motor Mode \n\r");
     }
     
 void calibrate(void){
     gpio.enable->write(1);                                                      // Enable gate drive
-    GPIOC->ODR |= (1 << 5);                                                     // Turn on status LED
+    gpio.led->write(1);                                                    // Turn on status LED
     order_phases(&spi, &gpio, &controller, &prefs);                             // Check phase ordering
     calibrate(&spi, &gpio, &controller, &prefs);                                // Perform calibration procedure
-    GPIOC->ODR &= !(1 << 5);                                                     // Turn off status LED
+    gpio.led->write(0);;                                                     // Turn off status LED
     wait(.2);
     gpio.enable->write(0);                                                      // Turn off gate drive
     printf("\n\r Calibration complete.  Press 'esc' to return to menu\n\r");
      state_change = 0;
-     
     }
     
 void print_encoder(void){
-    spi.Sample();
-    wait(.001);
     printf(" Mechanical Angle:  %f    Electrical Angle:  %f    Raw:  %d\n\r", spi.GetMechPosition(), spi.GetElecPosition(), spi.GetRawPosition());
     wait(.05);
     }
@@ -218,20 +213,25 @@
 /// This runs at 40 kHz, regardless of of the mode the controller is in ///
 extern "C" void TIM1_UP_TIM10_IRQHandler(void) {
   if (TIM1->SR & TIM_SR_UIF ) {
-        //toggle = 1;
 
         ///Sample current always ///
         ADC1->CR2  |= 0x40000000;                                               // Begin sample and conversion
         //volatile int delay;   
         //for (delay = 0; delay < 55; delay++);
-        controller.adc2_raw = ADC2->DR;                                         // Read ADC1 and ADC2 Data Registers
+        controller.adc2_raw = ADC2->DR;                                         // Read ADC Data Registers
         controller.adc1_raw = ADC1->DR;
+        controller.adc3_raw = ADC3->DR;
+        spi.Sample();                                                           // sample position sensor
+        controller.theta_elec = spi.GetElecPosition();
+        controller.theta_mech = (1.0f/GR)*spi.GetMechPosition();
+        controller.dtheta_mech = (1.0f/GR)*spi.GetMechVelocity();  
+        controller.dtheta_elec = spi.GetElecVelocity();
+        controller.v_bus = 0.95f*controller.v_bus + 0.05f*((float)controller.adc3_raw)*V_SCALE;
         ///
         
         /// Check state machine state, and run the appropriate function ///
-        //printf("%d\n\r", state);
         switch(state){
-            case REST_MODE:                                                     // Do nothing until
+            case REST_MODE:                                                     // Do nothing
                 if(state_change){
                     enter_menu_state();
                     }
@@ -249,35 +249,34 @@
                     count = 0;
                     }
                 else{
-                count++;
-                //toggle.write(1);
-                controller.theta_elec = spi.GetElecPosition();
-                controller.theta_mech = (1.0f/GR)*spi.GetMechPosition();
-                controller.dtheta_mech = (1.0f/GR)*spi.GetMechVelocity();  
-                //TIM1->CCR3 = 0x708*(1.0f);
-                //TIM1->CCR1 = 0x708*(1.0f);
-                //TIM1->CCR2 = 0x708*(1.0f);     
-                
-                //controller.i_q_ref = controller.t_ff/KT_OUT;   
-                
+                /*
+                if(controller.v_bus>28.0f){         //Turn of gate drive if bus voltage is too high, to prevent FETsplosion if the bus is cut during regen
+                    gpio.enable->write(0);
+                    controller.ovp_flag = 1;
+                    state = REST_MODE;
+                    state_change = 1;
+                    printf("OVP Triggered!\n\r");
+                    }
+                    */  
+
                 torque_control(&controller);     
                 if((controller.timeout > CAN_TIMEOUT) && (CAN_TIMEOUT > 0)){
                     controller.i_d_ref = 0;
                     controller.i_q_ref = 0;
+                    controller.kp = 0;
+                    controller.kd = 0;
+                    controller.t_ff = 0;
                     } 
-                //controller.i_q_ref = .4f;
-                commutate(&controller, &gpio, controller.theta_elec);           // Run current loop
-                spi.Sample();                                                   // Sample position sensor
-                //toggle.write(0);
+                commutate(&controller, &observer, &gpio, controller.theta_elec);           // Run current loop
                 controller.timeout += 1;
-                
+                /*
+                count++;
                 if(count == 1000){
                      count = 0;
-                     //wait(.001);
-                    //printf("%f\n\r", controller.theta_elec);
                      }
-                     }
-                     
+                     */
+            
+                }     
                 break;
             case SETUP_MODE:
                 if(state_change){
@@ -287,8 +286,7 @@
             case ENCODER_MODE:
                 print_encoder();
                 break;
-                }
-                 
+                }                 
       }
   TIM1->SR = 0x0;                                                               // reset the status register
 }
@@ -308,7 +306,7 @@
                 state_change = 1;
                 char_count = 0;
                 cmd_id = 0;
-                GPIOC->ODR &= !(1 << 5); 
+                gpio.led->write(0);; 
                 for(int i = 0; i<8; i++){cmd_val[i] = 0;}
                 }
         if(state == REST_MODE){
@@ -329,7 +327,21 @@
                     state = SETUP_MODE;
                     state_change = 1;
                     break;
-                    }
+                case 'z':
+                    spi.SetMechOffset(0);
+                    spi.Sample();
+                    wait_us(20);
+                    M_OFFSET = spi.GetMechPosition();
+                    if (!prefs.ready()) prefs.open();
+                        prefs.flush();                                                  // Write new prefs to flash
+                        prefs.close();    
+                        prefs.load(); 
+                    spi.SetMechOffset(M_OFFSET);
+                    printf("\n\r  Saved new zero position:  %.4f\n\r\n\r", M_OFFSET);
+                    
+                    break;
+                }
+                
                 }
         else if(state == SETUP_MODE){
             if(c == 13){
@@ -403,7 +415,8 @@
     //TIM1->CR1 |= TIM_CR1_UDIS; //enable interrupt
     
     wait(.1);
-    NVIC_SetPriority(TIM5_IRQn, 2);                                             // set interrupt priority
+    NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 2);                                             // commutation > communication
+    NVIC_SetPriority(CAN1_RX0_IRQn, 3);
 
 
     can.frequency(1000000);                                                     // set bit rate to 1Mbps
@@ -415,7 +428,10 @@
     rxMsg.len = 8;
     
     prefs.load();                                                               // Read flash
+    if(isnan(E_OFFSET)){E_OFFSET = 0.0f;}
+    if(isnan(M_OFFSET)){M_OFFSET = 0.0f;}
     spi.SetElecOffset(E_OFFSET);                                                // Set position sensor offset
+    spi.SetMechOffset(M_OFFSET);
     int lut[128] = {0};
     memcpy(&lut, &ENCODER_LUT, sizeof(lut));
     spi.WriteLUT(lut);                                                          // Set potision sensor nonlinearity lookup table
@@ -428,6 +444,7 @@
     printf(" Firmware Version: %s\n\r", VERSION_NUM);
     printf(" ADC1 Offset: %d    ADC2 Offset: %d\n\r", controller.adc1_offset, controller.adc2_offset);
     printf(" Position Sensor Electrical Offset:   %.4f\n\r", E_OFFSET);
+    printf(" Output Zero Position:  %.4f\n\r", M_OFFSET);
     printf(" CAN ID:  %d\n\r", CAN_ID);
         
     pc.attach(&serial_interrupt);                                               // attach serial interrupt
--- a/mbed-dev.lib	Fri Mar 02 15:24:00 2018 +0000
+++ b/mbed-dev.lib	Fri Apr 13 13:50:54 2018 +0000
@@ -1,1 +1,1 @@
-https://os.mbed.com/users/benkatz/code/mbed-dev-f303/#9f17883fb9b6
+https://os.mbed.com/users/benkatz/code/mbed-dev-f303/#902f8c6731d6
--- a/structs.h	Fri Mar 02 15:24:00 2018 +0000
+++ b/structs.h	Fri Apr 13 13:50:54 2018 +0000
@@ -8,6 +8,7 @@
 
 typedef struct{
     DigitalOut *enable;
+    DigitalOut *led;
     FastPWM *pwm_u, *pwm_v, *pwm_w;
     } GPIOStruct;
     
@@ -16,7 +17,7 @@
     }COMStruct;
     
 typedef struct{
-    int adc1_raw, adc2_raw;
+    int adc1_raw, adc2_raw, adc3_raw;
     float i_a, i_b, i_c;
     float v_bus;
     float theta_mech, theta_elec;
@@ -31,19 +32,19 @@
     int loop_count;
     int timeout;
     int mode;
+    int ovp_flag;
     float p_des, v_des, kp, kd, t_ff;
     float cogging[128];
     } ControllerStruct;
 
 typedef struct{
-    float vel_1;
-    float vel_1_old;
-    float vel_1_est;
-    float vel_2;
-    float vel_2_old;
-    float vel_2_est;
-    float ts;
-    float est;
-    } VelocityEstimatorStruct;
+    float theta_m, theta_est;
+    float thetadot_m, thetadot_est;
+    float i_d_m, i_d_est;
+    float i_q_m, i_q_est;
+    float i_d_dot, i_q_dot;
+    float e_d, e_q;
+    float e_d_int, e_q_int;
+    } ObserverStruct;
     
 #endif