Downgrade von ATMEL Studio 6.2 auf 6.0 wg GCC Fehler?

#3884987
Lesenswert?

Hallo zusammen,

gestern habe ich beginnem, zum Elch zu werden, heute bin ich fertig...

Ich arbeite normalerweise mit ATMEL Studio 6.0. Dort kompilierte SW 
(ATmega256) läuft auch einwandfrei. Nun habe ich auf dem Netbook STudio 
6.2 installiert, da ich außer Haus ggf. die SW ändern muß.

Die unter 6.0. funktionierenden Quelltexte habe ich zum 6.2. kopiert und 
dort kompileiert. Nach dem Flashen funktioniert die SW bei den 
LCD-Routinen nicht richtig. Fehlersuche und Tests in meinen Routinen 
haben nichts erbracht.

Ich will nun auf Studio 6.0. downgraden, nur wo finde ich den Download? 
Bei Atmel gibt es nur 6.2....

Danke

Yogy
#3885052
Lesenswert?

@ Hanns-Jürgen M. (yogy)

>Die unter 6.0. funktionierenden Quelltexte habe ich zum 6.2. kopiert und
>dort kompileiert. Nach dem Flashen funktioniert die SW bei den
>LCD-Routinen nicht richtig. Fehlersuche und Tests in meinen Routinen
>haben nichts erbracht.

Also ist ein kein NACHGEWIESENER GCC Fehler!

Was funktioniert denn nicht? Mit hoher Wahrscheinlichkeit liegt der 
Fehler bei deiner Software. Wo eine ältere Version vielleicht an einer 
Stelle nicht so massiv optimiert hat, fällt bei einer neueren Version 
dann halt mal ein fehlendes volatile oder ähnliches auf.
#3885067
Lesenswert?

"Natürlich" liegt das Problem in meiner SW. Ich finde es aber nicht. Es 
wäre auch viel zu aufwendig, hier die einzelnen SW-Teile hochzuladen.

Nur soviel: Mein SW-Lösungen arbeiten alle mit einem zweidimensionalen 
Sprungarray in der Hauptprogrammschleife, von der aus Event/Systemstate 
gesteuert die einzelnen Routinen angesprungen werden. Hier könnte das 
Problem liegen, aber andere Routinen werden fehlerfrei angesprungen und 
ausgeführt.

Auch die betreffende Routine (LCD-Ausgabe über TWI/I2C-Bus) wird korekt 
angesprungen, nur due Darstellung auf dem LCD ist völlig verquer. z.B. 
wird anstelle von $31...§39 $12...§92 ausgegeben. Dabei ist die 
Ansteuerung mkit den selbem Display-Routinen ín der Init-Phase korrekt.

Ich habe werder Zeit noch Lust, mit meinem lahmen Netbook tagelang damit 
zu amüsieren. Daher will ich auf 6.0 downgraden.

Ach ja, alle globalen variabklen sind volatile....
Persönliche Seite #3885092
Lesenswert?

Hanns-Jürgen M. schrieb:
> "Natürlich" liegt das Problem in meiner SW. Ich finde es aber nicht.
> Es wäre auch viel zu aufwendig, hier die einzelnen SW-Teile
> hochzuladen.
>
> [...] Ich habe werder Zeit noch Lust, mit meinem lahmen Netbook
> tagelang damit zu amüsieren. Daher will ich auf 6.0 downgraden.

Wenn sich ein Fehler manifestiert sollte man auf jeden Fall die Chance 
nutzen um ihn zu beheben!  Bewusst fehlerhafte Software verwenden / 
verteiben ist m.E. nicht weniger als ein Kunstfehler und spricht Bände 
über die Qualitätsstandards...

Einfach den Compiler wechsen oder die Optionen oder die Quelle solange 
umzustallen bis sich der Fehler nicht mehr manifestiert ist in dem Fall 
eine der schlechtesten Optionen.

Dadurch ist der Fehler ja nicht "weg", und keiner garantiert, daß er 
nicht auch irgendwann mit anderer Compilerversion x.y.z wieder auftritt.
#3885103
Lesenswert?

@ Hanns-Jürgen M. (yogy)

>Auch die betreffende Routine (LCD-Ausgabe über TWI/I2C-Bus) wird korekt
>angesprungen, nur due Darstellung auf dem LCD ist völlig verquer. z.B.
>wird anstelle von $31...§39 $12...§92 ausgegeben. Dabei ist die
>Ansteuerung mkit den selbem Display-Routinen ín der Init-Phase korrekt.

Komisch. Versuch mal, ohne Optimierung zu compilieren und das Programm 
zu starten (wenn es in den Flash passt).

>Ach ja, alle globalen variabklen sind volatile....

Was eher nach Holzhammer als nach Verständnis klingt.
#3885182
Lesenswert?

@Johann

natürlich hast Du damit Recht. Nur bislang mit 6.0. gab es keine 
Fehlermeldungen. Allerdings gab es damals Probleme beim der Portierung 
des Grundsystems von einem IAR-Compieler (für 68HC1) auf AVR-Studio 
(4-xx). Das kostete mich damals einige Tage Arbeit.

Wenn ich in den nächsten Wochen/Monaten Zeit finde, gebe ich mich auch 
án das 6.2. Problem. Nur aktuell habe ich genug vordringlichere Leichen 
auf dem Tisch... Die SW wird ja nicht verkauft und steuert auch keine 
Rakete.

@Falk

Ja, die Optimierung wollte ich schon abschalten bzw. den Level ändern. 
Ich wußte nur noch nicht wie (jetzt weiß ich es)

Holzhammer volatile: Ja, richtig, das hatte habe ich erst gestern 
nachgetragen, quasi als erster versuchter Workaround... hat nichts 
gebracht. Ich werde zum Abschluß das Vorgängerfile prüfen.

So, Version 6.0. wird aktuell installiert, morgen geht es dann weiter

Noch am Rande bemerkt: Jede SW enthält Fehler, mal mehr, mal weniger. 
GCC ist nicht davon auszunehmen. Idealerweise programmiert man halt in 
Assembler, Da hat der "Compiler" (der Assembler) keine Möglichkeit, den 
Binaercode nach Gutdünken zu manipulieren.  C++ und "Optimierungen" 
nehmen mir die Macht aus den Händen...
#3885225
Lesenswert?

@ Hanns-Jürgen M. (yogy)

