Problem mit asm Routine

OP #4251096
Ich verzweifle bei einer relativ einfachen asm - Routine.

Hintergrund: Ein kleines Programm für eine Funkfernsteuerung mit RFM12. 
Es werden immer 7 Bytes übertragen, wobei das erste als Startbyte "S" 
angesehen wird. Die restlichen 6 Bytes sind einstellbar. Diese Bytefolge 
wird zweimal gesendet und bei richtigem Empfang soll ein Befehl 
ausgeführt werden. So weit die Theorie.

Grundsätzlich macht das Programm auch das, was es machen soll, 
allerdings nur dann, wenn ich in der Vergleichschleife eine UART Ausgabe 
anspringe. Lasse ich die weg, spielt das Programm verrückt. Dabei ist es 
auch egal an welcher Stelle dieser Vergleichschleife ich den Sprung 
einbaue.
1
;Empfänger abfragen
2
receive:
3
  ldiw  Y, Eingang          ;Y -Pointer auf 1. Byte
4
  ldi    datacnt, 10          ;Anzahl Datenbytes +4
5
  rcall  rf12_rxdata_rec        ;10 empfangene Bytes werden im SRAM abgelegt
6
;prüfen, ob Startbyte = S
7
S_test:
8
  ldiw  Y, Eingang          ;Y - Pointer wieder auf Anfang setzen
9
S_test_loop:  
10
  ld    temp, Y+          ;Y - Byte laden und auf nächstes Byte stellen
11
  nop
12
  cpi    temp, 'S'
13
  breq  Vergleich          ;wenn S, dann die übrigen 6 Byte vergleichen
14
  inc    cnt
15
  cpi    cnt, 3            ;S muß in den ersten 3 Bytes enthalten sein
16
  breq  main
17
rjmp    S_test_loop
18

19
;weitere 6 Bytes überprüfen
20
Vergleich:
21
  clr    cnt
22
  ldi    ZL, LOW(Befehl_2*2)      ;Z - Pointer auf Befehlsmuster
23
  ldi    ZH, HIGH(Befehl_2*2)
24
Ver_loop:
25
  inc    cnt
26
  ldi    temp, '0'
27
  add    temp, cnt
28
  rcall  uart_transmit            ;!!!!hier liegt das Problem!!!
29
  cpi    cnt, 7            ;6 Bytes müssen verglichen werden
30
  breq  Ver_loop_exit
31
  lpm                  ;Z - Byte laden und Register erhöhen
32
  adiw  ZL, 1              
33
  ld    temp, Y+          ;Y - Byte laden und auf nächstes Byte stellen
34
  cp    r0, temp          ;Y mit Z vergleichen
35
  breq  Ver_loop          ;wenn gleich, nächstes Byte
36
  rjmp  Fehler
37
  ;rjmp  Vergleich_2            
38
Ver_loop_exit:
39
  clr    cnt
40
  inc    OKcnt_1            ;Zähler für erfolgreichen Vergleich
41
  rjmp  Clear            ;Daten im SRAM löschen
42
rjmp    main

Kann sich darauf jemand einen Reim machen?
Gast #4251165
Also PIC und MPASM ist es wahrscheinlich nicht. Ich muss passen.
Kann sonst jemand aus dem bloßen Aussehen des Quellcodes erraten, um 
welchen Mikrocontroller es geht?
OP #4251185
PIC kundiger schrieb im Beitrag #4251165:
> Also PIC und MPASM ist es wahrscheinlich nicht. Ich muss passen.
> Kann sonst jemand aus dem bloßen Aussehen des Quellcodes erraten, um
> welchen Mikrocontroller es geht?

Sorry, aber durch das lange Suchen und Testen bin ich schon etwas 
betriebsblind. Es ist ein ATMega48.
Gast #4251189
> spielt das Programm verrückt
Wie äußerst sich das?

> rcall  uart_transmit            ;!!!!hier liegt das Problem!!!
Die Routine wird nicht mitgeliefert, dafür sieben Ausrufezeichen.

Und das von jemandem, der seit über sechs Jahren dabei ist.
OP #4251192
S. Landolt schrieb:
> Die Routine wird nicht mitgeliefert, dafür sieben Ausrufezeichen.

Die Routine ist Standard und selbst auch nicht das Problem, sondern ein 
fehlender Sprung dahin (wie beschrieben).
1
uart_transmit:                  ;temp wird ausgegeben
2
  cli
3
  lds    r10, UCSR0A
4
  sbrs  r10, UDRE0
5
  rjmp  UART_Transmit
6
  sts    UDR0, temp
7
exit_usart_transmit:
8
  ret
Gast #4251208
Bruno M. schrieb:
> uart_transmit:                  ;temp wird ausgegeben
>   cli
>   lds    r10, UCSR0A
>   sbrs  r10, UDRE0
>   rjmp  UART_Transmit
>   sts    UDR0, temp
> exit_usart_transmit:
>   ret

Es ist ungewöhnlich, in einer Unterroutine das I-Flag zu löschen (cli), 
aber nicht wieder zu restaurieren.
Gast #4251212
Bruno M. schrieb:
> S_test:
>   ldiw  Y, Eingang          ;Y - Pointer wieder auf Anfang setzen
> S_test_loop:
>   ld    temp, Y+          ;Y - Byte laden und auf nächstes Byte stellen
>   nop
>   cpi    temp, 'S'
>   breq  Vergleich          ;wenn S, dann die übrigen 6 Byte vergleichen
>   inc    cnt
>   cpi    cnt, 3            ;S muß in den ersten 3 Bytes enthalten sein
>   breq  main
> rjmp    S_test_loop

