ATTiny 85 BRLO question

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

If I am comparing Rd to Rr the data sheet says
"Interchange Rd and Rr in the operation before the test, i.e., CP Rd,Rr → CP Rr,Rd" (seen on page 10) but the page that describes BRLO does not mention reversing the two registers to get a true compare. Which is correct? Also should I clr C before doing this compare?

BADBAUD

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

Which register you use as Rd and Rr are up to you. BRLO will branch after CP Rd, Rr if the value in Rd < the value in Rr.

Regards,
Steve A.

The Board helps those that help themselves.

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

Thanks, that is the way I wrote my code. Just having such a strange problem with this code it is driving me crazy and i am grasping at straws. I don't have any advanced tools to debug with and the assembler (build) says no errors in my syntax. I run a subroutine at power up and it runs fine. Later in the code I use it again and it locks on and won't exit. It's a ADC read subroutine that reads 50 times and stores a result. Try to run it again and the ADC never turns off and the port that is on enabling a load during the ADC read never turns off. I can remove the second call to the read subroutine and the rest of the code works fine. There is something exotic I am missing on this ATTiny85 and it is not in my basic assembler code, I assume it's a quirk with this product line that I am not privy to.

BADBAUD

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

Are you overunning the stack?

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

No, I don't think so. My first ADC read with the subroutine happens in a blip of time and i can read the EEPROM where the data is stored and it all appears correct. That's the calibration phase, a quick on and off to get the no load value and store it. Then I apply the load and power back up. Push a button and the load turns on via a MOSFET. There should be a brief blip of ADC test to compare with the no load condition then the load should stay on, with no further ADC checks, until the button is pressed again. I have the ADC on/off monitored via a unused pin. 5V =ADC is reading, 0V=ADC is not reading. I see the ADC running all of the time instead of a blip and the load is locked on and the push button is no longer seen. It's like the ADC read during load condition makes the CPU go into bullshit land. I have tacked .1uF caps on the power input, the regulator output, across the push button, and removed the MOSFET source lead from the board and tied it directly to the ground input at the power supply. The load I am turning on and off is a noisy little DC to AC inverter that puts out 300 VAC. it is not mounted on the board. The idiot who laid out the board put a ground plane on the bottom and tied the MOSFET source to it. As far away from the main DC voltage in as possible. Removing it from the ground plane helped a little and I can get the design to work for a couple of button presses then it locks up again. Is there some kind of software noise filtering I can apply to the ADC signal in hopes of reducing this problem?

BADBAUD

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

Don't know if you can post the code just in case someone can see something strange.

Another idea is to switch a 10:1 (or other) attenuator on the ADC input before turning the load on to see if it makes any difference.

edit Are you using the ADC in 8 bit or 10 bit mode? Are the registers compared above ADC values? If in 10 bit mode then it will not work of course...just thinking aloud.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

First step is to read the ADC 50 times and find the peak input voltage. Then I divide that 10 bit value by two giving me a midpoint. Then I read the ADC 50 times and if I see a voltage above the midpoint I increment a 16 bit counter that was initially set to one. Wait for a value below the midpoint then wait for the next value above midpoint. This gives me a numerical representation of the frequency the inverter is running at. If this is the first time (or programming mode) the 16 bit value is stored in EEPROM. This initial test is done when the inverter has no load and takes a short "blip" of time to accomplish. A load is applied to the inverter and the board is turned back on. The "blip" of the above test is performed again and it's count result is compared with the one stored in the EEPROM. If it is lower the inverter is kept on. Equal or higher and the inverter is turned off. The problem is that with load on the inverter noise is getting into the board and mucking up the MCU and the inverter locks up in the on position, pushing a button connected to a MCU port is suppose to turn it off. It stays on. I have read that there is a way to turn off the other clocks and allow only the ADC clock to run during a ADC read. I hope this will prevent the MCU from going bonkers. What assembly code would I have to insert to disable all of the clocks except the ADC clock right before a ADC read and then turn them all back on right after the ADC read?

BADBAUD

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

So you are using 10 bit mode, requiring 2 registers to hold the value but using an 8 bit test (1 register)?

Sorry if it's an unrelated question, just trying to get my head around how BRLO comes into the picture. :)

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

I test two 8 bit values, Freq high (MSD) and freq low (LSD).
If the stored MSD is higher then the just read MSD I leave the inverter on and don't have to check the LSD. If they are equal I need to test the LSD bytes. If it is less I turn the inverter off. You know, BRLO.

BADBAUD

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

May want to post that bit of code then. :-)

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
;
;
FREQ_CNTR:
	rcall FIND_HIGH_POINT	;find the highest voltage present
	rcall MATH_MIDPOINT		;calculate the midpoint voltage
	rcall COUNT_ADC_PULSES	;count pulses to determine frequency of inverter
	ret
