Jon Freeman / Mbed 2 deprecated Alternator2020_06

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