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
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.
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.
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
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;SetztauchCarry=.not.Zero
3
rrcRx;Rx=EinsderRegister,max.16Bit
4
mov#99,&TACCR0;(odermusses100sein?)
5
;JetztnochirgendwaszurEnde-Erkennung,z.B.
6
decRy;Bitszählen
7
jnzRetInt
8
clr#GIE,&SR;(Global)Interruptdisable
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...
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
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.
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
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?