Skip to content

Instantly share code, notes, and snippets.

@gshrikant
Last active January 4, 2016 09:19
Show Gist options
  • Save gshrikant/8601604 to your computer and use it in GitHub Desktop.
Save gshrikant/8601604 to your computer and use it in GitHub Desktop.
ADC peripheral driver for ATmega328P
/*
* adc.c
*
* Analog-Digital Conversion example
*
* Hardware: ATMega328P at 16 MHz
* Toolchain: avr-gcc v4.3.3
* Editor: Eclipse Kepler (4.0) with GNU Make
* Usage:
* Include and edit settings in adc.h and compile using 'make all'
*
* Created on: 22-Jan-2014
* Author: Shrikant Giridhar
*/
#include "adc.h"
/* Debug Mode; Set on Release */
#define _DEBUG 1
#if _DEBUG
#include <util/delay.h>
#include <stdlib.h>
#include "uart.h"
#endif
// Select channel of your choice
#define ADC_CHANNEL CHANNEL_3
/*! Sets up ADC reference voltage, channel and output format */
void initADC(void)
{
// Set selected channel as input
DDRC &= ~_BV(ADC_CHANNEL);
PORTC &= ~_BV(ADC_CHANNEL);
// AVCC reference; right-adjusted; channel selection
ADMUX |= (AVCC << REFS0) | (ADC_CHANNEL << MUX0);
ADCSRA = (PRESCALAR_4 << ADPS0);
ADC_ENABLE();
}
/*! \brief Retrieves converted data; blocking function */
uint16_t getConvData(void)
{
/*
* There are a couple of ways of checking if the conversion is over.
* 1. In a single-ended conversion, the ADSC is cleared as soon as the
* conversion is over otherwise it stays high.
* 2. The ADIF bit is set on conversion complete.
* 3. The ADIF bit could set off an interrupt to indicate end of conversion.
*
* Note that the first method wouldn't be useful if ADC is free-running, in
* which case methods 2 or 3 would be appropriate.
*
*/
uint16_t result;
ADC_START();
// while (ADCSRA & _BV(ADSC));
while(!ADC_DONE()); // Stay here while conversion completes
// ADC data update is blocked on reading ADCL, keeps read atomic
// result = (uint16_t) (ADCL + (ADCH << 8));
// Otherwise, just read the 16-bit register, ADCW
result = (uint16_t) (ADCW);
return result;
}
#if _DEBUG
int main(void)
{
char adcData[10];
uint16_t result;
initADC();
initUART();
while(1)
{
result = getConvData();
itoa(result, adcData, 10);
writeString(adcData);
putByte(' ');
putByte('\r');
putByte('\n');
}
return 0;
}
#endif
/*
* adc.h
*
* Created on: 23-Jan-2014
* Author: Shrikant Giridhar
*/
#ifndef ADC_H_
#define ADC_H_
#include <avr/io.h>
#include <stdint.h>
/* Auto-trigger options */
#define AUTO_TRIG 0
#if AUTO_TRIG
/* Define auto-triggering sources */
#define FREE_RUNNING (0x00)
#define AN_COMPARATOR (0x01)
#define EXT_IRQ (0x02)
#define TMR0_COMPA (0x03)
#define TMR0_OVF (0x04)
#define TMR1_COMPB (0x05)
#define TMR1_OVF (0x06)
#define TMR1_CAP (0x07)
#endif
/* ADC Channel Selection */
#define CHANNEL_0 (PINC0)
#define CHANNEL_1 (PINC1)
#define CHANNEL_2 (PINC2)
#define CHANNEL_3 (PINC3)
#define CHANNEL_4 (PINC4)
#define CHANNEL_5 (PINC5)
/* Reference voltage settings */
#define AREF (0x00)
#define AVCC (0x01)
#define BAND_REF (0x03)
/* ADC Clock settings */
#define PRESCALAR_2 (0x01) // ADC_CLK = CLK/2
#define PRESCALAR_4 (0x02) // ADC_CLK = CLK/4
#define PRESCALAR_8 (0x03) // ADC_CLK = CLK/8
#define PRESCALAR_16 (0x04) // ADC_CLK = CLK/16
#define PRESCALAR_32 (0x05) // ADC_CLK = CLK/32
#define PRESCALAR_64 (0x06) // ADC_CLK = CLK/64
#define PRESCALAR_128 (0x07) // ADC_CLK = CLK/128
/* Useful Macros */
#define POWER_DOWN() (PRR |= _BV(PRADC))
#define ADC_ENABLE() (ADCSRA |= _BV(ADEN))
#define ADC_DISABLE() (ADCSRA &= ~_BV(ADEN))
#define ADC_START() (ADCSRA |= _BV(ADSC))
#define ADC_DONE() (ADCSRA & _BV(ADIF))
#define ADC_INTEN() (ADCSRA |= _BV(ADIE))
#define AUTO_EN() (ADCSRA |= (AUTO_TRIG << ADATE))
/* Prototypes */
void initADC(void);
uint16_t getConvData(void);
#endif /* ADC_H_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment