Code for 'Smart Regulator' featured in 'Model Engineer', November 2020 on. Contains all work to August 2020 including all code described. Top level algorithm development is quite spares, leaving some work for you! Any questions - jon@jons-workshop.com

Dependencies:   mbed BufferedSerial Servo2 PCT2075 I2CEeprom FastPWM

Files at this revision

API Documentation at this revision

Comitter:
JonFreeman
Date:
Mon Jun 08 13:46:52 2020 +0000
Parent:
1:450090bdb6f4
Child:
3:43cb067ecd00
Commit message:
About to revamp i2c

Changed in this revision

Alternator.h Show annotated file Show diff for this revision Revisions of this file
FastPWM.lib Show annotated file Show diff for this revision Revisions of this file
cli.cpp Show annotated file Show diff for this revision Revisions of this file
i2c_bit_banged.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
--- a/Alternator.h	Sat Apr 25 15:35:58 2020 +0000
+++ b/Alternator.h	Mon Jun 08 13:46:52 2020 +0000
@@ -1,38 +1,34 @@
 #include    "Servo.h"
 #include    "BufferedSerial.h"
 
-#define SPEED_CONTROL_ENABLE    //  Includes engine revs servo control loop
+//#define SPEED_CONTROL_ENABLE    //  Includes engine revs servo control loop
 
-const   int TICKOVER_RPM = 2500;
-const   int MAX_RPM_LIMIT = 7500;
-const   double SERVO_MAX = 0.5;
-const   int eeprom_page = 17;   //  Determines where in eeprom 'settings' reside
+const   uint32_t    TICKOVER_RPM = 2500;
+const   uint32_t    PWM_OFF_RPM_LIMIT = (TICKOVER_RPM * 9) / 10;
+const   uint32_t    MAX_RPM_LIMIT = 7500;
+const   double      MAX_FIELD_PWM = 0.47;
+const   double      SERVO_MAX = 0.5;
+const   double      DRIVER_NEUTRAL = 0.18;
+const   uint32_t    eeprom_page = 17;   //  Determines where in eeprom 'settings' reside
 
-const   int lut_seg_size    =   60; //  steps per thousand RPM
-const   int lut_size = lut_seg_size * 8;    //  8 segments - 0-1, 1-2, 2-3, 3-4 etc 000 rpm
+//const   int lut_seg_size    =   60; //  steps per thousand RPM
+//const   int lut_size = lut_seg_size * 8;    //  8 segments - 0-1, 1-2, 2-3, 3-4 etc 000 rpm
 
 class   VEXT_Data   {
     public:
-    uint32_t    t_on, t_off, measured_pw_us, measured_period, rise_count, fall_count;
+    uint64_t    t_on, t_off, measured_pw_us, measured_period, rise_count, fall_count;
     double      duty_cycle  ()  {
         return  (double) measured_pw_us / (double) measured_period;
     }   ;
     VEXT_Data   ()  {   //  constructor
-        t_on = t_off = measured_pw_us =  measured_period = rise_count = fall_count = 0;
+        t_on = t_off = measured_pw_us =  measured_period = rise_count = fall_count = 0L;
     }   ;
 }   ;
 
 class   eeprom_settings {
     char        settings    [36];
-    double      max_pwm_lut [lut_size + 4];
-//    bool        rd_24LC64  (int start_addr, char * dest, int length)    ;
-//    bool        wr_24LC64  (int start_addr, char * dest, int length)    ;
-//    bool        set_24LC64_internal_address (int    start_addr) ;
-//    bool        ack_poll    ()  ;
-    void        build_lut   ()  ;
   public:
     eeprom_settings (); //  Constructor
-    double      get_pwm (int)   ;
     char        rd  (uint32_t)  ;           //  Read one setup char value from private buffer 'settings'
     bool        rd  (char *, uint32_t)  ;           //  Read one setup char value from private buffer 'settings'
     bool        wr  (char, uint32_t)  ;     //  Write one setup char value to private buffer 'settings'
@@ -50,12 +46,12 @@
     const char * t;     //  description
 }   ;
 
-const   int MAX_PARAMS = 10;
+const   int MAX_PARAMS = 12;    //  Up from 10 May 2020
 struct  parameters  {
     int32_t times[50];
     int32_t position_in_list, last_time, numof_dbls;
     double  dbl[MAX_PARAMS];
 }   ;
 
-const   int PWM_PERIOD_US = 2400    ;
+const   int PWM_PERIOD_US = 1800    ;   //  Was 2400, May want to reduce this, note would require change of resistor value on board
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FastPWM.lib	Mon Jun 08 13:46:52 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/Sissors/code/FastPWM/#d6c2b73d71f5
--- a/cli.cpp	Sat Apr 25 15:35:58 2020 +0000
+++ b/cli.cpp	Mon Jun 08 13:46:52 2020 +0000
@@ -15,11 +15,11 @@
 
 //extern  int ver, vef, measured_pw_us;
 extern  void    set_throttle_limit    (struct parameters & a)    ;
-extern  void    speed_control_factor_set    (struct parameters & a)    ;
+//extern  void    speed_control_factor_set    (struct parameters & a)    ;
 extern  void    query_system    (struct parameters & a)    ;
 extern  uint32_t    ReadEngineRPM  ()   ;
 extern  double  Read_BatteryVolts   ()  ;
-extern  void Read_Ammeter   (double *)  ;
+//extern  void Read_Ammeter   (double *)  ;
 
 
 
@@ -34,6 +34,32 @@
 extern  BufferedSerial pc;
 #endif
 //extern  double  test_pot;    //  These used in knifeandfork code testing only
+extern  void    maketable   ()  ;
+
+void    table_tweak_cmd   (struct parameters & a)   {     //  Requires two params. First '20', '25' etc representing hundreds RPM. Second 0 to 99 percent
+    char    txt[100];
+    uint32_t    d[3];
+    txt[0] = 0;
+    if  (a.numof_dbls != 2) 
+        sprintf   (txt, "Need 2 params, got %d, ", a.numof_dbls);
+    else    {
+        d[2] = (uint32_t)a.dbl[0];
+        d[0] = d[2] / 5;
+        d[1] = (uint32_t)a.dbl[1];
+        if  (d[0] > 16 || d[1] > 99 || d[2] != d[0] * 5)
+            sprintf (txt + strlen(txt), "Param out of range %d, %d, ", d[2], d[1]);
+        else    {
+            pc.printf   ("Off to reset table %d RPM, %d percent\r\n", d[2] * 100, d[1]);
+            user_settings.wr    ((char)d[1], d[0]);
+            user_settings.save  ();
+            maketable   ();
+        }
+    }
+    if  (txt[0])
+        pc.printf   ("Errors in table_tweak_cmd - %s\r\n", txt);
+    else
+        pc.printf   ("Good in table_tweak_cmd, RPM=%d, percentage=%d\r\n", d[0] * 500, d[1]);
+}
 
 //extern  int numof_eeprom_options2    ;
 //extern  struct  optpar const option_list2[]  ;
@@ -97,38 +123,39 @@
 
 }
 
-void    gpcmd   (struct parameters & a)   {
+/*void    gpcmd   (struct parameters & a)   {
     pc.printf   ("pwm=%.3f\r\n", user_settings.get_pwm    ((int)a.dbl[0]));
-}
+}*/
 
 extern  VEXT_Data   Field;
 
-void    rfcmd   (struct parameters & a)   {
-    pc.printf   ("Field.measured_period = %d, Field.measured_pw_us = %d, duty_cycle = %.3f\r\n", Field.measured_period, Field.measured_pw_us, Field.duty_cycle());
+void    rfcmd   (struct parameters & a)   {     //  Note casts all wrong here, values are 64 bit
+    pc.printf   ("Field.measured_period = %u", (uint32_t)Field.measured_period);
+    pc.printf   (", Field.measured_pw_us = %u, duty_cycle = %.3f\r\n", (uint32_t)Field.measured_pw_us, Field.duty_cycle());
 }
 
-extern  void    set_RPM_demand  (uint32_t   d)  ;
+//extern  void    set_RPM_demand  (uint32_t   d)  ;
 
-void    set_rpm_cmd   (struct parameters & a)   {
+/*void    set_rpm_cmd   (struct parameters & a)   {
     pc.printf   ("setting RPM to %d\r\n",(int)a.dbl[0]);
     set_RPM_demand  ((uint32_t)a.dbl[0]);
-}
+}*/
 
-void    speedcmd   (struct parameters & a)   {
+/*void    speedcmd   (struct parameters & a)   {
     int s = ReadEngineRPM  ();
     pc.printf   ("speed %d, pwm %.3f\r\n", s, user_settings.get_pwm(s));
-}
+}*/
 
 void    vcmd    (struct parameters & a)   {
     pc.printf   ("volts %.2f\r\n", Read_BatteryVolts());
 }
 
-void    icmd    (struct parameters & a)   {
+/*void    icmd    (struct parameters & a)   {
     double  results[4];
     //double * ampsptr = 
     Read_Ammeter(results)   ;
     pc.printf   ("amps %.3f, offset %.3f\r\n", results[0], results[1]);
-}
+}*/
 
 extern  void    set_servo   (double p)  ;   //  Only for test, called from cli
 
@@ -159,20 +186,21 @@
 
 struct  kb_command const command_list[] = {
     {"?", "Lists available commands, same as ls", menucmd},
+    {"tt", "Table Tweak - 2 params RPM/100, percentage 0-99", table_tweak_cmd},
     {"rf", "Check rise and fall on VEXT", rfcmd},
-    {"s", "Speed, RPM", speedcmd},
+//    {"s", "Speed, RPM", speedcmd},
     {"v", "Read Battery volts", vcmd},
-    {"i", "Read Ammeter", icmd},
+//    {"i", "Read Ammeter", icmd},
     {"p", "Set PWM 0 to 2400???", p_cmd},
     {"q", "Query system - toggle message stream on/off", query_system},
-    {"gp","Get pwm from RPM", gpcmd},
+//    {"gp","Get pwm from RPM", gpcmd},
     {"mode", "See or set eeprom values", mode19_cmd},
     {"nu", "do nothing", null_cmd},
 #ifndef SPEED_CONTROL_ENABLE    //  Includes engine revs servo control loop
     {"ser","set throttle servo direct 0 - 99", set_servo_cmd},
 #endif
-    {"sf","set speed control factor", speed_control_factor_set},
-    {"sv","set engine RPM demand 2500 - 6000", set_rpm_cmd},
+//    {"sf","set speed control factor", speed_control_factor_set},
+//    {"sv","set engine RPM demand 2500 - 6000", set_rpm_cmd},
     {"tl","set throttle_limit 0.0-1.0", set_throttle_limit},
 };
 
--- a/i2c_bit_banged.cpp	Sat Apr 25 15:35:58 2020 +0000
+++ b/i2c_bit_banged.cpp	Mon Jun 08 13:46:52 2020 +0000
@@ -1,6 +1,16 @@
 #include "mbed.h"
 #include "Alternator.h"
+
+#define I2CTEST
+
 #ifdef  TARGET_NUCLEO_L432KC    //
+#ifdef  I2CTEST
+extern  Serial  pc;
+extern  I2C i2c;
+const int ACK     = 1;  //  but acknowledge is 0, NAK is 1 6/6/2020 think this should be 1
+
+#else
+
 extern  Serial  pc;
 DigitalInOut    SDA (D4);       //  Horrible bodge to get i2c working using bit banging.
 DigitalInOut    SCL (D5);       //  DigitalInOut do not work as you might expect. Fine if used only as OpenDrain opuputs though!
@@ -13,6 +23,7 @@
 extern  I2C i2c;
 const int ACK     = 1;  //  but acknowledge is 0, NAK is 1
 #endif
+#endif
 const int _24LC_rd = 0xa1;  //  set bit 0 for read, clear bit 0 for write
 const int _24LC_wr = 0xa0;  //  set bit 0 for read, clear bit 0 for write
 
@@ -22,20 +33,35 @@
     const char * t;     //  description
 }   ;*/
 struct  optpar option_list2[] = {
-    {0, 100, 10, "max pwm% @ Eng RPM 0, 0 to 100"},
-    {0, 100, 10, "max pwm% @ Eng RPM 1000, 0 to 100"},
-    {0, 100, 20, "max pwm% @ Eng RPM 2000, 0 to 100"},
-    {0, 100, 30, "max pwm% @ Eng RPM 3000, 0 to 100"},
-    {0, 100, 40, "max pwm% @ Eng RPM 4000, 0 to 100"},
-    {0, 100, 50, "max pwm% @ Eng RPM 5000, 0 to 100"},
-    {0, 100, 50, "max pwm% @ Eng RPM 6000, 0 to 100"},
-    {0, 100, 50, "max pwm% @ Eng RPM 7000, 0 to 100"},
-    {0, 100, 50, "max pwm% @ Eng RPM 8000, 0 to 100"},
-    {0, 100, 50, "Set Overall PWM Scale Factor percent"},
+    {0, 100, 1, "max pwm% @ Eng RPM 0, 0 to 100"},
+    {0, 100, 1, "max pwm% @ Eng RPM 500, 0 to 100"},
+    {0, 100, 1, "max pwm% @ Eng RPM 1000, 0 to 100"},
+    {0, 100, 1, "max pwm% @ Eng RPM 1500, 0 to 100"},
+    {0, 100, 1, "max pwm% @ Eng RPM 2000, 0 to 100"},
+    {0, 100, 10, "max pwm% @ Eng RPM 2500, 0 to 100"},
+    {0, 100, 60, "max pwm% @ Eng RPM 3000, 0 to 100"},
+    {0, 100, 70, "max pwm% @ Eng RPM 3500, 0 to 100"},
+    {0, 100, 60, "max pwm% @ Eng RPM 4000, 0 to 100"},
+    {0, 100, 50, "max pwm% @ Eng RPM 4500, 0 to 100"},
+    {0, 100, 40, "max pwm% @ Eng RPM 5000, 0 to 100"},
+    {0, 100, 33, "max pwm% @ Eng RPM 5500, 0 to 100"},
+    {0, 100, 30, "max pwm% @ Eng RPM 6000, 0 to 100"},
+    {0, 100, 30, "max pwm% @ Eng RPM 6500, 0 to 100"},
+    {0, 100, 40, "max pwm% @ Eng RPM 7000, 0 to 100"},
+    {0, 100, 50, "max pwm% @ Eng RPM 7500, 0 to 100"},
+    {0, 100, 60, "max pwm% @ Eng RPM 8000, 0 to 100"},
     {0, 100, 0, "Future 2"},
     {0, 100, 0, "Future 3"},
     {0, 100, 0, "Future 4"},
     {0, 100, 0, "Future 5"},
+    {0, 100, 0, "Future 6"},
+    {0, 100, 0, "Future 7"},
+    {0, 100, 0, "Future 8"},
+    {0, 100, 0, "Future 9"},
+    {0, 100, 0, "Future 10"},
+    {0, 100, 0, "Future 11"},
+    {0, 100, 0, "Future 12"},
+    {0, 100, 0, "Future 13"},
 }   ;
 
 const   int    numof_eeprom_options2    = sizeof(option_list2) / sizeof (struct optpar);
@@ -79,16 +105,16 @@
     return  true;
 }
 
-double  eeprom_settings::get_pwm (int rpm)   {
+/*double  eeprom_settings::get_pwm (int rpm)   {
     int p = rpm * lut_size;
     p /= 8000;  //  8000 is upper RPM limit, p now scaled to sizeof lut
     if  (p < 0) p = 0;                    //  point to first
     if  (p >= lut_size) p = lut_size - 1; //  point to last
 //    pc.printf   ("In get_pwm, rpm = %d, lut entry = %d, pwm = %d\r\n", rpm, p, max_pwm_lut[p]);
     return  max_pwm_lut[p];
-}
+}*/
 
-void    eeprom_settings::build_lut   ()  {
+/*void    eeprom_settings::build_lut   ()  {
     int ptr = 0;
     int range, i;
     double  acc = 0.0, incr = 0.0;
@@ -114,12 +140,12 @@
     }
     pc.printf   ("lut_size = %d\r\n", lut_size);
 
-}
+}*/
 
 bool    eeprom_settings::load    ()  {               //  Get 'settings' buffer from EEPROM
     bool    rv  ;
     rv =    rd_24LC64   (eeprom_page * 32, settings, 32);   //  Can now build lookup table
-    build_lut   ();
+//Apr2020    build_lut   ();
     return  rv;
 }
 
@@ -139,6 +165,7 @@
 */
 bool    i2c_init(void) {
 #ifdef  TARGET_NUCLEO_L432KC    //
+#ifndef I2CTEST
     SDA.output();
     SCL.output();
     SDA.mode(OpenDrain);
@@ -151,12 +178,12 @@
     SCL = 1;
     wait_us (1);
     if  (SCL_IN == 0 || SDA_IN == 0)    return  false;
-  return true;
+#endif
 #endif
 #ifdef  TARGET_NUCLEO_F401RE    //
 //    return  i2c.init    ()  ; //  class has no member "init"
+#endif
     return  true;
-#endif
 }
 
 /**
@@ -171,6 +198,7 @@
 */
 int i2c_start  ()  {   // Should be Both hi, start takes SDA low
 #ifdef  TARGET_NUCLEO_L432KC    //
+#ifndef I2CTEST
     int    rv = 0;
     if  (SDA_IN == 0 )  {
         rv |= 1;    //  Fault - SDA was lo on entry
@@ -187,6 +215,11 @@
     SCL = 0;
     wait_us (1);
     return  rv;     //  Returns 0 on success, 1 with SDA fault, 2 with SCL fault, 3 with SDA and SCL fault
+#else
+    i2c.start   ()  ;
+    return  0;
+
+#endif
 #endif
 #ifdef  TARGET_NUCLEO_F401RE    //
     i2c.start   ()  ;
@@ -206,6 +239,10 @@
 */
 int i2c_stop  ()  {   //  Should be SDA=0, SCL=1, start takes SDA hi
 #ifdef  TARGET_NUCLEO_L432KC    //
+#ifdef  I2CTEST
+    i2c.stop    ()  ;
+    return  0;
+#else
     int    rv = 0;
     SDA = 0;    //  Pull SDA to 0
     wait_us (1);
@@ -224,6 +261,7 @@
         pc.printf   ("SDA stuck lo in stop\r\n");
     return  rv;     //  Returns 0 on success, 1 with SDA fault, 2 with SCL fault, 3 with SDA and SCL fault
 #endif
+#endif
 #ifdef  TARGET_NUCLEO_F401RE    //
     i2c.stop    ()  ;
     return  0;
@@ -231,6 +269,7 @@
 }
 
 #ifdef  TARGET_NUCLEO_L432KC    //
+#ifndef I2CTEST
 void    jclk    (int bit)   {
     SCL = bit;
     wait_us (1);
@@ -244,9 +283,13 @@
     wait_us (1);
 }
 #endif
+#endif
 
 int i2c_write (int    d)  {
 #ifdef  TARGET_NUCLEO_L432KC    //
+#ifdef  I2CTEST
+    return  i2c.write   (d);
+#else
     int ackbit = 0;
     if  (SCL_IN != 0)   {
         pc.printf   ("SCL hi on entry to write\r\n");
@@ -264,6 +307,7 @@
 //    pc.printf   ("wr 0x%x %s\r\n", d, ackbit == 0 ? "ACK" : "nak");
     return  ackbit; //      0 for acknowledged ACK, 1 for NAK
 #endif
+#endif
 #ifdef  TARGET_NUCLEO_F401RE    //
     return  i2c.write   (d);
 #endif
@@ -274,6 +318,9 @@
 
 int i2c_read    (int acknak)  {     //  acknak  indicates if the byte is to be acknowledged (0 = acknowledge)
 #ifdef  TARGET_NUCLEO_L432KC    //
+#ifdef  I2CTEST
+    return  i2c.read    (acknak)    ;
+#else
     int result = 0;                 //  SCL should be 1 on entry
     SDA = 1;        //  Master released SDA
     if  (SCL_IN != 0)   pc.printf   ("SCL hi arriving at read\r\n");
@@ -292,6 +339,7 @@
 //    pc.printf   ("rd 0x%x %s\r\n", result, acknak == 0 ? "ACK" : "nak");
     return  result;             //  Always ? nah
 #endif
+#endif
 #ifdef  TARGET_NUCLEO_F401RE    //
     return  i2c.read    (acknak)    ;
 #endif
--- a/main.cpp	Sat Apr 25 15:35:58 2020 +0000
+++ b/main.cpp	Mon Jun 08 13:46:52 2020 +0000
@@ -1,6 +1,14 @@
 #include "mbed.h"
 #include "Alternator.h"
-
+/*
+Test 6th June 2020 - i2c sda=grey, scl=white
+*/
+float  dpd = 0.0;
+/*
+    *   May 2020 NOTE input circuit to analogue in driver pot zeners input to 3v6, then pot reduces by about 1/3.
+    *   This makes input reading only about 0.0 to 0.66
+    *   Temp bodge, mult by 1.5
+*/
 
 /*
     Alternator Regulator
@@ -17,13 +25,11 @@
         Note only Field+ and MAX5035 supplied thus, all else powered from MAX outputs.
     Starting engine provides rectified tickle from magneto to enable MAX5035 creating +5 and +3v3 supplies.
     Alternative, selected by jumper pposition, is external switch - battery+ to MAX enable circuit.
-    Anytime engine revs measured < 2000 (or some such) RPM, field current OFF (by pwm 0)
+    Anytime engine revs measured < TICKOVER_RPM (or some such) RPM, field current OFF (by pwm 0)
     
     BEGIN
         Loop forever at 100 Hz   {
             Read engine RPM by monitoring engine tacho signal present on engine On/Off switch line
-            Read alternator output load current
-            Using RPM and current readings, regulate engine rpm via model control servo
             Adjust Alternator field current max limit according to RPM (analogue regulator limits output voltage)
             Measure system voltage (just in case this is ever useful)
             Respond to any commands arriving at serial port (setup and test link to laptop)
@@ -55,16 +61,20 @@
 DigitalIn       SCL_IN  (A5);   //  This works but is a pain. Inbuilt I2C should have worked but never does on small boards with 32 pin cpu.
 */
 Serial  pc      (USBTX, USBRX); //  Comms port to pc or terminal using USB lead
-BufferedSerial  LocalCom    (PA_9, PA_10);  //  New March 2019
+
+
+//BufferedSerial  LocalCom    (PA_9, PA_10);  //  New March 2019 - Taken out for i2c test 6/6/2020
+
+
 //  Above combo of Serial and BufferedSerial is the only one to work !
 
 //  INPUTS :
 AnalogIn    Ain_SystemVolts (A6);   //  Sniff of alternator output, not used in control loop as done using analogue MCP1630
-AnalogIn    Ammeter_In      (A1);   //  Output of ASC709LLFTR ammeter chip (pin 20), used to increase engine revs if need be
-AnalogIn    Ammeter_Ref     (A0);   //  Ref output from ASC709LLFTR used to set ammeter zero (pin 25)
+//AnalogIn    Ammeter_In      (A1);   //  Output of ASC709LLFTR ammeter chip (pin 20), used to increase engine revs if need be
+//AnalogIn    Ammeter_Ref     (A0);   //  Ref output from ASC709LLFTR used to set ammeter zero (pin 25)
 
 //  Nov 2019. Not convinced Ext_Rev_Demand is useful
-AnalogIn    Ext_Rev_Demand  (D3);   //  Servo determines engine revs, servo out to be higher of Ext_Rev_Demand and internal calc
+//AnalogIn    Ext_Rev_Demand  (D3);   //  Servo determines engine revs, servo out to be higher of Ext_Rev_Demand and internal calc
 
 AnalogIn    Driver_Pot      (A3);   //  If whole control system can be made to fit
 
@@ -102,6 +112,15 @@
 30  VIN         
 */
 
+//  Test 6/6/2020 to get i2c working
+//I2C i2c                     (D0, D1);   //  For 24LC64 eeprom
+//I2C i2c                     (D0, D1);   //  For 24LC64 eeprom
+
+I2C i2c                     (D0, D1);   //  For 24LC64 eeprom
+//I2C i2c                     (D1, D0);   //  For 24LC64 eeprom DEFINITELY WRONG
+//  Test 6/6/2020 to get i2c working
+
+
 InterruptIn pulse_tacho     (D9);  //  Signal from engine magneto (clipped by I limit resistor and 3v3 zener)
 InterruptIn VEXT            (D2);     //  PWM controller output folded back for cpu to monitor, useful on test to read what pwm required to do what
 //  OUTPUTS :
@@ -122,9 +141,9 @@
 
 //  INPUTS :
 AnalogIn    Ain_SystemVolts (PB_1);   //  Sniff of alternator output, not used in control loop as done using analogue MCP1630
-AnalogIn    Ammeter_In      (PC_5);   //  Output of ASC709LLFTR ammeter chip (pin 20), used to increase engine revs if need be
-AnalogIn    Ammeter_Ref     (PB_0);   //  Ref output from ASC709LLFTR used to set ammeter zero (pin 25)
-AnalogIn    Ext_Rev_Demand  (PC_1);   //  Servo determines engine revs, servo out to be higher of Ext_Rev_Demand and internal calc
+//AnalogIn    Ammeter_In      (PC_5);   //  Output of ASC709LLFTR ammeter chip (pin 20), used to increase engine revs if need be
+//AnalogIn    Ammeter_Ref     (PB_0);   //  Ref output from ASC709LLFTR used to set ammeter zero (pin 25)
+//AnalogIn    Ext_Rev_Demand  (PC_1);   //  Servo determines engine revs, servo out to be higher of Ext_Rev_Demand and internal calc
 AnalogIn    Driver_Pot      (PC_2);   //  If whole control system can be made to fit
 
 /*
@@ -149,29 +168,22 @@
 
 #endif
 
-Timer   microsecs;
+Timer   microsecs;      //  64 bit counter, rolls over in half million years
 Ticker  loop_timer;     //  Device to cause periodic interrupts, used to sync iterations of main programme loop - slow
 
-const   double  AMPS_CAL = 90.0;
+//const   double  AMPS_CAL = 90.0;
 extern  eeprom_settings user_settings  ;
 //  SYSTEM CONSTANTS
 /*  Please Do Not Alter these */
 const   int     MAIN_LOOP_REPEAT_TIME_US    = 10000;    //  10000 us, with TACHO_TAB_SIZE = 100 means tacho_ticks_per_time is tacho_ticks_per_second
 /*  End of Please Do Not Alter these */
 /*  Global variable declarations */
-uint32_t    //semaphore           = 0,
-            speed_control_factor= 75000,  //  fiddled from cli to tweak engine speed controller response
+uint32_t
             volt_reading        = 0,    //  Global updated by interrupt driven read of Battery Volts
-            ext_rev_req         = 0,
             driver_reading      = 0,
-            tacho_count         = 0,    //  Global incremented on each transition of InterruptIn pulse_tacho
+//            tacho_count         = 0,    //  Global incremented on each transition of InterruptIn pulse_tacho
             sys_timer100Hz      = 0;    //  gets incremented by our Ticker ISR every MAIN_LOOP_REPEAT_TIME_US
-double      amp_reading         = 0.0,
-            amp_offset          = 0.0,
-            raw_amp_reading     = 0.0,
-            raw_amp_offset      = 0.0;
 double      servo_position = 0.2;   //  set in speed control loop
-//    const double    throttle_limit = 0.4;
 double      throttle_limit = SERVO_MAX;
 bool        loop_flag   = false;    //  made true in ISR_loop_timer, picked up and made false again in main programme loop
 bool        flag_25Hz   = false;    //  As loop_flag but repeats 25 times per sec
@@ -179,7 +191,9 @@
 bool        flag_1Hz    = false;    //  As loop_flag but repeats 1 times per sec
 bool        query_toggle    = false;
 
-const int AMP_FILTER_FACTOR    = 6;
+bool        flag_V_rd   = false;
+bool        flag_Pot_rd = false;
+//const int AMP_FILTER_FACTOR    = 6;
 
 /*  End of Global variable declarations */
 
@@ -189,22 +203,24 @@
     Scope_probe = 1;    //  To show how much time spent in interrupt handler
     switch  (t) {
         case    0:
-            volt_reading    >>= 1;                                 //  Result = Result / 2
-            volt_reading    += Ain_SystemVolts.read_u16    ();     //  Result = Result + New Reading
+            flag_V_rd = true;
+//            volt_reading    >>= 1;                                 //  Result = Result / 2
+//            volt_reading    += Ain_SystemVolts.read_u16    ();     //  Result = Result + New Reading
             break;
-        case    1:
-            raw_amp_reading = (double) Ammeter_In.read();
-            break;
+//        case    1:
+//            raw_amp_reading = (double) Ammeter_In.read();
+//            break;
         case    2:
-            raw_amp_offset = Ammeter_Ref.read();    //  Feb 2020 Not convinced this is useful
+            flag_Pot_rd = true;
+//            raw_amp_offset = Ammeter_Ref.read();    //  Feb 2020 Not convinced this is useful
             break;
-        case    3:
-            ext_rev_req     >>= 1;                                 //  Result = Result / 2
-            ext_rev_req     += Ext_Rev_Demand.read_u16();
-            break;
+//        case    3:
+//            ext_rev_req     >>= 1;                                 //  Result = Result / 2
+//            ext_rev_req     += Ext_Rev_Demand.read_u16();
+//            break;
         case    4:
-            driver_reading  >>= 1;                                 //  Result = Result / 2
-            driver_reading  += Driver_Pot.read_u16();
+//            driver_reading  >>= 1;                                 //  Result = Result / 2
+//            driver_reading  += Driver_Pot.read_u16();
 //            break;
 //        case    5:
             loop_flag = true;   //  set flag to allow main programme loop to proceed
@@ -221,80 +237,11 @@
 }
 
 
-
-//  New stuff November 2019
-/**
-*   Obtaining Amps_Deliverable from RPM.
-*   Lucas workshop sheet shows exponential relationship between RPM over threshold, and Amps_Deliverable,
-*   That is Amps_Deliverable rises steeply with RPM, flattening off towards 6000 RPM
-*   Curve modeled by eqn
-*       I_del = I_max (1 - exp(-(RPM-3000)/Const1))       where Const1 = 1000 is a starting point
-*   This is probably fine when driving alternator with BIG engine.
-*   When using small engine, rising load current sags engine RPM.
-*   Using a linear relationship builds in a good safety margin, possible eqn
-*       I_del = I_max (RPM - 3000) / 3000     for use over RPM range 3000-6000
-*/
-const   double  RPM_Threshold   = 3000.0;
-const   double  RPM_Max         = 6000.0;
-//const   double  I_max = 30.0;
-const   double  RPM_Range   = RPM_Max - RPM_Threshold;
-//#define BIG_ENGINE
-
-double  Calculate_Amps_Deliverable (uint32_t RPM)  {
-    double r = (double)RPM - RPM_Threshold;
-    r /= RPM_Range;
-    if  (r < 0.0)
-        r = 0.0;
-    if  (r > 1.0)
-        r = 1.0;
-#ifdef  BIG_ENGINE
-    const   double  Const1 = -3.2;    //  Tweak this to adjust shape of exponential function
-    return  (1.0 - exp(r*Const1));
-#else
-    return  r;
-#endif
-}
-
-class   one_over_s_integrator   {   //  Need this to drive servo  Jan 2020 why?
-    double  internal_integral, max, min, Hz, gain;
-    public:
-    one_over_s_integrator   ()  {   internal_integral = 0.0; max = 1.0; min = -1.0; Hz = 100.0; gain = 1.0;}
-    double  integral    (double input)  ;
-    void    set_max (double)    ;
-    void    set_min (double)    ;
-    void    set_gain (double)    ;
-    void    set_sample_time (double)    ;
-}   ;
-
-void    one_over_s_integrator::set_max (double in)  {
-    max = in;
-}
-void    one_over_s_integrator::set_min (double in)  {
-    min = in;
-}
-void    one_over_s_integrator::set_gain (double in)  {
-    gain = in;
-}
-void    one_over_s_integrator::set_sample_time (double in)  {
-    Hz = 1.0 / in;
-}
-double  one_over_s_integrator::integral (double input)  {
-    internal_integral += gain * input / Hz;     //  100 for 100Hz update rate
-    if  (internal_integral > max)
-        internal_integral = max;
-    if  (internal_integral < min)
-        internal_integral = min;
-    return  internal_integral;
-}
-
-//double  one_over_s  ()
-//  End of New stuff November 2019
-
-
 //  New stuff June 2019
+//  Decent way of measuring engine speed
 bool    magneto_stretch = false;
 Timeout magneto_timo;
-uint32_t magneto_times[8] = {0,0,0,0,0,0,0,0};  //  June 2019, only 2 of these used
+uint64_t magneto_times[4] = {13543,0,0,0};  //  June 2019, only 2 of these used. Big non-zero prevents div0 error on first pass
 
 
 /**    
@@ -324,54 +271,27 @@
 */
 void    ISR_magneto_tacho   ()  //  This interrupt initiated by rising (or falling) edge of magneto output, (not both)
 {
-    if  (!magneto_stretch)
-    {
-        uint32_t    new_time = microsecs.read_us();
-        if  (new_time < magneto_times[1])      //  rollover detection
-            magneto_times[1] = 0;
+    uint64_t    new_time;
+    if  (!magneto_stretch)      //  May get this interrupt more than once per magneto pulse, respond to first, lock out subsequent
+    {                           //  until magneto_timeout time has elapsed
+        magneto_stretch = true;
+        new_time = microsecs.read_high_resolution_us();
         magneto_times[0] = new_time - magneto_times[1];    //  microsecs between most recent two sparks
         magneto_times[1] = new_time;    //  actual time microsecs of most recent spark
-        magneto_stretch = true;
         magneto_timo.attach_us (&magneto_timeout, 5000);    //  To ignore ringing and multiple counts on magneto output, all settled within about 5ms
-        tacho_count++;
         EngineTachoOut  = 1;    //  Cleaned tacho output brought out to pin to look at with scope
     }
 }
 
 //  Endof New stuff June 2019
 
-const   double  shrink = 0.2;
-/*double  lpf_4th_order_asym    (double input)  {
-*
-*   input is driver's control pot.
-*   This needs regular calling, maybe 8Hz - 32Hz
-*
-*   Output from 4th stage of cascaded Butterworth lpf section
-*   Used to delay rising input to motor controller allowing time for engine revs to rise
-*/
-double  lpf_4th_order_asym    (double input)  {
-    static  double  lpfs[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
-    if  (input < 0.0)   input = 0.0;
-    if  (input > 1.0)   input = 1.0;
-    lpfs[0] = input;    //  zeroth order filter
-    double tmp;
-    for (int order = 1; order < 5; order++) {
-        tmp = (lpfs[order] * (1.0 - shrink))
-              + (lpfs[order - 1] * shrink);
-        if  (tmp > input)
-            tmp = input;
-        lpfs[order] = tmp;
-    }
-    return  tmp;
-}
-
 
     VEXT_Data   Field;
 
 
 void    ISR_VEXT_rise    ()  //  InterruptIn interrupt service
 {   //  Here is possible to read back how regulator has controlled pwm - may or may not be useful
-    uint32_t    tmp = microsecs.read_us();
+    uint64_t    tmp = microsecs.read_high_resolution_us();
     Field.measured_period = tmp - Field.t_on;
     Field.t_on = tmp;
     Field.rise_count++;
@@ -379,7 +299,7 @@
 void    ISR_VEXT_fall    ()  //  InterruptIn interrupt service
 {
     Field.fall_count++;
-    Field.t_off = microsecs.read_us();
+    Field.t_off = microsecs.read_high_resolution_us();
     Field.measured_pw_us = Field.t_off - Field.t_on;
 }
 //  ****    End of Interrupt Service Routines   ****
@@ -392,7 +312,7 @@
 */
 uint32_t    ReadEngineRPM  ()
 {
-    uint32_t time_since_last_spark = microsecs.read_us() - magneto_times[1];
+    uint64_t time_since_last_spark = microsecs.read_high_resolution_us() - magneto_times[1];
     if  (time_since_last_spark > 250000)     //  if engine probably stopped, return old method RPM
         return  0;
     return  (60000000 / magneto_times[0]);  //  60 million / microsecs between two most recent sparks, eg 10,000us between sparks @ 6000 RPM
@@ -410,26 +330,11 @@
     return  rv / 4096.0;
 }
 
-double  Read_AlternatorAmps   ()
-{
-    int32_t diff    = amp_reading - amp_offset;
-    double  amps    = ((double) diff) / (1 << AMP_FILTER_FACTOR);
-    amps -= 365.0;  //  offset probably specific to particular board.
-    amps /= 1433.0;     //  fiddle factor
-    return  amps;
-}
-
 double  Read_BatteryVolts   ()
 {
     return  ((double) volt_reading) / 3282.5;    //  divisor fiddled to make voltage reading correct !
 }
 
-void    Read_Ammeter   (double * p)  
-{
-    p[0] = amp_reading;
-    p[1] = amp_offset;
-}
-
 /**
 void    set_servo   (double p)  {   //  Only for test, called from cli
 */
@@ -445,15 +350,36 @@
     return  * p;
 }
 
-uint32_t    RPM_demand = 0;         //  For test, set from cli 'sv'
-/**
+
+
+//const   double  DRIVER_NEUTRAL = 0.18;
+/**void    throttle_setter ()  {
+    *   
+    *   
+    *   
+    *   
+    *   
+    *   
 */
-void    set_RPM_demand  (uint32_t   d)  {
-    if  (d < 10)
-        d = 10;
-    if  (d > MAX_RPM_LIMIT)
-        d = MAX_RPM_LIMIT;
-    RPM_demand = d;
+void    throttle_setter ()  {
+//    double  Driver_demand = Read_Driver_Pot();
+    const   double  local_hysterics = 0.03;
+    static  double  most_recent_throttle = 0.0;
+    double  Driver_demand = dpd;
+//    pc.printf   ("Pot\t%.2f  \r\n", Driver_demand);
+//    pc.printf   ("Pot\t%d\t%.3f  \r\n", driver_reading, dpd);     //  Shown pot drives servo over full range.
+    if  (Driver_demand < DRIVER_NEUTRAL)    {   //  In braking or park
+        Throttle = 0.0;
+    }
+    else    {   //  Driving
+        Driver_demand -= DRIVER_NEUTRAL;
+        Driver_demand /= (1.0 - DRIVER_NEUTRAL);    //  Re-normalise what's left
+        if  ((most_recent_throttle - Driver_demand < -local_hysterics) || (most_recent_throttle - Driver_demand > local_hysterics))  {
+            Throttle = Driver_demand;
+            most_recent_throttle = Driver_demand;
+            servo_position = Driver_demand;         //  Copy to global for pc.printf only May 2020
+        }
+    }
 }
 
 /**void    set_pwm (double d)   {   Range 0.0 to 1.0
@@ -466,22 +392,24 @@
     This adjusts final PWM down to zero % as needed to maintain alternator output voltage.
 */
 void    set_pwm (double d)   {
+const   double    pwm_factor = MAX_FIELD_PWM * (double)PWM_PERIOD_US;
     uint32_t i;
     if  (d < 0.0)
         d = 0.0;
     if  (d > 1.0)
         d = 1.0;
-    i = (uint32_t)(d * (PWM_PERIOD_US / 2));   //  div 2 when using 12v alternator in 24v system
+//    i = (uint32_t)(d * (PWM_PERIOD_US / 2));   //  div 2 when using 12v alternator in 24v system
+    i = (uint32_t)(d * pwm_factor);   //  div 2 when using 12v alternator in 24v system
 //    pc.printf   ("Setting PWM to %d\r\n", i);
     PWM_OSC_IN.pulsewidth_us  (PWM_PERIOD_US - i);            //  Note PWM is inverted as MCP1630 uses inverted OSC_IN signal
 }
 
-void    speed_control_factor_set    (struct parameters & a)    {
+/*void    speed_control_factor_set    (struct parameters & a)    {
     uint32_t v = (uint32_t)a.dbl[0];
     if  (v > 10)
         speed_control_factor = v;
     pc.printf   ("speed_control_factor %d\r\n", speed_control_factor);
-}
+}*/
 
 void    set_throttle_limit    (struct parameters & a)    {
     if  (a.dbl[0] > 0.01 && a.dbl[0] < 1.001)
@@ -493,6 +421,103 @@
     query_toggle = !query_toggle;
 //    pc.printf   ("Stuff about current state of system\r\n");
 //    pc.printf   ("RPM=%d, servo%.2f\r\n", ReadEngineRPM  (), servo_position);
+//    pc.printf   ("RPM=%d\r\n", ReadEngineRPM  ());
+}
+
+    uint8_t     madetab[340];
+void    maketable   ()  {   //  Uses first 17 nums of user_settings relating to lim to be applied at 0, 500, 1000 --- 8000 RPM
+    double      tabvals[20];
+    double      diff, val = 0.0;
+    uint32_t    tabptr = 0;
+    for (int i = 0; i < 17; i++)    {
+        tabvals[i] = (double)user_settings.rd   (i);
+        pc.printf   ("%d\t%.0f\r\n", i*500, tabvals[i]);
+    }
+    for (int i = 1; i < 17; i++)    {
+        diff = tabvals[i] - tabvals[i - 1];
+        diff /= 20.0;   //  40 entries 25RPM apart per kRPM
+        for (int j = 0; j < 20; j++)    {
+//            pc.printf   ("%.0f\t", val);
+            madetab[tabptr++] = (uint8_t) val;
+            val += diff;
+        }
+    }
+    pc.printf   ("\r\nEnd of table creation with tabptr = %d\r\n", tabptr);
+    while   (tabptr < 340)
+        madetab[tabptr++] = (uint8_t) val;
+}
+
+
+/**void    set_pwm_limit   ()  {       //  May 2020
+    *   
+    *   Uses pure look up table to tailor pwm limit according to engine speed
+    *   
+    *   
+    *   
+    *   
+*/
+void    set_pwm_limit   (uint32_t    rpm)  {       //  May 2020
+//const   uint8_t    pwmtab  []  =   unsigned char array of percentages 0 to 99, spaced at 25RPM intervals
+/*const   uint8_t    pwmtab  []  =    {
+    02,02,02,02,02,02,02,02,  //  0   -   0175RPM   //  Slightly above 0 just to see signal on scope
+    02,02,02,02,02,02,02,02,  //  0200 -  0375RPM
+    02,02,02,02,02,02,02,02,  //  0400 -  0575RPM
+    02,02,02,02,02,02,02,02,  //  0600 -  0775RPM
+    02,02,02,02,02,02,02,02,  //  0800 -  0975RPM
+    02,02,02,02,02,02,02,02,  //  1000 -  1175RPM
+    02,02,02,02,02,02,02,02,  //  1200 -  1375RPM
+    02,02,02,02,02,02,02,02,  //  1400 -  1575RPM
+    02,03,04,05,06,07, 8, 9,  //  1600 -  1775RPM
+    10,11,12,13,14,15,16,17,  //  1800 -  1975RPM
+    18,19,20,21,22,23,24,25,  //  2000 -  2175RPM
+    26,27,28,29,30,31,32,33,  //  2200 -  2375RPM
+    34,35,36,37,38,39,40,40,  //  2400 -  2575RPM
+    41,41,41,42,42,42,43,43,  //  2600 -  2775RPM
+    43,44,44,44,45,45,45,46,  //  2800 -  2975RPM
+    46,46,47,47,47,48,48,48,  //  3000 -  3175RPM
+    49,49,49,50,50,50,51,51,  //  3200 -  3375RPM
+    52,52,52,53,53,53,54,54,  //  3400 -  3575RPM
+    54,55,55,55,56,56,56,57,  //  3600 -  3775RPM
+    57,57,58,58,58,59,59,59,  //  3800 -  3975RPM
+    60,60,60,61,61,61,62,62,  //  4000 -  4175RPM
+    62,63,63,63,64,64,64,65,  //  4200 -  4375RPM
+    65,65,66,66,66,67,67,67,  //  4400 -  4575RPM
+    68,68,68,69,69,69,70,70,  //  4600 -  4775RPM
+    71,71,72,72,73,73,74,74,  //  4800 -  4975RPM
+    75,75,76,76,77,77,78,78,  //  5000 -  5175RPM
+    79,79,80,80,81,81,82,82,  //  5200 -  5375RPM
+
+    83,83,84,84,85,85,86,86,  //  5400 -  5575RPM
+    87,87,88,88,89,89,90,90,  //  5600 -  5775RPM
+    91,91,92,92,93,93,94,94,  //  5800 -  5975RPM
+    95,95,96,96,97,97,98,98,  //  6000 -  6175RPM
+    99,99,99,99,99,99,99,99,  //  6200 -  6375RPM
+    99,99,99,99,99,99,99,99,  //  6400 -  6575RPM
+    99,99,99,99,99,99,99,99,  //  6600 -  6775RPM
+    99,99,99,99,99,99,99,99,  //  6800 -  6975RPM
+    99,99,99,99,99,99,99,99,  //  7000 -  7175RPM
+    99,99,99,99,99,99,99,99,  //  7200 -  7375RPM
+    99,99,99,99,99,99,99,99,  //  7400 -  7575RPM
+    99,99,99,99,99,99,99,99,  //  7600 -  7775RPM
+    99,99,99,99,99,99,99,99,  //  7800 -  7975RPM
+    99,99,99,99,99,99,99,99,  //  8000 -  8175RPM
+    }  ;
+*/
+//    uint32_t    rpm = ReadEngineRPM  ();
+    static  uint32_t    oldpcent = 1000;
+    uint32_t    index, pcent;
+    double  pwm = 0.0;
+    if  (rpm > 8000)
+        rpm = 8000;
+    index = rpm / 25;  //  to fit lut spacing of 25rpm intervals, turns rpm into index
+//    pcent = pwmtab[index];
+    pcent = madetab[index];
+    if  (pcent != oldpcent) {
+        oldpcent = pcent;
+        pwm = (double)pcent;
+        pwm /= 99.0;
+        set_pwm (pwm);
+    }
 }
 
 extern  void    command_line_interpreter    ()  ;   //  Comms with optional pc or device using serial port through board USB socket
@@ -502,15 +527,13 @@
 //  Programme Entry Point
 int main()
 {
+    const   double  filt = 0.2;
     //  local variable declarations
-//    double      servo_position = 0.2;   //  set in speed control loop
-    double      revs_error;
-    double      Amps_Deliverable = 0.0;     //  New Nov 2019
-//    double      tempfilt = 0.0, servo_fucker = 0.01;
+//    double      revs_error;
     
     int32_t    RPM_ave = 0, RPM_filt = 0, RPM_tmp;
-    int32_t irevs_error;
-    uint32_t ticks = 0;
+//    int32_t irevs_error;
+    uint32_t ticks25Hz = 0;
     
     pulse_tacho.fall        (&ISR_magneto_tacho); //    1 pulse per engine rev
     VEXT.rise               (&ISR_VEXT_rise);   //  Handles - MCP1630 has just turned mosfet on
@@ -521,14 +544,15 @@
     PWM_OSC_IN.period_us      (PWM_PERIOD_US); //  about 313Hz * 2
 //  PROBLEM using same pwm, common prescaler, can't update servo that fast, can't pwm field that slow.
 
-    PWM_OSC_IN.pulsewidth_us  (PWM_PERIOD_US / 2);            //  value is int
-//    PWM_OSC_IN.pulsewidth_us  (PWM_PERIOD_US);            //  value is int
+    set_pwm (0.02);     //  set_pwm(0.02) good for production. Set higher for test
+
 #ifdef  TARGET_NUCLEO_F401RE    //
     A_OUT.period_us     (100);  //  pwm as analogue out
     A_OUT.pulsewidth_us (19);
 #endif
     Throttle    = servo_position;
-    pc.printf   ("\r\n\n\n\n\nAlternator Regulator 2020, Jon Freeman, SystemCoreClock=%d\r\n", SystemCoreClock);
+//    pc.printf   ("\r\n\n\n\n\nAlternator Regulator 2020, Jon Freeman, SystemCoreClock=%d\r\n", SystemCoreClock);
+    pc.printf   ("\r\n\n\n\n\nAlternator Regulator 2020, Jon Freeman\r\n");
     if  (!i2c_init())
         pc.printf   ("i2c bus failed init\r\n");
     pc.printf   ("check_24LC64 returned 0x%x\r\n", check_24LC64());
@@ -537,10 +561,24 @@
     //  Setup Complete ! Can now start main control forever loop.
     loop_timer.attach_us    (&ISR_fast_interrupt, MAIN_LOOP_REPEAT_TIME_US / 10);    //  Start periodic interrupt generator 1000us at Feb 2020
 
+    maketable   ();
+
 //***** START OF MAIN LOOP
     while   (1) {      //  Loop forever, repeats synchroised by waiting for ticker Interrupt Service Routine to set 'loop_flag' true
         while   (!loop_flag)  {         //  Most of the time is spent in this loop, repeatedly re-checking for commands from pc port
             command_line_interpreter    ()  ;   //  Proceed beyond here once loop_timer ticker ISR has set loop_flag true
+            if  (flag_V_rd) {
+                flag_V_rd = false;
+                volt_reading    >>= 1;                                 //  Result = Result / 2
+                volt_reading    += Ain_SystemVolts.read_u16    ();     //  Result = Result + New Reading
+            }
+            if  (flag_Pot_rd)   {
+                flag_Pot_rd = false;
+                dpd *= (1.0 - filt);
+                dpd += filt * (Driver_Pot * 1.5);     //  Includes bodge around zener over-clipping input
+                driver_reading  >>= 1;                                 //  Result = Result / 2
+                driver_reading  += Driver_Pot.read_u16();
+            }
         }               //  Jun 2019 pass here 100 times per sec
 //  BEGIN 100Hz stuff
         loop_flag = false;              //  Clear flag set by ticker interrupt handler
@@ -550,21 +588,9 @@
         RPM_ave += RPM_tmp;     //  Rising sum needs dividing and resetting to 0 when used
         RPM_filt += RPM_tmp;
         RPM_filt >>= 1;
-        
-        amp_reading += (raw_amp_reading - 0.5) * AMPS_CAL;
-        amp_reading /= 2.0;
-        amp_offset  += (raw_amp_offset - 0.5) * AMPS_CAL;   //  This reading probably not useful
-        amp_offset /= 2.0;
-        
-        Amps_Deliverable = Calculate_Amps_Deliverable   (ReadEngineRPM  ());    //  Added Nov 2019, not yet used. Returns normalised 0.0 to 1.0
+
+        set_pwm_limit   (RPM_tmp);     //  according to RPM
         
-//        PWM_OSC_IN.pulsewidth_us  (user_settings.get_pwm(ReadEngineRPM()));    //  Update field current limit according to latest measured RPM
-
-//        while   (LocalCom.readable())   {
-//            int q = LocalCom.getc();
-//            //q++;
-//            pc.putc (q);
-//        }
 //  END 100Hz stuff
         if  (flag_25Hz)  {
             flag_25Hz = false;
@@ -574,7 +600,8 @@
 //  BEGIN   12.5Hz stuff
             flag_12Hz5 = !flag_12Hz5;
             if  (flag_12Hz5)  {   //  Do any even stuff to be done 12.5 times per second
-#ifdef  SPEED_CONTROL_ENABLE
+                throttle_setter();
+/*#ifdef  SPEED_CONTROL_ENABLE
                 if  (RPM_demand < TICKOVER_RPM)
                     servo_position = Throttle = 0.0;
                 else    {
@@ -594,35 +621,23 @@
                     }
                 }
                 RPM_ave = 0;    //  Reset needed
-#endif
+#endif  */
             }
             else    {               //  Do odd 12.5 times per sec stuff
                 flag_12Hz5  = false;
                 myled = !myled;
-                LocalCom.printf ("%d\r\n", volt_reading);
-    //void    set_pwm (double d)   {
-                
-    //            set_pwm (user_settings.get_pwm(ReadEngineRPM()));
-                
-    /*            servo_position += servo_fucker;
-                if  (servo_position > 1.0 || servo_position < 0.0)
-                    servo_fucker *= -1.0;
-                Throttle = servo_position;
-    */            
+//                LocalCom.printf ("%d\r\n", volt_reading);
             }   //  End of if(flag_12Hz5)
 //  END 12.5Hz stuff
-            ticks++;    //  advances @ 25Hz
-            if  (ticks > 24) {   //  once per sec stuff
+            ticks25Hz++;    //  advances @ 25Hz
+            if  (ticks25Hz > 24) {   //  once per sec stuff
 //  BEGIN   1Hz stuff
-                ticks = 0;
+                ticks25Hz = 0;
+//                secs++;
                 if  (query_toggle)  {
-                    pc.printf   ("V=%.1f\tI=%.1f\tRPM=%d\tservo%.2f\r\n", Read_BatteryVolts(), amp_reading, ReadEngineRPM  (), servo_position);
+                    pc.printf   ("V = %.2f\tRPM = %u\tservo%.2f    \r", Read_BatteryVolts(), /*amp_reading, */ReadEngineRPM  (), servo_position);
+//                    pc.printf   ("\tRPM = %u  (time %u seconds)      \r", ReadEngineRPM  (), (uint32_t)(microsecs.read_high_resolution_us() / 1000000));
                 }
-//                pc.printf   ("Tick %d\r\n", flag_12Hz5);
-//                tempfilt *= 0.99;
-//                tempfilt += Read_AlternatorAmps() * 0.01;
-//                pc.printf   ("RPM %d, err %.1f, s_p %.2f, lut %.3f\r\n", ReadEngineRPM  (), revs_error, servo_position, user_settings.get_pwm(ReadEngineRPM()));
-//                pc.printf   ("Vbat %.2f, servo %.3f, amps %.3f, filt %.3f\r\n", Read_BatteryVolts(), servo_position, Read_AlternatorAmps(), tempfilt);
 //  END 1Hz stuff
             }   //  eo once per second stuff
         }   //  End of 100Hz stuff