Functions | Variables

adc.c File Reference

Contains high level functions for initializing the ADC, interrupt handling, and treatment of samples. More...

#include "config.h"
#include "structs.h"
#include "main.h"
Include dependency graph for adc.c:

Go to the source code of this file.

Functions

__interrupt void ADC_ISR (void)
 Interrupt Service routine for ADC.
void ADC_Wait (void)
 Waits for two full cycles of ADC-conversions to occur.
void ADC_Init (void)
 Initializes ADC and input pins.

Variables

volatile ADC_Status_t ADCS
 Holds sampled data and ADC-status.

Detailed Description

Contains high level functions for initializing the ADC, interrupt handling, and treatment of samples.


The ADC is set to free running mode and uses an internal reference voltage.

Author:
Atmel Corporation: http://www.atmel.com
Support and FAQ: http://support.atmel.no/

Definition in file adc.c.


Function Documentation

__interrupt void ADC_ISR ( void   )

Interrupt Service routine for ADC.

This ISR stores the sampled values in the ADC status-struct, then updates the ADC MUX to the next channel in the scanning-sequence.
Once the sequence is completed, ADCS.Flag is set and unless ADCS.Halt has been set, the sequence starts over. Otherwise, the ADC is disabled.
If the mains voltage is below minimum, ADCS.Mains gets set to FALSE. VREF = 2.56V

Note:
Table of scanning sequence:
 Seq | MUX5 | MUX4:0 |  pos I/P  |  neg I/P |  gain |   measure   | signed
 ----+------+--------+-----------+----------+-------+-------------+-------
  01 |  0   | 01001  | ADC0/PF0  | diff/neg |   10x |   Vshunt-   |   no
     |      |        | ADC1/PF1  | diff/pos |   10x |   Vshunt+   |   no
     |      |        |           |          |       |             |
  02 |  0   | 00000  | ADC0/PF0  |   n/a    |   1x  |   Vbatt     |   no
     |      |        |           |          |       |             |
  03 |  1   | 00011  | ADC11/PB4 |   n/a    |   1x  |   NTC       |   no
     |      |        |           |          |       |             |
  04 |  1   | 00100  | ADC12/PB5 |   n/a    |   1x  |   RID       |   no
     |      |        |           |          |       |             |
  05 |  0   | 01001  | ADC0/PF0  | diff/neg |   10x |   Vshunt-   |   no
     |      |        | ADC1/PF1  | diff/pos |   10x |   Vshunt+   |   no         |          |       |             |  
     |      |        |           |          |       |             |
 
Todo:
IIN (#7 in sequence) is never used.
Todo:
Signed is never set. Signed measurements of IBAT will halve the measuring sensitivity, and is therefore not favourable. At the moment, great currents (f.ex. if something happens with the battery) will be interpreted as negative, which might cause unfavourable behaviour during charging (depending on what PWM behaviour is defined), f.ex. ConstantCurrent() will keep increasing the PWM output. This results in an PWM controller error being flagged and the program going into error-state and eventually reinitializing.

Definition at line 114 of file adc.c.

References ADCS, Clear_adc_mux, I_SCALE_1, I_SCALE_2, Select_adc_channel, Start_conv, TRUE, VBAT_SCALE_1, and VBAT_SCALE_2.

{
   static unsigned char avgIndex = 0;
   unsigned char i, Next;
   signed int  temp = 0;
   unsigned long temp_buffer;
   
   // Handle the conversion, depending on what channel it is from, then
   // switch to the next channel in the sequence.
   switch (ADCS.MUX){
     
      // MUX = 0x09 => ADC0/ADC1 (PF0/PF1) = Vshunt
      case 0x01:
      case 0x05:       
         //First differential with no accuracy
         //need second one
         if(ADCS.MUX == 0x01)
         {
            Next=0x05;
         }
         else
         {
         
            // If bipolar, from -512 to 0, to 511:
            // 0x200 ... 0x3ff, 0x000, 0x001 ... 0x1FF
            if (ADC > 511) {
               //Negative value (battery charge)
               temp_buffer = (I_SCALE_1 * (1024 -ADC)) / I_SCALE_2;  
               ADCS.IBAT = -(signed int)temp_buffer;

               //for demo current always positive
               ADCS.IBAT = 0;
            }
            else if (ADC > 0){
               //Positive value (battery discharge) 
               temp_buffer = (I_SCALE_1 * ADC) / I_SCALE_2;            
                 ADCS.IBAT = (signed int)temp_buffer;         
            }
            else{ 
               ADCS.IBAT = 0;
            }
         
            // Insert sample of battery current into the averaging-array
            // (overwriting the oldest sample), then recalculate and store the
            // average. This is the last conversion in the sequence, so
            // flag a complete ADC-cycle and restart sequence.
            ADCS.discIBAT[(avgIndex++ & 0x03)] = ADCS.IBAT;
            for (i = 0; i < 4 ; i++) {
               temp += ADCS.discIBAT[i];
            }
         
            ADCS.avgIBAT = (temp / 4);       
                     
            Next=0x02;           
                     
            //Mux 0x00 for next measurement (case 0x02)
            Clear_adc_mux();     
         }  
      break;
      
      // MUX = 0x00 => ADC0 (PF0) = VBAT
      case 0x02:
         temp_buffer = (VBAT_SCALE_1 * ADC )/VBAT_SCALE_2;

         ADCS.rawVBAT = (unsigned int)temp_buffer;
            ADCS.rawVBAT = ADCS.rawVBAT;
         
            //ADCS.VBAT = ADCS.rawVBAT;
           ADCS.VBAT = (ADCS.VBAT + ADCS.rawVBAT)>>1;


#if(TARGET_BOARD == MEGAU4EK)
         //Only to use the same SW that VARTA batteries
         ADCS.rawNTC = 671;
         ADCS.rawRID = 300;

         ADCS.Flag = TRUE;
         Next=0x01;  

         //Mux 09 for next measurement (case 0x01)
         Clear_adc_mux();
         Select_adc_channel(0x09); 

#else
         Next=0x03;


         //Mux Ox23 for next measurement (case 0x03)
         Clear_adc_mux();
         Select_adc_channel(0x23); 
#endif
            
      break;
      
      // MUX = 0x23 => ADC11 (PB4) = NTC
      case 0x03:
#ifdef TRUSTFIRE
         ADCS.rawNTC = 671;//ADC replaced for TrustFire battery (26°)
#else
         ADCS.rawNTC = ADC;
#endif

         Next=0x04;
         
         //Mux 0x24 for next measurement (case 0x04)
         Clear_adc_mux();
         Select_adc_channel(0x24);                       
      break;
   
      // MUX = 0x24 => ADC12 (PB5) = RID
      case 0x04:
#ifdef TRUSTFIRE
         ADCS.rawRID = 300;//ADC replaced for TrustFire battery (550mA)             
#else
         ADCS.rawRID = ADC;
#endif
         ADCS.Flag = TRUE;
         Next=0x01;  

         //Mux 09 for next measurement (case 0x01)
         Clear_adc_mux();
         Select_adc_channel(0x09);              
      break;
      
      default:  // Should not happen. (Invalid MUX-channel)
         Next=0x01;  // Start at the beginning of sequence.
         
         //Mux 09 for next measurement (case 0x01)
         Clear_adc_mux();
         Select_adc_channel(0x09);     
      break;
   }
   
   // Update MUX to next channel in sequence, set a bipolar conversion if
   // this has been flagged.
   ADCS.MUX = Next;                    
   
   // Re-enable the ADC unless a halt has been flagged and a conversion
   // cycle has completed.
   if (!(ADCS.Flag))
   {
      Start_conv();       
   }

}
void ADC_Wait ( void   )

Waits for two full cycles of ADC-conversions to occur.

This function clears the cycle complete-flag, then waits for it to be set again. This is then repeated once before the function exits.

Definition at line 268 of file adc.c.

References ADCS, FALSE, and Start_conv.

Referenced by ADC_Init().

{
   //adc enable
// Enable_adc();
   ADCS.Flag = FALSE; 

   //start a conversion
   Start_conv();

   //wait a complete conversion
   do {
   } while (ADCS.Flag == FALSE);      
       
   //adc enable
// Enable_adc();
   ADCS.Flag = FALSE; 
   
   //start a second conversion
   Start_conv();
  
   //wait a complete conversion
   do {
   } while (ADCS.Flag == FALSE);     
   
   //stop ADC (to share CPU time)
// Disable_adc();    
}

Here is the caller graph for this function:

void ADC_Init ( void   )

Initializes ADC and input pins.

This function initializes the ADC to free running mode,.

Definition at line 303 of file adc.c.

References ADC_Wait(), ADCS, Clear_adc_mux, Enable_adc, Enable_adc_high_speed_mode, Enable_adc_it, Enable_internal_vref, FALSE, Select_adc_channel, and Set_adc_prescaler.

{
   unsigned char i;

#ifdef __GNUC__
   Disable_interrupt();
#else
   __disable_interrupt();
#endif   

   ADCS.Halt = FALSE; // Enable consecutive runs of ADC.

   // Configure ADC pins (inputs and disabled pull-ups).
   //PF0 PF1
   DDRF &= ~((1<<DDF1)|(1<<DDF0));
   PORTF &= ~((1<<PORTF1)|(1<<PORTF0));

   //DIDR0: disable digital input buffer for PF1 and PF0
   //power consumption improvement
   DIDR0 |= ((1<<ADC1D)|(1<<ADC0D));

#if(TARGET_BOARD != MEGAU4EK) 
   //PB5 PB4
   DDRB &= ~((1<<DDB5)|(1<<DDB4));
   PORTB &= ~((1<<PORTB5)|(1<<PORTB4));

   //DIDR2: disable digital input buffer for PB5 and PB4
   //power consumption improvement
   DIDR2 |= ((1<<ADC12D)|(1<<ADC11D));       
#endif
      
   // Reset the ADC-cycle.
   ADCS.Flag = FALSE;   
   ADCS.MUX = 0x01; 
   
   //Vshunt measurement
   //Select 2.56V as reference + MUX = 0x09 
   //Mux 09
   Clear_adc_mux();
   Enable_internal_vref();
   Select_adc_channel(0x09);                    

    Enable_adc_high_speed_mode();

#if(TARGET_BOARD == MEGAU4EK)       
    //Set prescaler to 7 (\128) => 16MHz\128 = 125kHz (max 200kHz)
    Set_adc_prescaler(7);
#else
    //Set prescaler to 6 (\64) => 8MHz\64 = 125kHz (max 200kHz)
    Set_adc_prescaler(6);
#endif

   // Clear averaged battery current and the discrete readings.
   ADCS.avgIBAT = 0;
   
   for (i = 0; i < 4; i++) {
      ADCS.discIBAT[i] = 0;             
   }
   
   // Re-enable the ADC and ISR.
   Enable_adc_it();
   Enable_adc();

#ifdef __GNUC__
   Enable_interrupt();
#else
   __enable_interrupt();
#endif

   // Get a complete cycle of data before returning.
   ADC_Wait();    
}

Here is the call graph for this function:


Variable Documentation

volatile ADC_Status_t ADCS

Holds sampled data and ADC-status.

Definition at line 66 of file adc.c.

Referenced by ADC_Init(), ADC_ISR(), and ADC_Wait().