>Noch am Rande bemerkt: Jede SW enthält Fehler, mal mehr, mal weniger.
>GCC ist nicht davon auszunehmen.

Qualitativ sitmmt das, quantitativ eher nicht. 99% der Fehler liegen am 
Programmierer und nicht am Compiler.

> Idealerweise programmiert man halt in
>Assembler, Da hat der "Compiler" (der Assembler) keine Möglichkeit, den
>Binaercode nach Gutdünken zu manipulieren.  C++ und "Optimierungen"
>nehmen mir die Macht aus den Händen...

Quark. Man sollte schon seine Werkzeuge kennen und beherrschen und nicht 
in Assembler-Hobbyfricklermanier vorgehen. Embedded-Programmierung in C 
ist seit Jahrzehnten Usus.
#3885751
Lesenswert?

@Falk

bez. des "Usus". Das ist wie der Spruch: Leute, eßt Scheiße, Millionen 
Fliegen können sich nicht irren.

Natürlich ist "C" schneller und einfacher zu programmieren, ich nutze ja 
auch fast ausschließlich "C", aber das Kompilat und insb. das 
Linkergebnis ist bei verschiednen Compilern/Linkern nie identisch und 
damit nicht verhersagbar. Und C++ ist so gesehen der absolute Horror.

Assembler mit "Hobbyfrickelei" gleichzusetzen, zeigt aber von der nicht 
vorhanden Kenntnis von Assembler. Aber wer kann das heute noch von sich 
behaupten im Handyoten-Blähstation Zeitalter.

Zu der Bemerkung: "99% der Fehler liegen am Programmierer" gebe ich 
meine volle Zustimmung.
#3885935
Lesenswert?

So, ich habe mal die Optimierungsstufen durchgespielt. Eungestellt war 
-Os, das eragb ein HEX-File vom 70 kB und die beschriebnen Probleme.
Bei Verwendung der anderen Optimierungsstufen zeigt das System das an, 
was es soll.

Ich habe nun -O2 eingestellt, HEX Filegröße ist dann nur 9k größer.
-O1 bringt keine Vorteile.

Nur was ich in meiner SW ändern müßte, um das Problem auch bei Os zu 
vermeiden, läßt sich so wohl kaum feststellen.

Also, Thema geschlossen und vielen Dank an euch alle.
#3885936
Lesenswert?

@ Hanns-Jürgen M. (yogy)

>Natürlich ist "C" schneller und einfacher zu programmieren, ich nutze ja
>auch fast ausschließlich "C", aber das Kompilat und insb. das
>Linkergebnis ist bei verschiednen Compilern/Linkern nie identisch und
>damit nicht verhersagbar.

Sie sind logisch identisch, wenn der Compiler nicht defekt ist und der 
Programmierer weiß was er tut. Und taktgenaue Vorhersagen über den 
erzeugten Maschinencode hat C NIE versprochen, im Gegenteil. Dass das 
ein paar alte Assemblerdionsaurier mokieren ist normal.

>Assembler mit "Hobbyfrickelei" gleichzusetzen, zeigt aber von der nicht
>vorhanden Kenntnis von Assembler.

Ich hab genug Assembler programmiert (68000, AVR, 8051, Picoblaze), um 
zu wissen wie es geht, was Assembler kann und was man besser nicht in 
ASM machen sollte. Ausserdem bezog sich mein Kommentar indirekt auf die 
ewig gleichen, albernen Argumente, die einige Assemblerfanatiker hier 
immer wieder anbringen. Deine Argumente klingen genau so.
#3885941
Lesenswert?

@ Hanns-Jürgen M. (yogy)

>Nur was ich in meiner SW ändern müßte, um das Problem auch bei Os zu
>vermeiden, läßt sich so wohl kaum feststellen.

Mann, Mann, Mann!

Du wirfst die Flinte schon ins Korn, wo du noch nicht mal ANSATZWEISE 
das Thema Fehlersuche begonnen hast.

Wollen wir wetten, dass die Leute hier in weniger als 24h den Fehler 
finden, wenn du den Mumm hast, deine Quellen hier zu veröffentlichen?
Persönliche Seite #3885993
Lesenswert?

Hanns-Jürgen M. schrieb:
> Nur was ich in meiner SW ändern müßte, um das Problem auch bei Os zu
> vermeiden, läßt sich so wohl kaum feststellen.

Du kannst das Artefakt ja gut beschreiben und hast bestimmt noch mehr 
Information darüber, z.B. ob es immer auftritt oder sporadisch oder 
abhängig ist von der Vorgeschichte oder nur wenn bestimmte 
Hardware-Komponenten aktiv sind etc.

Wenn ich mal davon ausgehe, daß du deine Software einigermaßen kennst, 
dann hast du bereits jetzt eine ungefähre Vorstellung davon, wo im 
Code das Problem steckt:

Ist die Anzeigeroutine falsch oder bekommt sie falsche Daten?  Wer 
stellt im letzteren Fall die Daten nicht korrekt bereit oder zerschießt 
sie?  Kommt es zu Glitches, weil ISRs in Daten rumfummeln, die 
atomar sein müssten es aber nicht sind?  Läuft der Stack über und 
wieviel Luft ist da noch? Wurden alle Warnungen aktiviert und 
begutachtet?  Gibt es besonders "trickreiche" Hacks?  Welche 
Echtzeit-Anforderungen stellen die einzelnen Komponenten und kannst du 
(für dich) nachweisen, das diese erfüllt werden?  Gibt es Copy-Paste 
Sequenzen von XYZ etc. etc. etc.

Fehler beheben ist lästig, klar.  Keiner ist scharf drauf sich dadurch 
beim Arbeiten aufhalten zu lassen. Aber es gehört eben auch zum Metier 
dazu...

Im Endeffekt bleibt dir nur die Entscheidung, ob du den Fehler gleich 
behebst oder erst wenn er dich zum X-te mal nervt...
#3886019
Lesenswert?

Hanns-Jürgen M. schrieb:
> Nur was ich in meiner SW ändern müßte, um das Problem auch bei Os zu
> vermeiden, läßt sich so wohl kaum feststellen.

Das ließe sich schon feststellen mit systematischer Fehlersuche.

Mir würde das keine Ruhe lassen, egal ob es für ein kommerzielles 
Produkt ist oder nur eine Hobbybastelei. Ich könnte erst wieder ruhig 
schlafen wenn ich in allen Einzelheiten verstanden hätte was, wie und 
warum das da schief läuft oder an welcher Stelle mein Verständnis oder 
meine Annahmen über den C-Standard oder den Compiler unvollständig oder 
fehlerhaft waren und was ich zukünftig beachten muss um das zu 
vermeiden.
#3886398
Lesenswert?

Hanns-Jürgen M. schrieb:
> So, ich habe mal die Optimierungsstufen durchgespielt. Eungestellt war
> -Os, das eragb ein HEX-File vom 70 kB und die beschriebnen Probleme.
> Bei Verwendung der anderen Optimierungsstufen zeigt das System das an,
> was es soll.
>
> Ich habe nun -O2 eingestellt, HEX Filegröße ist dann nur 9k größer.
> -O1 bringt keine Vorteile.
>
> Nur was ich in meiner SW ändern müßte, um das Problem auch bei Os zu
> vermeiden, läßt sich so wohl kaum feststellen.
>
> Also, Thema geschlossen und vielen Dank an euch alle.

#pragma GCC push_options
#pragma GCC optimize ("O2")

// your code

#pragma GCC pop_options

Damit kannst Du die Optimierung nur für ein einzelnes Codestück ändern 
und so die Ursache einkreisen.
Persönliche Seite #3887264
Lesenswert?

Hanns-Jürgen M. schrieb:
> Frank K. schrieb:
>
>>
>> #pragma GCC push_options
>> #pragma GCC optimize ("O2")
>>
>> // your code
>>
>> #pragma GCC pop_options
>>
>> Damit kannst Du die Optimierung nur für ein einzelnes Codestück ändern
>> und so die Ursache einkreisen.
>
> Oh, danke, dann werde ich mich wohl noch einmal auf die Suche begeben.

Wobei dieses Pragma hier seine Fallstricke hat:

Falls "your code" geinlinet wurde wirkt das Pragma natürlich nicht wenn 
die Funktion, in die geinlinet wurde, außerhalb des Pragmas steht.  Auch 
Funktionen, die nicht explizit "inline" sind, können geinlinet werden, 
und umgekehrt kann eine "inline" Funktion nicht geinlinet sein.  Dies 
ist abhängig von Optionen, dem Kontext und auch dem GCC-Pass, der 
Inlining ausführt — da gibt es nämlich mehr als einen.

Analog gilt das für Partial Inlining und Function Cloning: Auch Code 
außerhalb des Pragmas kann sich ändern, oder Code, der scheinbar im 
Pragma steht, kann sich nicht ändern.

Ist zwar eher unwahrscheinlich das, aber ausgeschlossen ist es nicht und 
man sollte es im Hinterstübchen behalten.

Um zu sehen, welche Teile sich wirklich geändert haben, ist wohl ein 
Blick in die mit -save-temps erzeugt .s Assembler-Datei am 
praktikabelsten, denn bei Diasassemblies ändern sich ab der ersten 
Änderung alle Adressen, was das Vergleichen erschwert.  Es gibt 
diff-Programme, die es erlauben, die zu vergleichenden Daten 
vorzuverarbeiten, da kann man dann die Adressen entfernen.
#3887309
Lesenswert?

Nun, ich habe mich auf die Suche gamacht, und folgende Routine als 
Ursache ??? asusgemacht. Die gesamte Compilation läuft nun mit Opt=s, 
nur bei dieser Routine wird Opt=2 verwendet:
1
//***********************************************************
2
#pragma GCC optimize ("O2")
3
void writeI2C_LCDByte (U8 RS, U8 printchar,U16 j)
4
{
5
  U8 bTimeOld = 0;
6
  U8 LED = 1;
7
  U16 iLoop;
8
  writeI2CByte(RS, LED, printchar,0x27);
9

10
  for (iLoop = j*2;iLoop != 0;iLoop--) {
11
    bTimeOld = TCNT1L;
12
    while (bTimeOld == TCNT1L) {
13
      wdt_reset();
14
    }
15
  }  
16
}
17
//---------------------------------------------------------
18
#pragma GCC optimize ("Os")

Diese Routine ist Bestandteil der Display-Routinen und schreibt 1 Byte, 
sprich 2 Nibble, in den I2C-Bus Adapter für das im 4-Bitmode verwendete 
LCD ein.

Seltsam ist, daß dieselbe Routinen natürlich auch in der 
Initialiserungsphase des Systems verwendet wird, bei dem ebenfalls 
Displayausgaben korrekt erfolgten.

Verwendete Größen:
"j" ist eine Wartezeit, die je hier 100 ist. Der Counter TCNT1 taktet 
mit 2 MHz  (Clock / 8).

Der Verdacht richtet sich nat. auf die lokale Variable iLoop, die ggf. 
"wegoptimiert" wird. Aber da diese Routine in der Initphase einwandfrei 
arbeitet, könnte das problem auch ganz woanders liegen...

Ach ja: #pragma GCC pop_options generiert eine Fehlermeldung...
Moderator Persönliche Seite #3887326
Lesenswert?

Ruf' den Compiler doch mal, wie von Johann beschrieben, mit -save-temps
auf und sieh dir den generierten Assemblercode an.

Ich sehe auf Anhieb nichts Auffälliges, außer dass es mir eine
ziemlich umständliche Formulierung für etwas zu sein scheint, was
ich als:
1
  writeI2CByte(RS, 1, printchar,0x27);
2

3
  wdt_reset();
4
  _delay_us(100);
5
  wdt_reset();

geschrieben hätte.  (Da die kürsteste Periode für den Watchdog um die
15 ms lang ist, braucht man weißgott nicht Mikrosekundenweise den WDR
auslösen.)
Gast #3887331
Lesenswert?

Hanns-Jürgen M. schrieb:
> while (bTimeOld == TCNT1L) {
>       wdt_reset();
>     }

ist das überhaupt sinnvoll?

Wenn der Timer nicht mehr läuft (warum auch immer) wird der WD immer 
noch resettet.

1
for (iLoop = j*2;iLoop != 0;iLoop--) {
2
    bTimeOld = TCNT1L;
3
    while (bTimeOld == TCNT1L) { };
4
    wdt_reset();
5
}

aber einen fehler, der mit Optimierung zu tun hat, kann ich nicht sehen.
#3887340
Lesenswert?

@jörg

