Forum: Mikrocontroller und Digitale Elektronik [ASM]Identifikationsbyte bei mehreren UART Slave´s filtern


von BaeumeKommunizierenElektromagnetisch (Gast)


Lesenswert?

Guten Abend zusammen,

in einem Vorhaben sollen von einem Host (PC) Daten Seriel an ein 
Knotenpunkt gesendet, bearbeitet und weitergeleitet werden. Meine Wahl 
fiel auf den 2560 AVR da in dem Projekt einige Timer sowie ADC notwendig 
sind.

Es bildet sich folgende Konstellation fuer den "Knotenpunkt" 2560:
UART0 - Host (PC mit eigenem Interface)
UART1 - Slaveteilnehmer 1
UART2 - Slaveteilnehmer 2
UART3 - Slaveteilnehmer 3

Ueber Interruptroutinen der Slaves werden "Identifikationbytes" an den 
Host gesendet und anschließend die Nachricht aus dem Buffer des 2560, 
somit werden die 3 Slaves identifiziert.
Dabei gilt:
0xA0 - Slave 1 Nachrichtanfang
0xA1 - Slvae 2 Nachrichtanfang
0xA2 - Slave 3 Nachrichtanfang
0xA3 - Slave 1 Nachrichtende
0xA4 - Slave 2 Nachrichtende
0xA5 - Slave 3 Nachrichtende
Info:
Der Bereich 0xA0 bis 0xAF ist fuer dieses Vorhaben reserviert, die 
Nachrichten der Slaves enthalten diese nicht.

Folgende Zeilen habe ich schnell zusammen geschrieben zum Verstaendnis, 
dieser Aufruf existiert natuerlich 3 mal:
1
USART1_INTERRUPT:
2
  push  r16
3
  push  r17
4
  lds  r16, UDR1
5
  lds  r17, 0xA0 ;Slaveteilnehmer 1 [MSB]
6
  sts  UDR0, r17 ;An UART0 (Host) senden
7
  sts  UDR0, r16
8
  lds  r17, 0xA3 ;Slaveteilnehmer 1 [LSB]
9
  sts  UDR0, r17 ;An UART0 (Host) senden
10
  pop  r17
11
  pop  r16
12
  reti

Somit weiss Ich nun am Host von welchem Slave Nachrichten gesendet 
wurden und kann die Bytes zwischen MSB und LSB in einem String 
bearbeiten.

Es sollen Nachrichten vom Host an die Slaves versendet werden. Mein 
Problem hier ist das die Zuordnung der Nachrichten vom Host zu den 
einzelnen Slaves mit dem dazugehoerigen Daten nicht funktioniert.

Empfangene Identifikationsbytes:
0xAA - Slave 1
0xAB - Slave 2
0xAC - Slave 3

Versuch Nr. 1
Dafuer habe Ich nun eine Interruotroutine geschrieben, meine Idee war es 
aehnlich wie Slave -> Host, ein Identifikationsbyte vor der Nachricht an 
den 2560 zu senden und anschließend mit Verzoegerung die Nachricht an 
den gerichteten Slave (siehe Codezeilen unten)

Versuch Nr. 2
Mit jeder Nachricht vom Host zum 2560 das Identifikationsbyte mit der 
Nachricht zu versenden. Die Nachrichten selber sind immer 
unterschiedlich lang, das erste Byte waere somit interessant. Ich habe 
mich an die Befehle LSL und LSR gemueht um das erste Byte aus einem 
register filtern zu koennen um Entscheiden zu treffen. Dabei muss das 
Byte auch weggeschnitten werden bevor es zum Slave gesendet wird, wie in 
Versuch Nr.1 beabsichtigt.

Wie wuerdet Ihr das loesen um maximale Performance zu halten (unnoetige 
Delays vermeiden)?
Falls Jemand fragt - ja UART ist hier vorgegeben...

1
USART0_INTERRUPT:
2
  push  r16
3
  lds  r16, UDR0
4
  cpi  r16, 0xAA ;Empfangener Byte - String gerichtet an UART1?
5
  brne  NT1
6
  rjmp  SLAVE1_WORK
7
NT1:
8
  cpi  r16, 0xAB ;Empfangener Byte - String gerichtet an UART2?
9
  brne  NT2
10
  rjmp  SLAVE2_WORK
11
NT2:
12
  cpi  r16, 0xAC ;Empfangener Byte - String gerichtet an UART3?
13
  brne  HOST_ENDE
14
  rjmp  SLAVE3_WORK
15
HOST_ENDE:
16
  pop  r16
17
  reti
18
19
SLAVE1_WORK:
20
  lds r16, UDR0 ;Daten nochmal einlesen
21
  sts UDR1, r16 ;Und an Slave senden
22
  ret
23
SLAVE2_WORK:
24
  lds r16, UDR0 ;Daten nochmal einlesen
25
  sts UDR2, r16 ;Und an Slave senden
26
  ret
27
SLAVE3_WORK:
28
  lds r16, UDR0 ;Daten nochmal einlesen
29
  sts UDR3, r16 ;Und an Slave senden
30
  ret

von Sascha W. (sascha-w)


Lesenswert?

1
lds r17,0xa0       //lade r17 mit Wert aus SRam-Addr 0xA0
2
ldi r17,0xa0        //lade r17 mit 0xa0

alles klar?

Sascha

von BaeumeKommunizierenElektromagnetisch (Gast)


Lesenswert?

Hallo Herr W.

leider verstehe ich nicht ganz worauf die Anwort hinweisen soll..

Gruß
BKE

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Sascha W. schrieb:
> lds r17,0xa0       //lade r17 mit Wert aus SRam-Addr 0xA0
> ldi r17,0xa0        //lade r17 mit 0xa0

BaeumeKommunizierenElektromagnetisch schrieb:
> leider verstehe ich nicht ganz worauf die Anwort hinweisen soll..

 r17 wird NICHT mit 0xA0 geladen, sondern mit dem WERT aus der
 RAM-Addr 0xA0.

 Deine Slaven senden wie folgt:
1
  lds  r17, 0xA0 ;Slaveteilnehmer 1 [MSB] - NEIN, Inhalt der RAM-Addr[0xA0] wird gesendet !!!
2
  sts  UDR0, r17 ;An UART0 (Host) senden
3
  sts  UDR0, r16
4
  lds  r17, 0xA3 ;Slaveteilnehmer 1 [LSB] - NEIN, Inhalt der RAM-Addr[0xA3] wird gesendet !!!
5
  sts  UDR0, r17 ;An UART0 (Host) senden

 jetzt klarer ?

: Bearbeitet durch User
von BaeumeKommunizierenElektromagnetisch (Gast)


Lesenswert?

Sascha W. schrieb:
> lds r17,0xa0       //lade r17 mit Wert aus SRam-Addr 0xA0
> ldi r17,0xa0        //lade r17 mit 0xa0
>
> alles klar?
>
> Sascha

Marc V. schrieb:
>   lds  r17, 0xA3 ;Slaveteilnehmer 1 [LSB] - NEIN, Inhalt der
> RAM-Addr[0xA3] wird gesendet !!!
>   sts  UDR0, r17 ;An UART0 (Host) senden
>
>  jetzt klarer ?

Guten Abend Sascha und Marc,

erstmal Danke fuer eure Antworten. Den Zusammenhang mit dem Problem der 
Verstaendnisuebergabe habe ich nun erkannt.. Ihr beide habt Recht die 
oben stehenden Zeilen sind nicht korrekt:
1
lds  r17, 0xA0 ;Slaveteilnehmer 1 [MSB]
2
  sts  UDR0, r17 ;An UART0 (Host) senden
3
  sts  UDR0, r16
4
  lds  r17, 0xA3 ;Slaveteilnehmer 1 [LSB] 
5
  sts  UDR0, r17 ;An UART0 (Host) senden
