FromAnotherPlanet: 8254 - Counter 1

Hallo Leute,

hat jemand von euch mal unter C was mit 8254 Countern
programmiert ?

Ich habe da so ein Verständnisproblem.

Der 8254 hat ja drei Counter (0,1,2,3), wobei das dritte
das control register ist... BLA BLA BLA.

Wer sich auskennt, sollte wissen was ich meine :-).

So, das Problem ist folgendes. Ich habe ein fertiges Kontrollwort
das so lautet :

0111 0110 = 0x76

Dieses Kontrollwort will ich per C-Funktion "outp(portadress,bytevalue)" in das control register schreiben.

Ich habe eine Lösung zu diesem Problem vor mir, die folgendes beschreibt :

outp(0xAC + 3, 0x76); // init Control Word
outp(0xAC + 1, 100); // Reloadwert "100" wird LSB geschrieben

outp(0xAC + 1, 0); // Reloadwert "100" wird LSB geschrieben
---------
outp(0xAC + 3, 0x40); // latch

z = _inp(0xAC + 1)); // read LSB
z += _inp(0xAC + 1) << 8; // read MSB

Folgendes Schema wurde verwendet :
                                ___________
0   A0 ------------------------|           |
0   A1 ------------------------| 8254      |
                       ____    |           |
1   A2 ---------------|    |   | CS        |
1   A3 ---------------|    |-->|           |
0   A4 --------------o|    |   |___________|
1   A5 ---------------| &  |
0   A6 --------------o|    |
1   A7 ---------------|    |
                      |____|

Also die Basisadresse 0xAC ist links abgebildet :

1010 1100 = 0xAC. Ich glaube das so richtig oder ?

Woher kommt die Basisadresse 0xAC, die normale Basisadresse fangen doch bei 300H an oder ? ?

Kann mir jemand helfen, ich komme nicht richtig weiter ?

