Forum: Mikrocontroller und Digitale Elektronik Verständnisfrage PIC32


von alex (Gast)


Lesenswert?

Hallo,

Ich habe einen Quelltext aus einem Beispielprogramm doch verstehe dieses 
nicht wirklich.
1
 y = BIT_5 & ~LATB;  /* push LED state */
2
  LATBSET = BIT_5;  /* set LED pin high */
3
  TRISBSET = BIT_5;  /* set LED pin as input */
4
  LATBCLR = y;
5
        TRISBCLR = BIT_5;  /* set LED pin as output */

Kann mir jemand erklären, was hier passiert?

Für mich sieht es so aus als ob nur des Status des PINS ausgelesen wird. 
Liege ich da richtig? Aber warum so kompliziert?

Alex

von (prx) A. K. (prx)


Lesenswert?

alex schrieb:
> Für mich sieht es so aus als ob nur des Status des PINS ausgelesen wird.

Das ist so ungefähr das einzige, was da nicht passiert. ;-)

> Aber warum so kompliziert?

Bist du sicher, dass der Code Sinn ergeben soll?

von alex (Gast)


Lesenswert?

Also da soll eine Status LED an PB5 sein.

Oder soll das einfach nur die LED toggeln?

Ich verstehe die erste Zeile schon nicht.

Es könnte sein, dass LATB ein Macro in der plib.h ist welches die 
Startadresse des PortB angibt und BIT_5 ist ein Offset.

Würde das Sinn machen?

Allerdings verstehe ich dann immer noch nicht warum ein Offset mit AND 
NOT Adresse verknüpft wird?

von Karl H. (kbuchegg)


Lesenswert?

alex schrieb:

> Es könnte sein, dass LATB ein Macro in der plib.h ist welches die
> Startadresse des PortB angibt und BIT_5 ist ein Offset.

Offset ist das falsche Wort.
BIT_5 ist hier eher eine Bitmaske.

> Würde das Sinn machen?

Das Statement invertiert den Inhalt von LATB und löscht danach alle Bits 
(setzt sie auf 0), die in der Bitmaske BIT_5 nicht auf 1 stehen.

Wenn ich mal davon ausgehe, dass in BIT_5 nur ein einziges gesetztes Bit 
existiert, und zwar das an der Bitposition 5, dann in a Nutshell:
y hat danach den invertierten Zustand des Bits 5 von LATB.

Was immer dieser Wert dann aussagt, kann ich nicht sagen. Da ich kein 
PIC 'spreche', weiss ich nicht was sich hinter LATB verbirgt.

> Allerdings verstehe ich dann immer noch nicht warum ein Offset mit AND
> NOT Adresse verknüpft wird?

LATB ist ziemlich sicher nicht eine Adresse, sondern der Inhalt eines 
Registers.

Aber warum siehst du nicht einfach nach? Die Schreibweise mit alles 
komplett in Grossbuchstaben ist ein Hinweis darauf, dass es sich dabei 
um C Makros handelt. Die müssen irgendwo existieren. Und dort kann man 
nachsehen.

von (prx) A. K. (prx)


Lesenswert?

Bei den PIC32 wird das nicht anders als bei den übrigen PICs sein:
LATx = Ausgangsregister, vgl. PORTx bei AVRs.
TRIx = Richtungsregister, vgl. DDRx bei AVRs, aber 1=in/0=out.

Die seltsam anmutenden Bezeichnungen erwuchsen aus der langen Geschichte 
der PICs, die immerhin in die 70er zurückreicht. TRI steht hier für 
"tristate" und LAT für "latch". Die ersten PICs hatten implizit 
bidirektionale Ports ähnlich 8051 und folglich keines dieser Register.

Analog zu ähnlichen Ansätzen in diversen anderen RISC µCs werden die 
YYYxSET/CLR alle YYYx Bits setzen/löschen, wo die geschriebenen Daten 1 
sind, und den Rest in Ruhe lassen.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

alex schrieb:
> Ich verstehe die erste Zeile schon nicht.

  y = BIT_5 & ~LATB;  /* push LED state */

Aktuellen Zustand von Bit 5 des Port-Ausgangsregisters in 
komplementiertem Zustand in y sichern.

  LATBCLR = y;

Bit 5 des Port-Ausgangsregisters löschen, falls der Zustand anfangs 0 
war. Andernfalls nichts tun. Am Pin selbst ändert das (noch) nichts, da 
der Pin zu diesem Zeitpunkt ein Input ist (TRIB.5 = 1).

: Bearbeitet durch User
von WehOhWeh (Gast)


Lesenswert?

A. K. schrieb:
> alex schrieb:
>> Ich verstehe die erste Zeile schon nicht.
>
>   y = BIT_5 & ~LATB;  /* push LED state */
>
> Aktuellen Zustand von Bit 5 des Port-Ausgangsregisters in
> komplementiertem Zustand in y sichern.
>
>   LATBCLR = y;
>
> Bit 5 des Port-Ausgangsregisters löschen, falls der Zustand anfangs 0
> war. Andernfalls nichts tun. Am Pin selbst ändert das (noch) nichts, da
> der Pin zu diesem Zeitpunkt ein Input ist (TRIB.5 = 1).

Was ich dabei nicht kapiere:
Warum macht man nicht einfach folgendes:
1
#define port_LEDx LATBbits.LATB5   //LEDx : <kurzbeschreibung>
2
3
port_LEDx = xy;