Das resultiert daraus das ich sie schnell aus dem Kopf heraus 
geschrieben habe und kein C&P aus einem Projekt angewendet habe...

Ich versuche es anders zu uebermitteln:

a. Ich habe ein Interface programmiert welches ueber eine RS232 
Schnittstelle Daten von einem 2560 mit 3 Slave´s empfaengt

b. Diese besagte Schnittstelle (PC mit Interface) wird mit UART0 
realisiert, die 3 Slaves ueber UART1, UART2 und UART3

c. Wenn einer der 3 Slaves etwas ueber ihre RS232 Schnittstelle sendet 
wird ein Interrupt beim 2560 ausgeloest -> Es wird ein 
Identifizierungsbyte (LDI NICHT LDS Befehl zum laden eines Registers) 
zum Host gesendet und im Anschluss die Nachricht sowie ein Abschlussbyte

d. Ich weiß durch die Identifizierungsbytes welcher Slave (1, 2 oder 3) 
mir welche Nachricht gesendet hat -> Das Interface kann sie nun 
bearbeiten

Naechste realisierung ¶warum der Thread existiert¶:
e. Ich wuerde gerne den Slaves sagen was sie tun sollen, sie sollen 
Nachrichten vom Host empfangen..

f. Mein Interface versendet vom PC ueber RS232 an den 2560 (UART0) Daten 
-> Interruptroutine vom 2560 wird ausgeloest.

>>>> Wie koennte man jetzt anhand den empfangenen Bytes entscheiden an welchen 
Slave was gesendet wird?

Dazu schrieb ich oben bereits, siehe bitte USART0_INTERRUPT:

von BaeumeKommunizierenElektromagnetisch (Gast)


Lesenswert?

Folgendes habe ich festgestellt:
Wenn vom Interface das Byte 0xAA (gerichtet an UART1) und ein 
X-beliebiges Byte gesendet wird dann funktioniert der oben stehende 
Code, im Register r16 steht das zweitgesende Byte.
Wenn mehrere Bytes versendet werden nach 0xAA, dann wird das 
zuletztgesendete Byte im Register r16 geladen.. die Funktionsweise ist 
hier sehr interessant..

von c-hater (Gast)


Lesenswert?

BaeumeKommunizierenElektromagnetisch schrieb:
> Folgendes habe ich festgestellt:
> Wenn vom Interface das Byte 0xAA (gerichtet an UART1) und ein
> X-beliebiges Byte gesendet wird dann funktioniert der oben stehende
> Code, im Register r16 steht das zweitgesende Byte.
> Wenn mehrere Bytes versendet werden nach 0xAA, dann wird das
> zuletztgesendete Byte im Register r16 geladen.. die Funktionsweise ist
> hier sehr interessant..

Auch mit nur einem Datenbyte würde es nicht richtig funktionieren.

Das Problem besteht aus gleich fünf Teilproblemen, oder anders 
ausgedrückt: da sind fünf Fehler drin:

1) Du liest in einer ISR zweimal aus UDR (ohne weitere Maßnahmen). Das 
kann höchstens zufällig mal beim zweiten Byte den richtigen Wert 
liefern.

2) Du hast keinen Merker für die Adresse verwendet. Mußt du aber, weil 
halt in einer Instanz des Interrupts nur ein Byte empfangen werden kann. 
Aber selbst wenn du zwei Bytes liest und erst dann die ISR verläßt: du 
landest hier im unterbrochenen Code, der dann möglicherweise R16 
verändert, womit deine Adresse für die nächste Instanz des Interrupts 
verloren ist. Sowas geht nur dann, wenn R16 sozusagen reserviert ist.

3) Selbst wenn R16 reserviert ist und garantiert nicht außerhalb der ISR 
geändert wird, so machst du den Wert trotzdem beim nächsten Eintritt in 
die ISR selber kaputt, indem du das nächste empfangene Byte wieder nach 
R16 liest.