bez. des Watchdogs nat. richtig, aber es können beim Aufruf der Routine 
auch mögliche Zeiten bis zu 2^16 -1

Ich habe hier mal die Assember-Sources anghehängt: (save_temps ist 
aktiv)
1. Opt = 2
1
.global  writeI2C_LCDByte
2
  .type  writeI2C_LCDByte, @function
3
writeI2C_LCDByte:
4
.LFB6:
5
  .loc 1 522 0
6
  .cfi_startproc
7
.LVL28:
8
  push r28
9
.LCFI2:
10
  .cfi_def_cfa_offset 4
11
  .cfi_offset 28, -3
12
  push r29
13
.LCFI3:
14
  .cfi_def_cfa_offset 5
15
  .cfi_offset 29, -4
16
/* prologue: function */
17
/* frame size = 0 */
18
/* stack size = 2 */
19
.L__stack_usage = 2
20
  movw r28,r20
21
.LVL29:
22
  .loc 1 526 0
23
  ldi r18,lo8(39)
24
  mov r20,r22
25
.LVL30:
26
  ldi r22,lo8(1)
27
.LVL31:
28
  call writeI2CByte
29
.LVL32:
30
  .loc 1 528 0
31
  movw r24,r28
32
  lsl r24
33
  rol r25
34
.LVL33:
35
  sbiw r24,0
36
  breq .L44
37
.LVL34:
38
.L56:
39
  .loc 1 529 0
40
  lds r18,132
41
.LVL35:
42
  .loc 1 530 0
43
  lds r19,132
44
  cpse r19,r18
45
  rjmp .L46
46
.LVL36:
47
.L47:
48
  .loc 1 531 0
49
/* #APP */
50
 ;  531 "../c_display.c" 1
51
  wdr
52
 ;  0 "" 2
53
  .loc 1 530 0
54
/* #NOAPP */
55
  lds r18,132
56
  cp r18,r19
57
  breq .L47
58
.L46:
59
  .loc 1 528 0
60
  sbiw r24,1
61
.LVL37:
62
  sbiw r24,0
63
  brne .L56
64
.L44:
65
/* epilogue start */
66
  .loc 1 534 0
67
  pop r29
68
  pop r28
69
.LVL38:
70
  ret

Und das gleiche mit opt=s

1
.global  writeI2C_LCDByte
2
  .type  writeI2C_LCDByte, @function
3
writeI2C_LCDByte:
4
.LFB6:
5
  .loc 1 522 0
6
  .cfi_startproc
7
.LVL28:
8
  push r28
9
.LCFI2:
10
  .cfi_def_cfa_offset 4
11
  .cfi_offset 28, -3
12
  push r29
13
.LCFI3:
14
  .cfi_def_cfa_offset 5
15
  .cfi_offset 29, -4
16
/* prologue: function */
17
/* frame size = 0 */
18
/* stack size = 2 */
19
.L__stack_usage = 2
20
  movw r28,r20
21
.LVL29:
22
  .loc 1 526 0
23
  ldi r18,lo8(39)
24
  mov r20,r22
25
.LVL30:
26
  ldi r22,lo8(1)
27
.LVL31:
28
  call writeI2CByte
29
.LVL32:
30
  .loc 1 528 0
31
  movw r20,r28
32
  lsl r20
33
  rol r21
34
.LVL33:
35
.L45:
36
  .loc 1 528 0 is_stmt 0 discriminator 1
37
  cp r20,__zero_reg__
38
  cpc r21,__zero_reg__
39
  breq .L49
40
  .loc 1 529 0 is_stmt 1
41
  lds r25,132
42
.LVL34:
43
.L46:
44
  .loc 1 530 0 discriminator 1
45
  lds r24,132
46
  cpse r25,r24
47
  rjmp .L50
48
  .loc 1 531 0
49
/* #APP */
50
 ;  531 "../c_display.c" 1
51
  wdr
52
 ;  0 "" 2
53
/* #NOAPP */
54
  rjmp .L46
55
.L50:
56
  .loc 1 528 0
57
  subi r20,1
58
  sbc r21,__zero_reg__
59
.LVL35:
60
  rjmp .L45
61
.LVL36:
62
.L49:
63
/* epilogue start */
64
  .loc 1 534 0
65
  pop r29
66
  pop r28
67
.LVL37:
68
  ret

Ich habe nun mal testweise iLoop "volatile" deklariert, obwohl das doch 
eigentlich bei einer lokalen Variable wenig Sinn macht. Damit funzt es 
aber bei Opt=s
Persönliche Seite #3887389
Lesenswert?

Das sagt garnix, das ergibt nämlich komplett anderen Code.  Ohne .i File 
kann man nur raten; den Assembler Code könnte man sich daraus nämlich 
erzeugen und mit der Quelle gegenlesen.

Auf die Schnelle seh ich keinen großen Unterschied, außer dass mit -Os 
zero_reg verwendet wird.  Vielleicht ist das nicht 0?

Und der Code bis zum writeI2CByte ist doch der gleiche, oder seh ich das 
falsch?
Gast #3887515
Lesenswert?

Hanns-Jürgen M. schrieb:

> Seltsam ist, daß dieselbe Routinen natürlich auch in der
> Initialiserungsphase des Systems verwendet wird, bei dem ebenfalls
> Displayausgaben korrekt erfolgten.

