Andrew R
/
Power_Sequencer_Nov_10_2022
Power control and management
Diff: main.cpp
- Revision:
- 2:c449cfb7752c
- Parent:
- 0:36494271e31a
--- a/main.cpp Thu Feb 16 13:39:39 2017 +0000 +++ b/main.cpp Thu Nov 10 11:11:58 2022 +0000 @@ -2,125 +2,121 @@ /* Andrew C. Russell (c) 2015 */ /* The controller pin definitions are set in Pindef1114.h file. */ /* The main loop is driven by an interrupt on ACDET1 - 16.66ms for 60 Hz and 20ms for 50 Hz */ -/* The WDT is set for a 25ms timeout. If AC power is removed, the SPKR and INRUSH outputs */ -/* are driven LOW immediately. The power supply to the uC is supported by a 100uF 6.3V */ -/* capacityor to facilitate this. If the ERROR input goes LOW after power-up cycle, the */ +/* The WDT is set for a 25ms timeout. If AC power is removed, the MCU resets in 25ms */ +/* and all relays de-energized. If the ERROR input goes LOW after power-up cycle, the */ /* program disconnects the speaker. During the power up cycle - 150 mains cycles for */ -/* pre-charge and 150 mains cycles for the output to DC settle - and whenever an error */ +/* pre-charge and 250 mains cycles for the output to DC settle - and whenever an error */ /* condition is encountered, the power LED is flashed at 0.5 Hz */ /* The latency between the loss of ACDET1 and the SPKR being disengaged is ~25ms */ -/* Note that if the TRIGGER input is used, the +12V actually powers up the controller */ -/* which then bootstraps itself by applying AC power via the PWR_R */ +/* Provision for two 10k NTC thermistor sensors is also provided. The NTC is in the lower */ +/* leg of a divider with the upper leg a 10k resistor. The trip temp (TRIPON), */ +/* reset temp (TRIPOFF) and the temperature alarm (TEMPHIGH) are directly set in Volts */ +/* A low on the clip input will cause the clip LED to flash on for 1s. Note CLIP has to */ +/* recycle HIGH and then LOW again to retrigger the CLIP output - it does not flash */ +/* continuosly if held LOW */ +/* Note: if the amp clips for too long, the DC offset interuppt will be triggered because */ +/* the clip input and the DC offset detect inputs are connected. */ #include "mbed.h" -#include "WDT.h" +#include "WDT.h" // Watch Dog Timer #include "Pindef1114.h" // all microcontroller I/O pin assignments defined here -#include "AnalogIn.h" +#include "AnalogIn.h" // standard mbed supplied analog driver header file +#include "math.h" + #define AC_LOSS 0.025 // this is the wdt set value in seconds #define TRUE 1 #define FALSE 0 #define HIGH 1 #define LOW 0 -#define BAD 0 -#define OK 1 -#define INDIC 25 // the number of mains cycles between indicator lamp flip -#define inrush_t 150 //# of mains cycles to wait before bypassing the NTC +#define INDIC 25 // the number of mains cycles between LED illumination flip +#define inrush_t 200 //# of mains cycles to wait before bypassing the NTC #define amp_settle 300 //# of mains cycles to let amp module OP settle -#define CLIP_ON 5 // the clip LED goes on for ACDET1 periodes -#define TEMPHIGH 0.7 // temperature alarm -#define TRIPON 0.83 // this is the trip temperature - 830mV = 65 deg C on LM60 -#define TRIPOFF 0.75 // this is the lower re-activate amplifier - //temperature - ~59 deg C LM60 - -int T1; -int T2; -int T3; -int T4; +#define CLIP_ON 20 // the clip LED goes on for n ACDET1 periods +#define TEMPHIGH 65 // temperature alarm in Volts - 65 deg C +#define TRIPON 70 // this is the trip temperature in volts - 70 deg C +#define TRIPOFF 62 // this is the lower re-activate amplifier temperature in volts - 64 deg C + +//Following used in the calculation of temp in deg C from an NTC +#define Vref 3.31 // this is the A-D reference voltage +#define Ref 10000 // the upper reference resistor from VREF to the NTC [was 2.2k] +#define To 298 // coefficiants required for Steinhart-Hart equation +#define B 3900 // from NTC data sheet +#define Ro 10000 +#define cal65 3.3 // cal out any error at 65deg C - determined by applying + // required offset at 65 deg C - so at 65C the temp is accurate + +#define e 2.718281828459 + +int F1; // test flag used in trip() TRUE if overtemp has tripped int mains_cnt; // mains cycle counter -int FLAG1; // used to detect if we are in or out of power up process -int FLAG_TRIGGER; // TRUE if power up was via the trigger input +int FLAG1; // TRUE if power-up process is completed otherwise FALSE int indi_flip; // counts mains cycles - used in indicator status int clip_cnt; // ACDET1 int derived counter for the clip indicator -float templ; +float templ; // left and right channel temperature read in by A-D in deg C float tempr; -int temp_status; - -Ticker flipper; // this is the ACDET timer - runs at 13.2 or 20ms -// ref 60 Hz or 50 Hz mains frequency +float t_left; +float t_right; +Ticker flipper; // this is the ACDET1 WDT ticker timer + // declare function prototypes here -void analog_input(void); // measure the temperature -void output_clip(void); // clip indicator -void indi_flash (void); // universal indicator flash -void temp_trip (void); // action to be taken when overtemp -void acdetect(void); // triggers the counter +void trip(void); // assess what actions to take based on temperature +void temp_measure(void); // measure the temparature +void output_clip(void); // clip indicator +void indi_flash (void); // universal indicator flash +void temp_trip (void); // action to be taken when overtemp +void acdetect(void); // triggers the counter /************************************ analog_input *********************************/ +void trip(void) { -void analog_input (void) { - - templ = left_temp*3.3; - tempr = right_temp*3.3; - - //if ((templ > TRIPOFF) || (tempr > TRIPOFF)) { - // temp_status = BAD; } else (temp_status = OK); - - if ((templ > TEMPHIGH) || (tempr > TEMPHIGH)) { - clip = HIGH;} - else (clip = LOW); + + // temp alarm on either input + if ((t_left >= TEMPHIGH) || (t_right >= TEMPHIGH)) { + clip = HIGH; } - if (((templ > TRIPON) || (tempr > TRIPON))) { // && ((templ > TRIPOFF) || (tempr > TRIPOFF)) && (FLAG1 == TRUE)) { - SPKR = LOW; - indi_flash(); - } - - if ((templ <= TRIPOFF) && (tempr <= TRIPOFF) && (FLAG1 == TRUE)){ - SPKR = HIGH;} - } - + if ((t_left < TEMPHIGH) && (t_right < TEMPHIGH) && (FLAG1 == TRUE)) { + SPKR = HIGH; } + + if ((t_left > TRIPON) || (t_right > TRIPON)) { //temp trip + SPKR = LOW; + F1 = TRUE; } + + // below is to turn speaker relay back ON if the temperature has fallen BELOW TRIPOFF + + if (((t_left < TRIPOFF) && (t_right < TRIPOFF)) && (FLAG1 == TRUE)){ + SPKR = HIGH; + clip = LOW; + F1 = FALSE; } + + + } /*********************************** ACDET1 Interrupt ******************************/ void acdetect(void) { - ACDET1.rise(NULL); + ACDET1.rise(NULL); // prevent accidental re-entry + if (mains_cnt < amp_settle) { mains_cnt++; - FLAG1 = FALSE; + FLAG1 = FALSE; // FLAG1 only becomes TRUE after power up process is complete } else if (mains_cnt >= amp_settle) { - FLAG1 = TRUE; // fully powered up at this point - mains_cnt = amp_settle; - } // after power up mains_cnt is held to amp_settle - ACDET1.rise(&acdetect); + FLAG1 = TRUE; // fully powered up at this point + mains_cnt = amp_settle; // after power up mains_cnt is held to amp_settle + } + + ACDET1.rise(&acdetect); // reinstate the interrupt } /******************************** output clip ****************************************/ void output_clip(void) { - clip_cnt = CLIP_ON; - - } + clip_cnt = CLIP_ON; } -/********************** power down routine for Trigger input *************************/ -void power_down(void) -{ - __disable_irq(); - SPKR = LOW; - INDI = HIGH; - wait_ms(2); - INRUSH = LOW; - if (FLAG_TRIGGER == TRUE) { - FLAG_TRIGGER = FALSE; - PWR_R = LOW; - } - FLAG1 = FALSE; - do { - continue; - } while(1); // just wait here unit all power is gone - // amplifier is in power down mode -} - /******************************** indi_flash ***************************************/ +// this just flashes the power LED to indicate amp is in power-up cycle +// or a temperature shutdown void indi_flash(void) { @@ -129,72 +125,106 @@ indi_flip = 0; } } +/************************************ temp_measure **********************************/ +/* This routine fetches the NTC resistance as measured at the A-D inputs left_temp */ +/* and right Temp. It uses the Steinhart-Hart NTC R>T equation to compute the */ +/* temperature.left_temp and right_temp are A-D inputs defined in the pindef.h file */ -/************************************ main() ***************************************/ +void temp_measure(void) { + +float vo_left; +float vo_right; +float r_left; +float r_right; +float l_roh; +float r_roh; + +// first, fetch the NTC resistances + + vo_left = left_temp*Vref; //scale the A-D reading for Vref = 3.3V + vo_right = right_temp*Vref; + + r_left = vo_left/((Vref-vo_left)/Ref); + r_right = vo_right/((Vref-vo_right)/Ref); + +// from the NTC resistance, calculate the temperature in Kelvin using the +// simplified Steinhart-Hart Equation. + + l_roh = Ro*(pow(e,(-B/To))); + t_left = (B/(log(r_left/l_roh)))-(273+cal65); + + r_roh = Ro*(pow(e,(-B/To))); + t_right = (B/(log(r_right/r_roh)))-(273+cal65); + + //printf used for temp debugging. Clock must be slowed to ~ 1Hz + //printf("t_left = %f t_right = %f \n\r", t_left, t_right); + + } + + +/************************************* main() ***************************************/ int main(void) { - __disable_irq(); // just to make sure we can set up correctly without problems - INRUSH = LOW; // power bypass disabled - SPKR = LOW; // speakers muted - PWR_R = LOW; // power ON/OFF relay is OFF - INDI = HIGH; // open drain indicator output is deactivated - take LOW - clip = LOW; - clip_in.mode(PullUp); // clip input + __disable_irq(); // just to make sure we can set up correctly without problems + INRUSH = LOW; // power bypass disabled + SPKR = LOW; // speakers muted + PWR_R = LOW; // power ON/OFF relay is OFF - only used if TRIGGER is used + INDI = HIGH; // open drain indicator output is deactivated - active LOW + clip = LOW; // clip LED driver output + clip_in.mode(PullUp); // clip input clip_in.fall(&output_clip); clip_cnt = 0; + ERROR.mode(PullUp); + PWR_D.mode(PullDown); // used to detect power down ACDET1.mode(PullDown); - ACDET1.rise(&acdetect); // trigger counter on rising edge + ACDET1.rise(&acdetect); // trigger counter on rising edge + SYNC = LOW; // SYNC flips once every mains cycle - 20ms period @ 50 Hz + + FLAG1 = FALSE; // force a fault condition until first pass through main loop + F1 = TRUE; // assume we are over temperature until our first sensor reading + INDI = HIGH; // power LED is ON steady + __enable_irq(); - SYNC = LOW; - wait_ms(500); // let PSU etc settle in first ~1 mains cycles - -// if (PWR_D == HIGH) { // power came in via TRIGGER input -// FLAG_TRIGGER = TRUE; -// PWR_R = HIGH; // turn the main power relay ON - only used -// } // with amplifiers with TRIGGER input facility - INDI = HIGH; // power LED is ON - __enable_irq(); - Watchdog wdt; // enable the WDT just before we start the main loop - wdt.kick(AC_LOSS); + Watchdog wdt; // enable the WDT just before we start the main loop + wdt.kick(AC_LOSS); // kick the WDT at regular 25 ms intervals (set by AC_LOSS) -LOOP: // this main loop is driven by the 20ms/16.6ms interrupts - // generated by the ACDET1 input - // if the INT's fail to arrive after 25ms, the AC power - // is lost and the WDT will reset the system = power down - __WFI(); // waiting for ACDET1 INT - wait_ms(5); // make sure we are away from the zero crossing 50 Hz or 60 Hz - wdt.kick(); - acdetect(); - - if (PWR_D == HIGH) { // check if input power detector is HIGH - FLAG_TRIGGER = TRUE; - PWR_R = HIGH; } // turn on main power relay - - if ((ERROR == LOW) && (FLAG1 == TRUE)) { // we have a fault condition but will - SPKR = LOW; // skip this if the error clears itself +LOOP: // this main loop is driven by the 20ms/16.6ms interrupts + // generated by the ACDET1 input + // if the INT's fail to arrive after 25ms, the AC power + // is assumed lost and the WDT will reset the system = power down + // de-engergizing all relays + __WFI(); // waiting for ACDET1 INT + wait_ms(1); // make sure we are away from the zero crossing 50 Hz or 60 Hz + wdt.kick(); + + if ((mains_cnt >= amp_settle) && (ERROR == HIGH) && (FLAG1 == FALSE)) { + INDI = HIGH; + SPKR = HIGH; } // inrush and amp settle complete - enable SPKR if no ERROR + + if (mains_cnt > inrush_t) { + INRUSH = HIGH;} + + // make sure the clip LED goes OFF if all is ok + if((clip_cnt <= 0) && (SPKR == HIGH) && (ERROR == HIGH)) { + INDI = HIGH; } + + if (clip_cnt <= 0) { // note: clip flashes on change of state + clip = LOW;} // i.e on edges + else if (clip_cnt > 0) { + clip = HIGH; + INDI = LOW; } // so LED is RED on clip and not ORANGE + + if ((ERROR == LOW) || (FLAG1 == FALSE)) { + SPKR = LOW; + indi_flash(); } + + temp_measure(); + trip(); + + if (F1 == TRUE) { indi_flash(); } - - if ((ERROR == HIGH) && (FLAG1 == TRUE)){ - INDI = HIGH; } - - if(mains_cnt < amp_settle) { - INRUSH = HIGH; - indi_flash(); } - - if ((mains_cnt >= inrush_t) && (mains_cnt >= amp_settle) == TRUE) { - SPKR = HIGH; } - - if ((PWR_D == LOW) && (FLAG_TRIGGER == TRUE)) { - power_down(); } - - if (clip_cnt <= 0) { - clip = LOW;} - else if (clip_cnt != 0) { - clip = HIGH;} - analog_input(); - - SYNC = !SYNC; // ACDET1 sync output for debugging + SYNC = !SYNC; // ACDET1 sync output for debugging indi_flip++; clip_cnt--; goto LOOP;