4) Du springst in der ISR an drei Stellen zu Code, der den Stack kaputt 
macht und die Interrupts gesperrt hinterläßt. Somit ist garkein weiterer 
Empfang mehr möglich.

von BaeumeKommunizierenElektromagnetisch (Gast)


Lesenswert?

Hallo c-hater,

danke dir fuer deine Antwort, ich hatte fehlinterpretiert das der RX 
Interrupt nur fuer jeden Byte ausgeloest wird, urspruenglich ausgehend 
von der Annahme, dass ich die Bytes aus dem Internen Puffer herauslesen 
koennte. Wie koennte man den Buffer nutzen?

Habe den Interruptteil vom UART0 angepasst womit es funktionieren 
sollte, Nachteil ist hier das ein gesamtes Register (hier r17) fuer 
restlichen Code des µC unangetastet bleiben muss, weil wie du sagtest 
zwischen den Bytes beim Empfangen andere Interrupts diesen veraendern 
koennten.

Habe das nun so gestaltet, werde es vielleicht noch etwas anpassen - 
sollte gehen:

[ASM]
USART0_INTERRUPT:
  push  r16
  lds   r17, UDR0 ;In das "Entscheidungsregister" Byte einlesen
  mov   r16, r17  ;r16 wird gesendet falls kein Identifikationsbyte

  cpi   r17, 0xAA ;Empfangener Byte = Identifikationsbyte?
  brne  NT1
  rjmp  HOST_ENDE
NT1:
  cpi   r17, 0xAB ;Empfangener Byte = Identifikationsbyte?
  brne  NT2
  rjmp  HOST_ENDE
NT2:
  cpi   r17, 0xAC ;Empfangener Byte = Identifikationsbyte?
  brne  HOST_ENDE

  lds   r16, UDR0 ;Falls kein Definitionsbyte - in r16 laden

  cpi   r17, 0xAA
  brne  ET1
  sts   UDR1, r16
ET1:
  cpi   r17, 0xAB
  brne  ET2
  sts   UDR2, r16
ET2:
  cpi   r17, 0xAC
        brne  HOST_ENDE
  sts   UDR3, r16

HOST_ENDE:
  pop   r16
  reti
[/ASM]

von BaeumeKommunizierenElektromagnetisch (Gast)


Lesenswert?

Sorry die Zeile gehoert da nicht rein, habe oben den mov Befehl 
eingesetzt - zwei mal UDR0 sollten wir nicht einlesen...
[ASM]
  lds   r16, UDR0 ;Falls kein Definitionsbyte - in r16 laden
[/ASM]

[ASM]
USART0_INTERRUPT:
  push  r16
  lds   r17, UDR0 ;In das "Entscheidungsregister" Byte einlesen
  mov   r16, r17  ;r16 wird gesendet falls kein Identifikationsbyte

  cpi   r17, 0xAA ;Empfangener Byte = Identifikationsbyte?
  brne  NT1
  rjmp  HOST_ENDE
NT1:
  cpi   r17, 0xAB ;Empfangener Byte = Identifikationsbyte?
  brne  NT2
  rjmp  HOST_ENDE
NT2:
  cpi   r17, 0xAC ;Empfangener Byte = Identifikationsbyte?
  brne  HOST_ENDE


  cpi   r17, 0xAA
  brne  ET1
  sts   UDR1, r16
ET1:
  cpi   r17, 0xAB
  brne  ET2
  sts   UDR2, r16
ET2:
  cpi   r17, 0xAC
        brne  HOST_ENDE
  sts   UDR3, r16

HOST_ENDE:
  pop   r16
  reti
[/ASM]

von c-hater (Gast)


Lesenswert?

BaeumeKommunizierenElektromagnetisch schrieb:

> [ASM]
> ...
> [/ASM]

Die Tags waren falsch, korrekt ist avrasm.

