Power control and management

Dependencies:   mbed

Committer:
andrewcrussell
Date:
Fri Nov 18 15:57:25 2022 +0000
Revision:
3:92148e16d530
Parent:
2:c449cfb7752c
regen;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewcrussell 0:36494271e31a 1 /****************************** Power Sequencer and Controller V1.0 *************************/
andrewcrussell 0:36494271e31a 2 /* Andrew C. Russell (c) 2015 */
andrewcrussell 0:36494271e31a 3 /* The controller pin definitions are set in Pindef1114.h file. */
andrewcrussell 0:36494271e31a 4 /* The main loop is driven by an interrupt on ACDET1 - 16.66ms for 60 Hz and 20ms for 50 Hz */
andrewcrussell 2:c449cfb7752c 5 /* The WDT is set for a 25ms timeout. If AC power is removed, the MCU resets in 25ms */
andrewcrussell 2:c449cfb7752c 6 /* and all relays de-energized. If the ERROR input goes LOW after power-up cycle, the */
andrewcrussell 0:36494271e31a 7 /* program disconnects the speaker. During the power up cycle - 150 mains cycles for */
andrewcrussell 2:c449cfb7752c 8 /* pre-charge and 250 mains cycles for the output to DC settle - and whenever an error */
andrewcrussell 0:36494271e31a 9 /* condition is encountered, the power LED is flashed at 0.5 Hz */
andrewcrussell 0:36494271e31a 10 /* The latency between the loss of ACDET1 and the SPKR being disengaged is ~25ms */
andrewcrussell 2:c449cfb7752c 11 /* Provision for two 10k NTC thermistor sensors is also provided. The NTC is in the lower */
andrewcrussell 2:c449cfb7752c 12 /* leg of a divider with the upper leg a 10k resistor. The trip temp (TRIPON), */
andrewcrussell 2:c449cfb7752c 13 /* reset temp (TRIPOFF) and the temperature alarm (TEMPHIGH) are directly set in Volts */
andrewcrussell 2:c449cfb7752c 14 /* A low on the clip input will cause the clip LED to flash on for 1s. Note CLIP has to */
andrewcrussell 2:c449cfb7752c 15 /* recycle HIGH and then LOW again to retrigger the CLIP output - it does not flash */
andrewcrussell 2:c449cfb7752c 16 /* continuosly if held LOW */
andrewcrussell 2:c449cfb7752c 17 /* Note: if the amp clips for too long, the DC offset interuppt will be triggered because */
andrewcrussell 2:c449cfb7752c 18 /* the clip input and the DC offset detect inputs are connected. */
andrewcrussell 0:36494271e31a 19
andrewcrussell 0:36494271e31a 20 #include "mbed.h"
andrewcrussell 2:c449cfb7752c 21 #include "WDT.h" // Watch Dog Timer
andrewcrussell 0:36494271e31a 22 #include "Pindef1114.h" // all microcontroller I/O pin assignments defined here
andrewcrussell 2:c449cfb7752c 23 #include "AnalogIn.h" // standard mbed supplied analog driver header file
andrewcrussell 2:c449cfb7752c 24 #include "math.h"
andrewcrussell 2:c449cfb7752c 25
andrewcrussell 0:36494271e31a 26 #define AC_LOSS 0.025 // this is the wdt set value in seconds
andrewcrussell 0:36494271e31a 27 #define TRUE 1
andrewcrussell 0:36494271e31a 28 #define FALSE 0
andrewcrussell 0:36494271e31a 29 #define HIGH 1
andrewcrussell 0:36494271e31a 30 #define LOW 0
andrewcrussell 2:c449cfb7752c 31 #define INDIC 25 // the number of mains cycles between LED illumination flip
andrewcrussell 2:c449cfb7752c 32 #define inrush_t 200 //# of mains cycles to wait before bypassing the NTC
andrewcrussell 0:36494271e31a 33 #define amp_settle 300 //# of mains cycles to let amp module OP settle
andrewcrussell 2:c449cfb7752c 34 #define CLIP_ON 20 // the clip LED goes on for n ACDET1 periods
andrewcrussell 2:c449cfb7752c 35 #define TEMPHIGH 65 // temperature alarm in Volts - 65 deg C
andrewcrussell 2:c449cfb7752c 36 #define TRIPON 70 // this is the trip temperature in volts - 70 deg C
andrewcrussell 2:c449cfb7752c 37 #define TRIPOFF 62 // this is the lower re-activate amplifier temperature in volts - 64 deg C
andrewcrussell 2:c449cfb7752c 38
andrewcrussell 2:c449cfb7752c 39 //Following used in the calculation of temp in deg C from an NTC
andrewcrussell 2:c449cfb7752c 40 #define Vref 3.31 // this is the A-D reference voltage
andrewcrussell 2:c449cfb7752c 41 #define Ref 10000 // the upper reference resistor from VREF to the NTC [was 2.2k]
andrewcrussell 2:c449cfb7752c 42 #define To 298 // coefficiants required for Steinhart-Hart equation
andrewcrussell 2:c449cfb7752c 43 #define B 3900 // from NTC data sheet
andrewcrussell 2:c449cfb7752c 44 #define Ro 10000
andrewcrussell 2:c449cfb7752c 45 #define cal65 3.3 // cal out any error at 65deg C - determined by applying
andrewcrussell 2:c449cfb7752c 46 // required offset at 65 deg C - so at 65C the temp is accurate
andrewcrussell 2:c449cfb7752c 47
andrewcrussell 2:c449cfb7752c 48 #define e 2.718281828459
andrewcrussell 2:c449cfb7752c 49
andrewcrussell 2:c449cfb7752c 50 int F1; // test flag used in trip() TRUE if overtemp has tripped
andrewcrussell 0:36494271e31a 51 int mains_cnt; // mains cycle counter
andrewcrussell 2:c449cfb7752c 52 int FLAG1; // TRUE if power-up process is completed otherwise FALSE
andrewcrussell 0:36494271e31a 53 int indi_flip; // counts mains cycles - used in indicator status
andrewcrussell 0:36494271e31a 54 int clip_cnt; // ACDET1 int derived counter for the clip indicator
andrewcrussell 2:c449cfb7752c 55 float templ; // left and right channel temperature read in by A-D in deg C
andrewcrussell 0:36494271e31a 56 float tempr;
andrewcrussell 2:c449cfb7752c 57 float t_left;
andrewcrussell 2:c449cfb7752c 58 float t_right;
andrewcrussell 0:36494271e31a 59
andrewcrussell 2:c449cfb7752c 60 Ticker flipper; // this is the ACDET1 WDT ticker timer
andrewcrussell 2:c449cfb7752c 61
andrewcrussell 0:36494271e31a 62 // declare function prototypes here
andrewcrussell 2:c449cfb7752c 63 void trip(void); // assess what actions to take based on temperature
andrewcrussell 2:c449cfb7752c 64 void temp_measure(void); // measure the temparature
andrewcrussell 2:c449cfb7752c 65 void output_clip(void); // clip indicator
andrewcrussell 2:c449cfb7752c 66 void indi_flash (void); // universal indicator flash
andrewcrussell 2:c449cfb7752c 67 void temp_trip (void); // action to be taken when overtemp
andrewcrussell 2:c449cfb7752c 68 void acdetect(void); // triggers the counter
andrewcrussell 0:36494271e31a 69
andrewcrussell 0:36494271e31a 70 /************************************ analog_input *********************************/
andrewcrussell 2:c449cfb7752c 71 void trip(void) {
andrewcrussell 0:36494271e31a 72
andrewcrussell 2:c449cfb7752c 73
andrewcrussell 2:c449cfb7752c 74 // temp alarm on either input
andrewcrussell 2:c449cfb7752c 75 if ((t_left >= TEMPHIGH) || (t_right >= TEMPHIGH)) {
andrewcrussell 2:c449cfb7752c 76 clip = HIGH; }
andrewcrussell 0:36494271e31a 77
andrewcrussell 0:36494271e31a 78
andrewcrussell 2:c449cfb7752c 79 if ((t_left < TEMPHIGH) && (t_right < TEMPHIGH) && (FLAG1 == TRUE)) {
andrewcrussell 2:c449cfb7752c 80 SPKR = HIGH; }
andrewcrussell 2:c449cfb7752c 81
andrewcrussell 2:c449cfb7752c 82 if ((t_left > TRIPON) || (t_right > TRIPON)) { //temp trip
andrewcrussell 2:c449cfb7752c 83 SPKR = LOW;
andrewcrussell 2:c449cfb7752c 84 F1 = TRUE; }
andrewcrussell 2:c449cfb7752c 85
andrewcrussell 2:c449cfb7752c 86 // below is to turn speaker relay back ON if the temperature has fallen BELOW TRIPOFF
andrewcrussell 2:c449cfb7752c 87
andrewcrussell 2:c449cfb7752c 88 if (((t_left < TRIPOFF) && (t_right < TRIPOFF)) && (FLAG1 == TRUE)){
andrewcrussell 2:c449cfb7752c 89 SPKR = HIGH;
andrewcrussell 2:c449cfb7752c 90 clip = LOW;
andrewcrussell 2:c449cfb7752c 91 F1 = FALSE; }
andrewcrussell 2:c449cfb7752c 92
andrewcrussell 2:c449cfb7752c 93
andrewcrussell 2:c449cfb7752c 94 }
andrewcrussell 0:36494271e31a 95 /*********************************** ACDET1 Interrupt ******************************/
andrewcrussell 0:36494271e31a 96 void acdetect(void)
andrewcrussell 0:36494271e31a 97 {
andrewcrussell 2:c449cfb7752c 98 ACDET1.rise(NULL); // prevent accidental re-entry
andrewcrussell 2:c449cfb7752c 99
andrewcrussell 0:36494271e31a 100 if (mains_cnt < amp_settle) {
andrewcrussell 0:36494271e31a 101 mains_cnt++;
andrewcrussell 2:c449cfb7752c 102 FLAG1 = FALSE; // FLAG1 only becomes TRUE after power up process is complete
andrewcrussell 0:36494271e31a 103 }
andrewcrussell 0:36494271e31a 104
andrewcrussell 0:36494271e31a 105 else if (mains_cnt >= amp_settle) {
andrewcrussell 2:c449cfb7752c 106 FLAG1 = TRUE; // fully powered up at this point
andrewcrussell 2:c449cfb7752c 107 mains_cnt = amp_settle; // after power up mains_cnt is held to amp_settle
andrewcrussell 2:c449cfb7752c 108 }
andrewcrussell 2:c449cfb7752c 109
andrewcrussell 2:c449cfb7752c 110 ACDET1.rise(&acdetect); // reinstate the interrupt
andrewcrussell 0:36494271e31a 111 }
andrewcrussell 0:36494271e31a 112 /******************************** output clip ****************************************/
andrewcrussell 0:36494271e31a 113
andrewcrussell 0:36494271e31a 114 void output_clip(void) {
andrewcrussell 2:c449cfb7752c 115 clip_cnt = CLIP_ON; }
andrewcrussell 0:36494271e31a 116
andrewcrussell 0:36494271e31a 117 /******************************** indi_flash ***************************************/
andrewcrussell 2:c449cfb7752c 118 // this just flashes the power LED to indicate amp is in power-up cycle
andrewcrussell 2:c449cfb7752c 119 // or a temperature shutdown
andrewcrussell 0:36494271e31a 120
andrewcrussell 0:36494271e31a 121 void indi_flash(void)
andrewcrussell 0:36494271e31a 122 {
andrewcrussell 0:36494271e31a 123 if (indi_flip > INDIC) {
andrewcrussell 0:36494271e31a 124 INDI = !INDI;
andrewcrussell 0:36494271e31a 125 indi_flip = 0;
andrewcrussell 0:36494271e31a 126 }
andrewcrussell 0:36494271e31a 127 }
andrewcrussell 2:c449cfb7752c 128 /************************************ temp_measure **********************************/
andrewcrussell 2:c449cfb7752c 129 /* This routine fetches the NTC resistance as measured at the A-D inputs left_temp */
andrewcrussell 2:c449cfb7752c 130 /* and right Temp. It uses the Steinhart-Hart NTC R>T equation to compute the */
andrewcrussell 2:c449cfb7752c 131 /* temperature.left_temp and right_temp are A-D inputs defined in the pindef.h file */
andrewcrussell 0:36494271e31a 132
andrewcrussell 2:c449cfb7752c 133 void temp_measure(void) {
andrewcrussell 2:c449cfb7752c 134
andrewcrussell 2:c449cfb7752c 135 float vo_left;
andrewcrussell 2:c449cfb7752c 136 float vo_right;
andrewcrussell 2:c449cfb7752c 137 float r_left;
andrewcrussell 2:c449cfb7752c 138 float r_right;
andrewcrussell 2:c449cfb7752c 139 float l_roh;
andrewcrussell 2:c449cfb7752c 140 float r_roh;
andrewcrussell 2:c449cfb7752c 141
andrewcrussell 2:c449cfb7752c 142 // first, fetch the NTC resistances
andrewcrussell 2:c449cfb7752c 143
andrewcrussell 2:c449cfb7752c 144 vo_left = left_temp*Vref; //scale the A-D reading for Vref = 3.3V
andrewcrussell 2:c449cfb7752c 145 vo_right = right_temp*Vref;
andrewcrussell 2:c449cfb7752c 146
andrewcrussell 2:c449cfb7752c 147 r_left = vo_left/((Vref-vo_left)/Ref);
andrewcrussell 2:c449cfb7752c 148 r_right = vo_right/((Vref-vo_right)/Ref);
andrewcrussell 2:c449cfb7752c 149
andrewcrussell 2:c449cfb7752c 150 // from the NTC resistance, calculate the temperature in Kelvin using the
andrewcrussell 2:c449cfb7752c 151 // simplified Steinhart-Hart Equation.
andrewcrussell 2:c449cfb7752c 152
andrewcrussell 2:c449cfb7752c 153 l_roh = Ro*(pow(e,(-B/To)));
andrewcrussell 2:c449cfb7752c 154 t_left = (B/(log(r_left/l_roh)))-(273+cal65);
andrewcrussell 2:c449cfb7752c 155
andrewcrussell 2:c449cfb7752c 156 r_roh = Ro*(pow(e,(-B/To)));
andrewcrussell 2:c449cfb7752c 157 t_right = (B/(log(r_right/r_roh)))-(273+cal65);
andrewcrussell 2:c449cfb7752c 158
andrewcrussell 2:c449cfb7752c 159 //printf used for temp debugging. Clock must be slowed to ~ 1Hz
andrewcrussell 2:c449cfb7752c 160 //printf("t_left = %f t_right = %f \n\r", t_left, t_right);
andrewcrussell 2:c449cfb7752c 161
andrewcrussell 2:c449cfb7752c 162 }
andrewcrussell 2:c449cfb7752c 163
andrewcrussell 2:c449cfb7752c 164
andrewcrussell 2:c449cfb7752c 165 /************************************* main() ***************************************/
andrewcrussell 0:36494271e31a 166 int main(void)
andrewcrussell 0:36494271e31a 167 {
andrewcrussell 2:c449cfb7752c 168 __disable_irq(); // just to make sure we can set up correctly without problems
andrewcrussell 2:c449cfb7752c 169 INRUSH = LOW; // power bypass disabled
andrewcrussell 2:c449cfb7752c 170 SPKR = LOW; // speakers muted
andrewcrussell 2:c449cfb7752c 171 PWR_R = LOW; // power ON/OFF relay is OFF - only used if TRIGGER is used
andrewcrussell 2:c449cfb7752c 172 INDI = HIGH; // open drain indicator output is deactivated - active LOW
andrewcrussell 2:c449cfb7752c 173 clip = LOW; // clip LED driver output
andrewcrussell 2:c449cfb7752c 174 clip_in.mode(PullUp); // clip input
andrewcrussell 0:36494271e31a 175 clip_in.fall(&output_clip);
andrewcrussell 0:36494271e31a 176 clip_cnt = 0;
andrewcrussell 2:c449cfb7752c 177 ERROR.mode(PullUp);
andrewcrussell 2:c449cfb7752c 178 PWR_D.mode(PullDown); // used to detect power down
andrewcrussell 0:36494271e31a 179 ACDET1.mode(PullDown);
andrewcrussell 2:c449cfb7752c 180 ACDET1.rise(&acdetect); // trigger counter on rising edge
andrewcrussell 2:c449cfb7752c 181 SYNC = LOW; // SYNC flips once every mains cycle - 20ms period @ 50 Hz
andrewcrussell 2:c449cfb7752c 182
andrewcrussell 2:c449cfb7752c 183 FLAG1 = FALSE; // force a fault condition until first pass through main loop
andrewcrussell 2:c449cfb7752c 184 F1 = TRUE; // assume we are over temperature until our first sensor reading
andrewcrussell 2:c449cfb7752c 185 INDI = HIGH; // power LED is ON steady
andrewcrussell 2:c449cfb7752c 186 __enable_irq();
andrewcrussell 0:36494271e31a 187
andrewcrussell 2:c449cfb7752c 188 Watchdog wdt; // enable the WDT just before we start the main loop
andrewcrussell 2:c449cfb7752c 189 wdt.kick(AC_LOSS); // kick the WDT at regular 25 ms intervals (set by AC_LOSS)
andrewcrussell 0:36494271e31a 190
andrewcrussell 2:c449cfb7752c 191 LOOP: // this main loop is driven by the 20ms/16.6ms interrupts
andrewcrussell 2:c449cfb7752c 192 // generated by the ACDET1 input
andrewcrussell 2:c449cfb7752c 193 // if the INT's fail to arrive after 25ms, the AC power
andrewcrussell 2:c449cfb7752c 194 // is assumed lost and the WDT will reset the system = power down
andrewcrussell 2:c449cfb7752c 195 // de-engergizing all relays
andrewcrussell 2:c449cfb7752c 196 __WFI(); // waiting for ACDET1 INT
andrewcrussell 2:c449cfb7752c 197 wait_ms(1); // make sure we are away from the zero crossing 50 Hz or 60 Hz
andrewcrussell 2:c449cfb7752c 198 wdt.kick();
andrewcrussell 2:c449cfb7752c 199
andrewcrussell 2:c449cfb7752c 200 if ((mains_cnt >= amp_settle) && (ERROR == HIGH) && (FLAG1 == FALSE)) {
andrewcrussell 2:c449cfb7752c 201 INDI = HIGH;
andrewcrussell 2:c449cfb7752c 202 SPKR = HIGH; } // inrush and amp settle complete - enable SPKR if no ERROR
andrewcrussell 2:c449cfb7752c 203
andrewcrussell 2:c449cfb7752c 204 if (mains_cnt > inrush_t) {
andrewcrussell 2:c449cfb7752c 205 INRUSH = HIGH;}
andrewcrussell 2:c449cfb7752c 206
andrewcrussell 2:c449cfb7752c 207 // make sure the clip LED goes OFF if all is ok
andrewcrussell 2:c449cfb7752c 208 if((clip_cnt <= 0) && (SPKR == HIGH) && (ERROR == HIGH)) {
andrewcrussell 2:c449cfb7752c 209 INDI = HIGH; }
andrewcrussell 2:c449cfb7752c 210
andrewcrussell 2:c449cfb7752c 211 if (clip_cnt <= 0) { // note: clip flashes on change of state
andrewcrussell 2:c449cfb7752c 212 clip = LOW;} // i.e on edges
andrewcrussell 2:c449cfb7752c 213 else if (clip_cnt > 0) {
andrewcrussell 2:c449cfb7752c 214 clip = HIGH;
andrewcrussell 2:c449cfb7752c 215 INDI = LOW; } // so LED is RED on clip and not ORANGE
andrewcrussell 2:c449cfb7752c 216
andrewcrussell 2:c449cfb7752c 217 if ((ERROR == LOW) || (FLAG1 == FALSE)) {
andrewcrussell 2:c449cfb7752c 218 SPKR = LOW;
andrewcrussell 2:c449cfb7752c 219 indi_flash(); }
andrewcrussell 2:c449cfb7752c 220
andrewcrussell 2:c449cfb7752c 221 temp_measure();
andrewcrussell 2:c449cfb7752c 222 trip();
andrewcrussell 2:c449cfb7752c 223
andrewcrussell 2:c449cfb7752c 224 if (F1 == TRUE) {
andrewcrussell 0:36494271e31a 225 indi_flash(); }
andrewcrussell 0:36494271e31a 226
andrewcrussell 2:c449cfb7752c 227 SYNC = !SYNC; // ACDET1 sync output for debugging
andrewcrussell 0:36494271e31a 228 indi_flip++;
andrewcrussell 0:36494271e31a 229 clip_cnt--;
andrewcrussell 0:36494271e31a 230 goto LOOP;
andrewcrussell 0:36494271e31a 231
andrewcrussell 0:36494271e31a 232 }
andrewcrussell 0:36494271e31a 233
andrewcrussell 0:36494271e31a 234
andrewcrussell 0:36494271e31a 235