> while (bTimeOld == TCNT1L) {

Solch ein Vergleich sollte absolut tabu sein. Da muß nur ein passender 
Interrupt kommen, und der Vergleich mit TCNT1L scheitert zuhauf. Wenn 
man Timer nimmt, dann ist es besser ein OCx-Register zu verwenden und 
das betreffende Flag abzufragen, ob der 'compare' stattgefunden hat.

Sind während der Initialisierung schon alle Interrupts aktiv, oder 
werden diese erst anschließend zugeschaltet?

Fehler beim Schreiben auf LCDs treten in der Regel auf, wenn das Timing 
zu schnell eingestellt ist. Mein Vorschlag ist, den Schreibimpuls 
großzügig zu verzögern.
#3887517
Lesenswert?

Johann L. schrieb:
> Das sagt garnix, das ergibt nämlich komplett anderen Code.  Ohne .i File
> kann man nur raten; den Assembler Code könnte man sich daraus nämlich
> erzeugen und mit der Quelle gegenlesen.
>
Die i-Files sind ziemlich groß, was ist darin von Belang?

> Auf die Schnelle seh ich keinen großen Unterschied, außer dass mit -Os
> zero_reg verwendet wird.  Vielleicht ist das nicht 0?
>



> Und der Code bis zum writeI2CByte ist doch der gleiche, oder seh ich das
> falsch?

Yepp.
#3887740
Lesenswert?

@m.n.

nach dem Systemreset werden bei mir zunächst die Ports initialisiert und 
danach das Timing.System, da das für Zeitschleifen etc benötigt wird.

Geschwindigkeit der LCD-Beschreibung: Ja, ganeu, das wird das Problem 
sein. Aber dieses Problem tritt in der Initialisierungsphase der 
Peripherie (GSM-Modem, PIR-Sensoren, Temp Sensor), bei der die 
Grund-Initialisierung länghst abgeschlossen ist, nicht auf, dort 
erfolgen die Systemmeldungen einwandfrei auf dem LCD. Und alles 
reproduzierbar,
Persönliche Seite #3887748
Lesenswert?

Hanns-Jürgen M. schrieb:
> Johann L. schrieb:
>> Das sagt garnix, das ergibt nämlich komplett anderen Code.  Ohne .i File
>> kann man nur raten; den Assembler Code könnte man sich daraus nämlich
>> erzeugen und mit der Quelle gegenlesen.
>>
> Die i-Files sind ziemlich groß, was ist darin von Belang?

Alles.  Zusammen mit der Compilerausgabe mit -v.  Zumindest wenn man 
sicherstellenn will, dass der Compiler korrekten Code erzeugt hat -- wie 
soll man das ohne Quelle und Optionen und Compilerversion sonst 
anstellen?  Dass es sich bei writeI2CByte nicht um ein riesiges Makro 
handelt oder um eine Funktion, die geinlinet wird, erkennt man hier nur 
am erzeugten Code.  Und des Typ von iLoop kann auch nur geraten werden.

Nicht dass ich dir jetzt alle Infos häppchenweise aus der Nase ziehen 
will, sonder dies nur als Beispiel für zwei Dinge, die für dich 
sonnenklar sind, anderen aber völlig unbekannt sind und von denen, die 
sich mit so einem Puzzle beschäftigen und dir helfen wollen, geraten 
werden müssen.

Aus der Ferne betrachtet scheint es sich jedenfalls nicht um einen 
Compilerfehler wie die oben erwähnten PRs zu handeln, zumindest nicht 
für das von dir gepostete Assembler-Schnippel.

Damit geht es dir zwar wie 99.9 % der Anwender, die nicht für sich 
verbuchen können einen Compilerfehler gefunden zu haben, aber immerhin 
hast du es damit selbst in der Hand den Code zu korrigieren.

Es gibt ja schon genug Anmerkungen zum Code selbst; z.B. ist auch unklar 
ob er in einer ISR läuft oder nicht.  Falls er nämlich in einer ISR 
läuft und auf main-Ebene TCNT1 gelesen wird, liest man aus TCNT1H bzw. 
dessen Latch gerne mal Schrott aus.

Und übrigens kann es immer noch sein dass der Fehler woanders ist und 
eben nicht im gezeigten Quellschnipsel, etwa weil das Timing komplett 
anders ist.  Oder die Funktion wird mit -O2 geinlint und der erzeugte 
Code für -O2 so überhaupt nicht verwendet, sondern nur mit -Os.  Keiner 
weiß es...
#3887765
Lesenswert?

@Jörg

Ich habe keine Funktionen als "Inline" deklariert. Innerhalb der 
betreffenden Funktion ist der Watchdog-Reset ein asm Macro, aber das 
dürfte hier irrelevant sein.

Nun die i-File teile,

zunächst Opt=2
1
......
2

3
#pragma GCC optimize ("O2")
4
void writeI2C_LCDByte (uint8_t RS, uint8_t printchar,uint16_t j)
5
{
6
 uint8_t bTimeOld = 0;
7
 uint8_t LED = 1;
8

9
 uint16_t iLoop;
10
 writeI2CByte(RS, LED, printchar,0x27);
11

12
 for (iLoop = j*2;iLoop != 0;iLoop--) {
13
  bTimeOld = (*(volatile uint8_t *)(0x84));
14
  while (bTimeOld == (*(volatile uint8_t *)(0x84))) {
15
   __asm__ __volatile__ ("wdr");
16
  }
17
 }
18
}
19

20
#pragma GCC optimize ("Os")
21
....

und hier Opt=s
1
......
2

3
void writeI2C_LCDByte (uint8_t RS, uint8_t printchar,uint16_t j)
4
{
5
 uint8_t bTimeOld = 0;
6
 uint8_t LED = 1;
7

8
 uint16_t iLoop;
9
 writeI2CByte(RS, LED, printchar,0x27);
10

11
 for (iLoop = j*2;iLoop != 0;iLoop--) {
12
  bTimeOld = (*(volatile uint8_t *)(0x84));
13
  while (bTimeOld == (*(volatile uint8_t *)(0x84))) {
14
   __asm__ __volatile__ ("wdr");
15
  }
16
 }
17
}
18
.....
Und Opt=s aber mit volatile - iLoop

1
void writeI2C_LCDByte (uint8_t RS, uint8_t printchar,uint16_t j)
2
{
3
 uint8_t bTimeOld = 0;
4
 uint8_t LED = 1;
5
 volatile uint16_t iLoop;
6

7
 writeI2CByte(RS, LED, printchar,0x27);
8

9
 for (iLoop = j*2;iLoop != 0;iLoop--) {
10
  bTimeOld = (*(volatile uint8_t *)(0x84));
11
  while (bTimeOld == (*(volatile uint8_t *)(0x84))) {
12
   __asm__ __volatile__ ("wdr");
13
  }
14
 }
15
}

Ich sehe da keine bedeutenden Unterschiede.

Wäre das makefile interessant? Ich muß gestehen, daß ich dieses bei 
meinen ersten "Spielereien" mit dem AVR-Studio 4. irgendwas habe 
exportieren lassen, und bei dem ich danach nur die Filenamen ergänzt 
bzw. entfernt habe...
#3887851
Lesenswert?

Ich setze andere Ansprüche an Routinen als dieses bekannte LCD Library. 
Als erstes muss sie kompatibel zu allen meinen früheren Projekten sein. 
Dazu gehört die per bedingte Kompilation uneingeschränkte Verwendbarkeit 
mit 8-bit, 4-bit, SPI (MEINE Norm), Soft-I2C und Hard-I2C/TWI 
Schnittstellen.


Weiterhin sind zusätzlich eigene Funktionen vorhanden.

Vorgefertigten Algorithmen gegenüber stehe ich ohnehin kritisch 
gegenüber, da sie i.d.R. kaum meinen Vorgaben entsprechen sonder auch, 
wenn auch äußerst selten, Fehler beinhalten. Das trifft z.B. auf CRC16.h 
zu, das ich modifiziert und zusätzlich ein wenig beschleunigt habe. Ich 
habe das damals hier hochgeladen. Ist schon eine Weile her.

Ergänzung: Meine "LCD-Library"-Funktionen habe ich vor vielen vielen 
Jahren, zunächst noch in Assembler für einen 6809 und für ein anderes 
Display entworfen. Später erfolgte die Überarbeitung für diese 
HD-Controller in Assembler für einen HC11 und HC16, später portierte ich 
nach C.
Moderator Persönliche Seite #3887926
Lesenswert?

Hanns-Jürgen M. schrieb:
> Ich habe keine Funktionen als "Inline" deklariert.

Hat nichts zu sagen, der Compiler kann inlinen, was er gern möchte.

Hanns-Jürgen M. schrieb:
> Vorgefertigten Algorithmen gegenüber stehe ich ohnehin kritisch
> gegenüber, da sie i.d.R. kaum meinen Vorgaben entsprechen sonder auch,
> wenn auch äußerst selten, Fehler beinhalten.

Ach, und dein Code ist fehlerfrei? ;-)

