Pins schnell schalten

Gast #181534
Lesenswert?

Moin Moin

Bin gerade dabei mir einen Digitalen Rechteckgenerator zu bauen.
Nun suche ich eine schnelle Möglichkeit einen Pin zu tickern.

Mit einem 10MHz Quarz komme ich mit diesem Code...

for(;;)
PORTD = ~PORTD;

...auf ca. 1MHz an PORTD.

Allerdings brauche ich das Ganze für nur einen Pin an PORTD.
Mit folgendem Code funktionert es zwar aber die Frequnez fällt auf ca.
110KHz ab.

for(;;){
  if((PORTD&0x40)==0x00)
    PORTD += 0x40;
  else
    PORTD -= 0x40;
}

Wie schaffe ich es nun den Pin möglichst schnell zu tickern ?

MFG
Timo O.
Gast #181535
Lesenswert?

Soll der Controller nichts anderes machen?
Noch schneller geht es unter Umständen mit inline-Assembler. Ich an
deiner Stelle würde mir einen externen Schaltkreis dafür nehmen. Bei
dir darf in einem späteren Programm weder ein Interrupt noch Code in
die Hauptschleife kommen, ohne das es dir das Signal versaut.
Welchen Frequenzbereich musst du abedecken?
Gast #181536
Lesenswert?

Ich würde versuchen das ganze in assembler zu schreiben.
aber möchtest du nicht lieber einen timer mit pwm verwenden?

hab schon lange keinen AVR mehr programmiert, kann es sein das er den
wert 0x40 jedes mal aus dem speicher liest? oder ist der schon im
befehl integriert? wenn nicht würde ich ein register nehmen mit dem
wert, dadurch sparst du dir nochmals einen cyclus in dem du nur eine
fixe variable ladest.

for(;;){
    PORTD += 0x40;
    nop();
    nop();
    PORTD -= 0x40;
}
so hast du zwar eine längere auszeit als einzeit, aber das könntest du

mit ein paar nop angleichen.


allerdings wenn dir jetzt ein interrupt in die quere kommt kannst du
deine frequenz vergessen. bzw. kannst du derzeit nichts nebenbei
machen.

mfg Azrael
Gast #181538
Lesenswert?

Erstmal danke für eure Antworten.
Die Idee von Azrael ist natürlich top. Das ich da nicht selber drauf
gekommen bin. So eine Schande. :-(
Aber das Posting von Jörg beschreibt genau das wonach ich gesucht
habe.
Mit diesem befehl komme ich wieder auf ca. 1MHz.

Besten Dank
Timo O.
Gast #181541
Lesenswert?

> müsste einen Takt (compiliert mit -O2) von 3,33MHZ erzeugen wenn der
> AVR mit 10MHZ getaktet wird.

Ich komme dabei auf 6 Takte pro Iteration (CBI,CBI,BRxx brauchen je 2
Takte). Ergibt bei 10MHz Takt also 1,67MHz. Besser wird's mit

    h = PIND | 1<<6;
    l = PIND & ~(1<<6);
    for (;;) {
      PORTD = h;
      PORTD = l;
    }

da komme ich auf 4 Takte = 2,5MHz.
Gast #181542
Lesenswert?

Hmm, du hast Teilweise recht. Ich hatte cbi und sbi mit 1 Takt
Ausführungszeit in Erinnerung, sind aber wie du sagst zwei. Dann müsste
meine Routine 2MHZ erzeugen. Der Compiler scheint die Schleife teilweise
zu entrollen, so dass sbi-cbi zwei mal ausgeführt werden bevor der
Sprung erfolgt. Wenn der Compiler deinen Quelltext genau so entrollt,
müsste deiner dann aber 3,33MHZ ausgeben.
Gast #181544
Lesenswert?

Also, im Datenblatt zu meinem uC steht bei den Timern, dass man 1/4 vom
Clock maximal erhalten kann; das wären bei meinen 20MHz immerhin 5MHz.
Aber eben mit dem Timer und natürlich dem dazu gehörigen
Timer-Ausgangs-Pin.

Weiterer Vorteil der Timer ist, dass sie vollkommen autonom laufen; sie
benötigen nur beim ersten Verwenden die Initialisierung. Danach ist die
CPU frei für andere Aufgaben.

Stephan.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren