ADC woes

I had this working the other day, something changed between then and now, I cant figure out what…

Im trying to use the ADC in free running as a random number generator to drive TRIACs to generate a realistic flickering for lamps for Halloween this year…

I copied the ADC spinets from another project where it is working properly, yet I still have no luck. Im debuging with dW and what seems to be happening is ADCSRA|=(1<<ADSC); doesn’t change anything. It fails to set ADSC, and a conversion never starts. If i set it manually while debugging it runs a conversion fine. I assume the problem is the ADSC is never being set, why not?

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include "ADC.h"
#include "timer.h"

#define nop() volatile  asm("nop")
#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 << (x)) 

#define LIGHT0_ON PORTB&=(!(1<<PORTB0))
#define LIGHT0_OFF PORTB|=(1<<PORTB0)

#define LIGHT1_ON PORTB&=(!(1<<PORTB1))
#define LIGHT1_OFF PORTB|=(1<<PORTB1)

#define LIGHT2_ON PORTB&=(!(1<<PORTB2))
#define LIGHT2_OFF PORTB|=(1<<PORTB2)

#define LIGHT3_ON PORTC&=(!(1<<PORTC0))
#define LIGHT3_OFF PORTC|=(1<<PORTC0)

#define HEART_ON PORTD&=(!(1<<PORTD0))
#define HEART_OFF PORTD|=(1<<PORTD0)

#define PICKLE PIND3

unsigned char x, timer=0, adc;

ISR(TIMER2_OVF_vect){
	timer++;		//inc RTC
	PORTD ^= (1<<PORTD0) | (1<<PORTD7);	 // toggle heart beat LED
}

ISR(ADC_vect){
	adc=ADCH;
	adc=ADCL;	//
	ADCSRA|=(1<<ADSC); //start conversions
}

ISR(INT0_vect){
	x=150+(ADCL/3);  //set base delay + random number
	for (char i=0; i<x; i++){   //delay loop before fireing TRIAC
		_delay_us(25);
	}
	LIGHT0_ON;
	LIGHT1_ON;
	LIGHT2_ON;
	LIGHT3_ON;
	_delay_us(2);
	LIGHT0_OFF;
	LIGHT1_OFF;
	LIGHT2_OFF;
	LIGHT3_OFF;
}

void ADC_setup(void){
	ADCSRA|=(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0); // set the ADC clock prescaler to 64 (8m/64=125k) and enable ints
	ADMUX|=(0<<ADLAR)|(0<<MUX3)|(1<<MUX2)|(1<<MUX1)|(0<<MUX0); //set the ADC result register right justified and select ADC chan 6
	ADCSRA|=(1<<ADEN); //enable ADC

	ADCSRA|=(1<<ADSC); //start conversions
	}


void initialize (void) {
	CLKPR=(1<<CLKPCE); // enable divisor change to turn of clk/8
	CLKPR=0; // set divisor to 1 for a clock of 8mhz
	
	timer_setup();
	ADC_setup();

	DDRB |= (1<<DDB0) | (1<<DDB1) | (1<<DDB2);	//B0:2 output
	DDRC |= (1<<DDC0);
	DDRD |= (1<<DDD0) | (1<<DDD7) | (0<<DDD3);
//	PORTD |= (1<<PORTD3); //enable the pullup on PD3, an input
	EICRA |= (1<<ISC01) | (1<<ISC00); 	// Setup INT0 control reg
	EIMSK |= (1<<INT0);

	sei(); //enable global ints

	LIGHT0_OFF;
	LIGHT1_OFF;
	LIGHT2_OFF;
	LIGHT3_OFF;
}

int main (void){
	initialize();
	for(;;){
		;
	}
}
   adc=ADCH;
   adc=ADCL;   //

You need to read ADCH last. Once you read ADCL, the ADC register is

locked, and you won’t see another result until ADCH is read. (This applies

to your INT0_vect as well.) Given the flow of this code, you’ll only see one

conversion result Ever.

WinAVR defines a 16-bit pseudo-register (ADCW, as I recall); if you read

that, the two 8-bit reads will be done in the proper order.

This is only half-an-answer, since it doesn’t explain the particular effect

you’re seeing with ADSC. But I also don’t know in detail how dW interacts

with these registers.

