Forum: Compiler & IDEs Downgrade von ATMEL Studio 6.2 auf 6.0 wg GCC Fehler?


von Hanns-Jürgen M. (yogy)


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

von Maik (Gast)


Lesenswert?

http://www.atmel.com/tools/STUDIOARCHIVE.aspx

Ich nutze das Studio aktuell nicht, aber kurze auf Atmel.com ein paar 
Klicks.

von Falk B. (falk)


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.

von Hanns-Jürgen M. (yogy)


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....

von Johann L. (gjlayde) Benutzerseite


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.

von Falk B. (falk)


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.

von Hanns-Jürgen M. (yogy)


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...

von Falk B. (falk)


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.

von Oliver (Gast)


Lesenswert?

Falk Brunner schrieb:
> 99% der Fehler liegen am
> Programmierer und nicht am Compiler.

In diesem Fall werden es 100% sein.

Oliver

von Hanns-Jürgen M. (yogy)


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.

von Hanns-Jürgen M. (yogy)


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.

von Falk B. (falk)


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.

von Falk B. (falk)


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?

von Motek (Gast)


Lesenswert?

> 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?

Was ist dein Wetteinsatz?

von Johann L. (gjlayde) Benutzerseite


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...

von Bernd K. (prof7bit)


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.

von Frank K. (fchk)


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.

von Hanns-Jürgen M. (yogy)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


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.

von Hanns-Jürgen M. (yogy)


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...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Gibe es das auch übersetzbar?  Also mit -save-temps und

1) Compilerausgabe mit -v sowie
2) Präprozessierte Quelle, also .i Datei

Dann kann man es nachvollziehen was passiert.  Es gibt nämlich auch 
PR60486 und PR61055 die drauf passen könnten :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.)

von Peter II (Gast)


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.

von Hanns-Jürgen M. (yogy)


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

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


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?

von m.n. (Gast)


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.

von Peter II (Gast)


Lesenswert?

m.n. schrieb:
> Solch ein Vergleich sollte absolut tabu sein. Da muß nur ein passender
> Interrupt kommen, und der Vergleich mit TCNT1L scheitert zuhauf

genau das soll doch aber passieren. Es will damit nur eine delay 
nachbauen.

von Hanns-Jürgen M. (yogy)


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hanns-Jürgen M. schrieb:
> Die i-Files sind ziemlich groß, was ist darin von Belang?

Die aktuelle Funktion.  Zusätzlich natürlich noch die Frage, ob das
eventuell irgendwo inline expandiert worden ist.

von Hanns-Jürgen M. (yogy)


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,

von Johann L. (gjlayde) Benutzerseite


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...

: Bearbeitet durch User
von Hanns-Jürgen M. (yogy)


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...

von Falk B. (falk)


Lesenswert?

Was auch immer die exakte Ursache ist, allgemein kann man wiohl sagen, 
dass ohne Not ziemlich umständlich und fehlerträchtig eine einfache 
Funktion umgesetzt wurde. Naja. 8-0

von Falk B. (falk)


Lesenswert?

Beitrag "Re: I2CLCD Library für HD44780 LCDs"

Dort sind keinerlei Tricks drin, im Gegenteil, sämtliche Unsauberkeiten 
des Originals wurden wohlweislich entfernt. Und damit kommt man auch auf 
mehrere hundert Zeichen/s Schreibgeschwindigkeit. Reicht für einfache 
LCDs locker.

von Hanns-Jürgen M. (yogy)


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.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von m.n. (Gast)


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 ;-)

von Hanns-Jürgen M. (yogy)


Lesenswert?

>
> 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.
>

Leider ist mein Oskar immer noch kaputt, sonst hätte ich das ale erstes 
getan...

von Hanns-Jürgen M. (yogy)


Lesenswert?

@Jörg

Natürlich ist mein Code auch nicht zwangsweise fehlerfrei. :-)

Ergänzung zur crc16.h (Kleingeschrieben :-)

Dazu hatte ich hier Anfang 2012 folgendes gepostet, mit "meiner" 
Änderung:

Beitrag "CRC16 nach CCITT auf AVR mit crc16.h probs"

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Hanns-Jürgen M. (yogy)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Hanns-Jürgen M. (yogy)


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...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hanns-Jürgen M. schrieb:
> Leider hat mir 2012 bei meiner Frage hier im Forum niemand die Schuppen
> von den Augen entfernt.

Vermutlich ist mir sie damals nicht untergekommen, sonst hätte ich dir
das schreiben können.  Ich habe mir da schon früher das Gehirn mal
dran verrenkt. ;-)

von Hanns-Jürgen M. (yogy)


Lesenswert?

:-)

von Johann L. (gjlayde) Benutzerseite


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__))

von Johann L. (gjlayde) Benutzerseite


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...

von Hanns-Jürgen M. (yogy)


Lesenswert?

Nein, ICH habe keine Probleme mit dem makefile. Und schreibe Dir bitte 
nicht weiter die Finger blutig. Das Thema ist längst durch.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Hanns-Jürgen M. (yogy)


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

von Oliver S. (oliverso)


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

von Hanns-Jürgen M. (yogy)


Lesenswert?

Ich habe erst 2010 mit dem AVR-Studio und den ATmegas angefangen.

von Falk B. (falk)


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.

von Hanns-Jürgen M. (yogy)


Lesenswert?

@Jörg

Danke nochmals wegen der CRC-Information. Ich habe das soeben bei mir 
korrigiert, ging ganz schnell und problemlos.

Viele Grüße

Yogy

von Oliver S. (oliverso)


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

von Oliver S. (oliverso)


Lesenswert?

Hanns-Jürgen M. schrieb:
> Ich habe erst 2010 mit dem AVR-Studio und den ATmegas angefangen.

Die Versionen funktionierten auch ohne "sinnfreie" Befehle.

Oliver

von Hanns-Jürgen M. (yogy)


Lesenswert?

Oliver S. schrieb:
> Hanns-Jürgen M. schrieb:
>> Ich habe erst 2010 mit dem AVR-Studio und den ATmegas angefangen.
>
> Die Versionen funktionierten auch ohne "sinnfreie" Befehle.
>
> Oliver

Mag sein, ich habe mich damals nicht weiter darum gekümmert.

von Hanns-Jürgen M. (yogy)


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.

von Johann L. (gjlayde) Benutzerseite


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

:-)

OK, überzeugt, ich lass es, wie es ist.

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.