Power control and management

Dependencies:   mbed

main.cpp

Committer:
andrewcrussell
Date:
22 months ago
Revision:
2:c449cfb7752c
Parent:
0:36494271e31a

File content as of revision 2:c449cfb7752c:

/****************************** Power Sequencer and Controller V1.0 *************************/
/*                                  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 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 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            */ 
/* 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"            // Watch Dog Timer 
#include "Pindef1114.h"     // all microcontroller I/O pin assignments defined here    
#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 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 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;                  // 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;                // left and right channel temperature read in by A-D in deg C
float tempr;
float t_left;
float t_right;

Ticker flipper;             // this is the ACDET1 WDT ticker timer
                            
// declare function prototypes here
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) {

        
        // temp alarm on either input 
        if ((t_left >= TEMPHIGH) || (t_right >= TEMPHIGH)) {   
            clip = 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);              // prevent accidental re-entry
    
    if (mains_cnt < amp_settle) {
        mains_cnt++;
        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);         // reinstate the interrupt
}
/******************************** output clip ****************************************/

void output_clip(void) {
      clip_cnt = CLIP_ON;  }
    
/******************************** indi_flash ***************************************/
// this just flashes the power LED to indicate amp is in power-up cycle 
// or a temperature shutdown

void indi_flash(void)
{
    if (indi_flip > INDIC) {
        INDI = !INDI;
        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 */

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 - 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
    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();
    
    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 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(); }
    
    SYNC = !SYNC;          // ACDET1 sync output for debugging
    indi_flip++;
    clip_cnt--;
    goto LOOP;

}