Gruss

  1. Hallo,

    hat jemand von euch mal unter C was mit 8254 Countern programmiert ?

    nö, nicht direkt, eher in Assembler - aber ich kann mich aus der DOS-Programmiererzeit noch dunkel an den Keks erinnern.

    Ich habe da so ein Verständnisproblem.
    Der 8254 hat ja drei Counter (0,1,2,3), wobei das dritte
    das control register ist... BLA BLA BLA.

    Irgendwas ist an diesem Satz verunglückt.
    Der PIT hat drei Counter (bis hierher richtig) und vier Register (0,1,2,3).

    Wer sich auskennt, sollte wissen was ich meine :-).

    Ja. Ich warte noch auf die Stelle, wo's spannend wird. ;-)

    So, das Problem ist folgendes. Ich habe ein fertiges Kontrollwort das so lautet :
    0111 0110 = 0x76

    Okay. Also Counter 1, LSB vor MSB, generiere Rechtecksignal am Ausgang (Mode 3), und arbeite als 16bit-Binärzähler (nicht BCD).

    outp(0xAC + 3, 0x76); // init Control Word
    outp(0xAC + 1, 100); // Reloadwert "100" wird LSB geschrieben
    outp(0xAC + 1, 0); // Reloadwert "100" wird LSB geschrieben

    Beim zweiten Mal ist es das MSB, nicht das LSB. Du lädst den Zähler also mit dem Startwert 100 = 0x0064.

    outp(0xAC + 3, 0x40); // latch

    Vorsicht: Hier programmierst du den Zähler gleichzeitig auf Mode 0 um! Willst du nicht 0x46 nehmen und den Zähler im Hintergrund unabhängig vom Latch weiterlaufen lassen?[1]

    z = _inp(0xAC + 1)); // read LSB
    z += _inp(0xAC + 1) << 8; // read MSB

    Okay.

    1010 1100 = 0xAC. Ich glaube das so richtig oder ?

    Ja, das ist richtig.

    Woher kommt die Basisadresse 0xAC, die normale Basisadresse fangen doch bei 300H an oder ? ?

    Das kommt drauf an. ;-)
    Mir ist die Portadresse 0x00AC auch etwas "strange"; im alten PC/AT-Design der 90er Jahre wäre dieser Bereich noch dem zweiten Interruptcontroller zugeteilt (0x00A0..00BF), obwohl der eigentlich nur zwei Register hat und daher keine 32 Bytes Adressraum braucht. Die typischen Portadressen der später hinzudefinierten zusätzlichen Komponenten auf ATX-Boards kenne ich nicht, dafür habe ich mich zu lange nicht mehr mit Hardwareprogrammierung auf dieser Ebene befasst. Also kann 0x00AC durchaus richtig sein.

    Was du vielleicht meinst, ist der Bereich 0x0300..031F, der offiziell für Prototypen und Experimentierkarten reserviert ist. Allerdings arbeiten auch einige uralte Netzwerk- und Soundkarten für den ISA-Bus in diesem Bereich.

    Tatsächlich haben x86-CPUs einen Port-Adressraum von 64k, können also Ports von 0x0000..FFFF ansprechen. Im alten PC/AT-Design[2] war davon nur der Bereich bis 0x03FF vollständig ausdecodiert, höhere Portadressen wurden da gar nicht verwendet. Ein großer Teil dieses 1k großen Bereichs war für die Standardhardware reserviert.
    Heutige PCs können über den PCI-Bus den gesamten 64k großen Port-Adressraum nutzen.

    So long,
     Martin

    [1] http://heim.ifi.uio.no/~stanisls/helppc/8253.html
    [2] http://heim.ifi.uio.no/~stanisls/helppc/ports.html
    [3] Du plenkst!

    --
    Solange der Nagellack nicht trocken ist,
    ist eine Frau praktisch wehrlos.
      (Burt Reynolds, US-Schauspieler)
    1. Hallo,

      vielen dank erstmal für deine Antwort. Ich lese aus deinen Worten heraus, das du dich auskennst. Das beruhigt mich :-)

      nö, nicht direkt, eher in Assembler - aber ich kann mich aus der DOS-Programmiererzeit noch dunkel an den Keks erinnern.

      MOV AL, 11100010B ;Read Back, Modus ermitteln, Zähler 0
      OUT 43H,AL ;Steuerwort schreiben
      IN AL, 40H ;Modus von Zähler 0 lesen

      Nur ein Beispiel in Assembler ? Richtig oder ?

      Irgendwas ist an diesem Satz verunglückt.
      Der PIT hat drei Counter (bis hierher richtig) und vier Register (0,1,2,3).

      Drei Counter 0..2. 3 ist das Read-Back-Modus.
      Richtig ? Welche vier Register meinst du ? :-)

      Ja. Ich warte noch auf die Stelle, wo's spannend wird. ;-)

      Gleich wird es spannend. Mach dich auf was gefasst :-)

      Okay. Also Counter 1, LSB vor MSB, generiere Rechtecksignal am Ausgang (Mode 3), und arbeite als 16bit-Binärzähler (nicht BCD).

      Cool, du weisst wovon du sprichst. Ein Square Wave wird erstellt. So wie beim PWM.

      Beim zweiten Mal ist es das MSB, nicht das LSB. Du lädst den Zähler also mit dem Startwert 100 = 0x0064.

      Richtig, wieso muss man den MSB also das zweite 8-Bit-Wort
      nochmal schreiben, wenn es sowieso 0 ist ?

      outp(0xAC + 3, 0x40); // latch

      Vorsicht: Hier programmierst du den Zähler gleichzeitig auf Mode 0 um! Willst du nicht 0x46 nehmen und den Zähler im Hintergrund unabhängig vom Latch weiterlaufen lassen?[1]

      Wie meinst du das ? Counter-Latch verursacht, das der 8254 nicht
      unterbrochen werden muss und gelesen werden kann oder ?

      Woher kommt die Basisadresse 0xAC, die normale Basisadresse fangen doch bei 300H an oder ? ?

      Das 0xAC kommt von dieser Zeichnung die ich vorher gezeichnet habe.
      In dieser Zeichnung sind die Eingänge A0 und A1 auf "write into
      counter 0" gesetzt. Das verstehe ich auch nicht ? Der &-Gatter
      hat erstmal alles auf eins (schätze ich) und durch die Negation
      ist das dann zwei Nullen enthalten.

      Das mit 300H habe ich von hier :

      http://www.decisioncards.com/io/tutorials/8254_tut2.html

      Also ich will folgendes erzielen :

      Init einen 8254 Counter 1, Mode 3 als Binärzähler, so das
      immer 16 Bit gelesen und geschrieben werden. Reloadwert -> 100.
      Danach den Leserstand lesen. Basisadresse nicht bekannt, sondern
      nur die gegebene Zeichnung....

      Im großen und ganzen habe ich alles verstanden, aber
      warum ist z.B. "write counter 0 gesetzt" ??

      Gruss

      1. Hallo Außerirdischer, ;-)

        Ich lese aus deinen Worten heraus, das du dich auskennst.

        ja, ein bisschen. Digitaltechnik, Microprozessortechnik und Assembler-Programmierung waren mir mal so vertraut, dass ich die meisten Details auswendig kannte, hab das mal studiert. Inzwischen bin ich aus der Materie etwas raus, aber gelegentlich holt mich das Thema noch mit irgendeinem Wochenend-Hobbyprojekt ein.

        MOV AL, 11100010B ;Read Back, Modus ermitteln, Zähler 0
        OUT 43H,AL ;Steuerwort schreiben
        IN AL, 40H ;Modus von Zähler 0 lesen
        Nur ein Beispiel in Assembler ? Richtig oder ?

        Sieht plausibel aus.

        Welche vier Register meinst du ? :-)

        Na die vier Register des PIT 8253/54. Register 0..2 für die Zählerstände von Timer 0..2, und Register 3 ist das Command Register.

        Cool, du weisst wovon du sprichst. Ein Square Wave wird erstellt. So wie beim PWM.

        Ja, nur dass dein PWM ein konstantes Tastverhältnis von 50% hat. Eben ein symmetrisches Rechtecksignal. Irgendwie langweilig. ;-)

        Beim zweiten Mal ist es das MSB, nicht das LSB. Du lädst den Zähler also mit dem Startwert 100 = 0x0064.
        Richtig, wieso muss man den MSB also das zweite 8-Bit-Wort
        nochmal schreiben, wenn es sowieso 0 ist ?

        Ich bin mir bei den Interna des Timerbausteins nicht mehr ganz sicher, aber ich meine, dass der Zähler erst geladen wird, wenn _beide_ Bytes geschrieben wurden. Auch wenn das MSB 0 ist.
        Willst du dir den Portzugriff für das MSB sparen und nur das LSB lesen oder schreiben, dann verwende XX10XXXX als Command Word.

        outp(0xAC + 3, 0x40); // latch
        Vorsicht: Hier programmierst du den Zähler gleichzeitig auf Mode 0 um! Willst du nicht 0x46 nehmen und den Zähler im Hintergrund unabhängig vom Latch weiterlaufen lassen?[1]
        Wie meinst du das ? Counter-Latch verursacht, das der 8254 nicht
        unterbrochen werden muss und gelesen werden kann oder ?

        Das ist richtig, aber in den Bits [321] wird ja gleichzeitig der Counter Mode neu gesetzt - in diesem Fall auf Mode 0, vorher war's Mode 3.

        Das 0xAC kommt von dieser Zeichnung die ich vorher gezeichnet habe.

        Also ist das nur ein willkürliches Beispiel, das das Prinzip verdeutlichen soll? Ich weiß es echt nicht, aber das Adressmuster in der Skizze könnte ja ein beliebig gewähltes sein. Eben nur ein Beispiel.

        In dieser Zeichnung sind die Eingänge A0 und A1 auf "write into counter 0" gesetzt. Das verstehe ich auch nicht ? Der &-Gatter hat erstmal alles auf eins (schätze ich) und durch die Negation ist das dann zwei Nullen enthalten.

        Jaja, die Interpretation ist vollkommen richtig - nur ob die Grundannahme stimmt, wissen wir nicht. Außerdem wissen wir auch nicht, mit welcher CLK-Frequenz der Timerbaustein zählt. Beim ersten PIT (Port 0x40..43) ist es übrigens etwa 1.193MHz. Dividiere das durch 2^16, und du bekommst was? Ja, richtig: etwa 18.2, das ist die Anzahl der Timer-Interrupts pro Sekunde. Klingelt da was?  ;-)

        Das mit 300H habe ich von hier :
        http://www.decisioncards.com/io/tutorials/8254_tut2.html

        Ah ja, so wie ich das lese, gehen die tatsächlich von einer selbstgebauten universellen ISA-Steckkarte aus und wählen den Bereich 0x0300+, um (wahrscheinlich) keiner anderen Komponente in die Quere zu kommen.

        Also ich will folgendes erzielen :
        Init einen 8254 Counter 1, Mode 3 als Binärzähler, so das immer 16 Bit gelesen und geschrieben werden. Reloadwert -> 100. Danach den Leserstand lesen. Basisadresse nicht bekannt, sondern nur die gegebene Zeichnung....

        Dann vermute ich mal ganz stark, dass du den Standard-Timerbaustein im PC verwenden willst, und der hat die Basisadresse 0x40. Timer 2 dieses Bausteins steuert im üblichen PC-Design den Mainboard-Lautsprecher an, kann aber ansonsten nach Belieben verwendet werden.

        Im großen und ganzen habe ich alles verstanden, aber warum ist z.B. "write counter 0 gesetzt" ??

        Wie gesagt: Weil's vermutlich nur ein Beispiel ist.
        Außerdem hast du die Bit-Werte doch vermutlich zur Verdeutlichung selbst dazugeschrieben, oder? Die Skizze sagt ja nur, dass A0 und A1 direkt auf den PIT gehen, die Adressbits A2,A3,A5,A7 direkt auf ein AND-Gatter, und die Adressbits A4 und A6 invertiert.

        Ciao,
         Martin

        PS: Du plenkst immer noch.

        --
        Heutzutage gilt ein Mann schon dann als Gentleman, wenn er wenigstens die Zigarette aus dem Mund nimmt, bevor er eine Frau küsst.
          (Barbra Streisand, US-Schauspielerin)
        1. Hallo Irdischer :-),

          also, danke für alle Antworten. Die konstruktive Diskussion hat mir
          weitergeholfen. Wahrscheinlich nur ein Beispiel...

          Plenken ? Ist doch egal, ich plenke halt gerne. Ausserdem
          plenkt jeder mal. Solange es nicht im Gesetzbuch steht darf
          ich noch plenken :-)

          Gruss
          SmartyShark alias FromAnotherPlanet

        2. Hi,

          ich wollte noch was fragen.

          Weisst du wie man rechnerisch bei einem A/D-Wandler
          die Auflösung in Bit bestimmt ?

          Gruss

          1. Hallo,

            Weisst du wie man rechnerisch bei einem A/D-Wandler die Auflösung in Bit bestimmt ?

            wie jetzt, rechnerisch?
            Nee, die ist durch das Hardware-Design vorgegeben, woher willst du die berechnen?
            Wie berechnest du, wieviele Zylinder ein Ottomotor hat?
            Oder wieviele Sitzplätze ein Konzertsaal hat?

            Und wenn du die Auflösung in Bits hast, dazu den Wertebereich der analogen Größe, dann kannst du auch die Auflösung des eigentlichen Messwerts berechnen.
            Beispiel:

            Spannung 0..5V geht auf einen ADC mit 12bit Auflösung.
            12bit entspricht einem Wertebereich von 0..2^12 -1, also 0..4095.
            Dieser ADC hätte also eine Auflösung von 5V/4096 ~ 1.25mV.
            Achtung: Die Auflösung ist _nicht_ die Genauigkeit!

            So long,
             Martin

            --
            Die meisten Menschen werden früher oder später durch Computer ersetzt.
            Für manche würde aber auch schon ein einfacher Taschenrechner genügen.