Dual Brushless Motor ESC, 10-62V, up to 50A per motor. Motors ganged or independent, multiple control input methods, cycle-by-cycle current limit, speed mode and torque mode control. Motors tiny to kW. Speed limit and other parameters easily set in firmware. As used in 'The Brushless Brutalist' locomotive - www.jons-workshop.com. See also Model Engineer magazine June-October 2019.

Dependencies:   mbed BufferedSerial Servo PCT2075 FastPWM

Update 17th August 2020 Radio control inputs completed

Files at this revision

API Documentation at this revision

Comitter:
JonFreeman
Date:
Sun Sep 29 16:34:37 2019 +0000
Parent:
12:d1d21a2941ef
Child:
14:acaa1add097b
Commit message:
Stable code as at end of 2019 running season

Changed in this revision

24LC64_eeprom.cpp Show annotated file Show diff for this revision Revisions of this file
DualBLS.h Show diff for this revision Revisions of this file
F401RE.h Show annotated file Show diff for this revision Revisions of this file
F411RE.h Show annotated file Show diff for this revision Revisions of this file
STM3_ESC.h Show annotated file Show diff for this revision Revisions of this file
brushless_motor.cpp Show annotated file Show diff for this revision Revisions of this file
brushless_motor.h Show annotated file Show diff for this revision Revisions of this file
cli_BLS_nortos.cpp Show annotated file Show diff for this revision Revisions of this file
error_handler.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/24LC64_eeprom.cpp	Mon Mar 04 17:51:08 2019 +0000
+++ b/24LC64_eeprom.cpp	Sun Sep 29 16:34:37 2019 +0000
@@ -1,5 +1,5 @@
 #include "mbed.h"
-#include "DualBLS.h"
+#include "STM3_ESC.h"
 #include "BufferedSerial.h"
 extern  BufferedSerial pc;
 extern  error_handling_Jan_2019     ESC_Error    ;         //  Provides array usable to store error codes.
@@ -195,7 +195,7 @@
         pc.printf   ("in wr_24LC64, device thought good, mem addr write worked, failed writing string\r\n");
         return  false;
     }
-    pc.printf   ("In wr_24LC64 No Errors Found!\r\n");
+//    pc.printf   ("In wr_24LC64 No Errors Found!\r\n");
     return  true;
 }
 
