Forum: Mikrocontroller und Digitale Elektronik MSP430G2: Elegantester Weg Bits zu empfangen?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Peter M (Gast)


Lesenswert?

Hi,

Ich erhalte via simplem AM Denodulator/Slicer bits an P2.3. Die Bitrate 
ist etwa 160kbps.
Eingeleitet wird ein Transfer über eine „Päambel“ bei der der Eingang 
für eine bestimmte Zeit auf 0 geht und dann 1 und 0 (Das Protokoll 
könnte ich ggf. anpassen ... PWM, Manchester code etc geht aber eher 
nicht).

Was ist der eleganteste Weg so einen Receiver zu implementieren?

1.) Einfach von P2IN lesen und versuchen das timing mit NOPs 
hinzubekommen?

2.) I/O interrupt auf edges? Aber was wenn ich keine garantierte 
Transition per bit habe?

3.) Timer A? Welcher Mode?

Wenn ich zuerst den I/O interrupt nehme und auf eine fallende Flanke 
warte dann habe ich den „asynchronen“ Start gefunden. Hier könnte ich 
SMCLK auf 16 MHz setzen und den Counter bis 100 zählen lassen („up 
Mode“).
Das gäbe mir 160kbps. Allerdings sample ich dann am Ende des Bits was 
nicht optimal ist.

Wie bekomme ich das reliable zusammen sodass die Bits möglichst in der 
Mitte ausgelesen werden?

LG,
Peter

von Der Zahn der Zeit (Gast)


Lesenswert?

Leider zeigst du uns kein komplettes Datentelegramm. Von dem, was du 
beschreibst, könnte ein UART die Lösung sein, das es in den G2xx3 bis 
G2xx5 zwar gibt, aber nicht auf P2.

Ich habe zwar eine Idee, wie ich das (in Assembler) machen würde, aber 
bevor ich mich auslasse, um dann festzustellen, dass das in deiner 
Situation doch nicht geht, hätte ich gerne die vollständige Beschreibung 
des Telegramms.

von Clemens L. (c_l)


Lesenswert?

Mit Timer_A im Compare-Modus findest du den Zustand des Eingangs zum 
Ablaufzeitpunkt im SCCI-Bit.

Peter M schrieb:
> Allerdings sample ich dann am Ende des Bits was nicht optimal ist.

Direkt nach der ersten Flanke setzt du CCRx ein mal auf den halben (or 
3/2) Wert, dann landest du in der Mitte.

: Bearbeitet durch User
von Peter M (Gast)


Lesenswert?

Hi Der Zahn der Zeit & Clemens,

Danke! Erstmal sorry, ich glaub ich war da etwas unklar da jemand den 
Titel nach MSP430P2 geaendert hat. Mit P2 meinte ich Port 2 (Port 2.3 
konkret). Die Hardware ist vorhanden, ich moechte hardwareseitig nichts 
aendern und deswegen wollte ich das erwaehnen fuer den Fall dass es 
ueber UARTs etc. an anderen Pins moeglich waere.

Mein exaktes Device ist MSP430FR5969.

> Leider zeigst du uns kein komplettes Datentelegramm.
1
    (Delimiter,12.5us) 1  0 1 1 1  0 0  1 1 ...                  
2
___                   __    ______      ___
3
   \_________________/  \__/      \____/   \__


Das Signal ist "active high" und die Uebertragung beginnt mit einem 
Delimitter das ca. 12.5us ist. In diesem Delimiter geht das signal auf 
low. Danach folgen 2-3 Bits Preambel (z.B. 1 0 aber das kann geaendert 
werden). Dann folgen die Datenbits, im oberen Beispiel 1 1 1 0 0 1 1. 
Jedes Bit ist etwa 1/160kHz=6.25us lang.

> Ich habe zwar eine Idee, wie ich das (in Assembler) machen würde, aber
> bevor ich mich auslasse, um dann festzustellen, dass das in deiner
> Situation doch nicht geht, hätte ich gerne die vollständige Beschreibung
> des Telegramms.

Wunderbar.

> Mit Timer_A im Compare-Modus findest du den Zustand des Eingangs zum
> Ablaufzeitpunkt im SCCI-Bit.

Der Zustand des Einganssignals ist ob mein Port 2.3 signal 0 oder 1 ist? 
Gut, dann brauche ich ja gar nicht explizit von P2IN zu lesen?

> Direkt nach der ersten Flanke setzt du CCRx ein mal auf den halben (or
> 3/2) Wert, dann landest du in der Mitte.

Ja, gute Idee.
Ist folgende Strategie die richtige?
1
1.) Interrupt auf fallende Flanke von P2.3
2
2.) In der ISR mit NOPs zaehlen ob der Delimiter etwa 12.5us lang ist. Falls nein --> return
3
3.) Falls ja, warten auf die naechste fallende Flanke (die nach dem ersten "1").
4
4.) Timer A im compare Modus starten:
5
    a) P2.3 auf "primary module selection" aendern (via P2SEL0/P2SEL1)
6
    b) TA0CCR auf 16MHz/160kHz = 100 setzen.
7
    c) Counter (TA0CR) auf -50 setzen und timer starten
8
    d) Der erste compare interrupt sollte nach 150 timer zyklen kommen, also inter Mitte vom zweiten "1" bit.
9
    e) Folgende interrupts kommen in der Mitte der folgenden Bits
10
    f) Bit via TA0CCTL (bit SCCI) auslesen und speichern
11
    g) Abbruch wenn genuegens Bits gelesen sind.

von Der Zahn der Zeit (Gast)


Lesenswert?

Peter M schrieb:
> Mit P2 meinte ich Port 2 (Port 2.3 konkret)
 Das hatte ich auch genau so verstanden...