Wird "cnt" auch mal initialisiert?
Gast #4251218
Bruno M. schrieb:

> Die Routine ist Standard

Bestimmt nicht. Die ist so verbuggt, wenn das Standard wäre...

Erstmal sperrt sie die Interrupts (gibt sie aber niemals wieder frei). 
Einen tiefgreifenderen Eingriff in das System kann man sich schon fast 
nicht mehr vorstellen...

Des Weiteren ist sie blockierend, also de facto ein Delay mit der Größe 
einer Bytedauer. Jedenfalls ab dem dritten zu sendenden Byte...

Wenn "rf12_rxdata_rec" genauso Scheiße prgrammiert ist, braucht man sich 
über nichts mehr zu wundern. Aber auch das hast du uns ja 
vorenthalten...
Gast #4251234
Nase schrieb:

> Und das ist verboten?

Natürlich nicht. Man muß eben bloß dafür sorgen, dass andere 
Programmfunktionen dadurch nicht gestört werden.

Und das fällt auf Dauer am leichtesten, indem man sich auf blockierenden 
Code erst garnicht einläßt.

Entweder man macht's interruptgesteuert oder man pollt. Aber man 
blockiert niemals, wenn es sich irgendwie vermeiden läßt. Und bei einer 
USART-Ausgabe läßt es sich nun wirklich völlig problemlos vermeiden.
OP #4251273
Carl D. schrieb:
>> Poste den ganzen Quellcode
>
> als Attachment!

Das mache ich natürlich gerne, ich dachte ich könnte Euch das ersparen.
Den Sprung in den 2. Vergleich habe ich zum Testen entfernt.

An der Zeit liegt es übrigens nicht! An cli auch nicht, das habe ich 
entfernt.

Und so sehen die UART-Ausgaben aus:

Mit einem Sprung in die UART-Routine sowohl in der S-test Schleife als 
auch in der Vergleichschleife:

SYYBYYB7SYYBYYBAuftrag 1 ausfuehren!!!<\n><\r>

und so, wenn ich den UART-Sprung aus der Vergleichschleife nehme.

@?SVergleichs-Fehler!!<\n><\r>?/SVergleichs-Fehler!!<\n><\r>
Angehängte Dateien:
OP #4251320
Bruno M. schrieb:
> An der Zeit liegt es übrigens nicht!

Ich muß mich korrigieren! Es scheint doch ein timing Problem zu sein.
1
Vergleich:
2
  clr    cnt
3
  ldi    ZL, LOW(Befehl_2*2)      ;Z - Pointer auf Befehlsmuster
4
  ldi    ZH, HIGH(Befehl_2*2)
5
Ver_loop:
6
  inc    cnt
7
  cpi    cnt, 7            ;6 Bytes müssen verglichen werden
8
  breq  Ver_loop_exit
9
  rcall  wait
10
  rcall  wait
11
  lpm                  ;Z - Byte laden und Register erhöhen
12
  adiw  ZL, 1              
13
  ld    temp, Y+          ;Y - Byte laden und auf nächstes Byte stellen
14
  ;rcall  uart_transmit
15
  cp    r0, temp          ;Y mit Z vergleichen
16
  breq  Ver_loop          ;wenn gleich, nächstes Byte
17
  rjmp  Fehler
18
  ;rjmp  Vergleich_2            
19
Ver_loop_exit:
20
  clr    cnt
21
  inc    OKcnt_1            ;Zähler für erfolgreichen Vergleich
22
  rjmp  Clear            ;Daten im SRAM löschen
23
rjmp    main

So funktioniert es nämlich auch!

S??SAuftrag 1 ausfuehren!!!<\n><\r>
OP #4251326
Es bestätigt sich!!

Wenn ich auch aus S_test nur die Warteschleifen einbaue, sieht es bei 
mehrfachem Versuch so aus.

Auftrag 1 ausfuehren!!!<\n><\r>Auftrag 1 ausfuehren!!!<\n><\r>Auftrag 1 
ausfuehren!!!<\n><\r>Auftrag 1 ausfuehren!!!<\n><\r>Auftrag 1 
ausfuehren!!!<\n><\r>

Jetzt würde mich nur noch die Ursache interessieren. Da ich den 
Vergleich mit Daten aus dem SRAM durchführe, kann es ja mit der 
Funkübertragung nichts zu tun haben.
Gast #4251458
Schau mal was sich im SREG tut mit und ohne UART/Delay.
Ich wette fast drauf, dass du False-Poitives beim Vergleich bekommst, 
weil irgend was im SREG rummurkst.
Moderator (Firma: Titel) Persönliche Seite #4251709
Bruno M. schrieb:
> Wie soll ich das machen? Der Debugger meckert ja nicht.
Warum sollte er?
Sei dir sicher: das Programm macht im uC genau das, was du 
hingeschrieben hast.

Ich würde raten sagen, da funkt irgendein Interrupt dazwischen. Was 
anderes kann diese Routine ja nicht unterbrechen und an den Flags 
herumschrauben. Wie viele Interrupts hast du?
OP #4251717
Lothar M. schrieb:
> Wie viele Interrupts hast du?

keinen!

Aus Interesse habe ich in der Zwischenzeit testweise das Programm so 
abgeändert, daß nicht der RFM12 das SRAM füllt, sondern das Programm 
selbst. Dann verhält es sich so wie erwartet, d.h. der Vergleich 
funktioniert auch ohne wait-Schleife.

Es muß also doch ein timing - Problem mit dem RFM12 sein. Was das ist, 
kann ich mir allerdings nicht erklären.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 11 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.