> Das trifft z.B. auf CRC16.h
> zu, das ich modifiziert und zusätzlich ein wenig beschleunigt habe.

Wenn es in der Tat Fehler hatte, dann fehlt da ein Bugreport dafür.
(Heißt übrigens crc16.h, die avr-libc-Dateinamen werden alle klein
geschrieben.  Spielt bei portablem Code durchaus eine Rolle.)

Auch, wenn es eine sichere Optimierung bei Beibehaltung der exakten
Funktion gibt, wäre ein Bugreport (als Enhancement request) bei avr-libc
durchaus sinnvoll.

Wenn es natürlich nur deine private Erweiterung ist, dann isses egal.
Gast #3888531
Lesenswert?

Hanns-Jürgen M. schrieb:
> Aber dieses Problem tritt in der Initialisierungsphase der
> Peripherie (GSM-Modem, PIR-Sensoren, Temp Sensor), bei der die
> Grund-Initialisierung länghst abgeschlossen ist, nicht auf,

Dann würde ich vermuten, dass die IIC-Übertragung nicht sauber läuft und 
daher falche Daten am LCD landen.
Miss doch einfach mal das Timing mit dem Oskar.

Hanns-Jürgen M. schrieb:
> Und alles
> reproduzierbar,

Das sind doch paradiesische Zustände ;-)
Moderator Persönliche Seite #3888728
Lesenswert?

Hanns-Jürgen M. schrieb:
> Dazu hatte ich hier Anfang 2012 folgendes gepostet, mit "meiner"
> Änderung:

Naja, einen Bugreport bräuchten wir schon hier:

https://savannah.nongnu.org/bugs/?group=avr-libc

damit auch die avr-libc-Entwickler das sehen können.

Allerdings fürchte ich, dass das einer der üblichen Non-Bugs ist,
die aus den diversen Verwirrungen um die CRCs entstehen (Reihenfolge
der Bits in den Daten, Reihenfolge der Bits im Polynom, welcher
Startwert wird benutzt).

Für den CCITT-Algorithmus jedenfalls habe ich mir anlässlich eines
früheren Bugreports mal die Mühe gemacht, die Originalbeschreibung
in den entsprechenden CCITT-Dokumenten zu suchen und gegen den dort
vorhandenen Testvektor zu testen.
#3888898
Lesenswert?

@Jörg

Ja, ich sehe gerade, daß Du in der Datei crc16.h als Mitautor gelistet 
bist.

Es ist schon lange her, daß ioch mich damit beschäftigt habe. 2012 
wollte ich mein Busprotokoll von einer 16bit Checksum auf auf CRC16 gem. 
CCITT (RFC1171) umstellen. Startwert: 0xFFFF. Meine Erinnerung ist etwas 
verblaßt, auch habe ich es nicht richtig dokumentiert.  Das wird wohl 
kaum für einen "anständigen" Bugreport reichen. Es war, wie ich jetzt im 
Nachhinein sagen muß, auch kein "Bug" sondern eher ein "Vertauschen" der 
Bezeichnungen.

Nur folgendes: nach meinen rudimentären Aufzeichnungen und ebensolchen 
Erinnerungen: Die CRC16-Implementierung lieferte das falsche, jedoch die 
CRC-XMODEM Implementierung das richtige Ergebnis. Danach habe ich mich 
aus Spaß an der Freude daran gemacht, die ASM Implementierung zu 
modifizieren. Das Ergebnis hatte ich hier (siehe obigen Link) gepostet.

Wörtlich hatte ich in meiner SW dokumentiert (Mit Tippfehler...):
ZITAT
//  Uebrelegung, ob die Chgecksum des MHA Protolls nicht durch CRC.gem. 
CCITT
//  RFC1171 implementiert werden soll..
//  CRC funzt, aber mit der XMODEM-Routine... Mal die Ursache sucghen 
(10.2.2012)..
//  so, habe auf Basis der C / VB Routine eine neu ASM Routine fertig. 
funzt. 12.2.2012 stolz bin...
/ZITAT

Das jüngste Copyright in der Ori-crc16 war Deines von 2007. Ich sehe 
gerade, die neueren crc16 haben Copyrighteinträge von 2013.

VG yogy
Moderator Persönliche Seite #3888953
Lesenswert?

Hanns-Jürgen M. schrieb:
> Die CRC16-Implementierung lieferte das falsche, jedoch die CRC-XMODEM
> Implementierung das richtige Ergebnis.

Typischer Fall für vertauschte Bits.

Dazu muss man wissen, dass so gut wie alle Kommunikationsprotokolle
(mit Ausnahme von USB, wenn ich mich recht entsinne) mit dem
niederwertigen Bit in der Ausgabe anfangen.  Daher findet man in
den entsprechenden Niederschriften dann die Bitreihenfolge auch
so herum dargestellt, was unserer „natürlichen“ Leseweise jedoch
zuwider ist, da wir das höchstwertige Bit ganz links schreiben
würden.

