ADC-related problem in my head.

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Folks,  I'd appreciate a little help with my project.  This is my first attempt to use the ADC on the ATtiny85.  Eventually, the project will evolve, but at the moment, it is a stripped-to-the-bones attempt to get a result from the ADC.

 
My sketch is below.  The intention of the sketch is to get a voltage from a pot and light one of three LEDs, depending on whether the pot is in the lower third, middle- or upper third of its travel.  It appears to work in AS7 (by writing the "pot" value into the ASC register after the conversion), but when I put it on a chip, it lights one LED, and moving the pot does not cause it to light a different LED.  If I power it off, turn the pot, then power it on, the correct LED comes on, but that one stays on, and turning the pot does not change the LED on the fly.

The sketch is below. 

 

There are a few lines to set up the ADC.  These poke individual bits so I could play with them individually to see what they do.

 

The intention is ...

 

Set up the ADC

 

convert:  ; get pot reading into R16
call light_led
call delay
rjmp convert

 

light_led:
This function works.  Given a value in R16, it discovers what third of (0...255) R16 is in, and lights the appropriate LED.

 

delay:
This function also works, and delays about a second.

 

.org 0x0

 rjmp main                   ; Reset - Address 0
 reti                        ; INT0
 reti                        ; Pin Change Interrupt Request 0
 reti                        ; Timer/Counter1 Compare Match A
 reti                        ; Timer/Counter1 Overflow
 reti                        ; Timer/Counter0 Overflow
 reti                        ; EEPROM Ready
 reti                        ; Analog Comparator
 reti                        ; ADC Conversion Complete
 reti                        ; Timer/Counter1 Compare Match B
 reti ; TCC0_cmpA_handler    ; Timer/Counter0 Compare Match A
 reti                        ; Timer/Counter0 Compare Match B
 reti                        ; Watchdog Time-out
 reti                        ; USI START
 reti                        ; USI Overflow

;========================
; ISRs go here
;========================

main:
; Load stack register
LDI R16, HIGH(RAMEND) ; Upper byte
OUT SPH,R16 ; to stack pointer
LDI R16, LOW(RAMEND) ; Lower byte
OUT SPL,R16 ; to stack pointer

;===================================================
; initialise ADC   PB3-Red, PB4-Yellow, PB1-Green
;                   _____
;           PB5 [1]|*    |[8] VCC
;    (Red)  PB3 [2]|     |[7] PB2 (Pot in)
; (Yellow)  PB4 [3]|     |[6] PB1 (Green)
;           GND [4]|_____|[5] PB0 (to FET)
;
;===================================================
; ATTINY 85 at 1MHz
;===================================================

; set direction reg
ldi R16,(1<<PB0)|(1<<PB1)|(1<<PB3)|(1<<PB4) ; PB3-Red, PB4-Yellow, PB1-Green, PB0-FET
out DDRB,R16  ; PB0 drives pulses to LED via FET

sbi DIDR0,ADC1D    ; ADC1 (PB2) is analog, not digital
sbi ADCSRA, ADEN   ; ADC Enable
sbi ADCSRA, ADPS1  ;\_ Prescaler to div_8 for 125 khz sampling
sbi ADCSRA, ADPS0  ;/
sbi ADMUX, ADLAR   ; all msb's will be in ADCH
sbi ADMUX, MUX0    ; single-ended on ADC2 (PB4 - pin 3)

convert:
; get pot reading into R16  

sbi ADCSRA,ADSC     ; START conversion. I see bit-6 get set in ADCSRA. NOTE: the Cycle Counter = 11
cbi ADCSRA,ADIF     ; this does not clear ADIF in AS7, so I guess it is controlled by the hardware.
                    ; I have not discovered how to clear it, so this is probably the crux of my problem.

; Wait for ADSC to go low again.
wait_adif:        ; NOTE: The datasheet says that at the end of conversion,
sbic ADCSRA,ADSC  ;       ADSC will go false again.  It does in AS7, but when I test it with sbic,
rjmp wait_adif    ; the rjmp is not skipped, so I deduce that ADSC was not, in fact, false.
                  ; If I run the program down to the nop on the next line, I find that ADIF has gone true.
                  ; I experimented with waiting for ADIF to go true, but the result is the same as testing ADSC false.
                  ; That is also the reason why I manually reset ADIF a few lines above.