;
;
;read and store the highest ADC value
;
FIND_HIGH_POINT:
	ldi r26,0
	ldi r27,50			;50 times reading ADC over and over
;
del2x:
	rcall DO_ADC_CHECK
	sbiw r27:r26,1
	brne del2x
	ret
;
;
;** find the DC peak voltage of the ADC input port **
DO_ADC_CHECK:
	rcall READ_ADC		;read the ADC, results stored at ADCL and ADCH
	in r25,ADCL 		;temp store first ADCL read
	in r28,ADCH	  		;temp store first ADCH read
	rcall READ_ADC		;read the ADC, results stored at ADCL and ADCH
	in r29,ADCL 		;temp store second ADCL read
	in r30,ADCH	  		;temp store second ADCH read
	clc					;clear carry
	cp r30,r28			;compare second ADCH read to first
	brlo DO_AGAIN		;result is lower, do not store
;	clc					;clear carry bit
	cp r30,r28			;compare second ADCH read to first
	breq DO_LOWER		;result is equal, check lower value
;	clc					;clear carry bit
	cp r30,r28			;compare second ADCH read to first
	brsh STORE_NEW		;wasn't equal, is higher store new (higher) value
	ret
;
DO_AGAIN:
	ret
;
STORE_NEW:
	sts 0x0065,r29		;when time is done this should be the highest ADC voltage read
	sts 0x0066,r30
	ret
;
DO_LOWER:
	clc					;clear carry
	cp r29,r25			;compare second ADCL read to first
	brlo DO_AGAIN		;result is lower, do not store
;	clc					;clear carry bit
	cp r29,r25			;compare second ADCL read to first
	breq STORE_NEW		;ADCH and ADCL are both the same for two consecutive reads
;	clc					;clear carry bit
	cp r29,r25			;compare second ADCL read to first
	brsh STORE_NEW		;wasn't equal, is higher store new (higher) value
	ret
;
;
;
;
;
;
;
;**********************************************************
; SHIFT THE 16 BIT ADC VALUE TO THE RIGHT TWO PLACES
; THIS EQUALS A DIVIDE BY TWO GIVING THE MID POINT
; TO USE TO DETERMINE IF THE ADC INPUT VALUE IS A ONE
; (HIGHER THEN THE MIDPOINT) OR A ZERO (EQUAL OR LOWER THEN
; THE MIDPOINT). THIS ALLOWS MCU TO COUNT THE ONES FOR A
; GIVEN TIME FRAME AND PRODUCE A NUMBER RELATING
; TO THE FREQUENCY OF THE INVERTER.
;**********************************************************
;
;
;
MATH_MIDPOINT:
	lds TEMP, 0x0065	;get stored high point LSD
	mov r29,TEMP
	lds TEMP, 0x0066	;get stored high point MSD
	mov r30, TEMP
	lsr r30				;shift hi value right by one, MSB.7 resets, MSB.0 to carry bit
	ror r29				;rotate lo value, carry enters LSB.7 (divide hi by two)
	mov TEMP, r29
	sts 0x0063, TEMP	;store midpoint LSD calculation in RAM
	mov TEMP, r30
	sts 0x0064, TEMP	;store midpoint MSD calculation in RAM
	ret
;
;
;*********************************************
; THIS IS THE ACTUAL FREQUENCY COUNTER.
; IT READS THE ADC VOLTAGE AND COMPARES
; IT WITH THE MIDPOINT VALUE STORED
; IF THE READ VOLTAGE IS HIGHER THEN THE
; MIDPOINT A 16 BIT COUNTER IS INCREMENTED
; BY ONE, IT THEN WAITS FOR A VOLTAGE READING
; LOWER THEN THE STORED MIDPOINT TO INDICATE
; A ZERO. THEN IT WAITS FOR ANOTHER VOLTAGE
; ABOVE THE MIDPOINT BEFORE INCREASING THE
; 16 BIT COUNTER AGAIN.
;*********************************************
;
;
COUNT_ADC_PULSES:
	clr r30				;clear LSD of counter temporary register
	clr r31				;clear MSD of counter temporary register
	ldi r26,0
	ldi r27,50			;set for 50 times reading ADC over and over
;
del2y:
	rcall WATCH_LOOP
	sbiw r27:r26,1
	brne del2y
	sts 0x0068, r31		;store MSD of frequency
	sts 0x0067, r30		;store LSD of frequency
	ret
;
;
;
WATCH_LOOP:
	lds TEMP, 0x0064	;get stored MSD midpoint from RAM
	tst TEMP			;test MSD of midpoint for a zero, if so must check LSD
	breq TEST_LOWY		;if it is jump to testing lower byte
WATCH_J:
	rcall READ_ADC
	in r25,ADCL 		;temp store first ADCL read
	in r28,ADCH	  		;temp store first ADCH read
	lds TEMP, 0x0064	;get MSD midpoint
;	clc					;clear carry bit
	cp r28, TEMP		;is the ADC MSD read higher then the stored midpoint?
	brsh IS_A_ONE		;branch if same or higher
	ret
;
IS_A_ONE:
	ADIW r31:r30,1		;increment the frequency counter
A_ONE_LOOP:
	rcall READ_ADC
	in r25,ADCL 		;temp store first ADCL read
	in r28,ADCH	  		;temp store first ADCH read
	lds TEMP, 0x0064	;get stored MSD midpoint from RAM
;	clc					;clear carry bit
	cp r28, TEMP		;is ADC read same or higher
	brsh A_ONE_LOOP		;wait for EE_READH to go below midpoint (=0)
	ret
;
TEST_LOWY:
	rcall READ_ADC
	in r25,ADCL 		;temp store first ADCL read
	in r28,ADCH	  		;temp store first ADCH read
	lds TEMP, 0x0063	;get stored LSD midpoint
;	clc					;clear carry bit
	cp r25, TEMP		;is the ADC LSD higher then the stored midpoint?
	brsh LIS_A_ONE		;branch if same or higher
	ret
;
LIS_A_ONE:
	ADIW r31:r30,1		;increment the frequency counter
LIS_LOOP:
	rcall READ_ADC
	in r25,ADCL 		;temp store first ADCL read
	in r28,ADCH	  		;temp store first ADCH read
	lds TEMP, 0x0063	;get stored LSD midpoint from RAM
;	clc					;clear carry bit
	cp r25, TEMP		;wait for EE_READL to go below midpoint (=0)
	brsh LIS_LOOP		;branch if same or higher
	ret
;
;
;

BADBAUD

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

Any reason why you are not doing 16 bit compare as you have 16 bit values? Also why not use immediate compare when you need to compare to a fixed number? Had a look at AVR202?

A couple of routines you may find useful if you don't know about them:

;***************************************************************************
;* 
;* "cp16" - Comparing two 16-bit numbers 
;*
;* This example compares the register pairs (cp1l,cp1h) with the register
;* pairs (cp2l,cp2h)  If they are equal the zero flag is set(one) 
;* otherwise it is cleared(zero)
;*
;* Number of words	:2
;* Number of cycles	:2
;* Low registers used	:None
;* High registers used	:4
;*
;* Note: The contents of "cp1" will be overwritten.
;*
;***************************************************************************

;***** Register Variables
.def cp1l = r16
.def cp1h = r17
.def cp2l = r18
.def cp2h = r19

;***** Code
cp16:	cp	cp1l,cp2l	;Compare low byte
	cpc	cp1h,cp2h	;Compare high byte with carry from
				;previous operation
ncp16:
	;Expected result is Z=0



;***************************************************************************
;* 
;* "cpi16" - Comparing 16-bit register with 16-bit immediate 
;*
;* This example compares the register pairs (cpi1l,cpi1h) with the value
;* cpi2.  If they are equal the zero flag is set(one), otherwise it is 
;* cleared(zero). This is enabled by the AVR's zero propagation. Carry is
;* also set if the result is negative. This means that all conditional
;* branch instructions can be used after the comparison. 
;*
;* Number of words	:3
;* Number of cycles	:3
;* Low registers used	:None
;* High registers used	:3
;*
;*
;***************************************************************************

;***** Register Variables
.def cp1l =r16
.def cp1h =r17
.def c_tmp=r18 
.equ cp2 = 0x3412		;Immediate to compare with

;***** Code
cpi16:	cpi	cp1l,low(cp2)	;Compare low byte
	ldi	c_tmp,high(cp2)	;
	cpc	cp1h,c_tmp	;Compare high byte

	;Expected result is Z=1, C=

Also you said above that you are comparing ADC values against EEPROM values but I don't see any code to read from the EEPROM. I guess I'm just confused. :roll:

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Naw, that code is further back and I didn't include it, I call this subroutine twice. Once on power up and if the EEPROM locations read FF which means it has never been programmed. Then read the saved EEPROM and compare. Thanks for the compare routines. My 6502 and 8031 coding kicks in sometimes and i get caught up in the bits and bytes, forgetting how powerful the AVR actually is. Self taught.

Any code on how to turn off all of the clocks except the ADC clock during a ADC read then wake back up when the read is complete would also be helpful.

BADBAUD

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

I have never done it but you may want to look at the various sleep modes maybe.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Ya, i have been reading up on it but can't find any code examples. Sleep is the solution but getting it out of sleep is my concern.

BADBAUD

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

At my age my concern is getting any sleep and make sure I wake up in the morning. :?

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Quote:

Sleep is the solution but getting it out of sleep is my concern.

Each datasheet has a table showing which interrupt sources can wake a chip out of each sleep level.

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

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

OK, as the the discussion has moved on to sleep and there's more info in that other thread I will lock this one.

Topic locked