Ich kann dir versichern, dass die CCITT-CRC-Implementierung der
avr-libc sowohl direkt als auch als C-Code (den angegebenen
Pseudo-C-Code in richtiges C überführt, für den IAR-Compiler) bereits
erfolgreich in Atmels IEEE-802.15.4-Implemetierung benutzt worden ist.

Hier der Testvektor aus IEEE 802.15.4:
1
As an example, consider an acknowledgment frame with no payload and
2
the following 3 byte MHR:
3

4
  0100 0000 0000 0000 0101 0110        [leftmost bit (b0) transmitted first in time]
5
  b0..........................b23
6

7
The FCS for this case would be the following:
8

9
  0010 0111 1001 1110                  [leftmost bit (r0) transmitted first in time]
10
  r0................r15

In hexadezimalen Zahlen ist das: 0x02 0x00 0x6A, CRC 0xe4 0x79.

Hier nochmal als C-Code:
1
#include <stdint.h>
2
#include <stdio.h>
3

4
#define hi8(x) (((x) >> 8) & 0xff)
5
#define lo8(x) ((x) & 0xff)
6

7
uint16_t
8
crc_ccitt_update (uint16_t crc, uint8_t data)
9
{
10
    data ^= lo8 (crc);
11
    data ^= data << 4;
12

13
    return ((((uint16_t)data << 8) | hi8 (crc)) ^ (uint8_t)(data >> 4)
14
            ^ ((uint16_t)data << 3));
15
}
16

17
int
18
main(void)
19
{
20
    uint8_t data[] = { 0x02, 0x00, 0x6A };
21
    uint16_t crc = 0;
22

23
    for (int i = 0; i < 3; i++)
24
        crc = crc_ccitt_update(crc, data[i]);
25
    printf("CRC = 0x%04x\n", crc);
26
    return 0;
27
}

Ausgabe:
1
$ ./crc16
2
CRC = 0x79e4

oder eben in einzelnen Bytes 0xe4 0x79.
#3889148
Lesenswert?

@Jörg

Danke für Deine ausführliche Antwort. Na klar, bei mir ist das LSB 
rechts- und das MSB linksaussen. (Und alle Bytes sind bei mir in 
Motorola-Anordnung.) Leider hat mir 2012 bei meiner Frage hier im Forum 
niemand die Schuppen von den Augen entfernt.. Auch die Suche damals im 
Internet brachte nicht den richtigen Hinweis.

Das gibt dann wieder ein TODO für mich. Auch wenn es so aktuell bei mir 
funzt, so will ich mich doch lieber an die "Norm" halten. Der Winter 
wird zunehmend arbeitsreich...
Persönliche Seite #3889331
Lesenswert?

Jörg Wunsch schrieb:
> Auch, wenn es eine sichere Optimierung bei Beibehaltung der exakten
> Funktion gibt,

Da hat jemand mit der Geißkanne volatile spendiert, d.h. keins der asm 
brauch volatile zu sein; die Funktionen sind sogar const, d.h.
1
__attribute__((__const__))

Was ist eigentlich der Grund für das inline? Die Annahme, dass 
Geschwindigkeit klar vordringlich ist und der Code nicht öfter als 1x 
pro Applikation verwendet wird?  Wäre zumindest plausibel.  Zu erwägen 
ist dann auch
1
__attribute__((__always_inline__))
Persönliche Seite #3889414
Lesenswert?

Hanns-Jürgen M. schrieb:
> Wäre das makefile interessant?

Hast du Probleme mit dem Makefile?

> Nun die i-File teile,

Teile? TEILE? Was soll man mit bitte mit TEILEN anfangen???

> Ich sehe da keine bedeutenden Unterschiede.

Warum sollten da Unterschiede sein? Die gäb es bestenfalls mit
1
#ifdef __OPTIMIZE_SIZE__

Der Sinn davon wäre gewesen, weil in 95 % der Fälle der Fehler in 
Sequenzen steckt wie der da:
1
>
2
> ......
3
>

Hat aber wohl keinen Zweck sich hier weiter die Finger fusselisch zu 
tippen...
Moderator Persönliche Seite #3889599
Lesenswert?

Johann L. schrieb:

> Da hat jemand mit der Geißkanne volatile spendiert, ...

Das Wissen, wann ein asm statement ein "volatile" braucht, ist noch
nicht so sehr verbreitet.

Würdest du als Erinnerung einen Bugreport schreiben für diese Dinge?
Im Moment komme ich gerade nicht dazu.

> Was ist eigentlich der Grund für das inline?

War halt schon immer so. :-/

Wenn man es nicht inline machen würde, müsste man es als reguläre
Funktionen in separate Sourcecodedateien verfrachten, statt die
Implementierung im Headerfile zu haben.

In der Tat ist die Implementierung ja nicht ganz klein.

Was sagt dein „Bauchgefühl“, erscheint es sinnvoller, das als
reguläre Funktion zu realisieren?  Das bisschen call/ret macht ja dann
das Kraut auch nicht fett.

Hanns-Jürgen M. schrieb:
> Das Thema ist längst durch.

Was denn, hast du die Ursache deines Problems finden können?  Klang
mir bislang ja noch nicht so, du hast doch nur einen Hack gefunden,
der sich beim nächsten Compilerwechsel genausogut wieder in Luft
auflösen kann.
#3890123
Lesenswert?

@Jörg....

Zunächst reicht mir der Hack. Sobald ich meinen Oszi endlich reparaiert 
habe, werde ich das Timing des LCDs checken.

Aktuell habe ich ein wenig Zeit und ich teste die CRC-Korrektur.

Dann plane ich, das Testsystem soweit softwaremäßig abzuspecken, um den 
vermeintlichen Fehler eingrenzen zu können.

In diesem Zusammenhang fällt mir ein Problem ein, daß ich zu Beginn 
meiner AVR/GCC "Bastelei" hatte. Ich mußte in der Hauptprogrammschleife 
einen völlig sinnfreien Befehl / Functioncall einbauen, damit die SW 
lief. Mal sehen, ob ich noch eine alte Datensicherung mit diesem Problem 
finde. Ich habe das damals einfach ignoriert ("ist halt so").