; copy the pot reading to R16
nop
in R16,adch
rcall light_led
rjmp convert
;===================================================================

light_led:   ; PB3-Red, PB4-Yellow, PB1-Green
cpi R16,86
brlo red
cpi R16,171
brlo yellow
green:
ldi R17,(1<<PB1)
out PORTB,R17   ; Green
ret  ;rjmp convert
yellow:
ldi R17,(1<<PB4)
out PORTB,R17   ; Yellow
ret   ; rjmp convert
red:
ldi R17,(1<<PB3)
out PORTB,R17   ; Red
ret
;===================================================================

delay:
ldi R20,249
ldi R21,249
ldi R22,6
d2:
dec R20
brne d2
ldi R20,249
dec R21
brne d2
ldi R21,249
dec R22
brne d2
ret

There's obviously something about the ADC I have not understood.  Can somebody please explain what I'm missing?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
cbi ADCSRA,ADIF     ; this does not clear ADIF in AS7, so I guess it is controlled by the hardware.
                    ; I have not discovered how to clear it, so this is probably the crux of my problem.

You need to read the datasheet again. Now this may sound a little weird but the way you clear an interrupt flag is NOT by trying to set the bit to 0. You actually do it by writing 1 to the bit. So try making this an SBI instead. 

 

Having said that there is no need whatsoever to ever involve ADIF in an ADC reading. There are TWO ways to know when the conversion is complete and one is much easier than the other. Sure you can do a reading by setting ADSC then waiting to see ADIF but if you do this it is then your responsibility to clear the ADIF flag for next time (by the curious process of writing 1 to it). The much easier way is to set ADSC then just keep checking the state of the ADSC bit. It will remain 1 for the time while the conversion is happening. At the end it goes back to 0. So it is effectively "auto clearing". In that case you don't need to worry about doing anything but setting then watching it.

 

Actually, now that I look back at your code I see you are already doing it this way - in which case why are you bothering with ADIF at all?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I ought to stay out of this because I don't read ASM.

 

That said, when you reload ADCSRA with ADSC to trigger the start of the next conversion, are you keeping ADEN, the ADC enable bit set, or are you clearing it by mistake?

 

Just a thought for you to check on.

 

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, Clawson.  The only reason I involved ADIF was because I didn't understand what ADSC was doing.  When I set ADSC, I see it go true in AS7.  It goes false again after a short while (depending on my conversion rate - I have tried various), but when it goes false, I would expect the

sbic ADCSRA,ADSC

to say - Oh, that bit is false, I'll skip over the

rjmp wait_adif

... but that doesn't happen until ADIF is eventually set, many cycle counts later (looking at the cycle counter in the Processor Status pane).  What I see in AS7 is ADSC false, and the sbic apparently ignoring that fact.  If I put the cursor on the nop below it, and press ctrl-F10 (execute to cursor), it takes about 110 cycles (also 110 uS) to get there, and when it does, ADIF is red.  However, that only happens the first time.  On subsequent iterations, ADIF is already set.  That's why I tried to clear it.

That's why I experimented with waiting for ADIF instead of ~ADSC (and why my labels still indicate ADIF).  I have been trying various things for the past 3 days before asking for help.

 

---- pause for experimetation time ----

OK - I've just cleared ADIF (by writing a 1 to it as suggested) - and now, my sketch does what I had initially intended.  It changes LEDs on the fly.  So unless there's something else that has whooshed over my head (more than likely the case), it seems to me there there's a discrepancy between the datasheet and the way that AS7 represents ADSC and ADIF.

Any thoughts on that?

In the meantime, you have my full support to don your "Genius" cap and to go proudly about in public displaying it.

Thanks also for a very fast response.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for getting back to me, DocJC.  It wasn't what you suggested - but when you're up a gum tree, all suggestions are welcome.

Following what Clawson said, my sketch is working now - though I suspect I may have stumbled on an incorrect way of doing it, which will no doubt come out and bite me at a later stage of the development.