Forum: Compiler & IDEs Pins schnell schalten


von Timo O. (Gast)


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.

von Alex (Gast)


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?

von Azrael (Gast)


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

von Jörg Wunsch (Gast)


Lesenswert?

PORTD ^= 0x40;

von Timo O. (Gast)


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.

von Malte (Gast)


Lesenswert?

int main(void) {
DDRD |= (1<<4);
for(;;) {
PORTD |= (1<<4);
PORTD &= ~(1<<4);
}
}
müsste einen Takt (compiliert mit -O2) von 3,33MHZ erzeugen wenn der
AVR mit 10MHZ getaktet wird. Ist dann allerdings nicht exakt wegen dem
Rücksprung.
Vielliecht ist für dich noch
http://www.myplace.nu/avr/minidds/index.htm
interessant.

von A.K. (Gast)


Lesenswert?

Bei manchen AVRs (z.B. Tiny2313) kann man Pins mit
    PIN = 0x40;
toggeln.

von A.K. (Gast)


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.

von Malte (Gast)


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.

von A.K. (Gast)


Lesenswert?

... und der erzeugte Takt stolpert dank des loop unrolling. Keine gute
Idee, also lieber -Os statt -O2.

von Stephan (Gast)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.