Was den Inhalt betrifft, sieht der schon sehr wesentlich besser aus, es 
sind zumindest erstmal alle rein "technischen" Fehler ausgemerzt. Nur 
die Logik passt noch nicht. Das liegt vor allem daran, dass du noch 
nicht die ganze Bedeutung des "Entscheidungsbyte" erfasst hast und die 
Möglichkeiten, die sich daraus zur korrekten Steuerung des Ablaufes über 
mehrere Instanzen der ISR hinweg ergeben.

Was fehlt, sind einfach noch zwei Sachen: die korrekte Nutzung des 
Endekennzeichens der Nachricht in der ISR und die Initialisierung des 
"Entscheidungsbyte" vor der allerersten Auslösung des Interrupt. 
Sinnvollerweise nämlich auf das Endekennzeichen.

---

In der ISR liest du das empfangene Byte ein und prüfst du dann erstmal 
das "Entscheidungsbyte". Ist das "Endekennzeichen", bist du ausserhalb 
einer Nachricht, ansonsten innerhalb und das Entscheidungsbyte enthält 
die Zieladresse der Nachricht.

Entsprechend diesen zwei Fällen musst du verzweigen und zwei völlig 
unterschiedliche Routinen abarbeiten. Wenn ausserhalb der Nachricht, 
dann das empfangene Byte auf gültige Zieladresse prüfen und, falls ja, 
dem "Entscheidungsbyte" zuweisen. Das war alles in diesem Zweig, es 
folgt nur noch ordentlicher Exit aus der ISR.

Im anderen Zweig hingegen mußt du das empfangene Byte auf 
Endekennzeichen prüfen. Wenn ja, dem "Entscheidungsbyte" zuweisen und 
das war's, es folgt nur noch ordentlicher Exit aus der ISR.
Nur dann, wenn das empfangene Byte nicht das Endekennzeichen war, dann 
kommt die Sache mit der Weiterleitung an den zuständigen Empfänger, also 
das, was bisher der wesentliche Inhalt deiner ISR war...

von von BaeumeKommunizierenElektromagnetisch (Gast)


Lesenswert?

>> [ASM]
>> ...
>> [/ASM]
>
> Die Tags waren falsch, korrekt ist avrasm.
>
Improvisierend basierte Tastenfolge aus dem Kopf heraus resultierender 
Fehler

Hallo c-hater,

danke Dir fuer deine Nachricht, ich habe sie aus mehreren Winkel 
versucht zu interpretieren.

Zuerst einmal sollte ich die Aussage aendern das ein Register reserviert 
sein muss fuer den obigen Code ->

a. r17 im Hauptprogramm nicht verwenden. Sollte eine ISR in verwenden 
dann vor Beginn in Stack laden und beim Verlassen wiederherstellen.

außerdem war er fehlerbehaftet den mit jedem empfangenen Byte habe ich 
mir r17 ueberschrieben, den Teil habe ich angepasst nun empfangen alle 
Slaves das was vom Interface generiert wird:
1
USART0_INTERRUPT:
2
  push  r16
3
  lds   r16, UDR0    ;In das "Entscheidungsregister" Byte einlesen
4
  
5
  cpi   r17, 0xAA   
6
  brne  NT1
7
  mov   r17, r16     ;in r17 nur Byte laden wenn = Identifikationsbyte
8
  rjmp  HOST_ENDE
9
NT1:
10
  cpi   r17, 0xAB    ;Empfangener Byte = Identifikationsbyte?
11
  brne  NT2
12
  mov   r17, r16     ;in r17 nur Byte laden wenn = Identifikationsbyte
13
  rjmp  HOST_ENDE
14
NT2:
15
  cpi   r17, 0xAC    ;Empfangener Byte = Identifikationsbyte?
16
  mov   r17, r16     ;in r17 nur Byte laden wenn = Identifikationsbyte
17
  brne  HOST_ENDE

Mag zwar funktionieren doch plaediere ich die Optimierte Schiene zu 
fahren.  Mir liegen Verstaendnissteine im Wege den technischen Kontext 
zu meinem Ansatz im vollen Umfang zu verarbeiten.

Mir ist bewusst, dass solche Sprungbefehle nicht gerne verwendet werden, 
weil sie mehr Ressourcen benoetigen. Außerdem ist es nicht schoen, weil 
das eine Form einer Asymmetritaet darstellt -> Bytes an Slave 3 
gerichtet dauert laenger im Vergleich Slave 1.. Aus diesem Grund werde 
ich den Teil ueberarbeiten in dem ich eine .db erstelle und diese durch 
r30 und r31 mit lpm aus dem Flash vergleichen lasse. War das damit 
gemeint:

> und die Initialisierung des
> "Entscheidungsbyte" vor der allerersten Auslösung des Interrupt.
> Sinnvollerweise nämlich auf das Endekennzeichen.

?
Eine weitere sekundaere Variante die ich hier rauslese ist es das ich 
ein "Abschlussbyte" senden soll vom Interface um die Routine zu beenden. 
Bei den drei Slaves ist es notwendig, da jeder Bytes in die Pipeline 
feuern kann somit muss ich die ISR´s fuer die anderen 2 Slaves speeren 
waehrend einer sendet und mit einem Abschlussbyte versehen um sie wieder 
frei zugeben. Da in dieser Konstellation nur ein Host besteht der 
sendet, wozu das Abschlussbyte?

> Entsprechend diesen zwei Fällen musst du verzweigen und zwei völlig
> unterschiedliche Routinen abarbeiten.

Verstehe ich nicht ganz.. es wird die ISR beim Empfangen von Bytes 
ausgeloest, soll ich mittels "rcall" eine weitere Routine aufrufen, wo 
ist der Sinn dahinter wenn ich in der ISR alles erledigen kann?


> das war's, es folgt nur noch ordentlicher Exit aus der ISR.
Diesen Satz verfasstest Du zwei Mal. Mit dem Wiederherstellen aller 
Register sowie "reti" ist fuer mich die ISR sauber beendet, laesst sich 
dem etwas hinzufuegen?

Danke,
BkE

von S. Landolt (Gast)


Angehängte Dateien:

Lesenswert?

In der Hoffnung, die Aufgabenstellung überhaupt richtig verstanden zu 
haben: hier ein Vorschlag für die (letztbehandelte) Richtung PC->slaves. 
Ist zwar für einen AVR-Dx, und die Slaves heißen Kanal, sollte aber ja 
egal sein.

von c-hater (Gast)


Lesenswert?

von BaeumeKommunizierenElektromagnetisch schrieb:

> Mir ist bewusst, dass solche Sprungbefehle nicht gerne verwendet werden,
> weil sie mehr Ressourcen benoetigen. Außerdem ist es nicht schoen, weil
> das eine Form einer Asymmetritaet darstellt -> Bytes an Slave 3
> gerichtet dauert laenger im Vergleich Slave 1..

Das ist ein ziemlich sekundäres Problem, so lange du die Logik der 
Weiterleitung nicht korrekt abbildest.

Merke: erstmal korrekte Funktion des Codes herstellen. Über mögliche 
Optimierungen kann man danach immer noch nachdenken.

Die gibt es aber nicht unbedingt. Bei der geringen Zahl möglicher 
Clients (begrenzt durch die Zahl der vorhandenen UARTS) lohnt es nicht, 
groß über die Optimierung der Verteilung nachzudenken. Da ist nur wenig 
bis gar kein Optimierungspotential drinne, verglichen mit der 
Verzweigungslösung.

Die Verzweigung selber könnte man allerdings noch optimieren. In Asm 
kann man nämlich nach einer einzigen Vergleichsoperation in drei 
Richtungen verzweigen, also statt eines binären einen trinären Baum 
aufspannen. Diese Optimierung ist simpel und lohnt schon ab drei 
möglichen Zielen der Verzweigung. Also ist die Indikation für die 
Anwendung dieser Optimierung in deinen Fall eindeutig positiv.

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.