> Die Hardware ist vorhanden, ich moechte hardwareseitig nichts
> aendern
... und davon bin ich ausgegangen.

Was in deinem Datentelegramm vielleicht noch fehlt, ist die Anzahl der 
Datenbits und/oder wo dran man das Ende des Telegramms erkennt und ggf. 
wie lange das Ende vom nächsten Anfang entfernt ist. Aber wahrscheinlich 
geht es auch so:

Idle: Einen Interrupt auf die neg. Flanke P2.3 einrichten.
Wenn Delimiter low: Mit Pollen oder einem weiteren Interrupt auf die 
pos. Flanke warten.
Wenn Delimiter high: Timer (CCR0) auf eine halbe Bitzeit (~3.12 µs) 
setzen.
Z. B. Bitzähler setzen
Bei jedem Timerinterrupt:
- Bit einlesen
- Bit in ein Schieberegister
- Timer (CCR0) auf eine ganze Bitzeit (~6.25 µs) setzen

Letzteres ist prinzipiell nur beim ersten mal nötig. Das zu sparen ist 
möglich, dürfte aber unnötig umständlich sein.

Interrupt-Routine Bit einlesen und ins Schieberegister:
1
TA_Int:
2
 bit.b #BIT3,&P2IN    ;Setzt auch Carry = .not. Zero
3
 rrc   Rx             ;Rx = Eins der Register, max. 16 Bit
4
 mov   #99,&TACCR0    ;(oder muss es 100 sein?)
5
 ;Jetzt noch irgendwas zur Ende-Erkennung, z. B.
6
 dec   Ry             ;Bits zählen
7
 jnz   RetInt
8
 clr   #GIE,&SR       ;(Global) Interrupt disable
9
RetInt
10
 reti

In der Hauptroutine wird nachgesehen, ob Ry 0 ist, wenn ja, ausgewertet. 
Dann wieder Idle, also alles von vorne: Ry wieder auf Anzahl der Bits 
gestellt, Interrupt auf Flanke, GIE wieder gesetzt, warten auf Delimiter 
etc..

Ich neige dazu, auch bei wenigen Zeilen mal Blödsinn zu schreiben. Es 
ist doch angenehm, wenn man weniger Probleme als ein Chirurg bekommt, 
wenn man mal einen Fehler macht...

von Max G. (l0wside) Benutzerseite


Lesenswert?

Peter M schrieb:
> 1.) Interrupt auf fallende Flanke von P2.3
> 2.) In der ISR mit NOPs zaehlen ob der Delimiter etwa 12.5us lang ist.
> Falls nein --> return

NOPs in der ISR sind pfuibäh. DAnn kannst du auch gleich in der Main 
Loop pollen.
Folgenden Ansatz würde ich verwenden:
* Interrupt auf fallende Flanke von P2.3
* Timer starten und nach 11 und 14 µs jeweils die ISR triggern lassen 
(das geht bequem über TACCR0 und TACCR1 - Achtung, zwei verschiedene 
ISR). Dann kannst du schauen, ob dazwischen eine steigende Flanke war.
* Nun den Timer so einstellen, dass die ISR ganz gemütlich immer in der 
Mitte des Bits (oder auch in der zweiten Bithälfte) zurückliest. Der 
Rest ist ein bisschen Bitschieberei.

Timer im Capture Mode geht natürlich auch, dann muss man aber
1. in der ISR jeweils die Triggerbedingung zwischen steigend und fallend 
umschalten
2. bei mehreren aufeinander folgenden gleichen Bits (wo der 
Flankenwechsel ja fehlt) dann in der ISR die Anzahl der Bits rückrechnen
3. eine Lösung für das Ende des Datenpakets finden - wenn Idle = High 
und die letzten Bits ebenfalls High sind, triggert die ISR ja nicht.

Gruß,

Max

von Clemens L. (c_l)


Lesenswert?

Peter M schrieb:
> Ist folgende Strategie die richtige?

Grundsätzlich ja.

> 1.) Interrupt auf fallende Flanke von P2.3

Das ginge auch mit dem Timer im Capture-Modus. Dann hast du den genauen 
Zeitpunkt der Flanke und kannst so die folgenden Zeiten für die 
Bit-Mitten genauer festlegen.

> 2.) In der ISR mit NOPs zaehlen ob der Delimiter etwa 12.5us lang ist.
>     Falls nein --> return
> 3.) Falls ja, warten auf die naechste fallende Flanke (die nach dem
>     ersten "1").

Du könntest auch für die zweite fallende Flanke noch Capture-Modus 
benutzen, dann musst du nur prüfen, ob der Abstand ca. 18.75 µs ist.

>     b) TA0CCR auf 16MHz/160kHz = 100 setzen.

Wenn du mit Capture-Modus anfängst, dann benutzt du Continuous-Modus, 
und musst auf CCR den entsprechenden Abstand immer wieder dazuaddieren.

von Peter M (Gast)


Lesenswert?

Hi Der Zahn der Zeit, Max, Clemens,

Danke das hilft sehr weiter!
Ich werde mit der dem Flankentrigger und der TA_Int routine beginnen. 
Ende ist einfach nach N bits. Also genau wie du geschrieben hast (dec 
Ry, jnz retInt).

Peter

von jm2c (Gast)


Lesenswert?

Peter M schrieb:
> (Delimiter,12.5us) 1  0 1 1 1  0 0  1 1 ...
> __                   __    _____      ___
>    \_________________/  \__/      \____/   \__

Das erinnert mich an was, mmmhh ...

Wie konstant ist die Bitzeit? Wie lang ist ein Datentelegramm?

Die Darstellung trügt, den Delimiter ist nur 2 Bit lang; es könnten auch 
zwei '0' mitten im Telegramm sein. Wie wird zwischen den Teilnehmern 
synchronisiert?

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.