FWIW, a few years back I coded up a filtered-LFSR-based candle flicker routine from the ideas in [Philip Ching’s project here. Leaving off all the clever wind-sensor stuff, an old 90S1200 AVR easily produced four separate flicker outputs. The lack of hardware randomness input really isn’t perceptible. I could post my code if there’s interest, but Philip Ching’s article has some code, and I think there are other implementations floating around on the web as well.](http://instruct1.cit.cornell.edu/courses/eceprojectsland/STUDENTPROJ/2001to2002/pc59//index.htm)

I scraped all that code and started over fresh, and everything seems fine now. I have no idea what went wrong but I feel a lot better about it now.

The flicker seems fine. The incandescent lamps are probably more forgiving as far as blending all the randomness together to make it seem more smooth than it actually is. If i were using LEDs i would probably want to see your code wiml. Thanks for the help guys.

i changed my mind… i would like to see your code if you wouldn’t mind wiml. after testing it out today in the dark I realized it dosent look at all how I want it to.

Im having the same problem as before, which is a register is not being changed when it should. This is really frustrating.

Im trying to clean up my code… get those delay routines out of the ISR, instead just set a flag, and test for the flag in my main code and do the appropriate thing there. The ISR sets the Triac_refresh flag, which is tested in the main loop. The problem is the Triac_refresh=0 in the IF is not actually clearing the register, at least its not reporting this is happening when I debug. I know its posible the INT0 isr is being called so fast that its being set right after its cleared but thats not probable as that ISR is only being called 120 times a second, and the AVR is running at 8Mhz.

Im starting to think debugwire is lying to me or im missing something really basic. Any ideas?

/***********************************************************/
// Paul Mac
// Halloween show control board
// v1.0 Build Oct 24, 2008
//	
/***********************************************************/

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

/***********************************************************/
//Defines

#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 << (x))
#define NOP asm("nop")


#define LIGHT0_ON bit_clear(PORTB, BIT(0))
#define LIGHT0_OFF bit_set(PORTB, BIT(0))

#define LIGHT1_ON bit_clear(PORTB, BIT(1))
#define LIGHT1_OFF bit_set(PORTB, BIT(1))

#define LIGHT2_ON bit_clear(PORTB, BIT(2))
#define LIGHT2_OFF bit_set(PORTB, BIT(2))

#define LIGHT3_ON bit_clear(PORTC, BIT(0))
#define LIGHT3_OFF bit_set(PORTC, BIT(0))

#define HEART_ON bit_clear(PORTD, BIT(0))
#define HEART_OFF bit_set(PORTD, BIT(0))

#define BMID_ON bit_clear(PORTD, BIT(7))
#define BMID_OFF	bit_set(PORTD, BIT(7))

#define BTOP_ON bit_clear(PORTC, BIT(3))
#define BTOP_OFF	bit_set(PORTC, BIT(3))

/***********************************************************/
//Global Vars

char unsigned x, triac_fire=0, ch1_full;
char unsigned Triac_refresh;
static char unsigned timer=0;

/***********************************************************/
// ISRs

/*
ISR(INT0_vect){
	triac_fire=1;
	x=75+ADCH;
	//x=0;
	for (char i=0; i<x; i++){   //delay loop before fireing TRIAC
		_delay_us(25);
	}

	LIGHT0_ON;
	LIGHT1_ON;
	LIGHT2_ON;
	LIGHT3_ON;
	_delay_us(2);
	LIGHT0_OFF;
	LIGHT1_OFF;
	LIGHT2_OFF;
	LIGHT3_OFF;
}*/

ISR(INT0_vect){
	Triac_refresh=1;
}

ISR(TIMER2_OVF_vect){
	timer++;		//inc RTC
	PORTD ^= (1<<PORTD0);	 // toggle heart beat LED
}
/***********************************************************/
// Functions

void adc_setup(void) {
	ADCSRA|=(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0); // set the ADC clock prescaler to 64 (8m/64=125k) and enable ints
	ADMUX|=(1<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0); //set the ADC result register right justified and select ADC chan 6
	ADCSRA|=(1<<ADEN); //enable ADC
	DIDR0|=(1<<ADC1D); 	//disable digital buffer on ADC1
}

void port_setup(void){
	BTOP_OFF;
	BMID_OFF;

	DDRB |= (1<<DDB0) | (1<<DDB1) | (1<<DDB2);	//B0:2 output

	DDRC |= (1<<DDC0) | (1<<DDC3);

	DDRD |= (1<<DDD0) | (0<<DDD3) | (1<<DDD6) | (1<<DDD7);
	PORTD |= (1<<PORTD3); //enable the pullup on PD3, an input

	EICRA |= (1<<ISC01) | (1<<ISC00); 	// Setup INT0 control reg
	EIMSK |= (1<<INT0); //enable external int0
}

void timer_setup(void){
	ASSR|=(1<<AS2);
	TCCR2B|= (1<<CS22)|(0<<CS21)|(1<<CS20); //prescaler of 128
	TIMSK2|=(1<<TOIE2); //enable the timer 2 overflow int.
}

void initialize (void) {
	CLKPR=(1<<CLKPCE); // enable divisor change to turn of clk/8
	CLKPR=0; // set divisor to 1 for a clock of 8mhz

	port_setup();
	adc_setup();
	timer_setup();

	sei(); //enable global ints

	LIGHT0_OFF;
	LIGHT1_OFF;
	LIGHT2_OFF;
	LIGHT3_OFF;
	
}

/***********************************************************/
// Main Function

int main (void){
	initialize();
	for(;;)
	{
		ADCSRA|=(1<<ADSC); //start conversions
		if(!bit_get(PIND, BIT(3))){
			ch1_full=1;
		}
		if(Triac_refresh==1)
		{
			Triac_refresh=0;
			NOP;	
		}
	}
}

ugh. defining Triac_refresh as volatile seemed to fix all my problems. things are working a lot better now. very first FAQ from avrlibc page… ughhhh

http://www.nongnu.org/avr-libc/user-man … q_volatile

ide still like to see that flicker code if you have it wiml. thanks!