Zu gegebener zeit melde ich mich wieder in diesem Thread.

VG Yogy
#3890144
Lesenswert?

Hanns-Jürgen M. schrieb:
> Ich mußte in der Hauptprogrammschleife
> einen völlig sinnfreien Befehl / Functioncall einbauen, damit die SW
> lief.

Dann war der Befehl wohl doch nicht so sinnfrei ;)

Wenn deine AVR-Basteleien schon vor mehr als 10 Jahren begannen, dann 
mag das so gewesen sein. Auch heute noch findet man z.B Code im Netz, 
der in einer ansonsten leeren while-Hauptprogrammschleife ein "nop" 
ausführt. Ob das jemals erforderlich war, oder schon damals nur aus 
falschen Symptom-Fixing entstanden ist und dann als urban legend 
weiterlebte, keine Ahnung.

Selbst hier im Tutorial hält sich hartnäckig ein überflüssiger 
dummy-Read beim ADC-Auslesen, und wird fleißig in vielen Anwendungen 
eingesetzt.

Oliver
#3890182
Lesenswert?

@Oliver S. (oliverso)

>Selbst hier im Tutorial hält sich hartnäckig ein überflüssiger
>dummy-Read beim ADC-Auslesen,

Wo denn genau?

Eine EINMALIGER Dummy-Read ist nach der Initialisierung bzw. Umschalten 
der Referenzspannung nötig.

Datenblatt vom ATmega 48/88/168

"22.5.2 ADC Voltage Reference

If no external voltage is applied to the AREF pin, the user may switch 
between AVCC and 1.1V as reference selection. The first ADC conversion 
result after switching reference voltage source may be inaccurate, and 
the user is advised to discard this result."

> und wird fleißig in vielen Anwendungen eingesetzt.

Dass einige Leute nicht mal gescheites Copy & Paste hinkriegen, ist ein 
anderes Problem.
#3890330
Lesenswert?

Falk Brunner schrieb:
> Eine EINMALIGER Dummy-Read ist nach der Initialisierung bzw. Umschalten
> der Referenzspannung nötig.

Er ist (meistens) nur nach einem Umschalten der Referenzspannung 
erforderlich. Der erste Wandlungszyklus nach einer Initialisierung 
dauert ja extra deshalb länger, um dem Analogteil Zeit zum 
"Einschwingen" zu geben.

Aber:

>When the bandgap reference voltage is used as input to the ADC, it will take a 
>certain time for the voltage to stabilize.
>If not stabilized, the first value read after the first conversion may >be wrong.

Da ist dann doch wieder ein Dummy-Read erforderlich.


Oliver
#3890652
Lesenswert?

So, das ursprüngliche Problem ist gelöst bzw. ich habe die Ursache 
gefunden, indem ich die SW Stück für Stück auskomentiert habe.

Nach der Initialisierung der Peripherie und den zugehörigen 
funktionierenden Bildschirmausgaben erfolgte eine clearscreen, der 
bekanntlich bei dem HD-Controller etwas dauert als Cursorsetzen oder 
Zeichen ausgeben. Kurze Zeit später (im unteren ms Bereich) erfolgte 
dann die erste Ausgabe.

Durch die Optimierung war offenbar die eingestellte Wartzeit zur 
Laufzeit dann zu kurz für die Ausführung des Clearscreen. Diese Wartzeit 
war gerade im hier vorliegenden Hard- TWI-Betriebsmode fest vorgegeben, 
das war dann zu knapp. Ich habe sie nun wie bei den anderen Anschlußmodi 
variabel gemacht.

Also mein Fehler.

Das Problem ist damit gefunden und behoben.
Persönliche Seite #3890893
Lesenswert?

Hanns-Jürgen M. schrieb:
> Nach der Initialisierung der Peripherie [...]

Sag ich doch ;-)

Johann L. schrieb:
> [...] weil in 95 % der Fälle der Fehler in Sequenzen
> steckt wie der da:
1
>>
2
>> ......
3
>>


Jörg Wunsch schrieb:
> Johann L. schrieb:

>> Was ist eigentlich der Grund für das inline?
>
> War halt schon immer so. :-/
>
> Wenn man es nicht inline machen würde, müsste man es als reguläre
> Funktionen in separate Sourcecodedateien verfrachten, statt die
> Implementierung im Headerfile zu haben.

Oder als transparente Funktion; wär zwar effizienter aber hier der 
Overkill.

> In der Tat ist die Implementierung ja nicht ganz klein.
>
> Was sagt dein „Bauchgefühl“, erscheint es sinnvoller, das als
> reguläre Funktion zu realisieren?  Das bisschen call/ret macht ja dann
> das Kraut auch nicht fett.

CRC hab ich noch nie gebraucht; ich würd aber schätzen dass es nur in 
wenigen Stellen im Code gebraucht wird; mit "wenig = 1" in 95% der 
Fälle.

Falls dir die Leute deswegen nicht die Tür einrennen mit Bugreports, 
würd ich da keine Zeit reinstecken.  Außerdem kann jeder, der liber ne 
Funktion hätte, das Inline-Zeugs in eine Wrapper-Funktion packen und hat 
damit eine normale Funktion.  Mit einer Implementierung in der Lib ist 
das umgekehrte aber nicht möglich.

>> Da hat jemand mit der Geißkanne volatile spendiert, ...
>
> Das Wissen, wann ein asm statement ein "volatile" braucht, ist noch
> nicht so sehr verbreitet.
>
> Würdest du als Erinnerung einen Bugreport schreiben für diese Dinge?

Auch da würd ich keine Zeit reinstecken.

Auch wenn es korrekt wäre, so ein asm über einen davon unabhängigen 
volatile Zugriff oder ein anderes asm zu ziehen, kann es wünschenswert 
sein, das asm auf einer Bestimmten Seite eines SFR-Zugriffs stehen zu 
haben.  Macht zwar keinen Unterschied von der Semantik, kann aber wohl 
einen Unterschied für Timing bedeuten.

Mit volatile hat man also bessere Kontrolle über die Position des asm im 
Code, und das weiß der Programmierer i.d.R. besser als der Compiler.  Es 
gibt also auch Argumente für volatile.

Und wenn jemand so eine Funktion einsetzt und die Ergebnisse nicht 
verwendet dann ist er selber Schuld.  Soll er seinen Code aufräumen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren