In mijn huidige RDS encoder gebruik ik een CD4046 PLL die een signaal maakt van 57kHz die in fase loopt met het aangeboden 19kHz signaal die uit mijn stereocoder komt.

Het 57kHz signaal wordt op INT0 van de AtMega16 aangeboden en de interrupt routine genereert het RDS signaal.

Nu is mijn bedoeling om in plaats van 57kHz 19kHz aan te bieden aan de INT0 pin. Nu zou ik graag de 19kHz willen synchroniseren met de interne TIMER die op 57kHz draait.

Mijn idee is om bij elke 19kHz interrupt de TCNT van de timer te resetten en op deze manier de timer synchroon te laten lopen met 19kHz. Zou dit een mooi jitter vrij signaal op kunnen leveren? Of bestaan er nog andere mogelijkheden om de timer met 19kHz te kunnen synchroniseren?

Ik heb mijn idee nog niet getest maar heb nog geen andere mogelijkheden kunnen vinden.

Het is me niet precies duidelijk wat je wilt, maar volgens mij kun je het beste de oscillator van de microcontroller met een PLL aan die 19kHz vastknopen. Waarschijnlijk moet je dan wel een losse oscillator met varicap bouwen, maar dat lukt vast wel.

Je zult volgens mij hoe dan ook de clock van de microcontroller moeten synchroniseren voor een jittervrij signaal.

Nee, wat jij suggereert is niet goed.als je met de 19kHz een reset van je timer doet,help je het idee van de PLL
om zeep.Bij een PLL heb je immers een vrijlopende oscillator die bijgeregeld wordt.
Wat je moet doen is het volgende:
1)programmeer je timer zo dat die 57kHz genereert.
2)zorg dat de 19kHz op een ingang binnekomt die een capture kan uitvoeren van de timer waarde.
3)in de capture interrupt kijk je of je timer te snel,dan wel te langzaam loopt en regel je die bij.

Echoflex je hebt mail

[Bericht gewijzigd door Henry S. op (3%)]

@MC68000: Maar dan is de jitter even groot als de resolutie van de clock waarop je de microcontroller laat lopen. Bij 10MHz heb je dus 0.1us jitter. Dat vind ik best wel veel. De periodetijd van het signaal is slechts zo'n 200 maal groter. Oftewel 0.5% jitter. dat is volgens mij goed hoorbaar.

@Zweetvoetje,

Volgens mij ook maar het idee is wel goed. Volgens mij blijven er weinig varianten over.

Het idee van mij is wel heel erg kort door de bocht en introduceert volgens mij ook enorm veel jitter, Het idee van MC6800 doet het op een voorzichtigere manier.

Het idee met een varicap wil ik eigenlijk niet. De Pira RDS doet het ook zonder varicap en die voedt de uController ook met 19kHz. Zijn implementatie veroorzaakt geen hoorbare jitter. Hoe hij het doet, geen idee. Ik heb hem er wel eens naar gevraagd maar hij geeft zijn geheimen niet prijs.

De hoeveelheid jitter die inje uitgangssignaal doorkomt heb je zelf in de hand.Immers het PLL filter is in software.
Je moet natuurlijk zorgen dat de timer een clock krijgt die vele malen hoger is als je 57kHz.Laat die indien mogelijk op 20Mhz draaien.
Je timer loopt dan van 0.......349. en je moet niet meer als 1 punt bijsturen.Zeker niet als alles kristal gestuurd is.

@MC6800,

Mijn timer krijgt zijn clock zonder prescaling van de master clock die op dit moment 24MHz is.

De timer staat op 57kHz. TCNT0 telt van 0 tot 421 alvorens er een overflow interrupt optreed.

Ik wil een lock range van 10%. 10% van 422 is 42. Dit betekend dus dat ik in een frame van 42 counts bij mag regelen, alles buiten dit frame regel ik niet bij.

Volgens mij kan ik dan ook de fase relatie bepalen tussen 19 en 57kHz door de lock range te verschuiven.

Als voorbeeld neem ik als fase positie: TCNT0 = 210.

Dan zou het zoiets als dit moeten worden:

[code=C]

//external 19kHz interrupt
ISR(INT0_vect)
{
if(TCNT0 > 210 && TCNT0 < 231) --TCNT0;
if(TCNT0 < 210 && TCNT0 > 189) ++TCNT0;
}
[/code]

Overlaatste de volgende pagina tegengekomen. Het is bedoelt voor PICs, maar de theorie is perfect toe te passen op AVRs: http://www.romanblack.com/one_sec.htm
Op het einde van de pagina staat een zero-error, zero-jitter algoritme.

Nou nee Echoflex,ik denk toch niet dat het zo moet.
Als TCNT0 het capture register is,Wat is dan het het timer compare register ??
De meeste uC's hebben een timer(cnt) register ,die telt 0,1,2 etc
dan heb je een compare register,die kan je dan zo configureren dat als de waarde hetzelfe is als het(cnt) register,het cnt register wordt gereset.
Een capture register klokt het cnt register in op een opgaande of neergaande flank van een event (bijv een pin die van state verandert).
Ik heb eventjes het datasheet van de ATmega16 gedownload,en ik denk dat je inderdaad met dat TCNTx register niks van doen hebt.
Zowieso heb je aan timer0 niks,die is maar 8 bit en heeft geen capture register.
Gebruik dus Timer1.zorg dat je interrupt krijgt op ICF1 en lees in de interrupt routine de ICR uit.Aan de hand van wat je daar uitleest,pas je de waarde van OCR1A (of B) aan.hoger of lager.
De OC1A (of B) interrupt is je 57kHz.Je 19 kHz MOET dus binnenkomen op ICP1 (pin20 als je DIP40 hebt).

Ik gebruik nu Timer1. Het TCNT1 register telt van 0 tm de TOP waarde (in mijn geval 421) waarna de overflow interrupt getriggerd wordt. Daarna wordt TCNT1 gereset.

Met de PWM doe ik verder niets dus het OCR1A register waarmee ik de duty cycle kan instellen gebruik ik niet. Ik gebruik de interrupt alleen om een waarde uit een biphase tabel naar buiten te schuiven

Ik heb nu de 19kHz interrupt gebruikt om de waarde van TCNT1 aan te passen wanneer deze binnen mijn window van 42 counts valt

[code=C]
//external 19kHz interrupt
ISR(INT0_vect)
{
if(TCNT1 > 210 && TCNT1 < 231) --TCNT1;
if(TCNT1 < 210 && TCNT1 > 189) ++TCNT1;
}
[/code]

Dit werkt perfect! Ik zie op de scoop dat hij netjes locked. Om het te testen heb ik snel even een 10k potmeter in serie gezet met de piloot uit van mijn stereocoder en de INT0 in van de Atmega. van de INT0 naar aarde een 3n3 condensator. En waarempel, als ik aan de potmeter draai zie ik de fase tussen 19 en 57kHz netjes verschuiven!

Blij te horen dat het werkt.maarre...Ik zie in jouw code 4x een referentie naar TCNT1,ik neem aan dat dat de Timer-counter waarde is die "on the fly" wordt uitgelezen.Jouw software leest dan wel 4x een andere waarde omdat de teller intussen doortelt.
beter zou zijn met een tussen variabele werken:
unsigned int temp;
temp=TCNT1;
if(temp> 210 &&.......etc etc

op die manier doe je echt een "sample" op een specifiek moment van de timer waarde.

Allee weer een CD4046 uitgespaard.

Klopt maar dat had ik gisteren al aangepast. Daar kwam ik pas achter toen ik de 57kHz heen en weer zag dansen :-)

[code=C]
volatile uint16_t usCounter;

ISR(INT0_vect)
{
usCounter = TCNT1;
if(usCounter > 210 && usCounter < 231) --TCNT1;
if(usCounter < 210 && usCounter > 189) ++TCNT1;
}
[/code]

4046 heb ik idd bespaard maar daarvoor in de plaats zit er nu een TL071 en een NE567 PLL. Ik haal namelijk de piloottoon uit het MPX en hoeft dus niet appart aangeboden te worden.

Echo, wat je wilt is niet de COUNT waarde bijstellen maar je eindwaarde.

Wat jij doet met "--TCNT1" kan trouwens best wel een 4 of 5 verschil op de TCNT uitmaken. De code zal iets doen als


LD R1, cnt_low 
LD R2, tcnt_hi
sub R1, 1
subc R2, 0
ST cnt_low, R1
ST cnt_hi, R2

Zoals je ziet, zitten er vier cycles tussen, dus ondertussen is de counter al weer 4 verder voordat de "-1" waarde teruggeschreven wordt. (bij het ophogen gaat ie dus 3 achteruit ipv dat ie opgehoogd wordt!).

dat klopt idd.

Ik heb het nog niet op de eind waarde geprobeerd, ik zal hier vanavond nog eens naar kijken.

Ik zal dan ook even een aantal filmpjes posten van hetgeen ik op de scoop zie.