ATtiny2313 dual clock generator met fase shift.

Tijdens mijn testen van de verschillende functie's van de ATtiny2313 wou ik een instelbare clockgenerator testen. Dat enkel de OCR0A (Output Compare register A) gebruikt wordt om de teller te resetten had ik wel gelezen maar wat met de OCR0B, de tweede comparator. In de manual staat dat eigenlijk niet zo duidelijk, wel dat je die ook kunt gebruiken als een waveform output signaal. Vandaar dat ik aan het testen ben gegaan. Het kan zijn dat de meesten gaan denken welja dat weten we al lang maar als beginneling wist ik dat toch niet zo goed.

Terug enkele instructie's neergeschreven. Veel moest niet gewijzigd worden aan mijn voorgaande topic over de pwm problemen. Wel heb ik ook nog 2 instructie's toegevoegd die mij een juistere 8MHz interne clock geven via het calibreren van de interne oscillator. Die kun je uitlezen via AVRstudio en bij mij was de origineele chipwaarde $5b

Hieronder de code:


;***** clok pulse generator met phase verschuiving door fotoopa *****
.include "tn2313def.inc"
.def Temp 	=r16 ; Temporary register
RESET:
	ser		Temp
	out		DDRB,Temp		; Set PORTB alles voorlopig als output
	out		DDRD,Temp		; Set PORTD alles voorlopig als output
	ldi		Temp,$5a		; adjust osc (org chip waarde was $5b)
	out		OSCCAL,Temp
	ldi		Temp,1<<CS00	; WGM02=0, clkIO 001
	out		TCCR0B,Temp		; Timer/Counter Control Register B
	ldi		Temp,1<<COM0B0|1<<COM0A0|1<<WGM01	; Toggle OC0A on Compare Match
	out		TCCR0A,Temp		; Timer/Counter Control Register A
	ldi		Temp,$0f		; compare A waarde 15 -> 16 clocks (32 clocks periode)
	out		OCR0A,Temp		; Output Compare Register A
	ldi		Temp,$03		; phase verschuiving wordt: 3+1= 4 clocks
	out		OCR0B,Temp		; Output Compare Register B
LOOP:
	nop
	rjmp	loop			; Repeat loop forever

Ik heb die gewijzig naar $5a zodat de CLKio met DIV8 nu juist 1us bedraagt. Die clock heb ik naar buiten gebracht op PD2 zodat ik die kan zien op de LA. Het output signaal van OCR0A zit op PB2 en die van OCR0B op PD5. Gemakshalve heb ik alle pinnen als output gezet. Met de LA kan ik alle signalen uitlezen. Hierbij het resultaat van de test:

http://users.skynet.be/fotoopa/fpga/pwm2313b.png

Omdat ik eerst wat willekeurige waarden toegekent had zag ik niet altijd 2 wavevormen, soms enkel de bovenste (A). Maar stilaan begon mijnen euro te vallen dat die B comparator niet hoger mocht staan dan de A comparator. Het is de A comparator is die de teller gaat gaan resetten bij een match. Zolang B kleiner of gelijk is dan A heb je 2 wavevormen.

Maar al snel zag ik het juiste verband tussen die 2 comparatoren. De waarde toegekent aan comparator B zorgt er in feite voor dat je een wavevorm gaat gaan genereren die in phase verschoven is tov van A. Door die B comparatorwaarde aan te passen kun je de fazeverschuiving per clocklengte instellen. Ga je boven de waarde van A dan is er geen match meer met B en dus ook geen output.

Nu nog even de grenswaarden:
Een waarde van B=0 geeft je 1 clockpuls verschuiving. De verschuiving wordt dus B+1 clocks. Stel je A=B dan bekom je geen verschuiving meer en zijn beide clokken gelijk in faze. Deze instellingen laten je toe 2 wavevormen te genereren waarvan de de faze kunt instellen per clock. Hoe hoger de A waarde is (0-255) hoe fijner je de verschuiving kunt regelen. Ik heb in het voorbeeld de A waarde op 15 gezet ( wordt A+1= 16 clocks) en B op 3 wordt 3+1= 4 clocks). Het is bijgevolg niet moeilijk om een 90 graden verschuiving in te stellen. Als je 2 cloks nodig hebt die een hoeveelheid van elkaar verschoven zijn dan kun je dit op deze manier heel eenvoudig instellen.

Oké, waarschijndelijk wisten de meesten van jullie dit allang maar wieweet of er toch nog anderen zijn die hiervan niet op de hoogte waren. In ieder geval wordt dit niet beschreven in de manual (heb ik toch niet gevonden)

ps: Als je het stukje programma assembleert in AVRstudio kun je het zo draaien en testen. Meer is niet nodig.

Wat gebeurt er als je eerst die OCR's instelt en dan pas de timer start?

Ik veronderstel dat de teller zal starten vanaf nul en de beide outputs vanaf low output. Daarna zouden ze moeten omschakelen volgens het huidig schema. Maar of de timer echt vanaf nul start ga ik eens testen met een kleine routine en het resultaat op de LA bekijken. Er zijn zeker nog een hoop varianten mogelijk. Zo zou je via interrupt ook nog het geheel kunnen wijzigen zij het op punt van OCRA zij het op OCRB. Maar als de waarden heel dicht bij de nul liggen voor de OCR's blijft heel er weinig tijd over. Ik heb ook een soort mono met delayed puls nodig. Dat ligt eigenlijk in de lijn van deze probleemstelling. Maar eerst de zaak even onderzoeken.

Update:

Eerst had ik niet door dat je de teller niet kon resetten maar die heeft zijn eigen register TCNT0 en die kun je op ieder ogenblik zelf lezen of schrijven. Dus ook daar kun je de resetwaarde zelf inschrijven. Ik geef straks de resultaten hoe de wavevormen zijn bij de start.

[Bericht gewijzigd door fotoopa op (44%)]

Ik heb heel wat testen gedaan met de bedoeling een gecontroleerde opstart te verkrijgen van de wavevorm generator met fazeverschuiving. Vooral de vraag wat gebeurt er in de opstart heeft mijn extra aandacht getrokken, reden om wat dieper te graven in het ganse systeem.

Mijn testprogramma heb ik wat aangepast. Ik gebruik nu een afzonderlijke I/O pin om de LA te triggeren vanuit de software. Zo kan ik perfect timingen bekijken, instructie tijden nazien enz. met 2 instructie's sbi en cbi wordt de outputbit op PORTB bit3 getoggeld.

Het volledige testprogramma staat hieronder:


;***** clok pulse generator met phase verschuiving door fotoopa *****
.include "tn2313def.inc"
.def Temp 	=r16 ; Temporary register
.def Delay 	=r17 ; Delay variable 1

RESET:
	ser		Temp
	out		DDRB,Temp		; Set PORTB als output
	out		DDRD,Temp		; Set PORTD als output
	ldi		Temp,$5a	
	out		OSCCAL,Temp		; adjust osc (org chip waarde was $5b)
	ldi		Temp,$00		; 
	out		TCCR0B,Temp		; Clock uitschakelen
	out		PORTB,Temp		; uitgangen laag
	out		TCCR0A,Temp		; normal mode
	ldi		Temp,$0f		;
	out		OCR0A,Temp		; Compare A instellen
	ldi		Temp,$03		;
	out		OCR0B,Temp		; Compare B instellen
	cbi		PORTB,PINB2		; OCA level instellen
	cbi		PORTD,PIND5		; OCB level instellen

Loop:

	ldi		Temp,$00
	out		TCCR0B,Temp		; clock off
	ldi		Temp,$00
	out		TCNT0,Temp		; reset timer
	ldi		Temp,1<<COM0B1|1<<COM0A1|1<<WGM01	
	out		TCCR0A,Temp		; Mode = Toggle on Compare Match
	ldi		Temp,1<<FOC0B|1<<FOC0A
	out		TCCR0B,Temp		; forced output compair

	ldi		Temp,1<<COM0B0|1<<COM0A0|1<<WGM01	
	out		TCCR0A,Temp		; Mode = Toggle on Compare Match

	ldi		Delay,$20		; rustijd tussen 2 metingen
DLY:
	dec		Delay
	brne	DLY

	sbi		PORTB,PINB3		; triggerpuls LA
	cbi		PORTB,PINB3

	ldi		Temp,1<<CS00
	out		TCCR0B,Temp		; clock aanzetten

	ldi		Delay,$4f		; meettijd wavevormen
DLY1:
	dec		Delay
	brne	DLY1
	rjmp	Loop			; Repeat loop forever

Vooraleer de eigenlijke wavevorm aan te zetten heb ik vooraf de beide compair waarden A en B geladen in hun register. A bekomt $0F, B bekomt $03 wat 16 clocks en 4 clocks ( jeweet nog, waarde +1)

Uiteindelijk wou ik een wavevorm verkrijgen zoals hieronder te zien is in het eindresultaat van de test:

http://users.skynet.be/fotoopa/fpga/pwm2313c.png

Je ziet 3 signalen, het onderste signaal is de triggerpuls verkregen uit de software en wordt gebruikt als trigger signaal voor de LA. De 2 bovenste zijn de uitgangen van de wavevormen waarbij ik een onderlinge verschuiving wenste te gebruiken bepaald door de software. Als extra conditie wou ik dat de opstart altijd gebeurde vanuit beide signalen laag en dat na stoppen van de wavevormen en het later herstarten dit op dezelfde manier zou gebeuren.

Dit was blijkbaar toch niet zo evidend als ik eerst had gedacht en het is nodig geweest dat ik verschillende malen het ganse hoofdstuk over de timer/counter clock module heb moeten lezen en herlezen. Van nature uit ga ik het blijven zoeken ipv het eerst overal te gaan vragen. Voordeel ervan is dat je steeds beter de functie's van de controller begrijpt.

De timer kun je zelf op gelijk welk ogenblik herladen. Geeft je de waarde 00 dan komt dit overeen met een reset. Stoppen van de timer kun je in deze mode enkel door de clock te disabelen ( CS2..0 = 0) in de TCCR0B register. Dit werkte goed maar ik bleef een probleem hebben dat bij iedere heropstart het level van de beide wavevormen onbepaald was.

Om dit op te lossen is er een methode beschreven die je toelaat om een geforceerde level te bekomen op de uitgangen van OCA en OCB, van de wavevormen dus. Om dit toe te passen moet je eerst de clock afzetten, daarna de mode kiezen waarbij een geforceerde match de uitgangen geforceerd zal laag plaatsen en daarna alles weer in de mode plaatsen waarbij er een toggle plaatst vind bij iedere match. Dit wordt gedaan in volgend stukje code:


	ldi		Temp,$00
	out		TCCR0B,Temp		; clock off
	ldi		Temp,$00
	out		TCNT0,Temp		; reset timer
	ldi		Temp,1<<COM0B1|1<<COM0A1|1<<WGM01	
	out		TCCR0A,Temp		; Mode = Toggle on Compare Match
	ldi		Temp,1<<FOC0B|1<<FOC0A
	out		TCCR0B,Temp		; forced output compair

	ldi		Temp,1<<COM0B0|1<<COM0A0|1<<WGM01	
	out		TCCR0A,Temp		; Mode = Toggle on Compare Match

Als laatste moet je de clock weer aanzetten als je opnieuw wavevormen wilt maken die opdezelfde manier starten zoals bij de opstart.

Ik geef toe, dit is een stukje informatie waarvan alle randgevallen besproken worden in de manual maar dat je (ik) toch heel wat tijd nodig had om een en ander goed te begrijpen en te implementeren.

Je ziet hier ook hoe praktisch de hulp van een Logic analyser is tijdens deze testen. Ook is het heel belangrijk hoe je met een kleine ingreep een triggersignaal tussen je code kunt plaatsen waardoor je een perfect gekontroleerde trigger bekomt voor de LA of scoop.

Ik ben overtuigd dat niet iedereen mijn verhaal zal snappen. Ik kan het trouwens niet altijd goed uitleggen maar als je de methodes onthoudt om een wat moeiljkere functie te gaan onderzoeken ben je goed op weg voor om het even welke problemen zelf een oplossing te vinden.

Frans.