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:
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.
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:
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.