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

Committer:
JonFreeman
Date:
Sat Apr 25 15:35:58 2020 +0000
Revision:
1:450090bdb6f4
Parent:
0:77803b3ee157
Child:
2:8e7b51353f32
About to pick this up again late Apr 2020.;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JonFreeman 0:77803b3ee157 1 #include "mbed.h"
JonFreeman 0:77803b3ee157 2 #include "Alternator.h"
JonFreeman 0:77803b3ee157 3
JonFreeman 0:77803b3ee157 4
JonFreeman 0:77803b3ee157 5 /*
JonFreeman 0:77803b3ee157 6 Alternator Regulator
JonFreeman 0:77803b3ee157 7 Jon Freeman
JonFreeman 1:450090bdb6f4 8 June 2019 - Feb 2020
JonFreeman 1:450090bdb6f4 9
JonFreeman 1:450090bdb6f4 10 ** Prototype built using Nucleo L432KC. Final design likely to use F401RE. Code should compile for either. **
JonFreeman 0:77803b3ee157 11
JonFreeman 1:450090bdb6f4 12 ** main loop frequency upped from 32Hz to 100Hz **
JonFreeman 1:450090bdb6f4 13
JonFreeman 1:450090bdb6f4 14 WHAT THIS PROGRAMME DOES - Controls 4 stroke petrol engine driving vehicle alternator with new custom regulator
JonFreeman 1:450090bdb6f4 15
JonFreeman 1:450090bdb6f4 16 Electronics powered by higher voltage of small 12v backup battery, or alternator field output supply
JonFreeman 1:450090bdb6f4 17 Note only Field+ and MAX5035 supplied thus, all else powered from MAX outputs.
JonFreeman 1:450090bdb6f4 18 Starting engine provides rectified tickle from magneto to enable MAX5035 creating +5 and +3v3 supplies.
JonFreeman 1:450090bdb6f4 19 Alternative, selected by jumper pposition, is external switch - battery+ to MAX enable circuit.
JonFreeman 1:450090bdb6f4 20 Anytime engine revs measured < 2000 (or some such) RPM, field current OFF (by pwm 0)
JonFreeman 0:77803b3ee157 21
JonFreeman 0:77803b3ee157 22 BEGIN
JonFreeman 1:450090bdb6f4 23 Loop forever at 100 Hz {
JonFreeman 1:450090bdb6f4 24 Read engine RPM by monitoring engine tacho signal present on engine On/Off switch line
JonFreeman 1:450090bdb6f4 25 Read alternator output load current
JonFreeman 1:450090bdb6f4 26 Using RPM and current readings, regulate engine rpm via model control servo
JonFreeman 1:450090bdb6f4 27 Adjust Alternator field current max limit according to RPM (analogue regulator limits output voltage)
JonFreeman 0:77803b3ee157 28 Measure system voltage (just in case this is ever useful)
JonFreeman 0:77803b3ee157 29 Respond to any commands arriving at serial port (setup and test link to laptop)
JonFreeman 0:77803b3ee157 30 Flash LED at 8 Hz as proof of life
JonFreeman 0:77803b3ee157 31 }
JonFreeman 0:77803b3ee157 32 END
JonFreeman 0:77803b3ee157 33
JonFreeman 0:77803b3ee157 34 INPUTS AnalogIn x 2 - Ammeter chip - current and offset AnalogIns
JonFreeman 0:77803b3ee157 35 INPUT AnalogIn - System voltage for info only.
JonFreeman 0:77803b3ee157 36 INPUT AnalogIn - ExtRevDemand
JonFreeman 0:77803b3ee157 37 INPUT AnalogIn - DriverPot
JonFreeman 0:77803b3ee157 38 INPUT Pulse engine speed indicator, speed checked against EEPROM data to select max pwm duty ratio for this speed
JonFreeman 0:77803b3ee157 39 INPUT Final pwm gate drive wired back to InterruptIn ** MAYBE USEFUL OR NOT ** Could read this back via serial to laptop
JonFreeman 0:77803b3ee157 40 OUTPUT pwm to MCP1630. This is clock to pwm chip. Also limits max duty ratio
JonFreeman 0:77803b3ee157 41 RS232 serial via USB to setup eeprom data
JonFreeman 0:77803b3ee157 42 */
JonFreeman 1:450090bdb6f4 43 // Uses software bit banged I2C - DONE (because no attempt to get I2C working on these small boards has ever worked)
JonFreeman 0:77803b3ee157 44
JonFreeman 0:77803b3ee157 45 /**
JonFreeman 0:77803b3ee157 46 * Jumpers fitted to small mbed Nucleo boards - D5 - A5 and D4 - A4 CHECK - yes
JonFreeman 0:77803b3ee157 47 */
JonFreeman 1:450090bdb6f4 48 //#ifdef TARGET_NUCLEO_F303K8 // Code too large to fit
JonFreeman 1:450090bdb6f4 49 #ifdef TARGET_NUCLEO_L432KC //
JonFreeman 0:77803b3ee157 50 /*
JonFreeman 0:77803b3ee157 51 declared in file i2c_bit_banged.cpp
JonFreeman 0:77803b3ee157 52 DigitalInOut SDA (D4); // Horrible bodge to get i2c working using bit banging.
JonFreeman 0:77803b3ee157 53 DigitalInOut SCL (D5); // DigitalInOut do not work as you might expect. Fine if used only as OpenDrain opuputs though!
JonFreeman 0:77803b3ee157 54 DigitalIn SDA_IN (A4); // That means paralleling up with two other pins as inputs
JonFreeman 0:77803b3ee157 55 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.
JonFreeman 0:77803b3ee157 56 */
JonFreeman 0:77803b3ee157 57 Serial pc (USBTX, USBRX); // Comms port to pc or terminal using USB lead
JonFreeman 0:77803b3ee157 58 BufferedSerial LocalCom (PA_9, PA_10); // New March 2019
JonFreeman 0:77803b3ee157 59 // Above combo of Serial and BufferedSerial is the only one to work !
JonFreeman 0:77803b3ee157 60
JonFreeman 0:77803b3ee157 61 // INPUTS :
JonFreeman 1:450090bdb6f4 62 AnalogIn Ain_SystemVolts (A6); // Sniff of alternator output, not used in control loop as done using analogue MCP1630
JonFreeman 1:450090bdb6f4 63 AnalogIn Ammeter_In (A1); // Output of ASC709LLFTR ammeter chip (pin 20), used to increase engine revs if need be
JonFreeman 1:450090bdb6f4 64 AnalogIn Ammeter_Ref (A0); // Ref output from ASC709LLFTR used to set ammeter zero (pin 25)
JonFreeman 1:450090bdb6f4 65
JonFreeman 1:450090bdb6f4 66 // Nov 2019. Not convinced Ext_Rev_Demand is useful
JonFreeman 0:77803b3ee157 67 AnalogIn Ext_Rev_Demand (D3); // Servo determines engine revs, servo out to be higher of Ext_Rev_Demand and internal calc
JonFreeman 1:450090bdb6f4 68
JonFreeman 0:77803b3ee157 69 AnalogIn Driver_Pot (A3); // If whole control system can be made to fit
JonFreeman 0:77803b3ee157 70
JonFreeman 0:77803b3ee157 71 /*
JonFreeman 0:77803b3ee157 72 MODULE PIN USAGE
JonFreeman 0:77803b3ee157 73 1 PA_9 D1 LocalCom Tx
JonFreeman 0:77803b3ee157 74 2 PA_10 D0 LocalCom Rx
JonFreeman 0:77803b3ee157 75 3 NRST
JonFreeman 0:77803b3ee157 76 4 GND
JonFreeman 1:450090bdb6f4 77 5 PA12_D2 NEW June 2019 - Output engine tacho cleaned-up, brought out to testpoint 4
JonFreeman 0:77803b3ee157 78 6 PB_0 D3 AnalogIn Ext_Rev_Demand
JonFreeman 0:77803b3ee157 79 7 PB_7 D4 SDA i2c to 24LC memory
JonFreeman 0:77803b3ee157 80 8 PB_6 D5 SCL i2c to 24LC memory
JonFreeman 0:77803b3ee157 81 9 PB_12 D6 PwmOut PWM_OSC_IN Timebase for pwm, also determines max duty ratio
JonFreeman 0:77803b3ee157 82 10 N.C.
JonFreeman 0:77803b3ee157 83 11 N.C.
JonFreeman 1:450090bdb6f4 84 12 PA_8 D9 InterruptIn pulse_tacho from engine magneto, used to measure rpm
JonFreeman 1:450090bdb6f4 85 13 PA_11 D10 Throttle servo
JonFreeman 1:450090bdb6f4 86 14 PB_5 D11 // InterruptIn VEXT PWM controller output folded back for cpu to monitor, useful on test to read what pwm required to do what
JonFreeman 1:450090bdb6f4 87 15 PB_4 D12 Scope_probe
JonFreeman 0:77803b3ee157 88 16 PB_3 D13 LED Onboard LED
JonFreeman 0:77803b3ee157 89 17 3V3
JonFreeman 0:77803b3ee157 90 18 AREF
JonFreeman 1:450090bdb6f4 91 19 PA_0 A0 AnalogIn Ammeter_Ref
JonFreeman 0:77803b3ee157 92 20 PA_1 A1 AnalogIn Ammeter_In
JonFreeman 0:77803b3ee157 93 21 PA_3 A2 PWM analogue out
JonFreeman 1:450090bdb6f4 94 22 PA_4 A3 AnalogIn Driver_Pot
JonFreeman 0:77803b3ee157 95 23 PA_5 A4 n.c. SDA_IN paralleled to i2c pin, necessary because i2c has to be bit banged
JonFreeman 0:77803b3ee157 96 24 PA_6 A5 n.c. SCL_IN paralleled to i2c pin, necessary because i2c has to be bit banged
JonFreeman 1:450090bdb6f4 97 25 PA_7 A6 AnalogIn V_Sample system link voltage
JonFreeman 1:450090bdb6f4 98 26 PA_2 A7 Not used
JonFreeman 0:77803b3ee157 99 27 5V
JonFreeman 0:77803b3ee157 100 28 NRST
JonFreeman 0:77803b3ee157 101 29 GND
JonFreeman 0:77803b3ee157 102 30 VIN
JonFreeman 0:77803b3ee157 103 */
JonFreeman 0:77803b3ee157 104
JonFreeman 1:450090bdb6f4 105 InterruptIn pulse_tacho (D9); // Signal from engine magneto (clipped by I limit resistor and 3v3 zener)
JonFreeman 1:450090bdb6f4 106 InterruptIn VEXT (D2); // PWM controller output folded back for cpu to monitor, useful on test to read what pwm required to do what
JonFreeman 0:77803b3ee157 107 // OUTPUTS :
JonFreeman 0:77803b3ee157 108
JonFreeman 1:450090bdb6f4 109 DigitalOut Scope_probe (D12); // Handy pin to hang scope probe onto while developing code
JonFreeman 1:450090bdb6f4 110 DigitalOut myled (LED1); // Green LED on board is PB_3 D13
JonFreeman 1:450090bdb6f4 111 PwmOut PWM_OSC_IN (A2); // Can alter prescaler can not use A5
JonFreeman 1:450090bdb6f4 112 //PwmOut A_OUT (A2); // Can alter prescaler can not use A5 PIN STOLEN BY PWM_OSC_IN
JonFreeman 1:450090bdb6f4 113 Servo Throttle (D10); // Changed from A2, June 2019
JonFreeman 1:450090bdb6f4 114 DigitalOut EngineTachoOut (D11); // New June 2019
JonFreeman 0:77803b3ee157 115 #endif
JonFreeman 1:450090bdb6f4 116
JonFreeman 1:450090bdb6f4 117 #ifdef TARGET_NUCLEO_F401RE //
JonFreeman 1:450090bdb6f4 118 //Serial pc (USBTX, USBRX); // Comms port to pc or terminal using USB lead
JonFreeman 1:450090bdb6f4 119 BufferedSerial pc (PA_2, PA_3, 2048, 4, NULL); // Pins 16, 17 tx, rx to pc via usb lead
JonFreeman 1:450090bdb6f4 120 //BufferedSerial pc (USBTX, USBRX); // Pins 16, 17 tx, rx to pc via usb lead
JonFreeman 1:450090bdb6f4 121 BufferedSerial LocalCom (PC_6, PC_7); // Pins 37, 38 tx, rx to Touch Screen Controller
JonFreeman 1:450090bdb6f4 122
JonFreeman 1:450090bdb6f4 123 // INPUTS :
JonFreeman 1:450090bdb6f4 124 AnalogIn Ain_SystemVolts (PB_1); // Sniff of alternator output, not used in control loop as done using analogue MCP1630
JonFreeman 1:450090bdb6f4 125 AnalogIn Ammeter_In (PC_5); // Output of ASC709LLFTR ammeter chip (pin 20), used to increase engine revs if need be
JonFreeman 1:450090bdb6f4 126 AnalogIn Ammeter_Ref (PB_0); // Ref output from ASC709LLFTR used to set ammeter zero (pin 25)
JonFreeman 1:450090bdb6f4 127 AnalogIn Ext_Rev_Demand (PC_1); // Servo determines engine revs, servo out to be higher of Ext_Rev_Demand and internal calc
JonFreeman 1:450090bdb6f4 128 AnalogIn Driver_Pot (PC_2); // If whole control system can be made to fit
JonFreeman 1:450090bdb6f4 129
JonFreeman 1:450090bdb6f4 130 /*
JonFreeman 1:450090bdb6f4 131 MODULE PIN USAGE
JonFreeman 1:450090bdb6f4 132 */
JonFreeman 1:450090bdb6f4 133
JonFreeman 1:450090bdb6f4 134 InterruptIn pulse_tacho (PB_15); // Signal from engine magneto (clipped by I limit resistor and 3v3 zener)
JonFreeman 1:450090bdb6f4 135 InterruptIn VEXT (PC_12); // PWM controller output folded back for cpu to monitor, useful on test to read what pwm required to do what
JonFreeman 1:450090bdb6f4 136 // OUTPUTS :
JonFreeman 1:450090bdb6f4 137
JonFreeman 1:450090bdb6f4 138 DigitalOut Scope_probe (PB_3); // Handy pin to hang scope probe onto while developing code
JonFreeman 1:450090bdb6f4 139 DigitalOut myled (PA_5); // Green LED on board is PA_5
JonFreeman 1:450090bdb6f4 140 //PwmOut PWM_OSC_IN (PA_10); // PA_10 is pwm1/3 Can alter prescaler can not use A5
JonFreeman 1:450090bdb6f4 141 PwmOut PWM_OSC_IN (PB_9); // PA_10 is pwm4/4 Can alter prescaler can not use A5
JonFreeman 1:450090bdb6f4 142 PwmOut A_OUT (PB_5); // PB_5 is pwm3/2 Can alter prescaler can not use A5 PIN STOLEN BY PWM_OSC_IN
JonFreeman 1:450090bdb6f4 143 Servo Throttle (PA_0); // PA_8 is pwm1/1 Changed from A2, June 2019
JonFreeman 1:450090bdb6f4 144 DigitalOut EngineTachoOut (PA_7); // New June 2019
JonFreeman 1:450090bdb6f4 145
JonFreeman 1:450090bdb6f4 146 I2C i2c (PB_7, PB_6); // Pins 58, 59 For 24LC64 eeprom
JonFreeman 1:450090bdb6f4 147 //#define SDA_PIN PB_7
JonFreeman 1:450090bdb6f4 148 //#define SCL_PIN PB_6
JonFreeman 1:450090bdb6f4 149
JonFreeman 1:450090bdb6f4 150 #endif
JonFreeman 1:450090bdb6f4 151
JonFreeman 0:77803b3ee157 152 Timer microsecs;
JonFreeman 0:77803b3ee157 153 Ticker loop_timer; // Device to cause periodic interrupts, used to sync iterations of main programme loop - slow
JonFreeman 0:77803b3ee157 154
JonFreeman 1:450090bdb6f4 155 const double AMPS_CAL = 90.0;
JonFreeman 1:450090bdb6f4 156 extern eeprom_settings user_settings ;
JonFreeman 0:77803b3ee157 157 // SYSTEM CONSTANTS
JonFreeman 0:77803b3ee157 158 /* Please Do Not Alter these */
JonFreeman 1:450090bdb6f4 159 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
JonFreeman 0:77803b3ee157 160 /* End of Please Do Not Alter these */
JonFreeman 0:77803b3ee157 161 /* Global variable declarations */
JonFreeman 0:77803b3ee157 162 uint32_t //semaphore = 0,
JonFreeman 1:450090bdb6f4 163 speed_control_factor= 75000, // fiddled from cli to tweak engine speed controller response
JonFreeman 0:77803b3ee157 164 volt_reading = 0, // Global updated by interrupt driven read of Battery Volts
JonFreeman 0:77803b3ee157 165 ext_rev_req = 0,
JonFreeman 0:77803b3ee157 166 driver_reading = 0,
JonFreeman 0:77803b3ee157 167 tacho_count = 0, // Global incremented on each transition of InterruptIn pulse_tacho
JonFreeman 1:450090bdb6f4 168 sys_timer100Hz = 0; // gets incremented by our Ticker ISR every MAIN_LOOP_REPEAT_TIME_US
JonFreeman 1:450090bdb6f4 169 double amp_reading = 0.0,
JonFreeman 1:450090bdb6f4 170 amp_offset = 0.0,
JonFreeman 1:450090bdb6f4 171 raw_amp_reading = 0.0,
JonFreeman 1:450090bdb6f4 172 raw_amp_offset = 0.0;
JonFreeman 1:450090bdb6f4 173 double servo_position = 0.2; // set in speed control loop
JonFreeman 1:450090bdb6f4 174 // const double throttle_limit = 0.4;
JonFreeman 1:450090bdb6f4 175 double throttle_limit = SERVO_MAX;
JonFreeman 0:77803b3ee157 176 bool loop_flag = false; // made true in ISR_loop_timer, picked up and made false again in main programme loop
JonFreeman 1:450090bdb6f4 177 bool flag_25Hz = false; // As loop_flag but repeats 25 times per sec
JonFreeman 1:450090bdb6f4 178 bool flag_12Hz5 = false; // As loop_flag but repeats 12.5 times per sec
JonFreeman 1:450090bdb6f4 179 bool flag_1Hz = false; // As loop_flag but repeats 1 times per sec
JonFreeman 1:450090bdb6f4 180 bool query_toggle = false;
JonFreeman 0:77803b3ee157 181
JonFreeman 1:450090bdb6f4 182 const int AMP_FILTER_FACTOR = 6;
JonFreeman 0:77803b3ee157 183
JonFreeman 0:77803b3ee157 184 /* End of Global variable declarations */
JonFreeman 0:77803b3ee157 185
JonFreeman 1:450090bdb6f4 186 //void ISR_fast_interrupt () { // here at 10 times main loop repeat rate (i.e. 1000Hz, 1.0ms)
JonFreeman 1:450090bdb6f4 187 void ISR_fast_interrupt () {
JonFreeman 1:450090bdb6f4 188 static uint32_t t = 0;
JonFreeman 1:450090bdb6f4 189 Scope_probe = 1; // To show how much time spent in interrupt handler
JonFreeman 0:77803b3ee157 190 switch (t) {
JonFreeman 0:77803b3ee157 191 case 0:
JonFreeman 0:77803b3ee157 192 volt_reading >>= 1; // Result = Result / 2
JonFreeman 0:77803b3ee157 193 volt_reading += Ain_SystemVolts.read_u16 (); // Result = Result + New Reading
JonFreeman 0:77803b3ee157 194 break;
JonFreeman 0:77803b3ee157 195 case 1:
JonFreeman 1:450090bdb6f4 196 raw_amp_reading = (double) Ammeter_In.read();
JonFreeman 0:77803b3ee157 197 break;
JonFreeman 0:77803b3ee157 198 case 2:
JonFreeman 1:450090bdb6f4 199 raw_amp_offset = Ammeter_Ref.read(); // Feb 2020 Not convinced this is useful
JonFreeman 0:77803b3ee157 200 break;
JonFreeman 0:77803b3ee157 201 case 3:
JonFreeman 0:77803b3ee157 202 ext_rev_req >>= 1; // Result = Result / 2
JonFreeman 1:450090bdb6f4 203 ext_rev_req += Ext_Rev_Demand.read_u16();
JonFreeman 0:77803b3ee157 204 break;
JonFreeman 0:77803b3ee157 205 case 4:
JonFreeman 0:77803b3ee157 206 driver_reading >>= 1; // Result = Result / 2
JonFreeman 1:450090bdb6f4 207 driver_reading += Driver_Pot.read_u16();
JonFreeman 1:450090bdb6f4 208 // break;
JonFreeman 1:450090bdb6f4 209 // case 5:
JonFreeman 0:77803b3ee157 210 loop_flag = true; // set flag to allow main programme loop to proceed
JonFreeman 1:450090bdb6f4 211 sys_timer100Hz++; // Just a handy measure of elapsed time for anything to use
JonFreeman 1:450090bdb6f4 212 if ((sys_timer100Hz & 0x03) == 0) // is now 12.5Hz, not 8
JonFreeman 1:450090bdb6f4 213 flag_25Hz = true; // flag gets set 25 times per sec. Other code may clear flag and make use of this
JonFreeman 1:450090bdb6f4 214 default:
JonFreeman 0:77803b3ee157 215 break;
JonFreeman 0:77803b3ee157 216 }
JonFreeman 0:77803b3ee157 217 t++;
JonFreeman 0:77803b3ee157 218 if (t > 9)
JonFreeman 0:77803b3ee157 219 t = 0;
JonFreeman 1:450090bdb6f4 220 Scope_probe = 0; // To show how much time spent in interrupt handler
JonFreeman 0:77803b3ee157 221 }
JonFreeman 0:77803b3ee157 222
JonFreeman 0:77803b3ee157 223
JonFreeman 0:77803b3ee157 224
JonFreeman 1:450090bdb6f4 225 // New stuff November 2019
JonFreeman 1:450090bdb6f4 226 /**
JonFreeman 1:450090bdb6f4 227 * Obtaining Amps_Deliverable from RPM.
JonFreeman 1:450090bdb6f4 228 * Lucas workshop sheet shows exponential relationship between RPM over threshold, and Amps_Deliverable,
JonFreeman 1:450090bdb6f4 229 * That is Amps_Deliverable rises steeply with RPM, flattening off towards 6000 RPM
JonFreeman 1:450090bdb6f4 230 * Curve modeled by eqn
JonFreeman 1:450090bdb6f4 231 * I_del = I_max (1 - exp(-(RPM-3000)/Const1)) where Const1 = 1000 is a starting point
JonFreeman 1:450090bdb6f4 232 * This is probably fine when driving alternator with BIG engine.
JonFreeman 1:450090bdb6f4 233 * When using small engine, rising load current sags engine RPM.
JonFreeman 1:450090bdb6f4 234 * Using a linear relationship builds in a good safety margin, possible eqn
JonFreeman 1:450090bdb6f4 235 * I_del = I_max (RPM - 3000) / 3000 for use over RPM range 3000-6000
JonFreeman 0:77803b3ee157 236 */
JonFreeman 1:450090bdb6f4 237 const double RPM_Threshold = 3000.0;
JonFreeman 1:450090bdb6f4 238 const double RPM_Max = 6000.0;
JonFreeman 1:450090bdb6f4 239 //const double I_max = 30.0;
JonFreeman 1:450090bdb6f4 240 const double RPM_Range = RPM_Max - RPM_Threshold;
JonFreeman 1:450090bdb6f4 241 //#define BIG_ENGINE
JonFreeman 1:450090bdb6f4 242
JonFreeman 1:450090bdb6f4 243 double Calculate_Amps_Deliverable (uint32_t RPM) {
JonFreeman 1:450090bdb6f4 244 double r = (double)RPM - RPM_Threshold;
JonFreeman 1:450090bdb6f4 245 r /= RPM_Range;
JonFreeman 1:450090bdb6f4 246 if (r < 0.0)
JonFreeman 1:450090bdb6f4 247 r = 0.0;
JonFreeman 1:450090bdb6f4 248 if (r > 1.0)
JonFreeman 1:450090bdb6f4 249 r = 1.0;
JonFreeman 1:450090bdb6f4 250 #ifdef BIG_ENGINE
JonFreeman 1:450090bdb6f4 251 const double Const1 = -3.2; // Tweak this to adjust shape of exponential function
JonFreeman 1:450090bdb6f4 252 return (1.0 - exp(r*Const1));
JonFreeman 0:77803b3ee157 253 #else
JonFreeman 1:450090bdb6f4 254 return r;
JonFreeman 0:77803b3ee157 255 #endif
JonFreeman 1:450090bdb6f4 256 }
JonFreeman 1:450090bdb6f4 257
JonFreeman 1:450090bdb6f4 258 class one_over_s_integrator { // Need this to drive servo Jan 2020 why?
JonFreeman 1:450090bdb6f4 259 double internal_integral, max, min, Hz, gain;
JonFreeman 1:450090bdb6f4 260 public:
JonFreeman 1:450090bdb6f4 261 one_over_s_integrator () { internal_integral = 0.0; max = 1.0; min = -1.0; Hz = 100.0; gain = 1.0;}
JonFreeman 1:450090bdb6f4 262 double integral (double input) ;
JonFreeman 1:450090bdb6f4 263 void set_max (double) ;
JonFreeman 1:450090bdb6f4 264 void set_min (double) ;
JonFreeman 1:450090bdb6f4 265 void set_gain (double) ;
JonFreeman 1:450090bdb6f4 266 void set_sample_time (double) ;
JonFreeman 1:450090bdb6f4 267 } ;
JonFreeman 1:450090bdb6f4 268
JonFreeman 1:450090bdb6f4 269 void one_over_s_integrator::set_max (double in) {
JonFreeman 1:450090bdb6f4 270 max = in;
JonFreeman 0:77803b3ee157 271 }
JonFreeman 1:450090bdb6f4 272 void one_over_s_integrator::set_min (double in) {
JonFreeman 1:450090bdb6f4 273 min = in;
JonFreeman 1:450090bdb6f4 274 }
JonFreeman 1:450090bdb6f4 275 void one_over_s_integrator::set_gain (double in) {
JonFreeman 1:450090bdb6f4 276 gain = in;
JonFreeman 1:450090bdb6f4 277 }
JonFreeman 1:450090bdb6f4 278 void one_over_s_integrator::set_sample_time (double in) {
JonFreeman 1:450090bdb6f4 279 Hz = 1.0 / in;
JonFreeman 1:450090bdb6f4 280 }
JonFreeman 1:450090bdb6f4 281 double one_over_s_integrator::integral (double input) {
JonFreeman 1:450090bdb6f4 282 internal_integral += gain * input / Hz; // 100 for 100Hz update rate
JonFreeman 1:450090bdb6f4 283 if (internal_integral > max)
JonFreeman 1:450090bdb6f4 284 internal_integral = max;
JonFreeman 1:450090bdb6f4 285 if (internal_integral < min)
JonFreeman 1:450090bdb6f4 286 internal_integral = min;
JonFreeman 1:450090bdb6f4 287 return internal_integral;
JonFreeman 1:450090bdb6f4 288 }
JonFreeman 1:450090bdb6f4 289
JonFreeman 1:450090bdb6f4 290 //double one_over_s ()
JonFreeman 1:450090bdb6f4 291 // End of New stuff November 2019
JonFreeman 0:77803b3ee157 292
JonFreeman 0:77803b3ee157 293
JonFreeman 0:77803b3ee157 294 // New stuff June 2019
JonFreeman 0:77803b3ee157 295 bool magneto_stretch = false;
JonFreeman 0:77803b3ee157 296 Timeout magneto_timo;
JonFreeman 1:450090bdb6f4 297 uint32_t magneto_times[8] = {0,0,0,0,0,0,0,0}; // June 2019, only 2 of these used
JonFreeman 1:450090bdb6f4 298
JonFreeman 0:77803b3ee157 299
JonFreeman 1:450090bdb6f4 300 /**
JonFreeman 1:450090bdb6f4 301 void magneto_timeout ()
JonFreeman 1:450090bdb6f4 302 Here 5ms after magneto pulse detected
JonFreeman 1:450090bdb6f4 303 This is sufficient time for ringing to cease, not long enough to lose next pulse even at max engine revs.
JonFreeman 1:450090bdb6f4 304 Reset 'magneto_stretch' flag set and used in 'ISR_magneto_tacho'
JonFreeman 1:450090bdb6f4 305 */
JonFreeman 0:77803b3ee157 306 void magneto_timeout ()
JonFreeman 0:77803b3ee157 307 {
JonFreeman 0:77803b3ee157 308 magneto_stretch = false; // Magneto ringing finished by now, re-enable magneto pulse count
JonFreeman 1:450090bdb6f4 309 EngineTachoOut = 0; // Cleaned tacho output brought out to pin to look at with scope
JonFreeman 0:77803b3ee157 310 }
JonFreeman 0:77803b3ee157 311
JonFreeman 1:450090bdb6f4 312 /**
JonFreeman 1:450090bdb6f4 313 void ISR_magneto_tacho () ; // New June 2019
JonFreeman 1:450090bdb6f4 314 // Engine On/Off switch turns engine off by shorting ignition volts magneto to ground.
JonFreeman 1:450090bdb6f4 315 // Therefore when engine running, have pulse signal one pulse per rev (even though 4 stroke, spark delivered at 2 stroke rate)
JonFreeman 1:450090bdb6f4 316 // Pulse spacing 20ms @ 3000 RPM, 60ms @ 1000 RPM, 6ms @ 10000 RPM
JonFreeman 1:450090bdb6f4 317
JonFreeman 1:450090bdb6f4 318 Magneto signal rings, is quite unclean, therefore a cleanup strategy is needed.
JonFreeman 1:450090bdb6f4 319 Solution - On arrival at this interrupt handler,
JonFreeman 1:450090bdb6f4 320 If flag 'magneto_stretch' true, do nothing and return (to avoid multiple pulse count)
JonFreeman 1:450090bdb6f4 321 Set flag 'magneto_stretch' true;
JonFreeman 1:450090bdb6f4 322 Start timer 'magneto_timo' to cause 'magneto_timeout' interrupt in a time longer than ringing bt shorter than shortest time to next spark
JonFreeman 1:450090bdb6f4 323 Record time between most recent two sparks and set output bit for scope monitoring
JonFreeman 1:450090bdb6f4 324 */
JonFreeman 1:450090bdb6f4 325 void ISR_magneto_tacho () // This interrupt initiated by rising (or falling) edge of magneto output, (not both)
JonFreeman 0:77803b3ee157 326 {
JonFreeman 0:77803b3ee157 327 if (!magneto_stretch)
JonFreeman 0:77803b3ee157 328 {
JonFreeman 0:77803b3ee157 329 uint32_t new_time = microsecs.read_us();
JonFreeman 0:77803b3ee157 330 if (new_time < magneto_times[1]) // rollover detection
JonFreeman 0:77803b3ee157 331 magneto_times[1] = 0;
JonFreeman 0:77803b3ee157 332 magneto_times[0] = new_time - magneto_times[1]; // microsecs between most recent two sparks
JonFreeman 0:77803b3ee157 333 magneto_times[1] = new_time; // actual time microsecs of most recent spark
JonFreeman 0:77803b3ee157 334 magneto_stretch = true;
JonFreeman 0:77803b3ee157 335 magneto_timo.attach_us (&magneto_timeout, 5000); // To ignore ringing and multiple counts on magneto output, all settled within about 5ms
JonFreeman 0:77803b3ee157 336 tacho_count++;
JonFreeman 1:450090bdb6f4 337 EngineTachoOut = 1; // Cleaned tacho output brought out to pin to look at with scope
JonFreeman 0:77803b3ee157 338 }
JonFreeman 0:77803b3ee157 339 }
JonFreeman 0:77803b3ee157 340
JonFreeman 0:77803b3ee157 341 // Endof New stuff June 2019
JonFreeman 0:77803b3ee157 342
JonFreeman 1:450090bdb6f4 343 const double shrink = 0.2;
JonFreeman 1:450090bdb6f4 344 /*double lpf_4th_order_asym (double input) {
JonFreeman 0:77803b3ee157 345 *
JonFreeman 1:450090bdb6f4 346 * input is driver's control pot.
JonFreeman 1:450090bdb6f4 347 * This needs regular calling, maybe 8Hz - 32Hz
JonFreeman 1:450090bdb6f4 348 *
JonFreeman 1:450090bdb6f4 349 * Output from 4th stage of cascaded Butterworth lpf section
JonFreeman 1:450090bdb6f4 350 * Used to delay rising input to motor controller allowing time for engine revs to rise
JonFreeman 0:77803b3ee157 351 */
JonFreeman 1:450090bdb6f4 352 double lpf_4th_order_asym (double input) {
JonFreeman 1:450090bdb6f4 353 static double lpfs[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
JonFreeman 1:450090bdb6f4 354 if (input < 0.0) input = 0.0;
JonFreeman 1:450090bdb6f4 355 if (input > 1.0) input = 1.0;
JonFreeman 1:450090bdb6f4 356 lpfs[0] = input; // zeroth order filter
JonFreeman 1:450090bdb6f4 357 double tmp;
JonFreeman 1:450090bdb6f4 358 for (int order = 1; order < 5; order++) {
JonFreeman 1:450090bdb6f4 359 tmp = (lpfs[order] * (1.0 - shrink))
JonFreeman 1:450090bdb6f4 360 + (lpfs[order - 1] * shrink);
JonFreeman 1:450090bdb6f4 361 if (tmp > input)
JonFreeman 1:450090bdb6f4 362 tmp = input;
JonFreeman 1:450090bdb6f4 363 lpfs[order] = tmp;
JonFreeman 1:450090bdb6f4 364 }
JonFreeman 1:450090bdb6f4 365 return tmp;
JonFreeman 0:77803b3ee157 366 }
JonFreeman 0:77803b3ee157 367
JonFreeman 1:450090bdb6f4 368
JonFreeman 1:450090bdb6f4 369 VEXT_Data Field;
JonFreeman 1:450090bdb6f4 370
JonFreeman 1:450090bdb6f4 371
JonFreeman 0:77803b3ee157 372 void ISR_VEXT_rise () // InterruptIn interrupt service
JonFreeman 1:450090bdb6f4 373 { // Here is possible to read back how regulator has controlled pwm - may or may not be useful
JonFreeman 1:450090bdb6f4 374 uint32_t tmp = microsecs.read_us();
JonFreeman 1:450090bdb6f4 375 Field.measured_period = tmp - Field.t_on;
JonFreeman 1:450090bdb6f4 376 Field.t_on = tmp;
JonFreeman 1:450090bdb6f4 377 Field.rise_count++;
JonFreeman 0:77803b3ee157 378 }
JonFreeman 0:77803b3ee157 379 void ISR_VEXT_fall () // InterruptIn interrupt service
JonFreeman 0:77803b3ee157 380 {
JonFreeman 1:450090bdb6f4 381 Field.fall_count++;
JonFreeman 1:450090bdb6f4 382 Field.t_off = microsecs.read_us();
JonFreeman 1:450090bdb6f4 383 Field.measured_pw_us = Field.t_off - Field.t_on;
JonFreeman 0:77803b3ee157 384 }
JonFreeman 0:77803b3ee157 385 // **** End of Interrupt Service Routines ****
JonFreeman 0:77803b3ee157 386
JonFreeman 0:77803b3ee157 387
JonFreeman 0:77803b3ee157 388 /** uint32_t ReadEngineRPM ()
JonFreeman 1:450090bdb6f4 389 *
JonFreeman 1:450090bdb6f4 390 * June 2019 - Replaced count of alternator frequency by count of engine magneto pulses.
JonFreeman 1:450090bdb6f4 391 *
JonFreeman 0:77803b3ee157 392 */
JonFreeman 0:77803b3ee157 393 uint32_t ReadEngineRPM ()
JonFreeman 0:77803b3ee157 394 {
JonFreeman 0:77803b3ee157 395 uint32_t time_since_last_spark = microsecs.read_us() - magneto_times[1];
JonFreeman 1:450090bdb6f4 396 if (time_since_last_spark > 250000) // if engine probably stopped, return old method RPM
JonFreeman 1:450090bdb6f4 397 return 0;
JonFreeman 1:450090bdb6f4 398 return (60000000 / magneto_times[0]); // 60 million / microsecs between two most recent sparks, eg 10,000us between sparks @ 6000 RPM
JonFreeman 0:77803b3ee157 399 }
JonFreeman 0:77803b3ee157 400
JonFreeman 1:450090bdb6f4 401 /*double Read_Ext_Rev_Req ()
JonFreeman 1:450090bdb6f4 402 {
JonFreeman 1:450090bdb6f4 403 double rv = (double) ext_rev_req;
JonFreeman 1:450090bdb6f4 404 return rv / 4096.0;
JonFreeman 1:450090bdb6f4 405 }*/
JonFreeman 1:450090bdb6f4 406
JonFreeman 1:450090bdb6f4 407 double Read_Driver_Pot ()
JonFreeman 1:450090bdb6f4 408 {
JonFreeman 1:450090bdb6f4 409 double rv = (double) driver_reading;
JonFreeman 1:450090bdb6f4 410 return rv / 4096.0;
JonFreeman 1:450090bdb6f4 411 }
JonFreeman 1:450090bdb6f4 412
JonFreeman 1:450090bdb6f4 413 double Read_AlternatorAmps ()
JonFreeman 1:450090bdb6f4 414 {
JonFreeman 1:450090bdb6f4 415 int32_t diff = amp_reading - amp_offset;
JonFreeman 1:450090bdb6f4 416 double amps = ((double) diff) / (1 << AMP_FILTER_FACTOR);
JonFreeman 1:450090bdb6f4 417 amps -= 365.0; // offset probably specific to particular board.
JonFreeman 1:450090bdb6f4 418 amps /= 1433.0; // fiddle factor
JonFreeman 1:450090bdb6f4 419 return amps;
JonFreeman 1:450090bdb6f4 420 }
JonFreeman 0:77803b3ee157 421
JonFreeman 0:77803b3ee157 422 double Read_BatteryVolts ()
JonFreeman 0:77803b3ee157 423 {
JonFreeman 1:450090bdb6f4 424 return ((double) volt_reading) / 3282.5; // divisor fiddled to make voltage reading correct !
JonFreeman 0:77803b3ee157 425 }
JonFreeman 0:77803b3ee157 426
JonFreeman 1:450090bdb6f4 427 void Read_Ammeter (double * p)
JonFreeman 1:450090bdb6f4 428 {
JonFreeman 1:450090bdb6f4 429 p[0] = amp_reading;
JonFreeman 1:450090bdb6f4 430 p[1] = amp_offset;
JonFreeman 1:450090bdb6f4 431 }
JonFreeman 1:450090bdb6f4 432
JonFreeman 1:450090bdb6f4 433 /**
JonFreeman 1:450090bdb6f4 434 void set_servo (double p) { // Only for test, called from cli
JonFreeman 1:450090bdb6f4 435 */
JonFreeman 0:77803b3ee157 436 void set_servo (double p) { // Only for test, called from cli
JonFreeman 0:77803b3ee157 437 Throttle = p;
JonFreeman 0:77803b3ee157 438 }
JonFreeman 0:77803b3ee157 439
JonFreeman 0:77803b3ee157 440 double normalise (double * p) {
JonFreeman 0:77803b3ee157 441 if (*p > 0.999)
JonFreeman 0:77803b3ee157 442 *p = 0.999;
JonFreeman 0:77803b3ee157 443 if (*p < 0.001)
JonFreeman 0:77803b3ee157 444 *p = 0.001;
JonFreeman 0:77803b3ee157 445 return * p;
JonFreeman 0:77803b3ee157 446 }
JonFreeman 0:77803b3ee157 447
JonFreeman 1:450090bdb6f4 448 uint32_t RPM_demand = 0; // For test, set from cli 'sv'
JonFreeman 1:450090bdb6f4 449 /**
JonFreeman 1:450090bdb6f4 450 */
JonFreeman 0:77803b3ee157 451 void set_RPM_demand (uint32_t d) {
JonFreeman 0:77803b3ee157 452 if (d < 10)
JonFreeman 0:77803b3ee157 453 d = 10;
JonFreeman 1:450090bdb6f4 454 if (d > MAX_RPM_LIMIT)
JonFreeman 1:450090bdb6f4 455 d = MAX_RPM_LIMIT;
JonFreeman 0:77803b3ee157 456 RPM_demand = d;
JonFreeman 0:77803b3ee157 457 }
JonFreeman 0:77803b3ee157 458
JonFreeman 1:450090bdb6f4 459 /**void set_pwm (double d) { Range 0.0 to 1.0
JonFreeman 1:450090bdb6f4 460 This PWM used to limit max duty ratio of alternator field energisation.
JonFreeman 1:450090bdb6f4 461 With R25=33k and C4=100n controlling ramp input to CS pin of MCP1630 (not MCP1630V),
JonFreeman 1:450090bdb6f4 462 ramp terminates fet 'on' pulse after a max of approx 980 us.
JonFreeman 1:450090bdb6f4 463 With const int PWM_PERIOD_US = 2000 , duty ratio is thus limited to approx 50% max.
JonFreeman 1:450090bdb6f4 464 This is about right when using 12V alternator on 24V systems
JonFreeman 1:450090bdb6f4 465 A 1.225V reference (U7) is fed to the MCP1630 error amp which compares this to fed-back proportion of system voltage.
JonFreeman 1:450090bdb6f4 466 This adjusts final PWM down to zero % as needed to maintain alternator output voltage.
JonFreeman 1:450090bdb6f4 467 */
JonFreeman 1:450090bdb6f4 468 void set_pwm (double d) {
JonFreeman 1:450090bdb6f4 469 uint32_t i;
JonFreeman 1:450090bdb6f4 470 if (d < 0.0)
JonFreeman 1:450090bdb6f4 471 d = 0.0;
JonFreeman 1:450090bdb6f4 472 if (d > 1.0)
JonFreeman 1:450090bdb6f4 473 d = 1.0;
JonFreeman 1:450090bdb6f4 474 i = (uint32_t)(d * (PWM_PERIOD_US / 2)); // div 2 when using 12v alternator in 24v system
JonFreeman 1:450090bdb6f4 475 // pc.printf ("Setting PWM to %d\r\n", i);
JonFreeman 1:450090bdb6f4 476 PWM_OSC_IN.pulsewidth_us (PWM_PERIOD_US - i); // Note PWM is inverted as MCP1630 uses inverted OSC_IN signal
JonFreeman 1:450090bdb6f4 477 }
JonFreeman 1:450090bdb6f4 478
JonFreeman 1:450090bdb6f4 479 void speed_control_factor_set (struct parameters & a) {
JonFreeman 1:450090bdb6f4 480 uint32_t v = (uint32_t)a.dbl[0];
JonFreeman 1:450090bdb6f4 481 if (v > 10)
JonFreeman 1:450090bdb6f4 482 speed_control_factor = v;
JonFreeman 1:450090bdb6f4 483 pc.printf ("speed_control_factor %d\r\n", speed_control_factor);
JonFreeman 1:450090bdb6f4 484 }
JonFreeman 1:450090bdb6f4 485
JonFreeman 1:450090bdb6f4 486 void set_throttle_limit (struct parameters & a) {
JonFreeman 1:450090bdb6f4 487 if (a.dbl[0] > 0.01 && a.dbl[0] < 1.001)
JonFreeman 1:450090bdb6f4 488 throttle_limit = a.dbl[0];
JonFreeman 1:450090bdb6f4 489 pc.printf ("throttle_limit %.2f\r\n", throttle_limit);
JonFreeman 1:450090bdb6f4 490 }
JonFreeman 1:450090bdb6f4 491
JonFreeman 1:450090bdb6f4 492 void query_system (struct parameters & a) {
JonFreeman 1:450090bdb6f4 493 query_toggle = !query_toggle;
JonFreeman 1:450090bdb6f4 494 // pc.printf ("Stuff about current state of system\r\n");
JonFreeman 1:450090bdb6f4 495 // pc.printf ("RPM=%d, servo%.2f\r\n", ReadEngineRPM (), servo_position);
JonFreeman 1:450090bdb6f4 496 }
JonFreeman 1:450090bdb6f4 497
JonFreeman 0:77803b3ee157 498 extern void command_line_interpreter () ; // Comms with optional pc or device using serial port through board USB socket
JonFreeman 0:77803b3ee157 499 extern bool i2c_init () ;
JonFreeman 0:77803b3ee157 500 extern int check_24LC64 () ;
JonFreeman 0:77803b3ee157 501
JonFreeman 0:77803b3ee157 502 // Programme Entry Point
JonFreeman 0:77803b3ee157 503 int main()
JonFreeman 0:77803b3ee157 504 {
JonFreeman 0:77803b3ee157 505 // local variable declarations
JonFreeman 1:450090bdb6f4 506 // double servo_position = 0.2; // set in speed control loop
JonFreeman 0:77803b3ee157 507 double revs_error;
JonFreeman 1:450090bdb6f4 508 double Amps_Deliverable = 0.0; // New Nov 2019
JonFreeman 1:450090bdb6f4 509 // double tempfilt = 0.0, servo_fucker = 0.01;
JonFreeman 0:77803b3ee157 510
JonFreeman 1:450090bdb6f4 511 int32_t RPM_ave = 0, RPM_filt = 0, RPM_tmp;
JonFreeman 1:450090bdb6f4 512 int32_t irevs_error;
JonFreeman 1:450090bdb6f4 513 uint32_t ticks = 0;
JonFreeman 1:450090bdb6f4 514
JonFreeman 0:77803b3ee157 515 pulse_tacho.fall (&ISR_magneto_tacho); // 1 pulse per engine rev
JonFreeman 0:77803b3ee157 516 VEXT.rise (&ISR_VEXT_rise); // Handles - MCP1630 has just turned mosfet on
JonFreeman 0:77803b3ee157 517 VEXT.fall (&ISR_VEXT_fall); // Handles - MCP1630 has just turned mosfet off
JonFreeman 0:77803b3ee157 518 microsecs.reset() ; // timer = 0
JonFreeman 0:77803b3ee157 519 microsecs.start () ; // 64 bit, counts micro seconds and times out in half million years
JonFreeman 1:450090bdb6f4 520
JonFreeman 1:450090bdb6f4 521 PWM_OSC_IN.period_us (PWM_PERIOD_US); // about 313Hz * 2
JonFreeman 1:450090bdb6f4 522 // PROBLEM using same pwm, common prescaler, can't update servo that fast, can't pwm field that slow.
JonFreeman 1:450090bdb6f4 523
JonFreeman 1:450090bdb6f4 524 PWM_OSC_IN.pulsewidth_us (PWM_PERIOD_US / 2); // value is int
JonFreeman 1:450090bdb6f4 525 // PWM_OSC_IN.pulsewidth_us (PWM_PERIOD_US); // value is int
JonFreeman 1:450090bdb6f4 526 #ifdef TARGET_NUCLEO_F401RE //
JonFreeman 1:450090bdb6f4 527 A_OUT.period_us (100); // pwm as analogue out
JonFreeman 0:77803b3ee157 528 A_OUT.pulsewidth_us (19);
JonFreeman 1:450090bdb6f4 529 #endif
JonFreeman 0:77803b3ee157 530 Throttle = servo_position;
JonFreeman 1:450090bdb6f4 531 pc.printf ("\r\n\n\n\n\nAlternator Regulator 2020, Jon Freeman, SystemCoreClock=%d\r\n", SystemCoreClock);
JonFreeman 0:77803b3ee157 532 if (!i2c_init())
JonFreeman 0:77803b3ee157 533 pc.printf ("i2c bus failed init\r\n");
JonFreeman 0:77803b3ee157 534 pc.printf ("check_24LC64 returned 0x%x\r\n", check_24LC64());
JonFreeman 1:450090bdb6f4 535 user_settings.load () ; // Fetch values from eeprom, also builds table of speed -> pwm lookups
JonFreeman 1:450090bdb6f4 536 // pc.printf ("Loaded\r\n");
JonFreeman 0:77803b3ee157 537 // Setup Complete ! Can now start main control forever loop.
JonFreeman 1:450090bdb6f4 538 loop_timer.attach_us (&ISR_fast_interrupt, MAIN_LOOP_REPEAT_TIME_US / 10); // Start periodic interrupt generator 1000us at Feb 2020
JonFreeman 0:77803b3ee157 539
JonFreeman 0:77803b3ee157 540 //***** START OF MAIN LOOP
JonFreeman 0:77803b3ee157 541 while (1) { // Loop forever, repeats synchroised by waiting for ticker Interrupt Service Routine to set 'loop_flag' true
JonFreeman 0:77803b3ee157 542 while (!loop_flag) { // Most of the time is spent in this loop, repeatedly re-checking for commands from pc port
JonFreeman 0:77803b3ee157 543 command_line_interpreter () ; // Proceed beyond here once loop_timer ticker ISR has set loop_flag true
JonFreeman 1:450090bdb6f4 544 } // Jun 2019 pass here 100 times per sec
JonFreeman 1:450090bdb6f4 545 // BEGIN 100Hz stuff
JonFreeman 0:77803b3ee157 546 loop_flag = false; // Clear flag set by ticker interrupt handler
JonFreeman 1:450090bdb6f4 547
JonFreeman 1:450090bdb6f4 548 // Three variations on engine rpm.
JonFreeman 1:450090bdb6f4 549 RPM_tmp = ReadEngineRPM ();
JonFreeman 1:450090bdb6f4 550 RPM_ave += RPM_tmp; // Rising sum needs dividing and resetting to 0 when used
JonFreeman 1:450090bdb6f4 551 RPM_filt += RPM_tmp;
JonFreeman 1:450090bdb6f4 552 RPM_filt >>= 1;
JonFreeman 1:450090bdb6f4 553
JonFreeman 1:450090bdb6f4 554 amp_reading += (raw_amp_reading - 0.5) * AMPS_CAL;
JonFreeman 1:450090bdb6f4 555 amp_reading /= 2.0;
JonFreeman 1:450090bdb6f4 556 amp_offset += (raw_amp_offset - 0.5) * AMPS_CAL; // This reading probably not useful
JonFreeman 1:450090bdb6f4 557 amp_offset /= 2.0;
JonFreeman 1:450090bdb6f4 558
JonFreeman 1:450090bdb6f4 559 Amps_Deliverable = Calculate_Amps_Deliverable (ReadEngineRPM ()); // Added Nov 2019, not yet used. Returns normalised 0.0 to 1.0
JonFreeman 1:450090bdb6f4 560
JonFreeman 1:450090bdb6f4 561 // PWM_OSC_IN.pulsewidth_us (user_settings.get_pwm(ReadEngineRPM())); // Update field current limit according to latest measured RPM
JonFreeman 0:77803b3ee157 562
JonFreeman 0:77803b3ee157 563 // while (LocalCom.readable()) {
JonFreeman 0:77803b3ee157 564 // int q = LocalCom.getc();
JonFreeman 0:77803b3ee157 565 // //q++;
JonFreeman 0:77803b3ee157 566 // pc.putc (q);
JonFreeman 0:77803b3ee157 567 // }
JonFreeman 1:450090bdb6f4 568 // END 100Hz stuff
JonFreeman 1:450090bdb6f4 569 if (flag_25Hz) {
JonFreeman 1:450090bdb6f4 570 flag_25Hz = false;
JonFreeman 1:450090bdb6f4 571 // BEGIN 25Hz stuff
JonFreeman 0:77803b3ee157 572
JonFreeman 1:450090bdb6f4 573 // END 25Hz stuff
JonFreeman 1:450090bdb6f4 574 // BEGIN 12.5Hz stuff
JonFreeman 1:450090bdb6f4 575 flag_12Hz5 = !flag_12Hz5;
JonFreeman 1:450090bdb6f4 576 if (flag_12Hz5) { // Do any even stuff to be done 12.5 times per second
JonFreeman 1:450090bdb6f4 577 #ifdef SPEED_CONTROL_ENABLE
JonFreeman 1:450090bdb6f4 578 if (RPM_demand < TICKOVER_RPM)
JonFreeman 1:450090bdb6f4 579 servo_position = Throttle = 0.0;
JonFreeman 1:450090bdb6f4 580 else {
JonFreeman 1:450090bdb6f4 581 RPM_ave /= 8;
JonFreeman 1:450090bdb6f4 582 // irevs_error = RPM_demand - ReadEngineRPM ();
JonFreeman 1:450090bdb6f4 583 irevs_error = RPM_demand - RPM_filt;
JonFreeman 1:450090bdb6f4 584 revs_error = (double) irevs_error;
JonFreeman 1:450090bdb6f4 585 if (abs(revs_error) > 3.0) { // if speed error > 3rpm, tweak, otherwise deadband
JonFreeman 1:450090bdb6f4 586 //servo_position += (revs_error / 7500.0);
JonFreeman 1:450090bdb6f4 587 servo_position += (revs_error / speed_control_factor);
JonFreeman 1:450090bdb6f4 588 servo_position = normalise(&servo_position);
JonFreeman 1:450090bdb6f4 589 if (servo_position < 0.0 || servo_position > 1.0)
JonFreeman 1:450090bdb6f4 590 pc.printf ("servo_position error %f\r\n", servo_position);
JonFreeman 1:450090bdb6f4 591 if (servo_position > throttle_limit)
JonFreeman 1:450090bdb6f4 592 servo_position = throttle_limit;
JonFreeman 1:450090bdb6f4 593 Throttle = servo_position;
JonFreeman 1:450090bdb6f4 594 }
JonFreeman 1:450090bdb6f4 595 }
JonFreeman 1:450090bdb6f4 596 RPM_ave = 0; // Reset needed
JonFreeman 1:450090bdb6f4 597 #endif
JonFreeman 1:450090bdb6f4 598 }
JonFreeman 1:450090bdb6f4 599 else { // Do odd 12.5 times per sec stuff
JonFreeman 1:450090bdb6f4 600 flag_12Hz5 = false;
JonFreeman 1:450090bdb6f4 601 myled = !myled;
JonFreeman 1:450090bdb6f4 602 LocalCom.printf ("%d\r\n", volt_reading);
JonFreeman 1:450090bdb6f4 603 //void set_pwm (double d) {
JonFreeman 1:450090bdb6f4 604
JonFreeman 1:450090bdb6f4 605 // set_pwm (user_settings.get_pwm(ReadEngineRPM()));
JonFreeman 1:450090bdb6f4 606
JonFreeman 1:450090bdb6f4 607 /* servo_position += servo_fucker;
JonFreeman 1:450090bdb6f4 608 if (servo_position > 1.0 || servo_position < 0.0)
JonFreeman 1:450090bdb6f4 609 servo_fucker *= -1.0;
JonFreeman 1:450090bdb6f4 610 Throttle = servo_position;
JonFreeman 1:450090bdb6f4 611 */
JonFreeman 1:450090bdb6f4 612 } // End of if(flag_12Hz5)
JonFreeman 1:450090bdb6f4 613 // END 12.5Hz stuff
JonFreeman 1:450090bdb6f4 614 ticks++; // advances @ 25Hz
JonFreeman 1:450090bdb6f4 615 if (ticks > 24) { // once per sec stuff
JonFreeman 1:450090bdb6f4 616 // BEGIN 1Hz stuff
JonFreeman 0:77803b3ee157 617 ticks = 0;
JonFreeman 1:450090bdb6f4 618 if (query_toggle) {
JonFreeman 1:450090bdb6f4 619 pc.printf ("V=%.1f\tI=%.1f\tRPM=%d\tservo%.2f\r\n", Read_BatteryVolts(), amp_reading, ReadEngineRPM (), servo_position);
JonFreeman 1:450090bdb6f4 620 }
JonFreeman 1:450090bdb6f4 621 // pc.printf ("Tick %d\r\n", flag_12Hz5);
JonFreeman 1:450090bdb6f4 622 // tempfilt *= 0.99;
JonFreeman 1:450090bdb6f4 623 // tempfilt += Read_AlternatorAmps() * 0.01;
JonFreeman 1:450090bdb6f4 624 // pc.printf ("RPM %d, err %.1f, s_p %.2f, lut %.3f\r\n", ReadEngineRPM (), revs_error, servo_position, user_settings.get_pwm(ReadEngineRPM()));
JonFreeman 1:450090bdb6f4 625 // pc.printf ("Vbat %.2f, servo %.3f, amps %.3f, filt %.3f\r\n", Read_BatteryVolts(), servo_position, Read_AlternatorAmps(), tempfilt);
JonFreeman 1:450090bdb6f4 626 // END 1Hz stuff
JonFreeman 0:77803b3ee157 627 } // eo once per second stuff
JonFreeman 1:450090bdb6f4 628 } // End of 100Hz stuff
JonFreeman 0:77803b3ee157 629 } // End of main programme loop
JonFreeman 0:77803b3ee157 630 } // End of main function - end of programme
JonFreeman 0:77803b3ee157 631 //***** END OF MAIN LOOP