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:
Fri Jun 28 19:32:51 2019 +0000
Revision:
0:77803b3ee157
Child:
1:450090bdb6f4
As at end June 2019

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 #define MAGNETO_SPEED // Selects engine speed input as magneto coil on engine switch line
JonFreeman 0:77803b3ee157 5 #define SPEED_CONTROL_ENABLE // Includes engine revs servo control loop
JonFreeman 0:77803b3ee157 6
JonFreeman 0:77803b3ee157 7 /*
JonFreeman 0:77803b3ee157 8 Alternator Regulator
JonFreeman 0:77803b3ee157 9 Jon Freeman
JonFreeman 0:77803b3ee157 10 June 2019
JonFreeman 0:77803b3ee157 11
JonFreeman 0:77803b3ee157 12 WHAT THIS PROGRAMME DOES -
JonFreeman 0:77803b3ee157 13
JonFreeman 0:77803b3ee157 14 BEGIN
JonFreeman 0:77803b3ee157 15 Loop forever at 32 Hz {
JonFreeman 0:77803b3ee157 16 Read engine RPM
JonFreeman 0:77803b3ee157 17 Adjust Alternator field current max limit according to RPM
JonFreeman 0:77803b3ee157 18 Measure system voltage (just in case this is ever useful)
JonFreeman 0:77803b3ee157 19 Respond to any commands arriving at serial port (setup and test link to laptop)
JonFreeman 0:77803b3ee157 20 Flash LED at 8 Hz as proof of life
JonFreeman 0:77803b3ee157 21 }
JonFreeman 0:77803b3ee157 22 END
JonFreeman 0:77803b3ee157 23
JonFreeman 0:77803b3ee157 24 INPUTS AnalogIn x 2 - Ammeter chip - current and offset AnalogIns
JonFreeman 0:77803b3ee157 25 INPUT AnalogIn - System voltage for info only.
JonFreeman 0:77803b3ee157 26 INPUT AnalogIn - ExtRevDemand
JonFreeman 0:77803b3ee157 27 INPUT AnalogIn - DriverPot
JonFreeman 0:77803b3ee157 28 INPUT Pulse engine speed indicator, speed checked against EEPROM data to select max pwm duty ratio for this speed
JonFreeman 0:77803b3ee157 29 INPUT Final pwm gate drive wired back to InterruptIn ** MAYBE USEFUL OR NOT ** Could read this back via serial to laptop
JonFreeman 0:77803b3ee157 30 OUTPUT pwm to MCP1630. This is clock to pwm chip. Also limits max duty ratio
JonFreeman 0:77803b3ee157 31 RS232 serial via USB to setup eeprom data
JonFreeman 0:77803b3ee157 32 */
JonFreeman 0:77803b3ee157 33 // Uses software bit banged I2C - DONE (because no attempt to get I2C working on these small boards)
JonFreeman 0:77803b3ee157 34
JonFreeman 0:77803b3ee157 35 /**
JonFreeman 0:77803b3ee157 36 * Jumpers fitted to small mbed Nucleo boards - D5 - A5 and D4 - A4 CHECK - yes
JonFreeman 0:77803b3ee157 37 */
JonFreeman 0:77803b3ee157 38 /*
JonFreeman 0:77803b3ee157 39 declared in file i2c_bit_banged.cpp
JonFreeman 0:77803b3ee157 40 DigitalInOut SDA (D4); // Horrible bodge to get i2c working using bit banging.
JonFreeman 0:77803b3ee157 41 DigitalInOut SCL (D5); // DigitalInOut do not work as you might expect. Fine if used only as OpenDrain opuputs though!
JonFreeman 0:77803b3ee157 42 DigitalIn SDA_IN (A4); // That means paralleling up with two other pins as inputs
JonFreeman 0:77803b3ee157 43 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 44 */
JonFreeman 0:77803b3ee157 45 Serial pc (USBTX, USBRX); // Comms port to pc or terminal using USB lead
JonFreeman 0:77803b3ee157 46 BufferedSerial LocalCom (PA_9, PA_10); // New March 2019
JonFreeman 0:77803b3ee157 47 // Above combo of Serial and BufferedSerial is the only one to work !
JonFreeman 0:77803b3ee157 48
JonFreeman 0:77803b3ee157 49 // INPUTS :
JonFreeman 0:77803b3ee157 50 AnalogIn Ain_SystemVolts (A0); // Brought out to CN8 'AN' A0. Connect 3k3 resistor from A0 to ground.
JonFreeman 0:77803b3ee157 51 AnalogIn Ammeter_In (A1); // Output of ASC709LLFTR ammeter chip (pin 20)
JonFreeman 0:77803b3ee157 52 AnalogIn Ammeter_Ref (A6); // Ref output from ASC709LLFTR used to set ammeter zero (pin 25)
JonFreeman 0:77803b3ee157 53 AnalogIn Ext_Rev_Demand (D3); // Servo determines engine revs, servo out to be higher of Ext_Rev_Demand and internal calc
JonFreeman 0:77803b3ee157 54 AnalogIn Driver_Pot (A3); // If whole control system can be made to fit
JonFreeman 0:77803b3ee157 55 // Connect 33k resistor from A0 to nom 24 Volt system rail.
JonFreeman 0:77803b3ee157 56
JonFreeman 0:77803b3ee157 57 //#ifdef TARGET_NUCLEO_F303K8 //
JonFreeman 0:77803b3ee157 58 #ifdef TARGET_NUCLEO_L432KC //
JonFreeman 0:77803b3ee157 59 /*
JonFreeman 0:77803b3ee157 60 MODULE PIN USAGE
JonFreeman 0:77803b3ee157 61 1 PA_9 D1 LocalCom Tx
JonFreeman 0:77803b3ee157 62 2 PA_10 D0 LocalCom Rx
JonFreeman 0:77803b3ee157 63 3 NRST
JonFreeman 0:77803b3ee157 64 4 GND
JonFreeman 0:77803b3ee157 65 5 PA12_D2 NEW June 2019 - Output engine tacho cleaned-up
JonFreeman 0:77803b3ee157 66 6 PB_0 D3 AnalogIn Ext_Rev_Demand
JonFreeman 0:77803b3ee157 67 7 PB_7 D4 SDA i2c to 24LC memory
JonFreeman 0:77803b3ee157 68 8 PB_6 D5 SCL i2c to 24LC memory
JonFreeman 0:77803b3ee157 69 9 PB_12 D6 PwmOut PWM_OSC_IN Timebase for pwm, also determines max duty ratio
JonFreeman 0:77803b3ee157 70 10 N.C.
JonFreeman 0:77803b3ee157 71 11 N.C.
JonFreeman 0:77803b3ee157 72 12 PA_8 D9 InterruptIn pulse_tacho from alternator, used to measure rpm
JonFreeman 0:77803b3ee157 73 13 PA_11 D10
JonFreeman 0:77803b3ee157 74 14 PB_5 D11
JonFreeman 0:77803b3ee157 75 15 PB_4 D12
JonFreeman 0:77803b3ee157 76 16 PB_3 D13 LED Onboard LED
JonFreeman 0:77803b3ee157 77 17 3V3
JonFreeman 0:77803b3ee157 78 18 AREF
JonFreeman 0:77803b3ee157 79 19 PA_0 A0 AnalogIn V_Sample system link voltage
JonFreeman 0:77803b3ee157 80 20 PA_1 A1 AnalogIn Ammeter_In
JonFreeman 0:77803b3ee157 81 21 PA_3 A2 PWM analogue out
JonFreeman 0:77803b3ee157 82 22 PA_4 A3 InterruptIn VEXT PWM controller output folded back for cpu to monitor, useful on test to read what pwm required to do what
JonFreeman 0:77803b3ee157 83 23 PA_5 A4 n.c. SDA_IN paralleled to i2c pin, necessary because i2c has to be bit banged
JonFreeman 0:77803b3ee157 84 24 PA_6 A5 n.c. SCL_IN paralleled to i2c pin, necessary because i2c has to be bit banged
JonFreeman 0:77803b3ee157 85 25 PA_7 A6 AnalogIn Ammeter_Ref
JonFreeman 0:77803b3ee157 86 26 PA_2 A7 UART2_TX Throttle Servo out now on D10, can not use D11, can not use D12 for these
JonFreeman 0:77803b3ee157 87 27 5V
JonFreeman 0:77803b3ee157 88 28 NRST
JonFreeman 0:77803b3ee157 89 29 GND
JonFreeman 0:77803b3ee157 90 30 VIN
JonFreeman 0:77803b3ee157 91 */
JonFreeman 0:77803b3ee157 92
JonFreeman 0:77803b3ee157 93 InterruptIn pulse_tacho (D9); // Signal from 'W' alternator terminal via low pass filter and Schmitt trigger cleanup
JonFreeman 0:77803b3ee157 94 // NOTE D7 pin was no good for this
JonFreeman 0:77803b3ee157 95 //InterruptIn VEXT (A3); // PWM controller output folded back for cpu to monitor, useful on test to read what pwm required to do what
JonFreeman 0:77803b3ee157 96 InterruptIn VEXT (D11); // PWM controller output folded back for cpu to monitor, useful on test to read what pwm required to do what
JonFreeman 0:77803b3ee157 97 // OUTPUTS :
JonFreeman 0:77803b3ee157 98
JonFreeman 0:77803b3ee157 99 //DigitalOut Scope_probe (D0); // Handy pin to hang scope probe onto while developing code
JonFreeman 0:77803b3ee157 100 DigitalOut myled(LED1); // Green LED on board is PB_3 D13
JonFreeman 0:77803b3ee157 101 //PwmOut PWM_OSC_IN (A6); // Can alter prescaler can not use A5
JonFreeman 0:77803b3ee157 102 PwmOut PWM_OSC_IN (D6); // Can alter prescaler can not use A5
JonFreeman 0:77803b3ee157 103 PwmOut A_OUT (A2); // Can alter prescaler can not use A5
JonFreeman 0:77803b3ee157 104 //Servo Throttle (A2); // Pin A2, PA3
JonFreeman 0:77803b3ee157 105 //Servo Throttle (A7); // Changed from A2, June 2019
JonFreeman 0:77803b3ee157 106 Servo Throttle (D10); // Changed from A2, June 2019
JonFreeman 0:77803b3ee157 107 DigitalOut EngineTachoOut (D2); // New June 2019
JonFreeman 0:77803b3ee157 108 #endif
JonFreeman 0:77803b3ee157 109 Timer microsecs;
JonFreeman 0:77803b3ee157 110 Ticker loop_timer; // Device to cause periodic interrupts, used to sync iterations of main programme loop - slow
JonFreeman 0:77803b3ee157 111
JonFreeman 0:77803b3ee157 112 extern eeprom_settings mode ;
JonFreeman 0:77803b3ee157 113 // SYSTEM CONSTANTS
JonFreeman 0:77803b3ee157 114 /* Please Do Not Alter these */
JonFreeman 0:77803b3ee157 115 const int MAIN_LOOP_REPEAT_TIME_US = 31250; // 31250 us, with TACHO_TAB_SIZE = 32 means tacho_ticks_per_time is tacho_ticks_per_second
JonFreeman 0:77803b3ee157 116 const int MAIN_LOOP_ITERATION_Hz = 1000000 / MAIN_LOOP_REPEAT_TIME_US; // = 32 Hz
JonFreeman 0:77803b3ee157 117 //const int FAST_INTERRUPT_RATE = 3125;
JonFreeman 0:77803b3ee157 118 /* End of Please Do Not Alter these */
JonFreeman 0:77803b3ee157 119 /* Global variable declarations */
JonFreeman 0:77803b3ee157 120 uint32_t //semaphore = 0,
JonFreeman 0:77803b3ee157 121 volt_reading = 0, // Global updated by interrupt driven read of Battery Volts
JonFreeman 0:77803b3ee157 122 amp_reading = 0,
JonFreeman 0:77803b3ee157 123 amp_offset = 0,
JonFreeman 0:77803b3ee157 124 ext_rev_req = 0,
JonFreeman 0:77803b3ee157 125 driver_reading = 0,
JonFreeman 0:77803b3ee157 126 tacho_count = 0, // Global incremented on each transition of InterruptIn pulse_tacho
JonFreeman 0:77803b3ee157 127 tacho_ticks_per_time = 0, // Global tacho ticks in most recent (MAIN_LOOP_REPEAT_TIME_US * TACHO_TABLE_SIZE) micro secs
JonFreeman 0:77803b3ee157 128 sys_timer32Hz = 0; // gets incremented by our Ticker ISR every MAIN_LOOP_REPEAT_TIME_US
JonFreeman 0:77803b3ee157 129 bool loop_flag = false; // made true in ISR_loop_timer, picked up and made false again in main programme loop
JonFreeman 0:77803b3ee157 130 bool flag_8Hz = false; // As loop_flag but repeats 8 times per sec
JonFreeman 0:77803b3ee157 131
JonFreeman 0:77803b3ee157 132
JonFreeman 0:77803b3ee157 133 const double scale = 0.125;
JonFreeman 0:77803b3ee157 134 const double shrink_by = 1.0 - scale;
JonFreeman 0:77803b3ee157 135 double glob_rpm;
JonFreeman 0:77803b3ee157 136
JonFreeman 0:77803b3ee157 137 /* End of Global variable declarations */
JonFreeman 0:77803b3ee157 138
JonFreeman 0:77803b3ee157 139 //void ISR_fast_interrupt () { // here at 10 times main loop repeat rate (i.e. 320Hz)
JonFreeman 0:77803b3ee157 140 void ISR_fast_interrupt () { // here at ** 25 ** times main loop repeat rate (1250us, i.e. 800Hz)
JonFreeman 0:77803b3ee157 141 static int t = 0;
JonFreeman 0:77803b3ee157 142 switch (t) {
JonFreeman 0:77803b3ee157 143 case 0:
JonFreeman 0:77803b3ee157 144 volt_reading >>= 1; // Result = Result / 2
JonFreeman 0:77803b3ee157 145 volt_reading += Ain_SystemVolts.read_u16 (); // Result = Result + New Reading
JonFreeman 0:77803b3ee157 146 break;
JonFreeman 0:77803b3ee157 147 case 1:
JonFreeman 0:77803b3ee157 148 amp_reading >>= 1; // Result = Result / 2
JonFreeman 0:77803b3ee157 149 amp_reading = Ammeter_In.read_u16();
JonFreeman 0:77803b3ee157 150 break;
JonFreeman 0:77803b3ee157 151 case 2:
JonFreeman 0:77803b3ee157 152 amp_offset >>= 1; // Result = Result / 2
JonFreeman 0:77803b3ee157 153 amp_offset = Ammeter_Ref.read_u16();
JonFreeman 0:77803b3ee157 154 break;
JonFreeman 0:77803b3ee157 155 case 3:
JonFreeman 0:77803b3ee157 156 ext_rev_req >>= 1; // Result = Result / 2
JonFreeman 0:77803b3ee157 157 ext_rev_req = Ext_Rev_Demand.read_u16();
JonFreeman 0:77803b3ee157 158 break;
JonFreeman 0:77803b3ee157 159 case 4:
JonFreeman 0:77803b3ee157 160 driver_reading >>= 1; // Result = Result / 2
JonFreeman 0:77803b3ee157 161 driver_reading = Driver_Pot.read_u16();
JonFreeman 0:77803b3ee157 162 break;
JonFreeman 0:77803b3ee157 163 case 5:
JonFreeman 0:77803b3ee157 164 // semaphore++;
JonFreeman 0:77803b3ee157 165 const int TACHO_TABLE_SIZE = MAIN_LOOP_ITERATION_Hz; // Ensures table contains exactly one seconds worth of samples
JonFreeman 0:77803b3ee157 166 static uint32_t h[TACHO_TABLE_SIZE], // circular buffer to contain list of 'tacho_count's
JonFreeman 0:77803b3ee157 167 i = 0, last_temp = 0;
JonFreeman 0:77803b3ee157 168 static double rpm_filt = 0.0;
JonFreeman 0:77803b3ee157 169 double tmp;
JonFreeman 0:77803b3ee157 170
JonFreeman 0:77803b3ee157 171 uint32_t temp = tacho_count; // Read very latest total pulse count from global tacho_count
JonFreeman 0:77803b3ee157 172 tmp = (double) (temp - last_temp);
JonFreeman 0:77803b3ee157 173 last_temp = temp;
JonFreeman 0:77803b3ee157 174 #ifdef MAGNETO_SPEED
JonFreeman 0:77803b3ee157 175 tmp *= (scale * 32.0 * 60.0); // ???? Is this including alternator poles count ??? Do we need MAGNETO_SPEED included
JonFreeman 0:77803b3ee157 176 #else
JonFreeman 0:77803b3ee157 177 tmp *= (scale * 32.0 * 60.0 / 12.0); // ???? Is this including alternator poles count ??? Do we need MAGNETO_SPEED included
JonFreeman 0:77803b3ee157 178 #endif
JonFreeman 0:77803b3ee157 179 rpm_filt *= shrink_by;
JonFreeman 0:77803b3ee157 180 rpm_filt += tmp;
JonFreeman 0:77803b3ee157 181 glob_rpm = rpm_filt;
JonFreeman 0:77803b3ee157 182
JonFreeman 0:77803b3ee157 183 tacho_ticks_per_time = temp - h[i]; // latest tacho total pulse count - oldest stored tacho total pulse count
JonFreeman 0:77803b3ee157 184 h[i] = temp; // latest overwrites oldest in table
JonFreeman 0:77803b3ee157 185 i++; // index to next table position for next time around
JonFreeman 0:77803b3ee157 186 if (i >= TACHO_TABLE_SIZE)
JonFreeman 0:77803b3ee157 187 i = 0; // circular buffer
JonFreeman 0:77803b3ee157 188 loop_flag = true; // set flag to allow main programme loop to proceed
JonFreeman 0:77803b3ee157 189 sys_timer32Hz++; // Just a handy measure of elapsed time for anything to use
JonFreeman 0:77803b3ee157 190 if ((sys_timer32Hz & 0x03) == 0)
JonFreeman 0:77803b3ee157 191 flag_8Hz = true; // flag gets set 8 times per sec. Other code may clear flag and make use of this
JonFreeman 0:77803b3ee157 192 break;
JonFreeman 0:77803b3ee157 193 }
JonFreeman 0:77803b3ee157 194 t++;
JonFreeman 0:77803b3ee157 195 if (t > 9)
JonFreeman 0:77803b3ee157 196 t = 0;
JonFreeman 0:77803b3ee157 197 }
JonFreeman 0:77803b3ee157 198
JonFreeman 0:77803b3ee157 199
JonFreeman 0:77803b3ee157 200
JonFreeman 0:77803b3ee157 201 /** void ISR_loop_timer ()
JonFreeman 0:77803b3ee157 202 * This ISR responds to Ticker interrupts at a rate of (probably) 32 times per second (check from constant declarations above)
JonFreeman 0:77803b3ee157 203 * This ISR sets global flag 'loop_flag' used to synchronise passes around main programme control loop.
JonFreeman 0:77803b3ee157 204 * Also, updates global int 'tacho_ticks_per_time' to contain total number of transitions from alternator 'W' terminal in
JonFreeman 0:77803b3ee157 205 * time period from exactly one second ago until now.
JonFreeman 0:77803b3ee157 206 * Increments global 'sys_timer32Hz', usable anywhere as general measure of elapsed time
JonFreeman 0:77803b3ee157 207 */
JonFreeman 0:77803b3ee157 208 void ISR_loop_timer () // This is Ticker Interrupt Service Routine - loop timer - MAIN_LOOP_REPEAT_TIME_US
JonFreeman 0:77803b3ee157 209 { // Jan 2019 MAIN_LOOP_REPEAT_TIME_US = 31.25 ms
JonFreeman 0:77803b3ee157 210 const int TACHO_TABLE_SIZE = MAIN_LOOP_ITERATION_Hz; // Ensures table contains exactly one seconds worth of samples
JonFreeman 0:77803b3ee157 211 static uint32_t h[TACHO_TABLE_SIZE], // circular buffer to contain list of 'tacho_count's
JonFreeman 0:77803b3ee157 212 i = 0, last_temp = 0;
JonFreeman 0:77803b3ee157 213 static double rpm_filt = 0.0;
JonFreeman 0:77803b3ee157 214 double tmp;
JonFreeman 0:77803b3ee157 215
JonFreeman 0:77803b3ee157 216 uint32_t temp = tacho_count; // Read very latest total pulse count from global tacho_count
JonFreeman 0:77803b3ee157 217 tmp = (double) (temp - last_temp);
JonFreeman 0:77803b3ee157 218 last_temp = temp;
JonFreeman 0:77803b3ee157 219 #ifdef MAGNETO_SPEED
JonFreeman 0:77803b3ee157 220 tmp *= (scale * 32.0 * 60.0); // ???? Is this including alternator poles count ??? Do we need MAGNETO_SPEED included
JonFreeman 0:77803b3ee157 221 #else
JonFreeman 0:77803b3ee157 222 tmp *= (scale * 32.0 * 60.0 / 12.0); // ???? Is this including alternator poles count ??? Do we need MAGNETO_SPEED included
JonFreeman 0:77803b3ee157 223 #endif
JonFreeman 0:77803b3ee157 224 // tmp *= (scale * 32.0 * 60.0 / 12.0);
JonFreeman 0:77803b3ee157 225 rpm_filt *= shrink_by;
JonFreeman 0:77803b3ee157 226 rpm_filt += tmp;
JonFreeman 0:77803b3ee157 227 glob_rpm = rpm_filt;
JonFreeman 0:77803b3ee157 228
JonFreeman 0:77803b3ee157 229 tacho_ticks_per_time = temp - h[i]; // latest tacho total pulse count - oldest stored tacho total pulse count
JonFreeman 0:77803b3ee157 230 h[i] = temp; // latest overwrites oldest in table
JonFreeman 0:77803b3ee157 231 i++; // index to next table position for next time around
JonFreeman 0:77803b3ee157 232 if (i >= TACHO_TABLE_SIZE)
JonFreeman 0:77803b3ee157 233 i = 0; // circular buffer
JonFreeman 0:77803b3ee157 234 loop_flag = true; // set flag to allow main programme loop to proceed
JonFreeman 0:77803b3ee157 235 sys_timer32Hz++; // Just a handy measure of elapsed time for anything to use
JonFreeman 0:77803b3ee157 236 if ((sys_timer32Hz & 0x03) == 0)
JonFreeman 0:77803b3ee157 237 flag_8Hz = true; // flag gets set 8 times per sec. Other code may clear flag and make use of this
JonFreeman 0:77803b3ee157 238 }
JonFreeman 0:77803b3ee157 239
JonFreeman 0:77803b3ee157 240
JonFreeman 0:77803b3ee157 241 // New stuff June 2019
JonFreeman 0:77803b3ee157 242 //uint32_t magneto_count = 0;
JonFreeman 0:77803b3ee157 243 #ifdef MAGNETO_SPEED
JonFreeman 0:77803b3ee157 244 bool magneto_stretch = false;
JonFreeman 0:77803b3ee157 245 Timeout magneto_timo;
JonFreeman 0:77803b3ee157 246 uint32_t magneto_times[8] = {0,0,0,0,0,0,0,0};
JonFreeman 0:77803b3ee157 247
JonFreeman 0:77803b3ee157 248 void ISR_magneto_tacho () ; // New June 2019
JonFreeman 0:77803b3ee157 249 // Engine On/Off switch turns engine off by shorting magneto to ground.
JonFreeman 0:77803b3ee157 250 // Therefore have pulse signal one pulse per rev (even tghough 4 stroke, spark delivered at 2 stroke rate)
JonFreeman 0:77803b3ee157 251 // Pulse spacing 20ms @ 3000 RPM, 60ms @ 1000 RPM, 6ms @ 10000 RPM
JonFreeman 0:77803b3ee157 252
JonFreeman 0:77803b3ee157 253 // Relies also on a timeout
JonFreeman 0:77803b3ee157 254 void magneto_timeout ()
JonFreeman 0:77803b3ee157 255 {
JonFreeman 0:77803b3ee157 256 magneto_stretch = false; // Magneto ringing finished by now, re-enable magneto pulse count
JonFreeman 0:77803b3ee157 257 EngineTachoOut = 0;
JonFreeman 0:77803b3ee157 258 }
JonFreeman 0:77803b3ee157 259
JonFreeman 0:77803b3ee157 260 void ISR_magneto_tacho () // Here rising or falling edge of magneto output, not both
JonFreeman 0:77803b3ee157 261 {
JonFreeman 0:77803b3ee157 262 if (!magneto_stretch)
JonFreeman 0:77803b3ee157 263 {
JonFreeman 0:77803b3ee157 264 uint32_t new_time = microsecs.read_us();
JonFreeman 0:77803b3ee157 265 if (new_time < magneto_times[1]) // rollover detection
JonFreeman 0:77803b3ee157 266 magneto_times[1] = 0;
JonFreeman 0:77803b3ee157 267 magneto_times[0] = new_time - magneto_times[1]; // microsecs between most recent two sparks
JonFreeman 0:77803b3ee157 268 magneto_times[1] = new_time; // actual time microsecs of most recent spark
JonFreeman 0:77803b3ee157 269 magneto_stretch = true;
JonFreeman 0:77803b3ee157 270 magneto_timo.attach_us (&magneto_timeout, 5000); // To ignore ringing and multiple counts on magneto output, all settled within about 5ms
JonFreeman 0:77803b3ee157 271 tacho_count++;
JonFreeman 0:77803b3ee157 272 EngineTachoOut = 1;
JonFreeman 0:77803b3ee157 273 }
JonFreeman 0:77803b3ee157 274 }
JonFreeman 0:77803b3ee157 275
JonFreeman 0:77803b3ee157 276 #endif
JonFreeman 0:77803b3ee157 277 // Endof New stuff June 2019
JonFreeman 0:77803b3ee157 278
JonFreeman 0:77803b3ee157 279 //uint32_t time_diff;
JonFreeman 0:77803b3ee157 280 /** void ISR_pulse_tacho ()
JonFreeman 0:77803b3ee157 281 *
JonFreeman 0:77803b3ee157 282 */
JonFreeman 0:77803b3ee157 283 void ISR_pulse_tacho () // Interrupt Service Routine - here after each lo to hi and hi to lo transition on pulse_tacho pin
JonFreeman 0:77803b3ee157 284 {
JonFreeman 0:77803b3ee157 285 // static uint64_t ustot = 0;
JonFreeman 0:77803b3ee157 286 // uint64_t new_time = microsecs.read_high_resolution_us();
JonFreeman 0:77803b3ee157 287 static uint32_t ustot = 0;
JonFreeman 0:77803b3ee157 288 uint32_t new_time = microsecs.read_us();
JonFreeman 0:77803b3ee157 289 if (new_time < ustot) // rollover detection
JonFreeman 0:77803b3ee157 290 ustot = 0;
JonFreeman 0:77803b3ee157 291 //// time_diff = (uint32_t) new_time - ustot;
JonFreeman 0:77803b3ee157 292 // time_diff = new_time - ustot; // always 0 or positive
JonFreeman 0:77803b3ee157 293 ustot = new_time;
JonFreeman 0:77803b3ee157 294 tacho_count++;
JonFreeman 0:77803b3ee157 295 }
JonFreeman 0:77803b3ee157 296
JonFreeman 0:77803b3ee157 297 uint32_t t_on = 0, t_off = 0, measured_pw_us = 0;
JonFreeman 0:77803b3ee157 298 int ver = 0, vef = 0;
JonFreeman 0:77803b3ee157 299 void ISR_VEXT_rise () // InterruptIn interrupt service
JonFreeman 0:77803b3ee157 300 { // Here is possible to read back how regulator has controlled pwm
JonFreeman 0:77803b3ee157 301 ver++;
JonFreeman 0:77803b3ee157 302 t_on = microsecs.read_us();
JonFreeman 0:77803b3ee157 303 }
JonFreeman 0:77803b3ee157 304 void ISR_VEXT_fall () // InterruptIn interrupt service
JonFreeman 0:77803b3ee157 305 {
JonFreeman 0:77803b3ee157 306 vef++;
JonFreeman 0:77803b3ee157 307 t_off = microsecs.read_us();
JonFreeman 0:77803b3ee157 308 measured_pw_us = t_off - t_on;
JonFreeman 0:77803b3ee157 309 }
JonFreeman 0:77803b3ee157 310 // **** End of Interrupt Service Routines ****
JonFreeman 0:77803b3ee157 311
JonFreeman 0:77803b3ee157 312
JonFreeman 0:77803b3ee157 313 /** uint32_t ReadEngineRPM ()
JonFreeman 0:77803b3ee157 314 * System timers arranged such that tacho_ticks_per_time contains most up to the moment count of tacho ticks per second.
JonFreeman 0:77803b3ee157 315 * This * 60 / number of alternator poles gives Revs Per Minute
JonFreeman 0:77803b3ee157 316 * Band pass filter alternator phase output - LF rolloff about 50Hz, HF rolloff about 1500Hz
JonFreeman 0:77803b3ee157 317 */
JonFreeman 0:77803b3ee157 318 uint32_t ReadEngineRPM ()
JonFreeman 0:77803b3ee157 319 {
JonFreeman 0:77803b3ee157 320 #ifdef MAGNETO_SPEED
JonFreeman 0:77803b3ee157 321 uint32_t time_since_last_spark = microsecs.read_us() - magneto_times[1];
JonFreeman 0:77803b3ee157 322 if (time_since_last_spark > 50000) // if engine probably stopped, return old method RPM
JonFreeman 0:77803b3ee157 323 return tacho_ticks_per_time * 60; // 1 pulse per rev from magneto
JonFreeman 0:77803b3ee157 324 return (60000000 / magneto_times[0]); // 60 million / microsecs between two most recent sparks
JonFreeman 0:77803b3ee157 325 #else
JonFreeman 0:77803b3ee157 326 return tacho_ticks_per_time * 60 / 12; // Numof alternator poles, 12, factored in.
JonFreeman 0:77803b3ee157 327 #endif
JonFreeman 0:77803b3ee157 328 }
JonFreeman 0:77803b3ee157 329
JonFreeman 0:77803b3ee157 330
JonFreeman 0:77803b3ee157 331 double Read_BatteryVolts ()
JonFreeman 0:77803b3ee157 332 {
JonFreeman 0:77803b3ee157 333 return (double) volt_reading / 1626.0; // divisor fiddled to make voltage reading correct !
JonFreeman 0:77803b3ee157 334 }
JonFreeman 0:77803b3ee157 335
JonFreeman 0:77803b3ee157 336 void set_servo (double p) { // Only for test, called from cli
JonFreeman 0:77803b3ee157 337 Throttle = p;
JonFreeman 0:77803b3ee157 338 }
JonFreeman 0:77803b3ee157 339
JonFreeman 0:77803b3ee157 340 double normalise (double * p) {
JonFreeman 0:77803b3ee157 341 if (*p > 0.999)
JonFreeman 0:77803b3ee157 342 *p = 0.999;
JonFreeman 0:77803b3ee157 343 if (*p < 0.001)
JonFreeman 0:77803b3ee157 344 *p = 0.001;
JonFreeman 0:77803b3ee157 345 return * p;
JonFreeman 0:77803b3ee157 346 }
JonFreeman 0:77803b3ee157 347
JonFreeman 0:77803b3ee157 348 uint32_t RPM_demand = 0; // For test, set from cli
JonFreeman 0:77803b3ee157 349 void set_RPM_demand (uint32_t d) {
JonFreeman 0:77803b3ee157 350 if (d < 10)
JonFreeman 0:77803b3ee157 351 d = 10;
JonFreeman 0:77803b3ee157 352 if (d > 5600)
JonFreeman 0:77803b3ee157 353 d = 5600;
JonFreeman 0:77803b3ee157 354 RPM_demand = d;
JonFreeman 0:77803b3ee157 355 }
JonFreeman 0:77803b3ee157 356
JonFreeman 0:77803b3ee157 357 extern void command_line_interpreter () ; // Comms with optional pc or device using serial port through board USB socket
JonFreeman 0:77803b3ee157 358 extern bool i2c_init () ;
JonFreeman 0:77803b3ee157 359 extern int check_24LC64 () ;
JonFreeman 0:77803b3ee157 360
JonFreeman 0:77803b3ee157 361 // Programme Entry Point
JonFreeman 0:77803b3ee157 362 int main()
JonFreeman 0:77803b3ee157 363 {
JonFreeman 0:77803b3ee157 364 // local variable declarations
JonFreeman 0:77803b3ee157 365 double servo_position = 0.2; // set in speed control loop
JonFreeman 0:77803b3ee157 366 double revs_error;
JonFreeman 0:77803b3ee157 367 int irevs_error;
JonFreeman 0:77803b3ee157 368 int ticks = 0;
JonFreeman 0:77803b3ee157 369 const double throttle_limit = 0.4;
JonFreeman 0:77803b3ee157 370
JonFreeman 0:77803b3ee157 371 loop_timer.attach_us (&ISR_loop_timer, MAIN_LOOP_REPEAT_TIME_US); // Start periodic interrupt generator
JonFreeman 0:77803b3ee157 372 #ifdef MAGNETO_SPEED
JonFreeman 0:77803b3ee157 373 pc.printf ("Magneto Mode\r\n");
JonFreeman 0:77803b3ee157 374 pulse_tacho.fall (&ISR_magneto_tacho); // 1 pulse per engine rev
JonFreeman 0:77803b3ee157 375 #else
JonFreeman 0:77803b3ee157 376 pc.printf ("Alternator W signal Mode\r\n");
JonFreeman 0:77803b3ee157 377 pulse_tacho.rise (&ISR_pulse_tacho); // Handles - Transition on filtered input version of alternator phase output
JonFreeman 0:77803b3ee157 378 pulse_tacho.fall (&ISR_pulse_tacho); //
JonFreeman 0:77803b3ee157 379 #endif
JonFreeman 0:77803b3ee157 380 VEXT.rise (&ISR_VEXT_rise); // Handles - MCP1630 has just turned mosfet on
JonFreeman 0:77803b3ee157 381 VEXT.fall (&ISR_VEXT_fall); // Handles - MCP1630 has just turned mosfet off
JonFreeman 0:77803b3ee157 382 microsecs.reset() ; // timer = 0
JonFreeman 0:77803b3ee157 383 microsecs.start () ; // 64 bit, counts micro seconds and times out in half million years
JonFreeman 0:77803b3ee157 384 PWM_OSC_IN.period_us (PWM_PERIOD_US); // about 313Hz
JonFreeman 0:77803b3ee157 385 PWM_OSC_IN.pulsewidth_us (9); // value is int
JonFreeman 0:77803b3ee157 386 A_OUT.period_us (100);
JonFreeman 0:77803b3ee157 387 A_OUT.pulsewidth_us (19);
JonFreeman 0:77803b3ee157 388 Throttle = servo_position;
JonFreeman 0:77803b3ee157 389 pc.printf ("\r\n\n\n\n\nAlternator Regulator 2019, Jon Freeman, SystemCoreClock=%d\r\n", SystemCoreClock);
JonFreeman 0:77803b3ee157 390 if (!i2c_init())
JonFreeman 0:77803b3ee157 391 pc.printf ("i2c bus failed init\r\n");
JonFreeman 0:77803b3ee157 392 // end of local variable declarations
JonFreeman 0:77803b3ee157 393 pc.printf ("check_24LC64 returned 0x%x\r\n", check_24LC64());
JonFreeman 0:77803b3ee157 394 mode.load () ; // Fetch values from eeprom, also builds table of speed -> pwm lookups
JonFreeman 0:77803b3ee157 395
JonFreeman 0:77803b3ee157 396 // Setup Complete ! Can now start main control forever loop.
JonFreeman 0:77803b3ee157 397
JonFreeman 0:77803b3ee157 398 //***** START OF MAIN LOOP
JonFreeman 0:77803b3ee157 399 while (1) { // Loop forever, repeats synchroised by waiting for ticker Interrupt Service Routine to set 'loop_flag' true
JonFreeman 0:77803b3ee157 400 while (!loop_flag) { // Most of the time is spent in this loop, repeatedly re-checking for commands from pc port
JonFreeman 0:77803b3ee157 401 command_line_interpreter () ; // Proceed beyond here once loop_timer ticker ISR has set loop_flag true
JonFreeman 0:77803b3ee157 402 } // Jan 2019 pass here 32 times per sec
JonFreeman 0:77803b3ee157 403 loop_flag = false; // Clear flag set by ticker interrupt handler
JonFreeman 0:77803b3ee157 404 #ifdef SPEED_CONTROL_ENABLE
JonFreeman 0:77803b3ee157 405 // uint32_t RPM_demand = 0; // For test, set from cli
JonFreeman 0:77803b3ee157 406 // double servo_position = 0.0; // set in speed control loop
JonFreeman 0:77803b3ee157 407 // double revs_error;
JonFreeman 0:77803b3ee157 408
JonFreeman 0:77803b3ee157 409 // time_since_last_spark = microsecs.read_us() - magneto_times[1];
JonFreeman 0:77803b3ee157 410 irevs_error = RPM_demand - ReadEngineRPM ();
JonFreeman 0:77803b3ee157 411 revs_error = (double) irevs_error;
JonFreeman 0:77803b3ee157 412 if (RPM_demand < 3000)
JonFreeman 0:77803b3ee157 413 servo_position = Throttle = 0.0;
JonFreeman 0:77803b3ee157 414 else {
JonFreeman 0:77803b3ee157 415 servo_position += (revs_error / 75000.0);
JonFreeman 0:77803b3ee157 416 servo_position = normalise(&servo_position);
JonFreeman 0:77803b3ee157 417 if (servo_position < 0.0 || servo_position > 1.0)
JonFreeman 0:77803b3ee157 418 pc.printf ("servo_position error %f\r\n", servo_position);
JonFreeman 0:77803b3ee157 419 if (servo_position > throttle_limit)
JonFreeman 0:77803b3ee157 420 servo_position = throttle_limit;
JonFreeman 0:77803b3ee157 421 Throttle = servo_position;
JonFreeman 0:77803b3ee157 422 }
JonFreeman 0:77803b3ee157 423 #endif
JonFreeman 0:77803b3ee157 424
JonFreeman 0:77803b3ee157 425 PWM_OSC_IN.pulsewidth_us (mode.get_pwm((int)glob_rpm)); // Update field current according to latest measured RPM
JonFreeman 0:77803b3ee157 426
JonFreeman 0:77803b3ee157 427 // while (LocalCom.readable()) {
JonFreeman 0:77803b3ee157 428 // int q = LocalCom.getc();
JonFreeman 0:77803b3ee157 429 // //q++;
JonFreeman 0:77803b3ee157 430 // pc.putc (q);
JonFreeman 0:77803b3ee157 431 // }
JonFreeman 0:77803b3ee157 432
JonFreeman 0:77803b3ee157 433 if (flag_8Hz) { // Do any stuff to be done 8 times per second
JonFreeman 0:77803b3ee157 434 flag_8Hz = false;
JonFreeman 0:77803b3ee157 435 myled = !myled;
JonFreeman 0:77803b3ee157 436 LocalCom.printf ("%d\r\n", volt_reading);
JonFreeman 0:77803b3ee157 437
JonFreeman 0:77803b3ee157 438 ticks++;
JonFreeman 0:77803b3ee157 439 if (ticks > 7) { // once per sec stuff
JonFreeman 0:77803b3ee157 440 ticks = 0;
JonFreeman 0:77803b3ee157 441 pc.printf ("RPM %d, err %.1f, s_p %.2f\r\n", ReadEngineRPM (), revs_error, servo_position);
JonFreeman 0:77803b3ee157 442 } // eo once per second stuff
JonFreeman 0:77803b3ee157 443 } // End of if(flag_8Hz)
JonFreeman 0:77803b3ee157 444 } // End of main programme loop
JonFreeman 0:77803b3ee157 445 } // End of main function - end of programme
JonFreeman 0:77803b3ee157 446 //***** END OF MAIN LOOP