adc improvements

master
Ondřej Hruška 8 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 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_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 <avr/io.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include "calc.h" #include "calc.h"
#include "adc.h" #include "adc.h"
@ -8,7 +9,7 @@
void adc_init(enum ADC_Prescaller presc) void adc_init(enum ADC_Prescaller presc)
{ {
ADCSRA |= presc; // 128 prescaler -> 125 kHz ADCSRA |= presc; // 128 prescaler -> 125 kHz
ADMUX |= _BV(REFS0); // Voltage reference ADMUX |= _BV(REFS0); // Voltage reference
sbi(ADCSRA, ADEN); // Enable ADC sbi(ADCSRA, ADEN); // Enable ADC
} }
@ -24,26 +25,53 @@ void adc_enable(void)
sbi(ADCSRA, ADEN); 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 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 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 */ /** 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); adc_convert(channel);
return ADCH; // The upper 8 bits of ADC result return adc_read_8bit();
} }
/** Sample analog pin with 10-bit precision */ /** 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); 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 */ /** Enable (already initialized) ADC */
void adc_enable(void); void adc_enable(void);
/** Sample analog pin with 8-bit precision */ /** Start a new conversion */
uint8_t adc_read_byte(uint8_t channel); void adc_start_conversion(uint8_t channel);
/** Sample analog pin with 10-bit precision */ /** Check if ADC is done converting */
uint16_t adc_read_word(uint8_t channel); 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/pgmspace.h> // storing data in program memory
#include <avr/interrupt.h> // interrupt vectors #include <avr/interrupt.h> // interrupt vectors
#include <util/delay.h> // delay functions #include <util/delay.h> // delay functions
#include <stdint.h> // C header for int types like uint8_t #include <stdint.h> // C header for int types like uint8_t
#include <stdbool.h> // C header for the bool type #include <stdbool.h> // C header for the bool type
#include <stdio.h>
// Include stuff from the library // Include stuff from the library
#include "lib/iopins.h" #include "lib/iopins.h"
@ -14,6 +14,9 @@
#include "pinout.h" #include "pinout.h"
/**
* Configure pins
*/
void setup_io(void) void setup_io(void)
{ {
as_output(PIN_DISP_CP); as_output(PIN_DISP_CP);
@ -35,35 +38,56 @@ void setup_io(void)
} }
// --- LED display brightness control --- // --- 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) void setup_pwm(void)
{ {
// PWM for LED display dimming OCR2B = disp_brightness = 0xFF;
TCCR2A |= (1 << WGM20) | (1 << WGM21) | (1 << COM2B1); TCCR2A |= _BV(WGM20) | _BV(WGM21) | _BV(COM2B1);
TCCR2B |= (1 << CS20); 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() void main()
{ {
usart_init(BAUD_115200); 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_io();
setup_pwm(); setup_pwm();
adc_init(ADC_PRESC_128);
// SPI conf // SPI conf
spi_init_master(SPI_LSB_FIRST, // TODO verify the cpha and cpol. those seem to work, but it's a guess
CPOL_1, CPHA_0, spi_init_master(SPI_LSB_FIRST, CPOL_1, CPHA_0, SPI_DIV_2);
SPI_DIV_2);
// globally enable interrupts // globally enable interrupts
sei(); sei();
uint8_t cnt = 0; uint8_t cnt = 0;
char buf[100];
while (1) { while (1) {
pin_down(PIN_DISP_STR); pin_down(PIN_DISP_STR);
spi_send(cnt); spi_send(cnt);
@ -73,15 +97,7 @@ void main()
_delay_ms(100); _delay_ms(100);
// Brightness directly proportional to light level sprintf(buf, "%d\n", disp_brightness);
DISP_BRIGHTNESS = 255 - adc_read_byte(6); 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_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 #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 #define PIN_LIGHT_SENSE A6 // ADC exclusive pin
#endif //FIRMWARE_PINOUT_H #endif //FIRMWARE_PINOUT_H

Loading…
Cancel
Save