--- a/DualBLS.h	Mon Mar 04 17:51:08 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-#include "mbed.h"
-
-#ifndef MBED_DUALBLS_H
-#define MBED_DUALBLS_H
-
-//#define USING_DC_MOTORS     //  Uncomment this to play with Dinosaur DC motors
-
-#include "BufferedSerial.h"
-const   int     MOTOR_HANDBRAKE   = 0,
-                MOTOR_FORWARD     = 8,
-                MOTOR_REVERSE     = 16,
-                MOTOR_REGENBRAKE  = 24;
-
-const   int     TIMEOUT_SECONDS = 2;
-
-/*  Please Do Not Alter these */
-const   int     PWM_PRESECALER_DEFAULT      = 2,
-                VOLTAGE_READ_INTERVAL_US    = 50,       //  Interrupts timed every 50 micro sec, runs around loop performing 1 A-D conversion per pass
-                MAIN_LOOP_REPEAT_TIME_US    = 31250,    //  31250 us, with TACHO_TAB_SIZE = 32 means tacho_ticks_per_time is tacho_ticks_per_second
-                MAIN_LOOP_ITERATION_Hz      = 1000000 / MAIN_LOOP_REPEAT_TIME_US,
-//                CURRENT_SAMPLES_AVERAGED    = 100,     //  Current is spikey. Reading smoothed by using average of this many latest current readings
-                PWM_HZ              = 15000,    //  chosen to be above cutoff frequency of average human ear
-//                PWM_HZ              = 8000,    //  chosen to be above cutoff frequency of average human ear - clearly audible annoying noise
-                MAX_PWM_TICKS       = (SystemCoreClock / (PWM_HZ * PWM_PRESECALER_DEFAULT)),
-                TICKLE_TIMES    =   100 ,
-                WATCHDOG_RELOAD = (TIMEOUT_SECONDS * 8);    //  WatchDog counter ticked down in 8Hz loop
-
-/*  End of Please Do Not Alter these */
-const   double      PI      = 4.0 * atan(1.0),
-                    TWOPI   = 8.0 * atan(1.0);
-
-enum    {COM_SOURCES, COM1, COM2, HAND, RC_IN1, RC_IN2,THEEND}  ;
-
-enum    {MOTADIR, MOTBDIR, MOTAPOLES, MOTBPOLES, ISHUNTA, ISHUNTB, SVO1, SVO2, RCIN1, RCIN2, 
-            COMM_SRC, BOARD_ID, TOP_SPEED, WHEELDIA, MOTPIN, WHEELGEAR, 
-            FUT1, FUT2, FUT3, FUT4, FUT5}  ;  //  
-
-enum    {
-    FAULT_0,
-    FAULT_EEPROM,
-    FAULT_BOARD_ID,
-    FAULT_COM_LINE_LEN,
-    FAULT_COM_LINE_NOMATCH,
-    FAULT_COM_LINE_LEN_PC,
-    FAULT_COM_LINE_LEN_TS,
-    FAULT_COM_LINE_NOMATCH_PC,
-    FAULT_COM_LINE_NOMATCH_TS,
-    FAULT_UNRECOGNISED_STATE,
-    FAULT_MAX,
-    NUMOF_REPORTABLE_TS_ERRORS
-    }  ;
-
-class   error_handling_Jan_2019
-{
-    int32_t    ESC_fault[NUMOF_REPORTABLE_TS_ERRORS]    ;   //  Some number of reportable error codes, accessible through set and read members
-    public:
-    error_handling_Jan_2019 ()  {   //  default constructor
-        for (int i = 0; i < (sizeof(ESC_fault) / sizeof(int32_t)); i++)
-            ESC_fault[i] = 0;
-    }
-    void        set   (uint32_t, int32_t)   ;
-    void        clr     (uint32_t)  ;
-    uint32_t    read  (uint32_t)   ;
-    bool        all_good    ()  ;
-    void        report_any  (bool)  ;   //  retain ? true or false
-}   ;
-
-enum    {SOURCE_PC, SOURCE_TS}  ;
-const int   BROADCAST   = '\r';
-const   int MAX_PARAMS = 20;
-const   int MAX_CMD_LEN = 220;
-
-struct  parameters  {
-    struct kb_command const * command_list;
-    BufferedSerial * com;   //  pc or com2
-    int32_t position_in_list, numof_dbls, target_unit, source, numof_menu_items;
-    double  dbl[MAX_PARAMS];
-    bool    respond, resp_always;
-}   ;
-
-class   cli_2019    {
-    struct  kb_command const * commandlist ;
-    int     clindex;
-    char    cmdline[MAX_CMD_LEN + 8];
-    char    * cmdline_ptr;
-    parameters  a   ;
-public:
-    cli_2019    (BufferedSerial * comport, kb_command const * list, int list_len, int source)  {
-        a.com           = comport ;
-        a.command_list = commandlist  = list  ;
-        a.numof_menu_items  = list_len  ;
-        a.source        = source    ;
-        cmdline_ptr = cmdline;
-        clindex    = 0;
-        if  (source == SOURCE_PC)
-            a.resp_always = true;
-        else
-            a.resp_always = false;
-    }  ;
-    void    core   ()  ;
-    void    test   ()  ;
-}   ;
-
-class   eeprom_settings {
-    I2C i2c;
-    uint32_t    errors;
-    char        settings    [36];
-    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    ()  ;
-  public:
-    eeprom_settings (PinName sda, PinName scl); //  Constructor
-    char        rd  (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'
-    bool        save    ()  ;               //  Write 'settings' buffer to EEPROM
-    bool        set_defaults    ();         //  Put default settings into EEPROM and local buffer
-    uint32_t    errs    ()  ;               //  Return errors
-}   ;
-
-
-
-
-#endif
-
--- a/F401RE.h	Mon Mar 04 17:51:08 2019 +0000
+++ b/F401RE.h	Sun Sep 29 16:34:37 2019 +0000
@@ -1,3 +1,4 @@
+#include    "STM3_ESC.h"
 //  Feb 2018 Now using DGD21032 mosfet drivers via 74HC00 pwm gates (low side) - GOOD, works well with auto-tickle of high side drivers
 
 //  Jan 2019    Trying to add two Radio Control inputs on PC_14 and PC_15, previously connected to unused LF Xtal. 
@@ -71,8 +72,9 @@
 //  Pin 1   VBAT    NET +3V3
 
 //DigitalIn   J3         (PC_13, PullUp);//  Pin 2   Jumper pulls to GND, R floats Hi
+#ifdef  TEMP_SENSOR_ENABLE
 InterruptIn   Temperature_pin   (PC_13);//  Pin 2   June 2018 - taken for temperature sensor - hard wired to T1 due to wrong thought T1 could be InterruptIn
-
+#endif
 
 //  Pin 3   PC14-OSC32_IN   NET O32I    Xtal chucked off these pins, now needed for RC inputs
 //  Pin 4   PC15-OSC32_OUT  NET O32O
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/F411RE.h	Sun Sep 29 16:34:37 2019 +0000
@@ -0,0 +1,187 @@
+#include    "STM3_ESC.h"
+//  Feb 2018 Now using DGD21032 mosfet drivers via 74HC00 pwm gates (low side) - GOOD, works well with auto-tickle of high side drivers
+
+//  Jan 2019    Trying to add two Radio Control inputs on PC_14 and PC_15, previously connected to unused LF Xtal. 
+//              Problem - Appears to conflict with serial port used for comms with controller
+//              Earlier efforts to use 'Servo' ports as 'you choose' between I/O failed as pins not capable of use as 'InterruptIn'
+
+//  CORRECTION  Comms problem with Touch Screen was insufficient pull-up on STM3_ESC opto. Change R12 from 1k to 470R
+
+//                  Experiment disabling RC inputs to see if clearing serial conflict is possible
+
+
+//  Port A -> MotorA, Port B -> MotorB
+const   uint16_t
+//  This is where port bits get assigned to motor output phase switches.
+//  Phases are U, V and W.
+//  Each phase uses two bits, one for the low side switch, one for the high side switch.
+//MotorN_port_bits[] =  {UL, VL, WL, UH, VH, WH},   //  Order must be as shown - 3 low side switches U,V,W followed by 3 high side switches U,V,W
+MotorA_port_bits[] =    {0,  6,  4,  1,  7,  8},    //  List of port A bits used to drive motor A UL, VL, WL, UH, VH, WH
+MotorB_port_bits[] =    {0,  1,  2, 10, 12, 13},    //  List of port B bits used to drive motor B UL, VL, WL, UH, VH, WH
+//  Using port bit info in the two lines above, the compiler sorts all this into creation of lookup table
+//  to provide correct energisation sequencing as motors rotate.
+//  You need concern yourself no further about any of this.
+
+
+AUL = (1 << MotorA_port_bits[0]),
+AVL = (1 << MotorA_port_bits[1]),   //  These are which port bits connect to which mosfet driver
+AWL = (1 << MotorA_port_bits[2]),
+
+AUH = (1 << MotorA_port_bits[3]),
+AVH = (1 << MotorA_port_bits[4]),
+AWH = (1 << MotorA_port_bits[5]),
+
+AUHVL =   AUH | AVL,  //  Each of 6 possible output energisations made up of one hi and one low
+AVHUL =   AVH | AUL,
+AUHWL =   AUH | AWL,
+AWHUL =   AWH | AUL,
+AVHWL =   AVH | AWL,
+AWHVL =   AWH | AVL,
+
+KEEP_L_MASK_A   = AUL | AVL | AWL,
+KEEP_H_MASK_A   = AUH | AVH | AWH,
+
+BRA = AUL | AVL | AWL,  //  All low side switches on (and all high side off) for braking
+
+BUL = (1 << MotorB_port_bits[0]),   //  Likewise for MotorB but different port bits on different port
+BVL = (1 << MotorB_port_bits[1]),
+BWL = (1 << MotorB_port_bits[2]),
+
+BUH = (1 << MotorB_port_bits[3]),
+BVH = (1 << MotorB_port_bits[4]),
+BWH = (1 << MotorB_port_bits[5]),
+
+BUHVL =   BUH | BVL,
+BVHUL =   BVH | BUL,
+BUHWL =   BUH | BWL,
+BWHUL =   BWH | BUL,
+BVHWL =   BVH | BWL,
+BWHVL =   BWH | BVL,
+
+KEEP_L_MASK_B   = BUL | BVL | BWL,
+KEEP_H_MASK_B   = BUH | BVH | BWH,
+
+BRB = BUL | BVL | BWL,
+
+PORT_A_MASK = AUL | AVL | AWL | AUH | AVH | AWH,            //  NEW METHOD FOR DGD21032 MOSFET DRIVERS
+PORT_B_MASK = BUL | BVL | BWL | BUH | BVH | BWH;
+
+//PortOut MotA    (PortA, PORT_A_MASK);   //  Activate output ports to motor drivers
+//PortOut MotB    (PortB, PORT_B_MASK);
+
+//  Pin 1   VBAT    NET +3V3
+
+//DigitalIn   J3         (PC_13, PullUp);//  Pin 2   Jumper pulls to GND, R floats Hi
+#ifdef  TEMP_SENSOR_ENABLE
+InterruptIn   Temperature_pin   (PC_13);//  Pin 2   June 2018 - taken for temperature sensor - hard wired to T1 due to wrong thought T1 could be InterruptIn
+#endif
+
+//  Pin 3   PC14-OSC32_IN   NET O32I    Xtal chucked off these pins, now needed for RC inputs
+//  Pin 4   PC15-OSC32_OUT  NET O32O
+//  Pin 5   PH0-OSC_IN      NET PH1
+//  Pin 6   PH1-OSC_OUT     NET PH1
+//  Pin 7   NRST            NET NRST
+AnalogIn    Ain_DriverPot   (PC_0); //  Pin 8   Spare Analogue in, net SAIN fitted with external pull-down
+AnalogIn    Ain_SystemVolts (PC_1); //  Pin 9
+#define MOT_A_I_ADC PC_2
+#define MOT_B_I_ADC PC_3
+//AnalogIn    Motor_A_Current (PC_2); //  Pin 10
+//AnalogIn    Motor_B_Current (PC_3); //  Pin 11
+//  Pin 12 VSSA/VREF-   NET GND
+//  Pin 13 VDDA/VREF+   NET +3V3
+//  Pin 14  Port_A AUL
+//  Pin 15  Port_A AUH
+//  Pins 16, 17 BufferedSerial pc
+BufferedSerial  pc          (PA_2, PA_3, 2048, 4, NULL);    //  Pins 16, 17    tx, rx to pc via usb lead
+//  Pin 18  VSS     NET GND
+//  Pin 19  VDD     NET +3V3
+//  Pin 20  Port_A AWL
+//  Pin 21  DigitalOut led1(LED1);
+DigitalOut  LED           (PA_5); //  Pin 21
+//  Pin 22  Port_A AVL
+//  Pin 23  Port_A AVH
+//InterruptIn  MBH2      (PC_4); //  Pin 24
+//InterruptIn  MBH3      (PC_5); //  Pin 25
+#define _MBH2   PC_4
+#define _MBH3   PC_5
+//  Pin 26  Port_B BUL
+//  Pin 27  Port_B BVL
+//  Pin 28  Port_B BWL
+//  Pin 29  Port_B BUH
+//  Pin 30  VCAP1
+//  Pin 31  VSS
+//  Pin 32  VDD
+//  Pin 33  Port_B BVH
+//  Pin 34  Port_B BWH
+DigitalOut  T4        (PB_14);    //  Pin 35
+DigitalOut  T3        (PB_15);    //  Pin 36
+//  BufferedSerial com2 pins 37 Tx, 38 Rx
+BufferedSerial  com2          (PC_6, PC_7);    //  Pins 37, 38  tx, rx to Touch Screen Controller
+#define APWMV   PC_8
+#define APWMI   PC_9
+//FastPWM     A_MAX_V_PWM     (PC_8, PWM_PRESECALER_DEFAULT),  //  Pin 39                  pwm3/3
+//            A_MAX_I_PWM     (PC_9, PWM_PRESECALER_DEFAULT); //  pin 40, prescaler value  pwm3/4
+//InterruptIn MotB_Hall   (PA_8); //  Pin 41
+//  Pin 41  Port_A AWH
+//  BufferedSerial com3 pins 42 Tx, 43 Rx
+//InterruptIn tryseredge  (PA_9);
+BufferedSerial  com3        (PA_9, PA_10);    //    Pins 42, 43  tx, rx to any aux module
+//  PA_9 is Tx. I wonder, can we also use InterruptIn on this pin to generate interrupts on tx bit transitions ? Let's find out !
+//  No.
+
+//  Feb 2018 Pins 44 and 45 now liberated, could use for serial or other uses
+//BufferedSerial  extra_ser   (PA_11, PA_12);    //  Pins 44, 45  tx, rx to XBee module
+DigitalOut  T2  (PA_11);    //  Pin 44
+// was DigitalOut  T1  (PA_12);    //  Pin 45
+
+
+//InterruptIn T1  (PA_12);    //  Pin 45 now input counting pulses from LMT01 temperature sensor
+//  InterruptIn DOES NOT WORK ON PA_12. Boards are being made, will have to wire link PA12 to PC13
+DigitalIn   T1    (PA_12);
+////InterruptIn T1  (PC_13);    //  Pin 45 now input counting pulses from LMT01 temperature sensor
+
+
+
+//  Pin 46  SWDIO
+//  Pin 47  VSS
+//  Pin 48  VDD
+//  Pin 49  SWCLK
+
+//Was DigitalOut  T5  (PA_15); //  Pin 50
+DigitalIn   T5  (PA_15); //  Pin 50 now fwd/rev from remote control box if fitted
+#define _MAH1   PC_10   //  Pin 51
+#define _MAH2   PC_11   //  Pin 52
+#define _MAH3   PC_12   //  Pin 53
+//InterruptIn MBH1    (PD_2);     //  Pin 54
+#define _MBH1   PD_2
+DigitalOut  T6      (PB_3);     //  Pin 55
+#define BPWMV   PB_4
+#define BPWMI   PB_5
+//FastPWM     B_MAX_V_PWM     (PB_4, PWM_PRESECALER_DEFAULT),  //  Pin 56                  pwm3/3
+//            B_MAX_I_PWM     (PB_5, PWM_PRESECALER_DEFAULT); //  pin 57, prescaler value  pwm3/4
+
+//I2C i2c                     (PB_7, PB_6);   //  Pins 58, 59 For 24LC64 eeprom
+#define SDA_PIN PB_7
+#define SCL_PIN PB_6
+//  Pin 60  BOOT0
+
+//  Servo pins, 2 off. Configured as Input to read radio control receiver
+//      ** Update December 2018 **
+//  These pins can not be used as InterruptIn.
+//  Can be used as outputs by 'Servo'
+//  If used as servo output, code gives pin to 'Servo' - seems to work
+//InterruptIn Servo1_i    (PB_8); //  Pin 61  to read output from rc rx
+//InterruptIn Servo2_i    (PB_9); //  Pin 62  to read output from rc rx
+//  *** NOTE *** Above InterruptIn Servo using PB pins seems not to work, probably due to other Port B pins used as PortOut (try PortInOut?)
+//  Nov 2018 - Yet to try using PC14, PC15, free now as 32k768 xtal not fitted
+
+
+//  Pin 63  VSS
+//  Pin 64  VDD
+//  SYSTEM CONSTANTS
+//  December 2018   ** NEED TO PROVE SERVO OUT WORKS ** YES, DONE.
+    Servo   Servo1  (PB_8)  ;
+//    Servos[0] = & Servo1;
+    Servo   Servo2  (PB_9)  ;
+//    Servos[1] = & Servo2;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/STM3_ESC.h	Sun Sep 29 16:34:37 2019 +0000
@@ -0,0 +1,127 @@
+#include "mbed.h"
+
+#ifndef MBED_DUALBLS_H
+#define MBED_DUALBLS_H
+
+//#define USING_DC_MOTORS     //  Uncomment this to play with Dinosaur DC motors
+
+//#define TEMP_SENSOR_ENABLE    //  
+
+#include "BufferedSerial.h"
+const   int     MOTOR_HANDBRAKE   = 0,
+                MOTOR_FORWARD     = 8,
+                MOTOR_REVERSE     = 16,
+                MOTOR_REGENBRAKE  = 24;
+
+const   int     TIMEOUT_SECONDS = 2;
+
+/*  Please Do Not Alter these */
+const   int     PWM_PRESECALER_DEFAULT      = 2,
+                VOLTAGE_READ_INTERVAL_US    = 50,       //  Interrupts timed every 50 micro sec, runs around loop performing 1 A-D conversion per pass
+                MAIN_LOOP_REPEAT_TIME_US    = 31250,    //  31250 us, with TACHO_TAB_SIZE = 32 means tacho_ticks_per_time is tacho_ticks_per_second
+                MAIN_LOOP_ITERATION_Hz      = 1000000 / MAIN_LOOP_REPEAT_TIME_US,
+//                CURRENT_SAMPLES_AVERAGED    = 100,     //  Current is spikey. Reading smoothed by using average of this many latest current readings
+                PWM_HZ              = 15000,    //  chosen to be above cutoff frequency of average human ear
+//                PWM_HZ              = 8000,    //  chosen to be above cutoff frequency of average human ear - clearly audible annoying noise
+                MAX_PWM_TICKS       = (SystemCoreClock / (PWM_HZ * PWM_PRESECALER_DEFAULT)),
+                TICKLE_TIMES    =   100 ,
+                WATCHDOG_RELOAD = (TIMEOUT_SECONDS * 8);    //  WatchDog counter ticked down in 8Hz loop
+
+/*  End of Please Do Not Alter these */
+const   double      PI      = 4.0 * atan(1.0),
+                    TWOPI   = 8.0 * atan(1.0);
+
+enum    {COM_SOURCES, COM1, COM2, HAND, RC_IN1, RC_IN2,THEEND}  ;
+
+enum    {MOTADIR, MOTBDIR, MOTAPOLES, MOTBPOLES, ISHUNTA, ISHUNTB, SVO1, SVO2, RCIN1, RCIN2, 
+            COMM_SRC, BOARD_ID, TOP_SPEED, WHEELDIA, MOTPIN, WHEELGEAR, 
+            FUT1, FUT2, FUT3, FUT4, FUT5}  ;  //  
+
+enum    {
+    FAULT_0,
+    FAULT_EEPROM,
+    FAULT_BOARD_ID,
+    FAULT_COM_LINE_LEN,
+    FAULT_COM_LINE_NOMATCH,
+    FAULT_COM_LINE_LEN_PC,
+    FAULT_COM_LINE_LEN_TS,
+    FAULT_COM_LINE_NOMATCH_PC,
+    FAULT_COM_LINE_NOMATCH_TS,
+    FAULT_UNRECOGNISED_STATE,
+    FAULT_MAX,
+    NUMOF_REPORTABLE_TS_ERRORS
+    }  ;
+
+class   error_handling_Jan_2019
+{
+    int32_t    ESC_fault[NUMOF_REPORTABLE_TS_ERRORS]    ;   //  Some number of reportable error codes, accessible through set and read members
+    public:
+    error_handling_Jan_2019 ()  {   //  default constructor
+        for (int i = 0; i < (sizeof(ESC_fault) / sizeof(int32_t)); i++)
+            ESC_fault[i] = 0;
+    }
+    void        set   (uint32_t, int32_t)   ;
+    void        clr     (uint32_t)  ;
+    uint32_t    read  (uint32_t)   ;
+    bool        all_good    ()  ;
+    void        report_any  (bool)  ;   //  retain ? true or false
+}   ;
+
+enum    {SOURCE_PC, SOURCE_TS}  ;
+const int   BROADCAST   = '\r';
+const   int MAX_PARAMS = 20;
+const   int MAX_CMD_LEN = 220;
+
+struct  parameters  {
+    struct kb_command const * command_list;
+    BufferedSerial * com;   //  pc or com2
+    int32_t position_in_list, numof_dbls, target_unit, source, numof_menu_items;
+    double  dbl[MAX_PARAMS];
+    bool    respond, resp_always;
+}   ;
+
+class   cli_2019    {
+    struct  kb_command const * commandlist ;
+    int     clindex;
+    char    cmdline[MAX_CMD_LEN + 8];
+    char    * cmdline_ptr;
+    parameters  a   ;
+public:
+    cli_2019    (BufferedSerial * comport, kb_command const * list, int list_len, int source)  {
+        a.com           = comport ;
+        a.command_list = commandlist  = list  ;
+        a.numof_menu_items  = list_len  ;
+        a.source        = source    ;
+        cmdline_ptr = cmdline;
+        clindex    = 0;
+        if  (source == SOURCE_PC)
+            a.resp_always = true;
+        else
+            a.resp_always = false;
+    }  ;
+    void    core   ()  ;
+    void    test   ()  ;
+}   ;
+
+class   eeprom_settings {
+    I2C i2c;
+    uint32_t    errors;
+    char        settings    [36];
+    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    ()  ;
+  public:
+    eeprom_settings (PinName sda, PinName scl); //  Constructor
+    char        rd  (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'
+    bool        save    ()  ;               //  Write 'settings' buffer to EEPROM
+    bool        set_defaults    ();         //  Put default settings into EEPROM and local buffer
+    uint32_t    errs    ()  ;               //  Return errors
+}   ;
+
+
+
+
+#endif
+
--- a/brushless_motor.cpp	Mon Mar 04 17:51:08 2019 +0000
+++ b/brushless_motor.cpp	Sun Sep 29 16:34:37 2019 +0000
@@ -1,8 +1,9 @@
 //  Cloned from 'DualBLS2018_06' on 23 November 2018
 #include "mbed.h"
 //#include    "users/mbed_official/code/mbed-dev/file/707f6e361f3e/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F401xE/device/stm32f401xe.h"
-#include    "stm32f401xe.h"
-#include "DualBLS.h"
+//#include    "stm32f401xe.h"
+//#include    "stm32f411xe.h"
+#include "STM3_ESC.h"
 #include "BufferedSerial.h"
 #include "FastPWM.h"
 #include "Servo.h"
@@ -47,10 +48,10 @@
     numof_current_sense_rs = 1.0;
     RPM_filter  = 0.0;
     dv_by_dt = 0.0;
-    s[1] = 0.25;
-    s[2] = 9.0;
-    s[3] = 0.4;
-    s[4] = 0.2;
+    sdbl[1] = 0.25;     //  Remind me. What are these all about ?
+    sdbl[2] = 9.0;
+    sdbl[3] = 0.4;
+    sdbl[4] = 0.2;
     dRPM        = 0.0;
     V_clamp =   1.0 ;       //  Used to limit top speed
     motor_poles   = 8;    //  Default to 8 pole motor
@@ -80,7 +81,7 @@
         max_rpm = (uint32_t) (((double)mode.rd(TOP_SPEED) / rpm2mph) / 10.0)  ;
         target_speed = (double)mode.rd(TOP_SPEED) / 10.0;
         numof_current_sense_rs = (double)mode.rd(current_sense_rs_offset);
-        pc.printf   ("max_rpm=%d, tp speed=%.1f, rpm2mph=%.6f\r\n", max_rpm, target_speed, rpm2mph);
+        pc.printf   ("max_rpm=%d, top speed=%.1f, rpm2mph=%.6f\r\n", max_rpm, target_speed, rpm2mph);
     }
     if  (p == 4 || p == 6 || p == 8)    {
         motor_poles = p;
@@ -152,6 +153,11 @@
 }
 
 
+extern  double  Current_Scaler_Sep_2019;
+extern  int WatchDog;
+#define DRIVING (visible_mode == MOTOR_FORWARD || visible_mode == MOTOR_REVERSE)
+#define ESTOP   (WatchDog == 0 && DRIVING)
+
 /**
 *   void    brushless_motor::set_V_limit (double p)  //  Sets max motor voltage.
 *
@@ -159,13 +165,13 @@
 */
 void    brushless_motor::set_V_limit (double p)  //  Sets max motor voltage.
 {
-    if  (p < 0.0)
+    if  (p < 0.0 || ESTOP)
         p = 0.0;
     if  (p > 1.0)
         p = 1.0;
     last_V = p;     //  Retains last voltage limit demanded by driver
     
-    if  ((V_clamp < last_V) && (inner_mode == MOTOR_FORWARD || inner_mode == MOTOR_REVERSE))    //  Jan 2019 limit top speed when driving
+    if  ((V_clamp < last_V) && DRIVING)    //  Jan 2019 limit top speed when driving
         p = V_clamp;    //  If motor runnable, set voltage limit to lower of last_V and V_clamp
 
     p *= 0.95;      //  need limit, ffi see MCP1630 data
@@ -173,6 +179,7 @@
     maxV.pulsewidth_ticks  ((int)(p * MAX_PWM_TICKS));  //  PWM output to MCP1630 inverted motor pwm as MCP1630 inverts
 }
 
+
 /**void    brushless_motor::set_I_limit (double p)     //  Sets max motor current. pwm integrated to dc ref voltage level
 *
 *   Set motor current limit from zero (p=0.0) to max determined by current sense resistors (p=1.0)
@@ -195,14 +202,22 @@
 *
 *   Board designed to have 1, 2, 3 or 4 0R05 current sense resistors per motor for 10A, 20A, 30A or 40A peak motor currents
 */
+
 void    brushless_motor::set_I_limit (double p)     //  Sets max motor current. pwm integrated to dc ref voltage level
 {
     const   uint32_t MPR = ((MAX_PWM_TICKS * 9) / 11);    //  Scales 3.3v pwm DAC output to 2.7v V_Ref input
-    if  (p < 0.0)
+    if  (p < 0.0 || ESTOP)
         p = 0.0;
     if  (p > 1.0)
         p = 1.0;
     last_I = p;     //  Retains last current limit demanded by driver
+    if  (DRIVING)    {
+        if  (Current_Scaler_Sep_2019 > 1.0)
+            Current_Scaler_Sep_2019 = 1.0;
+        if  (Current_Scaler_Sep_2019 < 0.0)
+            Current_Scaler_Sep_2019 = 0.0;
+        p *= Current_Scaler_Sep_2019;
+    }
     maxI.pulsewidth_ticks  ((uint32_t)(p * MPR));  //  PWM
 }
 
@@ -226,10 +241,10 @@
 #endif
 //  Feb 2019 - coefficients currently values in ram to allow for tweaking via command line. Will be 'const' once settled upon.
 //    const   double  samp_scale  = 0.35;                  //  Tweak this value only to tune filter
-    double  samp_scale  = s[1];                  //  Tweak this value only to tune filter
+    double  samp_scale  = sdbl[1];                  //  Tweak this value only to tune filter
     double  shrink_by   = 1.0 - samp_scale;
 //    const   double  dv_scale    =   0.15;
-    double  dv_scale    =   s[3];
+    double  dv_scale    =   sdbl[3];
     double  dv_shrink   = 1.0 - dv_scale;
     double  speed_error, d, t;
     uint32_t        Hall_tot_copy = Hall_total;     //  Copy value for use throughout function as may get changed at any instant during exec !
@@ -253,7 +268,7 @@
     
     if  (inner_mode == MOTOR_FORWARD || inner_mode == MOTOR_REVERSE) {  //  Speed control only makes sense when motor runnable
         speed_error    = (target_speed - dMPH) / 1000.0;                //  'P' Proportional contribution to PID control
-        d = V_clamp + (speed_error * s[2]) + ((dv_by_dt / 1000.0) * s[4]);  //  Apply P+I+D (with I=0) control
+        d = V_clamp + (speed_error * sdbl[2]) + ((dv_by_dt / 1000.0) * sdbl[4]);  //  Apply P+I+D (with I=0) control
         if  (d > 1.0)   d = 1.0;
         if  (d < 0.0)   d = 0.0;
         V_clamp = d;
--- a/brushless_motor.h	Mon Mar 04 17:51:08 2019 +0000
+++ b/brushless_motor.h	Sun Sep 29 16:34:37 2019 +0000
@@ -6,7 +6,7 @@
 #define MBED_BRUSHLESSMOTOR_H
 
 #include "mbed.h"
-#include "DualBLS.h"
+#include "STM3_ESC.h"
 #include "FastPWM.h"
 
 class   brushless_motor
@@ -15,7 +15,7 @@
     uint32_t    Hall_index[2], encoder_error_cnt, motor_poles, current_sense_rs_offset;
     uint32_t    Hall_total,         //  Incremented on every Hall sensor transition
                 Hall_previous,
-                visible_mode, 
+                visible_mode,       //  One of MOTOR_HANDBRAKE, MOTOR_FORWARD, MOTOR_REVERSE, MOTOR_REGENBRAKE
                 inner_mode; 
     uint32_t    direction;
     int         temp_tick;
@@ -39,7 +39,10 @@
     uint32_t    tickleon;
     double      Idbl;
     double      last_V, last_I;
-    double      dRPM, dMPH, s[8];
+    double      dRPM, dMPH, 
+                sdbl[8];        //  Filter coefficients for filtering RPM and MPH reading stuff, I think!
+                                //  Used in brushless_motor::speed_monitor_and_control   ()
+                                
 //    brushless_motor   ()  {}   ;  //  can not use this with exotic elements PortOut, FastPWM etc
     brushless_motor   (PinName iadc, PinName pwv, PinName pwi, const uint16_t *, PinName h1, PinName h2, PinName h3, PortName, int, uint32_t)   ;   //  Constructor
     bool    poles       (int)   ;   //  Set number of motor poles - 4, 6, or 8
--- a/cli_BLS_nortos.cpp	Mon Mar 04 17:51:08 2019 +0000
+++ b/cli_BLS_nortos.cpp	Sun Sep 29 16:34:37 2019 +0000
@@ -18,7 +18,7 @@
 //  Brushless_STM3_Ctrl_2018_11
 #include "mbed.h"
 #include "BufferedSerial.h"
-#include "DualBLS.h"
+#include "STM3_ESC.h"
 #include "brushless_motor.h"
 
 #include <cctype>
@@ -26,8 +26,8 @@
 
 extern  eeprom_settings     mode     ;
 extern  error_handling_Jan_2019     ESC_Error    ;         //  Provides array usable to store error codes.
-extern  int     WatchDog;
-extern  bool    WatchDogEnable;
+extern  int     WatchDog;           //  from main
+extern  bool    WatchDogEnable;     //  from main
 extern  double  rpm2mph ;
 
 extern  brushless_motor MotorA, MotorB;     //  Controlling two motors together or individually
@@ -202,9 +202,9 @@
                 break;
             case    2:      //  MotorA_ current sense resistors [1 to 4], MotorB_ current sense resistors [1 to 4]
                 if  (temps[1] > 0 && temps[1] < 5) 
-                    mode.wr(temps[1], MOTADIR);
+                    mode.wr(temps[1], ISHUNTA);     //  Corrected since published
                 if  (temps[2] > 0 && temps[2] < 5)  
-                    mode.wr(temps[2], MOTBDIR);
+                    mode.wr(temps[2], ISHUNTB);
                 break;
             case    3:      //  2 Servo1 [0 or 1], Servo2 [0 or 1]
                 if  (temps[1] == 0 || temps[1] == 1)
@@ -265,6 +265,16 @@
 
 }
 
+
+void    ssl_cmd  (struct parameters & a)  {     //  set speed limit NEW and untested July 2019
+    if  (a.dbl[0] > 25.0)   a.dbl[0] = 25.0;
+    if  (a.dbl[0] < 1.0)    a.dbl[0] = 1.0;
+    mode.wr((char)(a.dbl[0] * 10.0), TOP_SPEED);
+    mode.save   ();
+}
+
+#ifdef  TEMP_SENSOR_ENABLE
+
 extern  uint32_t    last_temperature_count;
 /**
 *   void    temperature_cmd  (struct parameters & a)  {
@@ -275,6 +285,7 @@
         a.com->printf ("tem%c %d\r\n", mode.rd(BOARD_ID), (last_temperature_count / 16) - 50);
     }
 }
+#endif
 
 /**
 *void    rpm_cmd (struct parameters & a) //  to report e.g. RPM 1000 1000 ; speed for both motors
@@ -352,6 +363,10 @@
 /**
 *void    kd_cmd (struct parameters & a)  //  kick and enable the watch dog
 *
+*   Brute_TS_Controller or other external controller to issue regular 'kd\r' to come here.
+*   WatchDog disabled by default, enabled on first call to here
+*   This is where WatchDog timer is reset and reloaded.
+*   Timeout may be detected and handled in 8Hz loop in main programme loop
 */
 void    kd_cmd (struct parameters & a)  //  kick the watchdog. Reached from TS or pc.
 {
@@ -359,6 +374,10 @@
     WatchDogEnable = true;                          //  Receipt of this command sufficient to enable watchdog
 }
 
+void    wd_report (struct parameters & a)     //  Reachable always from pc. Only addressed board responds to TS
+{
+    pc.printf   ("WatchDog %d\r\n", WatchDog);
+}
 /**
 *void    who_cmd (struct parameters & a)     //  Reachable always from pc. Only addressed board responds to TS
 *
@@ -386,16 +405,16 @@
 {
     switch  ((int)a.dbl[0]) {
         case    1:
-            MotorA.s[1] = MotorB.s[1] = a.dbl[1];
+            MotorA.sdbl[1] = MotorB.sdbl[1] = a.dbl[1];
             break;
         case    2:
-            MotorA.s[2] = MotorB.s[2] = a.dbl[1];
+            MotorA.sdbl[2] = MotorB.sdbl[2] = a.dbl[1];
             break;
         case    3:
-            MotorA.s[3] = MotorB.s[3] = a.dbl[1];
+            MotorA.sdbl[3] = MotorB.sdbl[3] = a.dbl[1];
             break;
         case    4:
-            MotorA.s[4] = MotorB.s[4] = a.dbl[1];
+            MotorA.sdbl[4] = MotorB.sdbl[4] = a.dbl[1];
             break;
         case    5:
             MotorA.set_speed    (a.dbl[1]);
@@ -404,11 +423,12 @@
         default:
             pc.printf   ("Wrong use of scmd %f\r\n", a.dbl[0]);
     }
+    pc.printf   ("Filter Coefficient Fiddler - used in brushless_motor::speed_monitor_and_control   ()");
     pc.printf   ("Filter Coeffs 1 to 4\r\n");
-    pc.printf   ("1 %.3f\tPscale 0.01-0.5\r\n",     MotorA.s[1]);
-    pc.printf   ("2 %.3f\tP_gain 1.0-1000.0\r\n",   MotorA.s[2]);
-    pc.printf   ("3 %.3f\tDscale 0.01-0.5\r\n",     MotorA.s[3]);
-    pc.printf   ("4 %.3f\tD_gain 1.0-1000.0\r\n",   MotorA.s[4]);
+    pc.printf   ("1 %.3f\tPscale 0.01-0.5\r\n",     MotorA.sdbl[1]);
+    pc.printf   ("2 %.3f\tP_gain 1.0-1000.0\r\n",   MotorA.sdbl[2]);
+    pc.printf   ("3 %.3f\tDscale 0.01-0.5\r\n",     MotorA.sdbl[3]);
+    pc.printf   ("4 %.3f\tD_gain 1.0-1000.0\r\n",   MotorA.sdbl[4]);
     pc.printf   ("5 Set target_speed\r\n");
 }
 
@@ -456,8 +476,11 @@
     {"?v", "Report system bus voltage", sysV_report},
     {"?i", "Report motor both currents", sysI_report},
     {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd},
+#ifdef  TEMP_SENSOR_ENABLE
     {"tem", "report temperature", temperature_cmd},
+#endif
     {"mph", "read loco speed miles per hour", mph_cmd},
+    {"ssl", "set speed limit e.g. 10.7", ssl_cmd},              //  NEW July 2019
 //    {"rvi", "read most recent values sent to pwms", rvi_cmd},
 //    {"rdi", "read motor currents and power voltage", rdi_cmd},
     //  ***** Endof
@@ -474,7 +497,7 @@
 #ifdef  USING_DC_MOTORS
     {"mtypes", "report types of motors found", mt_cmd},
 #endif
-    {"s","1-4, filter param", scmd},
+    {"s","1-4, RPM and speed filter param", scmd},
     {"pot", "read drivers control pot", pot_cmd},
     {"fw", "forward", fw_cmd},
     {"re", "reverse", re_cmd},
@@ -485,10 +508,14 @@
     {"vi", "set motors V and I percent RANGE 0 to 100", vi_cmd},
     {"?v", "Report system bus voltage", sysV_report},
     {"?i", "Report motor both currents", sysI_report},
+    {"?w", "show WatchDog timer contents", wd_report},
     {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd},
     {"mode", "read or set params in eeprom", mode19_cmd},                                 //  Big change Jan 2019
+    {"ssl", "set speed limit e.g. 10.7", ssl_cmd},              //  NEW July 2019 ONLY HERE FOR TEST, normal use is from Touch Screen only.
 //    {"erase", "set eeprom contents to all 0xff", erase_cmd},
+#ifdef  TEMP_SENSOR_ENABLE
     {"tem", "report temperature", temperature_cmd},                                     //  Reports -50 when sensor not fitted
+#endif
     {"kd", "kick the dog, reloads WatchDog", kd_cmd},
     {"ver", "Version", ver_cmd},
     {"rcin", "Report Radio Control Input stuff", rcin_pccmd},
--- a/error_handler.cpp	Mon Mar 04 17:51:08 2019 +0000
+++ b/error_handler.cpp	Sun Sep 29 16:34:37 2019 +0000
@@ -1,5 +1,5 @@
 #include "mbed.h"
-#include "DualBLS.h"
+#include "STM3_ESC.h"
 #include "BufferedSerial.h"
 extern  BufferedSerial  pc;
 
--- a/main.cpp	Mon Mar 04 17:51:08 2019 +0000
+++ b/main.cpp	Sun Sep 29 16:34:37 2019 +0000
@@ -1,29 +1,34 @@
-//  Cloned from 'DualBLS2018_06' on 23 November 2018
+/*
+    STM3_ESC    Electronic Speed Controller board, drives Two Brushless Motors, full Four Quadrant Control.
+    Jon Freeman  B. Eng Hons
+    2015 - 2019
+*/
 #include "mbed.h"
-//#include    "users/mbed_official/code/mbed-dev/file/707f6e361f3e/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F401xE/device/stm32f401xe.h"
-#include "DualBLS.h"
-
-#include    "stm32f401xe.h"
+#include "STM3_ESC.h"
 #include "BufferedSerial.h"
 #include "FastPWM.h"
 #include "Servo.h"
 #include "brushless_motor.h"
 #include "Radio_Control_In.h"
+//#ifdef  TARGET_NUCLEO_F401RE    //
 
+//#endif
 /*
-Brushless_STM3 board
+Brushless_STM3_ESC board
 Jan 2019    *   WatchDog implemented. Default is disabled, 'kd' command from TS controller enables and reloads
             *   Tidied brushless_motor class, parameter passing now done properly
             *   class   RControl_In created. Inputs now routed to new pins, can now use two chans both class   RControl_In and Servo out
-                (buggery board required for new inputs)
+                (buggery board required for new inputs on June 2018 issue boards)
             *   Added version string
             *   Error handler written and included
             *   Realised Nanotec motors are 6 pole, all others are 8 pole. Modified 'mode' to include 'motor poles' in EEPROM data, now speed reading correct for all
             *   Reorganised EEPROM data - mode setting now much easier, less error prone
-            *   Maximum speed now one EEPROM option, range 1.0 to 25.0 MPH
+            *   Maximum speed now one EEPROM option, range 1.0 to 25.0 MPH in 0.1 MPH steps
                 
 New 29th May 2018 **
                 LMT01 temperature sensor routed to T1 - and rerouted to PC_13 as InterruptIn on T1 (ports A and B I think) not workable
+        March 2019 temp sensor only included with TEMP_SENSOR_ENABLE defined. Temp reading not essential, LMT01 was not a good choice due to
+        significant loading of interrupts, threatening integrity of Real Time System
 */
 
 
@@ -34,7 +39,7 @@
 
 ____________________________________________________________________________________
         CONTROL PHILOSOPHY
-This Bogie drive board software should ensure sensible control when commands supplied are not sensible !
+This STM3_ESC Bogie drive board software should ensure sensible control when commands supplied are not sensible !
 
 That is, smooth transition between Drive, Coast and Brake to be implemented here.
 The remote controller must not be relied upon to deliver sensible command sequences.
@@ -49,17 +54,21 @@
 #if defined (TARGET_NUCLEO_F401RE)  //  CPU in 64 pin LQFP
 #include    "F401RE.h"  //  See here for warnings about Servo InterruptIn not working
 #endif
+#if defined (TARGET_NUCLEO_F411RE)  //  CPU in 64 pin LQFP
+#include    "F411RE.h"  //  See here for warnings about Servo InterruptIn not working
+#endif
 #if defined (TARGET_NUCLEO_F446ZE)  //  CPU in 144 pin LQFP
 #include    "F446ZE.h"              //  A thought for future version
 #endif
 /*  Global variable declarations */
-char   const    const_version_string[] = {"1.0.0\0"};  //  Version string, readable from serial ports
+char   const_version_string[] = {"1.0.y2019.m09.d29\0"};  //  Version string, readable from serial ports
 volatile    uint32_t    fast_sys_timer      = 0;    //  gets incremented by our Ticker ISR every VOLTAGE_READ_INTERVAL_US
-int         WatchDog    = WATCHDOG_RELOAD + 80; //  Allow extra few seconds at powerup
+//int         WatchDog    = WATCHDOG_RELOAD + 80; //  Allow extra few seconds at powerup
+int         WatchDog    = 0; //  Set this up in main once pre-flight checks done. Allow extra few seconds at powerup
 bool        WatchDogEnable  = false;    //  Must recieve explicit instruction from pc or controller to enable
 uint32_t    volt_reading        = 0,    //  Global updated by interrupt driven read of Battery Volts
             driverpot_reading   = 0,    //  Global updated by interrupt driven read of Drivers Pot
-            sys_timer           = 0,    //  gets incremented by our Ticker ISR every MAIN_LOOP_REPEAT_TIME_US
+            sys_timer           = 0,    //  gets incremented by our Ticker ISR every MAIN_LOOP_REPEAT_TIME_US, 31250us at Sept 2019
             AtoD_Semaphore      = 0;
 
 bool        loop_flag   = false;        //  made true in ISR_loop_timer, picked up and made false again in main programme loop
@@ -67,15 +76,24 @@
 bool        temp_sensor_exists = false;
 double      rpm2mph;
 
+double      Current_Scaler_Sep_2019 = 1.0;  //  New idea - Sept 2019. Plan is to scale down motor current limit when voltage lower than nom.
+                                            //  See schematic for full details, but cycle-by-cycle current limit has the effect of allowing larger average I
+                                            //  at lower voltages. This is simply because current takes longer to build in motor inductance when voltage
+                                            //  is low. Conversely, at high supply voltages, motor current reaches limit quickly, cutting drive, meaning
+                                            //  similar current flows for shorter times at higher voltages.
+
+#ifdef  TEMP_SENSOR_ENABLE
 uint32_t    temp_sensor_count = 0,  //  incremented by every rising edge from LMT01
             last_temperature_count = 0;  //  global updated approx every 100ms after each LMT01 conversion completes
+#endif
 /*  End of Global variable declarations */
 
 Ticker  tick_vread;     //  Device to cause periodic interrupts, used to time voltage readings etc
 Ticker  loop_timer;     //  Device to cause periodic interrupts, used to sync iterations of main programme loop
+#ifdef  TEMP_SENSOR_ENABLE
 Ticker  temperature_find_ticker;
 Timer   temperature_timer;
-
+#endif
 #ifdef USING_DC_MOTORS
 Timer   dc_motor_kicker_timer;
 Timeout motors_restore;
@@ -127,6 +145,7 @@
 extern  cli_2019    pcc, tsc;   //  command line interpreters from pc and touch screen
 
 //  Interrupt Service Routines
+#ifdef  TEMP_SENSOR_ENABLE
 void    ISR_temperature_find_ticker ()      //  every 960 us, i.e. slightly faster than once per milli sec
 {
     static  bool    readflag = false;
@@ -139,7 +158,7 @@
     if  (t == 6)
         readflag = false;
 }
-
+#endif
 /** void    ISR_loop_timer  ()
 *   This ISR responds to Ticker interrupts at a rate of (probably) 32 times per second (check from constant declarations above)
 *   This ISR sets global flag 'loop_flag' used to synchronise passes around main programme control loop.
@@ -164,6 +183,7 @@
     fast_sys_timer++;        //  Just a handy measure of elapsed time for anything to use
 }
 
+#ifdef  TEMP_SENSOR_ENABLE
 void    temp_sensor_isr ()      //  got rising edge from LMT01. ALMOST CERTAIN this misses some
 {
     int t = temperature_timer.read_us   (); //  Must be being overrun by something, most likely culprit A-D reading ?
@@ -173,7 +193,7 @@
         temp_sensor_count++;
 //    T2 = !T2;   //  scope hanger
 }
-
+#endif
 //  End of Interrupt Service Routines
 
 
@@ -281,6 +301,24 @@
 }
 
 
+void    Update_Current_Scaler   ()  {       //  ***NEW Sept 2019*** Called at 8Hz
+const   double  Vnom = 48.0,
+                Vmin = Vnom / 3.0,
+                Voff = Vnom / 4.0;
+                
+    double  v = Read_BatteryVolts   ();
+    if  (v > Vnom)
+        v = Vnom;
+    if  (v < Voff)
+        v = Voff;
+    if  (v > Vmin)  {   //  In expected normal operating voltage range
+        Current_Scaler_Sep_2019 = v / Vnom;         //  May need to revisit law
+    }
+    else    {   //  In very low voltage region
+        Current_Scaler_Sep_2019 = 0.5 * (v / Vnom);
+    }
+}
+
 void    mode_set_both_motors   (int mode, double val)      //  called from cli to set fw, re, rb, hb
 {
     MotorA.set_mode (mode);
@@ -356,7 +394,7 @@
     const   int buflen = sizeof(dirbuf) / sizeof(int);
     const   double      Pot_Brake_Range = 0.35;  //pow   (0.5, SERVOIN_PWR_BENDER); //0.353553 for SERVOIN_PWR_BENDER = 1.5;
 
-    direction_old = direction_new;
+   direction_old = direction_new;
 
 //      Test for change in direction switch setting.
 //      If whole buffer NEWLY filled with all Fwd or all Rev, state = brake_wait
@@ -460,16 +498,16 @@
 int main()
 {
     int eighth_sec_count = 0;
-    double  servo_angle = 0.0;  //  For testing servo outs
-
-    Temperature_pin.fall (&temp_sensor_isr);
-    Temperature_pin.mode (PullUp);
     //  Setup system timers to cause periodic interrupts to synchronise and automate volt and current readings, loop repeat rate etc
     tick_vread.attach_us    (&ISR_voltage_reader, VOLTAGE_READ_INTERVAL_US);    //  Start periodic interrupt generator
     loop_timer.attach_us    (&ISR_loop_timer, MAIN_LOOP_REPEAT_TIME_US);    //  Start periodic interrupt generator
+#ifdef  TEMP_SENSOR_ENABLE
     temperature_find_ticker.attach_us   (&ISR_temperature_find_ticker, 960);
+    Temperature_pin.fall (&temp_sensor_isr);
+    Temperature_pin.mode (PullUp);
+    temperature_timer.start ();
+#endif
     //  Done setting up system interrupt timers
-    temperature_timer.start ();
 
     pc.baud     (9600);     //  COM port to pc
     com3.baud   (1200);     //  Once had an idea to use this for IR comms, never tried
@@ -495,8 +533,10 @@
 //    T5 = 0; now input from fw/re on remote control box
     T6 = 0;
 
+#ifdef  TEMP_SENSOR_ENABLE
     if  ((last_temperature_count > 160) && (last_temperature_count < 2400))   //  in range -40 to +100 degree C
         temp_sensor_exists  = true;
+#endif
 #ifdef  USING_DC_MOTORS
     dc_motor_kicker_timer.start   ();
 #endif
@@ -514,6 +554,10 @@
 //    pc.printf   ("SystemCoreClock=%d, MAX_PWM_TICKS=%d\r\n", SystemCoreClock, MAX_PWM_TICKS);
 //    pcc.test    ()  ;
 //    tsc.test    ()  ;
+
+    WatchDog    = WATCHDOG_RELOAD + 80; //  Allow extra few seconds at powerup
+
+
     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
             pcc.core    ()  ;   //  Proceed beyond here once loop_timer ticker ISR has set loop_flag true
@@ -522,8 +566,8 @@
         }                       //  32Hz original setting for loop repeat rate
         loop_flag = false;              //  Clear flag set by ticker interrupt handler. WHEN LAST CHECKED this was about every 32ms
 
-        RC_chan_1.validate_rx();
-        RC_chan_2.validate_rx();
+        RC_chan_1.validate_rx();   //  Tests for pulse width and repetition rates being believable signal from radio control
+        RC_chan_2.validate_rx();    //  bool return values not noted here, these 2 lines are pointless.
 
         switch  (mode.rd(COMM_SRC))  {   //  Look to selected source of driving command, act on commands from wherever
             case    0:  //  Invalid
@@ -574,14 +618,14 @@
             LED = !LED;                   // Toggle LED on board, should be seen to fast flash
             if  (WatchDogEnable)    {
                 WatchDog--;
-                if  (WatchDog == 0) {   //  Deal with WatchDog timer timeout here
+                if  (WatchDog < 1) {   //  Deal with WatchDog timer timeout here
+                    WatchDog = 0;
                     setVI  (0.0, 0.0);  //  set motor volts and amps to zero
 //                    com2.printf ("TIMEOUT %c\r\n", mode.rd(BOARD_ID));   //  Potential problem of multiple units reporting at same time overcome by adding board number to WATCHDOG_RELOAD
                     pc.printf ("TIMEOUT %c\r\n", mode.rd(BOARD_ID));   //  Brute touch screen controller can do nothing with this
                 }                       //  End of dealing with WatchDog timer timeout
-                if  (WatchDog < 0)
-                    WatchDog = 0;
             }
+            Update_Current_Scaler   ();
             eighth_sec_count++;
             if  (eighth_sec_count > 6)    {   //  Send some status info out of serial port every second and a bit or thereabouts
                 eighth_sec_count = 0;
@@ -593,8 +637,9 @@
                                     pc.printf   ("Temp %.2f\r\n", tmprt);
                                 }*/
             }
-#define SERVO_OUT_TEST
+//#define SERVO_OUT_TEST
 #ifdef  SERVO_OUT_TEST
+    static double  servo_angle = 0.0;  //  For testing servo outs
             //  servo out test here     December 2018
             servo_angle += 0.01;
             if  (servo_angle > TWOPI)