Nachdem sich Microchip soviel Mühe gemacht hat, die ganzen Bitfelder zu 
deklarieren, warum die nicht hernehmen?
Das #define kann man in einen eigenen Header packen. Damit lässt sich 
der Code leichter portieren, weil im eigentlichen Code nicht 
projektspezifisches mehr steht, sondern nur allgemeines.
Die Zuweisungen port <> Funktion kann man an einer zentralen Stelle 
übersichtlich machen.

von pic (Gast)


Lesenswert?

>Was ich dabei nicht kapiere:

Da ist erstmal nix zu kapieren.

Wer hat dieses Stück Software geschrieben?
Zu welche Zweck?
Ist der Programmierer gut?
Weiß er was er tut?
Warum schaltet er Ports kurzzeitig von Output auf Input und dann wieder 
zurück?


Warum sollte sich hier Leute mit Software auseinander setzen, von der 
nix bekannt ist? Nicht einmal, ob sie läuft.

von Frank K. (fchk)


Lesenswert?

alex schrieb:

> Kann mir jemand erklären, was hier passiert?

Bei AVR und PIC12/16/18/24 hast Du Bit-Befehle, die atomar Bits in 
Prozessor- und Peripherieregistern ändern können. Atomar heißt 
wortwörtlich "unteilbar", d.h. es ist unter allen Umständen gesichert, 
dass dieser Befehl an einem Stück in einem Zyklus ausgeführt wird. Das 
geht genau deswegen, weil Peripherieregister oder SFRs quasi das gleiche 
wie Prozessorregister sind.

Bei ARM und MIPS (PIC32 ist MIPS) geht das nicht. Der zugekaufte 
Prozessorkern hat definierte Schnittstellen, und alles, was darüber 
geht, sind Zugriffe auf externen Speicher. Das Setzen eines Bits 
erfordert also mindestens drei Befehle:
1. Wert aus Speicher in Register laden
2. Bit in Register setzen
3. Wert aus Register in Speicher schreiben
Es ist offensichtlich, dass das jetzt nicht mehr atomar ist, weil die
ganze Prozedur durch Interrupts, DMA-Zugriffe etc unterbrochen werden
kann.

Um das doch realisieren zu können, gibts das sogenannte Bit-Banding. 
Heißt also: Schreibzugriffe auf bestimmte Adressräume bedeuten nicht 
mehr *a=x in C-Notation, sondern *a|=x oder *a&=(~x) oder *a^=x.

Deswegen gibts nicht nur das Ausgabelatch LAT? und das 
Datenrichtungsregister TRIS?, sondern auch LAT?CLR und LAT?SET bzw 
TRIS?CLR und TRIS?SET.

Das Datenrichtungsregister ist bei PIC gegenüber AVR genau invertiert. 
0=o für output und 1=i für input.

fchk

von (prx) A. K. (prx)


Lesenswert?

Frank K. schrieb:
> Um das doch realisieren zu können, gibts das sogenannte Bit-Banding.

Bitbanding (ARM Bitbanding) ist eine spezielle Eigenschaft 
bestimmter ARM Cores der Cortex M Reihe. Aber auch da nicht aller Cores, 
so hat der Cortex M0 es nicht und beim M0+ ist optional.

Die SET/CLR-Register sind kein Bitbanding, sondern eine besondere Form 
von I/O-Registern, wie sie bei vielen µCs mit RISC Architektur 
vorzufinden sind.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

WehOhWeh schrieb:
> Nachdem sich Microchip soviel Mühe gemacht hat, die ganzen Bitfelder zu
> deklarieren, warum die nicht hernehmen?

Wenn du um die Nebenwirkungen des entstehenden Codes weisst, dann kannst 
du das tun. Nur ist die Wahrscheinlichkeit recht gross, dass bei einem 
32 Bits breiten Port irgendwelche Pins dabei sind, die in einem 
Interrupt-Handler direkt manipuliert werden. Und dann musst du im 
Hauptprogramm entweder mittels der SET/CLR-Register atomaren Code 
verwenden, oder jedesmal die Sequenz der Maschinenbefehle gegen 
Interrupts sperren.

Besonders interessant ist dieses Thema, wenn man nicht einfach bloss 
einen Pin aktiviert, sondern beispielsweise die 4 Datenbits eines 
Text-LCD auf den Port schmeisst. Wenn man das auf klassische Weise mit
  PORT = (PORT & ~MASK) | ((data << SHIFT) & MASK);
macht, dann hat man das beschriebene Problem mit ISRs bei jedem 
Prozessor, egal ob 8051, 8-Bit oder 32-Bit PIC. Bitfeldoperationen 
erzeugen auch solchen Code, falls der Prozessor dafür keine speziellen 
Befehle kennt.

Effiziente Lösungen dieses Problems unterscheiden sich stark von µC zu 
µC. Bei nicht zu alten AVRs kann dazu man in etwas hinterfotziger Weise 
auf PINx schreiben, bei den STM32 gibts ein kombiniertes 
SET/CLR-Register (genau deshalb sind deren Ports nur 16 Bits breit), 
manche haben ein separates Maskenregister für die Ports (NXP ARMs) und 
bei manchen fährt man besser, wenn man die Einsen und die Nullen 
getrennt über SET/CLR Register steuert.

: Bearbeitet durch User
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.