Test code for proving multi-NCO implementation on Altera FPGA using DEO Nano development board

Dependencies:   MODSERIAL mbed-rtos mbed

Revision:
0:7f5b51873953
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Apr 24 15:35:38 2014 +0000
@@ -0,0 +1,510 @@
+#include "mbed.h"
+#include "rtos.h"
+#include "MODSERIAL.h"
+#include "cnc.h"
+extern  void    i2c_handler    (void const *);
+extern  void    command_line_interpreter    (void const *) ;
+extern  fl_typ  feed_rate;      //  float type is 'float'
+extern  signed long spindle_rpm;
+
+const   int BAUD = 38400;
+MODSERIAL  pc(USBTX, USBRX);    //  tx, rx to pc via usb lead
+Ticker  msec;                   //  Ticker updating global millisecs counter
+
+bool    running         = false,
+        new_run_pending = false,
+        idle            = false,
+        move_ended      = false;
+
+unsigned long   millisecs = 0L;        //  32 bit
+
+#if defined (TARGET_KL25Z)
+    const char Target[] = "KL25Z";  //  Note need PTE0 (sda) and PTE1 (scl)
+    DigitalOut intled               (PTD7); //(PTE1);     //J2p19, was 20
+    DigitalOut charge_pumpD25pin1   (PTD6); //(PTE0);     //J2p17, was 18    
+    DigitalIn     D25pin10_EStop    (PTE20);    //j10p1   KL25 J10 is KL46 j4
+    DigitalIn       D25pin11_XLim     (PTE21);    //j10p3
+    DigitalIn       D25pin12_YLim     (PTE22);    //j10p5
+    DigitalIn       D25pin13_ZLim     (PTE23);    //j10p7
+    DigitalIn       D25pin15_unkn     (PTE30);    //j10p11
+#if defined I2C_Enable
+    I2CSlave slave(PTE0, PTE1); //  PTE0 sda, (yellow) PTE1 scl (blue)
+#endif
+#if defined SPI_Enable
+    SPI spi(PTD2, PTD3, PTD1, PTD0); // mosi, miso, sclk (uses p11, p12, p13 on mbed LPC1768)
+#endif
+    //                 J2p08,J2p10,J2p12, J2p06
+    #define STEPPER_PORT    PortC
+    const   int PortBitXSt   = 3,    //  Port bit num X Step    J1P05   D25pin 2
+                PortBitXDi   = 4,    //  Port bit num X Dir     J1P07   D25pin 3
+                PortBitYSt   = 5,    //  Port bit num Y Step    J1P09   D25pin 4
+                PortBitYDi   = 6,    //  Port bit num Y Dir     J1P11   D25pin 5
+                PortBitZSt   = 10,    //  Port bit num Z Step   J1P13   D25pin 6
+                PortBitZDi   = 11,    //  Port bit num Z Dir    J1P15   D25pin 7
+                PortBitASt   = 12,    //  Port bit num A Step   J2P01   D25pin 8
+                PortBitADi   = 13,    //  Port bit num A Dir    J2P03   D25pin 9
+                PortBitSSt   = 8,    //  Port bit num Spin Step   J1P14 D25pin 14
+                PortBitSDi   = 9;    //  Port bit num Spin Dir    J1P16 D25pin 16
+#endif
+
+
+
+#if defined (TARGET_KL46Z)
+    const char Target[] = "KL46Z";
+    DigitalOut intled               (PTE1);    //J2p20 checked
+
+
+    DigitalOut charge_pumpD25pin1   (PTE0);    //J2p18 checked
+//    InterruptIn     D25pin10_EStop    (PTE20);  // j4p1  KL46 J4 is KL25 J10
+    DigitalIn     D25pin10_EStop    (PTE20);  // j4p1  KL46 J4 is KL25 J10 checked
+    DigitalIn       D25pin11_XLim     (PTE21);  // j4p3 checked
+    DigitalIn       D25pin12_YLim     (PTE22);  // j4p5 checked
+    DigitalIn       D25pin13_ZLim     (PTE23);  // j4p7 checked
+    DigitalIn       D25pin15_unkn     (PTE30);  // j4p11 checked
+#if defined I2C_Enable
+    I2CSlave slave(p9, p10);
+#endif
+#if defined SPI_Enable
+    SPI spi(PTA16, PTA17, PTA15, PTA14); // mosi, miso, sclk, ssel (uses p11, p12, p13, p? on mbed LPC)
+#endif
+    //                 J2p13, J2p15, J2p11, J2p09
+                // Easy way to allocate port bits for
+                // output of stepper motor Step and DIR sigs
+    #define STEPPER_PORT    PortC
+    const   int PortBitXSt   = 0,    //  Port bit num X Step    J1P05   D25pin 2 checked
+                PortBitXDi   = 4,    //  Port bit num X Dir     J1P07   D25pin 3 checked
+                PortBitYSt   = 6,    //  Port bit num Y Step    J1P09   D25pin 4 checked
+                PortBitYDi   = 7,    //  Port bit num Y Dir     J1P11   D25pin 5 checked
+                PortBitZSt   = 10,    //  Port bit num Z Step   J1P13   D25pin 6 checked
+                PortBitZDi   = 11,    //  Port bit num Z Dir    J1P15   D25pin 7 checked
+                PortBitASt   = 13,    //  Port bit num A Step   J2P01   D25pin 8 checked
+                PortBitADi   = 16,    //  Port bit num A Dir    J2P03   D25pin 9 checked
+                PortBitSSt   = 8,    //  Port bit num Spin Step J1P14   D25pin 14 checked
+                PortBitSDi   = 9;    //  Port bit num Spin Dir  J1P16   D25pin 16 checked
+#endif
+#if defined (TARGET_MBED_LPC1768)
+    const char Target[] = "MBED LPC1768";
+    DigitalOut intled(LED2);                    //  Correct
+    DigitalOut charge_pumpD25pin1      (p25);    //
+//    InterruptIn D25pin10_EStop  (p26);    //P2.0
+    DigitalIn D25pin10_EStop  (p26);    //P2.0
+    DigitalIn   D25pin11_XLim   (p24);    //P2.2
+    DigitalIn   D25pin12_YLim   (p23);    //P2.3
+    DigitalIn   D25pin13_ZLim   (p19);    //P1.30
+    DigitalIn   D25pin15_unkn   (p20);    //P1.31
+#if defined I2C_Enable
+    I2CSlave slave(p9, p10);
+#endif
+//#if defined SPI_Enable
+    SPI spi(p5, p6, p7);
+//#endif
+                // Easy way to allocate port bits
+                // output of stepper motor Step and DIR sigs
+    #define STEPPER_PORT    Port0
+    /* Port 0 bits routed to DIP pins as follows:-
+        P0.00   p09 Reserve SDA
+        P0.01   p10 Reserve SCL
+        P0.04   p30 CAN rd  -   USE X Step  D25pin 2
+        P0.05   p29 CAN td  -   USE X Dir   D25pin 3
+        P0.10   p28 SDA     -   USE Y Step  D25pin 4
+        P0.11   p27 SCL     -   USE Y Dir   D25pin 5
+        P0.15   p13 Tx      -   USE Z Step  D25pin 6
+        P0.16   p14 Rx      -   USE Z Dir   D25pin 7
+        P0.17   p12 miso    -   USE A Step  D25pin 8
+        P0.18   p11 mosi    -   Use A Dir   D25pin 9
+        P0.23   p15 A In    -   Use S Step  D25pin 14
+        P0.24   p16 A In    -   Use S Dir   D25pin 16
+        P0.25   p17 Reserve A In
+        P0.26   p18 Reserve A Out
+    */
+    const   int PortBitXSt  = 4,    //  Port bit num X Step
+                PortBitXDi  = 5,    //  Port bit num X Dir
+                PortBitYSt  = 10,    //  Port bit num Y Step
+                PortBitYDi  = 11,    //  Port bit num Y Dir
+                PortBitZSt  = 15,    //  Port bit num Z Step
+                PortBitZDi  = 16,    //  Port bit num Z Dir
+                PortBitASt  = 17,    //  Port bit num A Step
+                PortBitADi  = 18,    //  Port bit num A Dir
+                PortBitSSt  = 23,   //  Port bit num Spin Step
+                PortBitSDi  = 24;   //  Port bit num Spin Dir
+#endif
+
+const   long    //  Assemble mask bits from now known port bit positions
+        XSt =   1 << PortBitXSt,    //  X axis Step signal
+        XDi =   1 << PortBitXDi,    //  X axis Direction signal
+        YSt =   1 << PortBitYSt,    //  Y axis Step, etc
+        YDi =   1 << PortBitYDi,
+        ZSt =   1 << PortBitZSt,    //  Z axis
+        ZDi =   1 << PortBitZDi,
+        ASt =   1 << PortBitASt,    //  A axis, not implemented in full, for e.g. rotary axis
+        ADi =   1 << PortBitADi,
+        SDi =   1 << PortBitSDi,     //  Spindle, also driven by Step and Dir signals up to 5kHz
+        SSt =   1 << PortBitSSt,     //  for 5000 RPM
+
+        SM_MASK = (XSt | XDi | YSt | YDi | ZSt | ZDi | ASt | ADi | SDi | SSt);
+//        direction_swappers = XDi | YDi | ZDi | SDi; //  include bit to swap direction
+
+    PortOut Steppers    (STEPPER_PORT, SM_MASK);
+
+int freq_to_n   (int freq)  {
+    const double factor = (1 << 25) / 390625.0;
+//    unsigned long long ll = ((1 << 31) * freq) / 50000000; 
+    double ll = factor * (double)freq;
+    return  (long) ll;
+}
+//  freq = (50E6 * 'n' / 2**BUS_WIDTH)
+//  'n' = freq * 2**BUS_WIDTH / 50000000
+//  'n' = freq * 2**31 / 25000000
+//  'n' = freq * 2**30 / 12500000
+//  'n' = freq * 2**29 / 6250000
+//  'n' = freq * 2**25 / 390625
+
+int pirs[8], dros[8];
+
+void    FPGA_bit    (int whichbit, int hiorlo)    {
+    int port = Steppers;
+    if  (hiorlo)    port |= whichbit;
+    else            port &= ~whichbit;
+    Steppers = port;
+}
+
+void    FPGA_setup  ()  {
+    int port = Steppers;
+    port |= sclr | clken;
+    Steppers = port;
+    port &= ~sclr;
+    port &= ~clken;
+    port &= ~ld_osr;
+    port &= ~ld_pir;
+    Steppers = port;
+    for (int i = 0; i < 8; i++)
+        pirs[i] = dros[i] = 0;
+}
+
+/*
+--    About Use of 16 bit Command Word
+--    bit 0   -   '1' causes zero reset of phase_inc_reg
+--    bit 1   -   '1' causes zero reset of dro_udcounter
+--    bit 2   -   '1' causes load of phase_inc_reg from input shift reg
+--    bit 3   -   '1' causes load of dro_udcounter from input shift reg 
+--    bit 4   -   '1' causes dro_udcounter --> shift reg ready to read dro value
+--    bit 5   -   '1' causes phase_inc_reg --> shift reg ready to read pir value
+--    bit 6   -   '1' causes reset everything to 0
+--
+--    bit 15  -   '1' causes reset of command_word to all 0 after one clock
+
+*/
+#define zero_pir            0x8001
+#define zero_dro            0x8002
+#define load_pir_from_sr    0x8004
+#define load_dro_from_sr    0x8008
+#define load_dro_into_sr    0x8010
+#define load_pir_into_sr    0x8020
+
+void    FPGA_cmd    (int command_word)  {
+    int port = Steppers;
+    int spirx[8], command_copy = command_word;
+//    pc.printf("At FPGA_cmd, sending %d\r\n", command_word);
+    port |= sclr;       //  cmdhi_datalo set to 1
+    Steppers = port;    //  
+    spirx[0] = spi.write(command_copy >> 8);
+    spirx[1] = spi.write(command_copy);
+    port &= ~sclr;       //  cmdhi_datalo set to 0
+    Steppers = port;    //  
+//    pc.printf("Read spi %x %x\r\n", spirx[0], spirx[1]);
+}
+
+void    setcmd_cmd  (struct singleGparam * a)  {
+    FPGA_cmd    (a[1].i);
+}
+
+//#define load_pir_from_sr    0x8004
+//#define load_dro_into_sr    0x8010
+
+//    DigitalIn   D25pin15_unkn   (p20);    //P1.31 use this to read osr
+int FPGA_rdandwr    (int tosend)  { //  send 32 bits to in_sr, read 32 bits from out_sr
+    int torecv = 0, port = Steppers, tmp;
+//    tosend = freq_to_n(tosend);
+    for (int j = 3; j >= 0; j--) {
+        torecv <<= 8;
+        tmp = tosend >> (j << 3);
+        torecv |= spi.write(tmp);
+    }
+    return  torecv;
+}
+
+const int   numof_ncos = 4;
+
+void    setdro_cmd  (struct singleGparam * a)  {
+    int recd[numof_ncos + 1];
+    pc.printf("At setdro with values ");
+    FPGA_cmd(load_dro_into_sr);
+    for (int k = 0; k < numof_ncos; k++)    {
+        recd[k] = FPGA_rdandwr    (a[k + 1].i);
+        pc.printf("%d, ", a[k + 1].i);
+    }
+    FPGA_cmd(load_dro_from_sr);
+    pc.printf("end\r\n");
+}
+
+void    setpir_cmd  (struct singleGparam * a)  {
+    int recd[numof_ncos + 1];
+    pc.printf("At setpir with values ");
+    FPGA_cmd(load_dro_into_sr);
+    for (int k = 0; k < numof_ncos; k++)    {
+        recd[k] = FPGA_rdandwr    (a[k + 1].i);
+        pc.printf("%d, ", a[k + 1].i);
+    }
+    FPGA_cmd(load_pir_from_sr);
+    pc.printf("end\r\n");
+}
+
+void    getdro_cmd  (struct singleGparam * a)  {
+    int read_dro[numof_ncos + 1];
+    pc.printf("At rddro, retrieved values ");
+    FPGA_cmd(load_dro_into_sr);
+    for (int k = 0; k < numof_ncos; k++)    {
+        read_dro[k] = FPGA_rdandwr (0);
+        pc.printf("%d, ", read_dro[k]);
+    }
+    pc.printf(" end\r\n");
+}
+
+void    getpir_cmd  (struct singleGparam * a)  {
+    int read_pir[numof_ncos + 1];
+    pc.printf("At rdpir, retrieved values ");
+    FPGA_cmd(load_pir_into_sr);
+    for (int k = 0; k < numof_ncos; k++)    {
+        read_pir[k] = FPGA_rdandwr (0);
+        pc.printf("%d, ", read_pir[k]);
+    }
+    pc.printf(" end\r\n");
+}
+
+void    clrpir_cmd  (struct singleGparam * a)  {
+    FPGA_cmd(zero_pir);
+    getpir_cmd(a);    
+}
+
+void    clrdro_cmd  (struct singleGparam * a)  {
+    FPGA_cmd(zero_dro);
+    getdro_cmd(a);    
+}
+
+
+char const * target_str_addr  ()  {
+    return  Target;
+}
+
+void    grain_clr   (struct singleGparam & g)  {
+    g.flt = 0.0;
+    g.ul = 0L;
+    g.i = g.c = 0;
+    g.changed = false;
+}
+void    Gparams_clr    (struct Gparams & p)   {
+    grain_clr   (p.x);    grain_clr   (p.y);    grain_clr   (p.z);    grain_clr   (p.i);    grain_clr   (p.j);
+    grain_clr   (p.r);    grain_clr   (p.a);    grain_clr   (p.b);    grain_clr   (p.c);    grain_clr   (p.d);
+}
+
+class digital_readout_stuff  {   //  class does not need to be named here
+    private:
+    char *  readout (char * txt, long p)         //  p has running subtotal of all pulses issued to stepper driver
+    {
+        txt[0] = '+';               //  constructs string e.g. "+123.456"
+        txt[8] = 0;                 //  null terminated
+        if  (p < 0)    {
+            txt[0] = '-';
+            p = -p;
+        }
+        p *= 1000;
+//??        p /= pulses_per_mm;
+        if  (p > 999999)    {
+            sprintf(txt + 1, "OVRANGE");
+            return  txt;
+        }
+        for(int k = 7; k > 0; k--)  {
+            if  (k == 4)
+                txt[k] = '.';
+            else    {
+                txt[k] = '0' + (p % 10);
+                p /= 10;
+            }
+        }
+        return  txt;    //  Returns pointer unaltered for subsequent use by e.g. cout
+    }
+        public:
+    signed long x, y, z, a;    //  Could easily expand up to six or more dros
+//    bool    dro_output;             //  To enabe / disable output to terminal
+    void    init    ()  {
+        x = y = z = a = 0;   //  These dro registers count pulses delivered to stepper motor driver
+//        dro_output = true;
+    }
+    void    update  ()  {
+        static  long    t = 300;    //  Prevent display immediately upon startup
+        if  (millisecs < t)
+            return;
+//        if(!idle && dro_output)  {
+        if(!idle)  {
+            char    txt[12];
+            pc.printf("dros X %s,", readout(txt, x));    //  dro.n has running subtotal of all pulses issued to stepper driver.n
+            pc.printf(" Y %s, Z ", readout(txt, y));
+            pc.printf("%s, %s\r\n", readout(txt, z), running ? "R":"idle");
+            if(!running)    idle = true;    //  Purpose of idle flag is to stop dro updates JUST AFTER run completes.
+            t = millisecs + 350;    //  Schedule next update after this non-blocking delay
+        }
+    }
+}   dro_out ;   //  single instance of class digital_readout_stuff
+
+void    millisec_update_ISR ()  {
+    millisecs++;
+}
+
+/*#define STEP_IDLE_HI    //  Choose IDLE_HI or LO to suit any power save function of stepper motor drive units
+//#define STEP_IDLE_LO
+void    Numerically_Controlled_Oscillators_ISR ()  {   // services Ticker 'NCO_gen' generated interrupts ***ISR***
+    static  const   long    step_mask   = ASt | XSt | YSt | ZSt,    //  Added 6th Feb 14 Mask Does NOT include spindle bits
+                            dir_mask    = ADi | XDi | YDi | ZDi;    //  Added 6th Feb 14 Mask Does NOT include spindle bits
+    static  signed  long     //  27 Feb 14 changed from unsigned
+#if defined Fourth_Axis
+        acc_a   = 0L,        pir_a   = 0L,
+#endif
+        acc_x       = 0L,   //  acc Accumuloators
+        pir_x       = 0L,   //  pir Phase Increment Registers
+        acc_y       = 0L,        pir_y   = 0L,
+        acc_z       = 0L,        pir_z   = 0L,
+        acc_spin    = 0L,  //  separate acc for spindle rotation NCO
+        inc_x       = 1L,   //  inc_x, y, z for updating DRO registers
+        inc_y       = 1L,        inc_z   = 1L,
+        dir_bits    = 0L,  //  direction flags for up to four axes
+        oldSteps    = 0L;  //  
+    long tmp, newSteps = 0L;
+
+    intled = 1;     //  LED on for duration of interrupt service - point for scope probing
+    ticks++;        //  count of interrupts serviced, vital to time end of movement
+    charge_pumpD25pin1 = ticks & 0x01;  //  Can use 0x01 or 0x02 here to alter charge pump freq
+    tmp = Steppers ^ direction_swappers;
+#if defined STEP_IDLE_LO
+    tmp &= ~step_mask;   //  Step bits prepared for idle lo
+#endif
+#if defined STEP_IDLE_HI
+    tmp |= step_mask;   //  Step bits prepared for idle hi
+#endif
+    acc_spin += pir_spin;   //  Spindle NCO
+    if  (acc_spin < 0)  tmp |= SSt;
+    else                tmp &= ~SSt;
+    if  (!running)      Steppers = tmp ^ direction_swappers;    //  Axes not moving, spindle may be turning or not
+    else    {   //  running == true, Further manipulation of tmp follows, prior to rewriting to 'Steppers' IO Port
+//        newSteps = 0L;   //  Added 6th Feb 14
+#if defined Fourth_Axis
+        acc_a   += pir_a;
+        if  (acc_a < 0)    newSteps |= ASt;//  Added 6th Feb 14
+#endif
+        acc_x   += pir_x;     //  Update phase of signals in accumulators
+        if  (acc_x < 0)    newSteps |= XSt;//  Added 6th Feb 14
+        acc_y   += pir_y;
+        if  (acc_y < 0)    newSteps |= YSt;//  Added 6th Feb 14
+        acc_z   += pir_z;
+        if  (acc_z < 0)    newSteps |= ZSt;//  Added 6th Feb 14
+        //  newSteps has copy of all 4 'acc' MSBs shifted into port bit positions
+        oldSteps    ^= newSteps;  //  Any bit of stbits set to initiate a Step pulse
+        tmp         ^= oldSteps;
+        Steppers = tmp ^ direction_swappers; //  Output signals to stepper motor drivers, next update dros from 'clocked' bits CLOCK IDLES HIGH
+        if(oldSteps & XSt)  dro_out.x += inc_x;       //  got clk edge for axis X
+        if(oldSteps & YSt)  dro_out.y += inc_y;       //  got clk edge for axis Y
+        if(oldSteps & ZSt)  dro_out.z += inc_z;       //  got clk edge for axis Z
+        oldSteps    = newSteps;   //  Added 6th Feb 14
+        if  (tickrun <= ticks & !new_run_pending)   {   //  End of a machine movement detected, start next move here if possible
+                running = false;
+                move_ended = true;
+                pir_x = 0L; //  stop all stepper motors
+                pir_y = 0L;
+                pir_z = 0L;
+#if defined Fourth_Axis
+                pir_a = 0L;
+#endif
+    //          ticks = 0L; //  Simply to avoid having to think about overflow problems
+        }       //  end of if   (tickrun <= ticks)  {
+    }           //  end of else is   (running)   {
+    if  (!running & new_run_pending)  { //  Start axis movement
+        dir_bits= dir_bits_next;
+#if defined Fourth_Axis
+        pir_a   = pir_a_next;
+#endif
+        pir_x   = pir_x_next;
+        pir_y   = pir_y_next;
+        pir_z   = pir_z_next;
+        inc_x   = inc_x_next;
+        inc_y   = inc_y_next;
+        inc_z   = inc_z_next;
+        tmp     = Steppers ^ direction_swappers;  //  read output lines
+        tmp     &= ~dir_mask;
+        tmp     |= dir_bits;
+        Steppers = tmp ^ direction_swappers;
+        tickrun = ticks + ticks_next;
+        running = true;     //  Start the new run
+        new_run_pending = false;    //  Clear the flag which initiated this update
+        idle = false;
+    }       //  end of     else    {   //  Not running. Grab next data here when or if available
+    intled = 0;         //  LED off
+}           //  end of interrupt handler
+*/
+/*
+*   End of Interrupt Service Routine
+*/
+/*bool    spindle_running ()  {
+*/
+class   inputsreaderstuff   {
+    private:
+    long    ins_now;//,    ins_old,    ins_changed;
+    public:
+        void    init    ()  {   ins_now = 0L;}//ins_old = ins_changed = 0L;   }
+        long    read    ()  {
+            ins_now = 0;
+            if  (D25pin10_EStop)    ins_now |= ESTOP;
+            if  (D25pin11_XLim)     ins_now |= XLIM;
+            if  (D25pin12_YLim)     ins_now |= YLIM;
+            if  (D25pin13_ZLim)     ins_now |= ZLIM;
+            if  (D25pin15_unkn)     ins_now |= UNKN;
+//            ins_changed = ins_now ^ ins_old;
+//            ins_old = ins_now;
+            return  ins_now;
+        }
+//        long    changed ()  {   return  ins_changed;    }
+    }   Inputs_From_Machine;
+
+void    report_inputs   ()  {
+    long    i = Inputs_From_Machine.read();
+    pc.printf("Inputs: EStop %d, XLim %d, YLim %d, ", i & ESTOP ? 1:0, i & XLIM ? 1:0, i & YLIM ? 1:0);
+    pc.printf("ZLim %d, unkn %d\r\n", i & ZLIM ? 1:0, i & UNKN ? 1:0);
+}
+
+int main() {
+    long    ins, ins_old, ins_changed = 0;
+    pc.baud(BAUD); //  comms to 'PuTTY' serial terminal via mbed usb
+    spi.format  (8,0);          //  use 8 bit format for compatibility with Freescale KLxxZ
+    spi.frequency(12000000);    //  12MHz, fast enough
+    dro_out.init    ();
+    FPGA_setup();
+    pc.printf("\r\n*\n*\nFound Computer %s\r\n", Target);
+
+    msec.attach_us(&millisec_update_ISR, 1001);
+
+    Thread comlin (command_line_interpreter,    (void *)"cli"); //  Read any instructions arriving via serial port and act upon them
+//#if defined I2C_Enable
+//    Thread i2cstuff (i2c_handler, (void *)"i2c thing");
+//#endif
+    ins = ins_old = Inputs_From_Machine.read    ();
+    move_ended = true;  //  Needed to kickstart system
+    
+    while(1) {  //  Round Robin loop
+        dro_out.update  ();             //  Update DRO readings if, and as often as needed
+        ins = Inputs_From_Machine.read    ();
+        ins_changed = ins ^ ins_old;
+        ins_old = ins;
+        if  (ins_changed)
+            pc.printf("Inputs Have Changed 0x%x, read 0x%x\r\n", ins_changed, ins);
+        osThreadYield();                //
+    }   //  end of Round Robin loop
+}       //  end of int main()
+