Excerpts from "AdcInput.h" // Cooling System ADC input pin assignments. // ADC Channel A (Has b3 clear) #define ADCIN_A_PH_A_I 0 // Phase A Current #define ADCIN_A_PH_B_I 1 // Phase B Current #define ADCIN_A_PH_C_I 2 // Phase C Current #define ADCIN_A_PH_A_V 3 // Phase A Voltage #define ADCIN_A_PH_B_V 4 // Phase B Voltage #define ADCIN_A_PH_C_V 5 // Phase C Voltage #define DUMMY_ADC_INPT 6 // Unused ADC Input // ADC Channel B (Has b3 set) #define ADCIN_B_TEMP_1 16 // Liquid I/P Temperature #define ADCIN_B_TEMP_2 17 // Liquid O/P Temperature #define ADCIN_B_TEMP_3 18 // Air Inlet Temperature #define ADCIN_B_TEMP_4 19 // Air Outlet Temperature #define ADCIN_B_PRES_1 20 // Pump Inlet Pressure #define ADCIN_B_PRES_2 21 // Pump Output Pressure #define ADCIN_B_TEMP_5 22 // Pump Motor Temperature Excerpts from "AdcInput.c" // Local Definitions // Delay Period required for ADC Module before // ADC Sampling starts. #define ADC_usDELAY 5000L // 7/8 averaging for Pressures/Temperatures. // (7 Times old value, plus new, divided by 8). #define ADC_AVERAGE 7U // Half Scale ADC (zero AC Current) #define HALVE_SCALE 2048U // The zero Current point is 2048 ADC Units. // Easy to change the Peak/Valley detection // Values here, without any re-coding involved. // High Side: 2048 to 4097; 3072 is ~ 4 Amps // Low Side: 2047 to 0; 1024 is ~-4 Amps #define HI_THR_AMPS 3072U #define LO_THR_AMPS 1024U // Uninitialized local Data static Uint16 loopVariable; // AC Current associated Variables static Uint16 phase_A_Curr[2]; // Raw ADC Phase Currents static Uint16 phase_B_Curr[2]; static Uint16 phase_C_Curr[2]; static Uint16 sumPk_A_Curr; // Summation Currents for all static Uint16 sumVa_A_Curr; // three Phases, Peak & Valley static Uint16 sumPk_B_Curr; static Uint16 sumVa_B_Curr; static Uint16 sumPk_C_Curr; static Uint16 sumVa_C_Curr; static Uint16 avePk_A_Curr; // Average Currents for all static Uint16 aveVa_A_Curr; // three Phases, Peak & Valley static Uint16 avePk_B_Curr; static Uint16 aveVa_B_Curr; static Uint16 avePk_C_Curr; static Uint16 aveVa_C_Curr; static Uint16 count_A_Peak; // Counts used for averaging static Uint16 count_A_Vall; // Phase Peaks and Valleys static Uint16 count_B_Peak; static Uint16 count_B_Vall; static Uint16 count_C_Peak; static Uint16 count_C_Vall; // Pressures (double sampled) and Temperatures // (single sampled) - ADC based Values. static Uint16 liq_Inp_PRaw[2]; // Pressure 1 double Raw Samples static Uint16 liq_Inp_PAve; // Pressure 1 Smoothed static Uint16 liq_Out_PRaw[2]; // Pressure 2 double Raw Samples static Uint16 liq_Out_PAve; // Pressure 2 Smoothed static Uint16 liq_Inp_TRaw; // Temperature 1 Raw static Uint16 liq_Inp_TAve; // Temperature 1 Smoothed static Uint16 liq_Out_TRaw; // Temperature 2 Raw static Uint16 liq_Out_TAve; // Temperature 2 Smoothed static Uint16 air_Inp_TRaw; // Temperature 3 Raw static Uint16 air_Inp_TAve; // Temperature 3 Smoothed static Uint16 air_Out_TRaw; // Temperature 4 Raw static Uint16 air_Out_TAve; // Temperature 4 Smoothed static Uint16 ac_MotorTRaw; // Temperature 5 Raw static Uint16 ac_MotorTAve; // Temperature 5 Smoothed /**************************************************************************** * FUNCTION: * void InitAdcModule (void) * * PURPOSE: * Power up and initializes the on chip A/D converter. * ****************************************************************************/ void initAdcModule (void) { static struct ADC_REGS adcRegs; // To power-up the ADC the ADCENCLK bit should be set first to enable // clocks, followed by powering up the band-gap, reference circuitry, // and ADC core. // Before the first conversion is performed, a 5ms delay must be observed // after power up, to give all analog circuits time to power up/settle. // Note that ADCENCLK must be enabled in 'InitModClocks()' Function, // located within "SysCtrl.c" Module. AdcRegs.ADCTRL1.bit.RESET = 1; // reset ADC DELAY_US(1); // Delay after reset (> 2 ADCCLK) // The (almost) full Buffer Fill provides two sets of Current Samples for // all 3 VAC Phases. Also two sets of in/out Liquid Pressure Samples. // All of these are temporally spaced 150µS apart, close to half the // 312.50µS ADC trigger Period. The five Temperatures are sampled once. // // There are four ways to slow down the (effective) ADC Clock from the // SYSCLKOUT input Reference. Three of these involve dividing SYSCLKOUT // by Prescaler Values (HSPCLK, ADCCLKPS and CPS), to each physically slow // the input ADC Clock. // // The first method uses HSPCLK, set to 50 (HISPCP Register set within // "SysCtrl.c"). This divides SYSCLKOUT by 100, and reduces the System // Clock from 20MHz to 200kHz (input ADC Clock). This gives a 5µS ADC // Clock Period. // // The second method, ADCCLKPS, supports slowing down the input ADC Clock, // with variable values. // // The third method, the CPS Bit, halves the ADC Clock, when set. // // The fourth method is to add one or more additional ADC Sample Clocks, // prior to each ADC Conversion. This method is employed, to lengthen // the sampling Period from the minimum of 1, to 2 ADC Clock intervals. // // ADCTRL3.bit.ADCCLKPS <3..0> Prescaler of 0..15 multiplied by 2. // ADCTRL1.bit.CPS <0> Prescaler of 0.. 1 1 or 2 multiply. // ADCTRL1.bit.ACQ_PS <3..0> Sample ticks 0..15 (1..16) ADC Clocks. // // For zero ACQ_PS delay, each ADC Sample/Conversion completes in 2 ADC // Clocks. Minimum sampling time is 1 ADC Clock. // // Texas Instrument's Example of Sequential Sampling Mode (Section 1.2.1 // within "spru716d.pdf") shows an Acquisition Window stretched from 1 // to 2 ADC Clocks, with ACQ_PS is set to 1. Each ADC Sample/Conversion // then effectively takes 3 ADC Clocks. This is what is adopted. // CPS is reset to 0, allowing the slowest HSPCLK possible (power save). // // 15 ADC conversions are performed per full Buffer, which should take // 225µS (15 * 15µS). This falls well within Timer1 Schedule Interval // (312.5µS), also driving Scheduled Tasks in the Background. // // Problems were found getting ANY of the Peripheral Interrupt Expansion // Module Interrupts to work. CPU-Timer1 does not go through the PIE // Module, but it works. It calls the ADC Service routine (in Flash). // // 8 ADC full-Buffers should be collected per nominal 2.5mS (1/400Hz) // Cycle Period. (2500µS / 312.5µS). // Note that AC Current monitoring is by far the largest CPU load on // the Cooling System Software. The ADC Paths need to be efficient. // // Set ADCTRL1 (b14..4 used) as follows: // RESET = 0 No effect (b14) // SUSMOD = 0 Emulation suspend ignored (b13..12) // ACQ_PS = 1 Additional Sample hold of 2 ADC Clock Cycles (bit11..8) // CPS = 0 Core clock PreScaler (halves ADC Clock when set) (b7) // CONT_RUN = 0 Continuous run mode disabled (b6) // SEQ_OVRD = 0 Stop sequencing at end of Buffer (b5) // SEQ_CASC = 1 Cascaded Sequence, SEQ1+2 (b4) adcRegs.ADCTRL1.all = 0; // Clear default adcRegs.ADCTRL1.bit.ACQ_PS = 1; // One extra (2 total) Sampling Clocks. adcRegs.ADCTRL1.bit.CPS = 0; // Leave ADC Clock unchanged (/ 1). adcRegs.ADCTRL1.bit.SEQ_CASC = 1; // Cascaded SEQ (SEQ1 + SEQ2) AdcRegs.ADCTRL1.all = adcRegs.ADCTRL1.all; // Set ADCTRL2 as follows: // ePWM_SOCB_SEQ2 = 0 ePWM SOCB enable bit for SEQ2 (b15) // RST_SEQ1 = 0 No reset of SEQ1 (b14) // SOC_SEQ1 = 0 Clear a pending SOC Trigger (b13) // INT_ENA_SEQ1 = 0 SEQ1 Interrupt Disable (b11) // INT_MOD_SEQ1 = 0 Set INT_SEQ1 Flag upon every SEQ1 completion (b10) // ePWM_SOCA_SEQ1 = 0 SEQ1 cannot be started by ePWMx SOCA trigger (b8) // EXT_SOC_SEQ1 = 0 No external SEQ1 action to start Conversion (b7) // RST_SEQ2 = 0 No action to reset SEQ2 (b6) // SOC_SEQ2 = 0 Clear a pending SOC trigger (b5) // INT_ENA_SEQ2 = 0 SEQ2 Interrupt Disable (b3) // INT_MOD_SEQ2 = 0 Set INT_SEQ2 Flag upon every SEQ2 completion (b2) // ePWM_SOCB_SEQ = 0 No action (for ePWM SOCB) (b0) adcRegs.ADCTRL2.all = 0; // Clear default AdcRegs.ADCTRL2.all = adcRegs.ADCTRL2.all; // Set ADCTRL3 as follows: // ADCBGFRDN = 3 Bandgap and Reference Circuits powered up (b7..6) // ADCPWDN = 1 Analog circuitry powered up (b5) // ADCCLKPS = 0 Pre-Scaler ADC Clock unchanged (b4..1) // SMODE_SEL = 0 Sequential sampling Mode disabled (b0) adcRegs.ADCTRL3.all = 0; // Clear default adcRegs.ADCTRL3.bit.ADCBGRFDN = 3; // The band-gap & reference circuits powered up. adcRegs.ADCTRL3.bit.ADCPWDN = 1; // The analog circuitry is powered up. adcRegs.ADCTRL3.bit.ADCCLKPS = 0; // ADCCLKPS = Prescale ADC Clock / 1 (b4..1) AdcRegs.ADCTRL3.all = adcRegs.ADCTRL3.all; // Set number of ADC Samples to collect for the full Buffer. AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 14; // SEQ (cascaded SEQ1+2) ADC count = 15 // Please note that for the 5mS delay function below to operate correctly, // the CPU_CLOCK_SPEED define statement in the DSP280x_Examples.h file // must contain the correct CPU clock period (in nanoseconds). // The TI Assembler Function is run from Flash (it locks-up in RAM). DELAY_US(ADC_usDELAY); // Delay before converting ADC channels setAdcChannel(); return; } void setAdcChannel (void) { // Configure ADCs collected for cascaded SEQ (SEQ1 + SEQ2). // These map ADC Input Pin Numbers into A (IM Currents) // and B (Temperatures & Pressures) Channels. // SEQ1 AdcRegs.ADCCHSELSEQ1.all = (ADCIN_A_PH_A_I | // CONV00 -> [0] (ADCIN_B_PRES_1 << 4) | // CONV01 -> [0] (ADCIN_A_PH_B_I << 8) | // CONV02 -> [0] (ADCIN_B_PRES_2 << 12) ); // CONV03 -> [0] AdcRegs.ADCCHSELSEQ2.all = (ADCIN_A_PH_C_I | // CONV04 -> [0] (ADCIN_B_TEMP_1 << 4) | // CONV05 (ADCIN_B_TEMP_2 << 8) | // CONV06 (ADCIN_B_TEMP_3 << 12) ); // CONV07 // SEQ2 AdcRegs.ADCCHSELSEQ3.all = (ADCIN_B_TEMP_4 | // CONV08 (ADCIN_B_TEMP_5 << 4) | // CONV09 (ADCIN_A_PH_A_I << 8) | // CONV10 -> [1] (ADCIN_B_PRES_1 << 12) ); // CONV11 -> [1] AdcRegs.ADCCHSELSEQ4.all = (ADCIN_A_PH_B_I | // CONV12 -> [1] (ADCIN_B_PRES_2 << 4) | // CONV13 -> [1] (ADCIN_A_PH_C_I << 8) | // CONV14 -> [1] (DUMMY_ADC_INPT << 12) ); // CONV15 return; } // Simulant of ADC SEQ Interrupt... void read_ADC_Casc (void) { // Copy cascaded SEQ ADCRESULT0..14 // ADCRESULT0..4 are the first set of // double Samples, Currents & Pressures. phase_A_Curr[0] = AdcMirror.ADCRESULT0; // AI liq_Inp_PRaw[0] = AdcMirror.ADCRESULT1; // P1 phase_B_Curr[0] = AdcMirror.ADCRESULT2; // BI liq_Out_PRaw[0] = AdcMirror.ADCRESULT3; // P2 phase_C_Curr[0] = AdcMirror.ADCRESULT4; // CI // ADCRESULT5..9 are the single // Samples, for Temperature Sensing. liq_Inp_TRaw = AdcMirror.ADCRESULT5; // T1 liq_Out_TRaw = AdcMirror.ADCRESULT6; // T2 air_Inp_TRaw = AdcMirror.ADCRESULT7; // T3 air_Out_TRaw = AdcMirror.ADCRESULT8; // T4 ac_MotorTRaw = AdcMirror.ADCRESULT9; // T5 // ADCRESULT10..14 are the second set of // double Samples, Currents & Pressures. phase_A_Curr[1] = AdcMirror.ADCRESULT10; // AI liq_Inp_PRaw[1] = AdcMirror.ADCRESULT11; // P1 phase_B_Curr[1] = AdcMirror.ADCRESULT12; // BI liq_Out_PRaw[1] = AdcMirror.ADCRESULT13; // P2 phase_C_Curr[1] = AdcMirror.ADCRESULT14; // CI // All ADCs Values have been copied out. // Reset SEQ1 to start at ADCBUFFER0. AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // Reload the number-1 of collected ADC. AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 14; // Start cascaded SEQ ADC collection. AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1; // Process the previous ADC Buffer content, // while the new ADC content commences. // Liquid Pressures and Phase Currents // are double sampled, per full Buffer. for (loopVariable = 0U;loopVariable < 2U; loopVariable++) { // Multiply the averaged Pump Input // Pressure ADC Value by 7, add the // Sample A ADC Value, then shift // right three times to divide by 8. liq_Inp_PAve = ( (liq_Inp_PAve * ADC_AVERAGE) + liq_Inp_PRaw[loopVariable]) >> 3; ... // Check whether Phase A Current (raw ADC Units), // is forming a Peak or Valley. if (phase_A_Curr[loopVariable] > HALVE_SCALE) { // Sum ADC Value for present Phase Peak. sumPk_A_Curr += (phase_A_Curr[loopVariable] - HALVE_SCALE); // Count number of Peak Samples. count_A_Peak++; // Check for the first ADC Peak Current // at, or above 3/4 Raw Scale (~4 Amps). if (phase_A_Curr[loopVariable] >= HI_THR_AMPS) { ...