adc improvements

master
Ondřej Hruška 7 years ago
parent 552e3f309b
commit 0d5288a4f3
  1. 2
      Makefile
  2. 46
      lib/adc.c
  3. 20
      lib/adc.h
  4. 58
      main.c
  5. 2
      pinout.h

@ -49,7 +49,7 @@ CFLAGS += -ffunction-sections -fdata-sections -Os
LDFLAGS = -Wl,--gc-sections -Wl,--relax -lm
#LD_FLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
#LD_FLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
LD_FLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
#############################################

@ -1,5 +1,6 @@
#include <avr/io.h>
#include <stdint.h>
#include <stdbool.h>
#include "calc.h"
#include "adc.h"
@ -8,7 +9,7 @@
void adc_init(enum ADC_Prescaller presc)
{
ADCSRA |= presc; // 128 prescaler -> 125 kHz
ADMUX |= _BV(REFS0); // Voltage reference
ADMUX |= _BV(REFS0); // Voltage reference
sbi(ADCSRA, ADEN); // Enable ADC
}
@ -24,26 +25,53 @@ void adc_enable(void)
sbi(ADCSRA, ADEN);
}
static void adc_convert(uint8_t channel)
/** Start a new conversion */
void adc_start_conversion(uint8_t channel)
{
set_low_nibble(ADMUX, channel); // Select channel to sample
sbi(ADMUX, ADLAR); // Align result to left
cbi(ADMUX, ADLAR); // Align result to right
sbi(ADCSRA, ADSC); // Start conversion
}
/** Check if ADC is done converting */
bool adc_ready(void)
{
return bit_is_low(ADCSRA, ADSC);
}
/** Read the result of last conversion with 8bit precision */
uint8_t adc_read_8bit()
{
uint8_t low = ADCL;
uint8_t high = ADCH;
return low >> 2 | high << 6;
}
while (bit_is_high(ADCSRA, ADSC)); // Wait for it...
/** Read the result of last conversion with 10bit precision */
uint16_t adc_read_10bit()
{
uint8_t low = ADCL;
uint8_t high = ADCH;
return ((uint16_t) high << 8) | low;
}
/** Start ADC conversion and wait for the result */
static void adc_convert(uint8_t channel)
{
adc_start_conversion(channel);
while (!adc_ready()); // Wait for it...
}
/** Sample analog pin with 8-bit precision */
uint8_t adc_read_byte(uint8_t channel)
uint8_t adc_convert_8bit(uint8_t channel)
{
adc_convert(channel);
return ADCH; // The upper 8 bits of ADC result
return adc_read_8bit();
}
/** Sample analog pin with 10-bit precision */
uint16_t adc_read_word(uint8_t channel)
uint16_t adc_convert_10bit(uint8_t channel)
{
adc_convert(channel);
return ADCW; // The whole ADC word (10 bits)
return adc_read_10bit();
}

@ -25,8 +25,20 @@ void adc_disable(void);
/** Enable (already initialized) ADC */
void adc_enable(void);
/** Sample analog pin with 8-bit precision */
uint8_t adc_read_byte(uint8_t channel);
/** Start a new conversion */
void adc_start_conversion(uint8_t channel);
/** Sample analog pin with 10-bit precision */
uint16_t adc_read_word(uint8_t channel);
/** Check if ADC is done converting */
bool adc_ready(void);
/** Read the result of last conversion with 8bit precision */
uint8_t adc_read_8bit(void);
/** Read the result of last conversion with 10bit precision */
uint16_t adc_read_10bit(void);
/** Sample analog pin with 8-bit precision. Blocking! */
uint8_t adc_convert_8bit(uint8_t channel);
/** Sample analog pin with 10-bit precision. Blocking! */
uint16_t adc_convert_10bit(uint8_t channel);

@ -2,9 +2,9 @@
#include <avr/pgmspace.h> // storing data in program memory
#include <avr/interrupt.h> // interrupt vectors
#include <util/delay.h> // delay functions
#include <stdint.h> // C header for int types like uint8_t
#include <stdbool.h> // C header for the bool type
#include <stdio.h>
// Include stuff from the library
#include "lib/iopins.h"
@ -14,6 +14,9 @@
#include "pinout.h"
/**
* Configure pins
*/
void setup_io(void)
{
as_output(PIN_DISP_CP);
@ -35,35 +38,56 @@ void setup_io(void)
}
// --- LED display brightness control ---
#define DISP_BRIGHTNESS OCR2B
volatile uint8_t disp_brightness;
#define LIGHT_ADC_CHANNEL 6
/**
* PWM for LED display dimming
*/
void setup_pwm(void)
{
// PWM for LED display dimming
TCCR2A |= (1 << WGM20) | (1 << WGM21) | (1 << COM2B1);
TCCR2B |= (1 << CS20);
OCR2B = disp_brightness = 0xFF;
TCCR2A |= _BV(WGM20) | _BV(WGM21) | _BV(COM2B1);
TIMSK2 |= _BV(TOIE2);
TCCR2B |= _BV(CS20);
adc_start_conversion(LIGHT_ADC_CHANNEL);
}
/** ISR that writes the PWM register - to avoid glitches */
ISR(TIMER2_OVF_vect)
{
// convert in background
if (adc_ready()) {
disp_brightness = 255 - adc_read_8bit();
adc_start_conversion(LIGHT_ADC_CHANNEL);
}
DISP_BRIGHTNESS = 0x7F;
OCR2B = disp_brightness;
}
/**
* Let's gooo
*/
void main()
{
usart_init(BAUD_115200);
usart_isr_rx_enable(true); // enable RX interrupt handler
//usart_isr_rx_enable(true); // enable RX interrupt handler
adc_init(ADC_PRESC_128);
setup_io();
setup_pwm();
adc_init(ADC_PRESC_128);
// SPI conf
spi_init_master(SPI_LSB_FIRST,
CPOL_1, CPHA_0,
SPI_DIV_2);
// TODO verify the cpha and cpol. those seem to work, but it's a guess
spi_init_master(SPI_LSB_FIRST, CPOL_1, CPHA_0, SPI_DIV_2);
// globally enable interrupts
sei();
uint8_t cnt = 0;
char buf[100];
while (1) {
pin_down(PIN_DISP_STR);
spi_send(cnt);
@ -73,15 +97,7 @@ void main()
_delay_ms(100);
// Brightness directly proportional to light level
DISP_BRIGHTNESS = 255 - adc_read_byte(6);
sprintf(buf, "%d\n", disp_brightness);
usart_puts(buf);
}
}
// UART receive handler
ISR(USART_RX_vect)
{
// "ECHO" function:
uint8_t b = usart_rx();
usart_tx(b); // send back
}

@ -30,7 +30,7 @@
#define PIN_PWR_KEY A4 // Direct input from the power key, used for power-off
#define PIN_PWR_HOLD A5 // Hold the buck enabled. Set 0 for shutdown
// Ambient light sensor (Vdd -> 10k -> * -> phototransistor -> GND)
// Ambient light sensor (Vdd -> 10k -> * -> photo transistor -> GND)
#define PIN_LIGHT_SENSE A6 // ADC exclusive pin
#endif //FIRMWARE_PINOUT_H

Loading…
Cancel
Save