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.

- Compiler: IAR EWAVR and GNU GCC for AVR
- Supported devices: ATmega32U4

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().