PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Hat jemand eine Idee bevor ich verzweifel?



RolfD
13.05.2014, 23:35
Bei folgendem Code.. und c=0x00;


#define LCD_LL 0x0f

static uint8_t lcd_cpos;
static uint8_t lcd_line;
c=0x00;
lcd_line = 0x00;
lcd_cpos = (c - (lcd_line * LCD_LL));


Kommt bei mir in lcd_cpos immer 1 raus.. obwohl es 0 sein muss.
Bei (lcd_line * LCD_LL) müsste es sich zu 0 x 15 also 0 berechnen was es nicht tut und bei c=0 dann 0 - (0 x 15) = 0 !!! nicht 1
Erst hab ich gedacht, es liegt am casting weil c ein typ char ist und hab alles mit (uint8_t) versehen aber es ändert sich nichts.
Es werden auch keine Bereichsgrenzen überschritten, keine Division durch 0.. oder sonstiger Unfug...

Ist der Compiler defekt?
Ich habs unter Amtel Studio 6.1 2730 SP2 im Sim laufen lassen und da kommt auch 1 raus. CPU Defekt ist damit auszuschließen.
Da dieser Machinecode simuliert, scheint ja der Code nicht ok zu sein... hier mal eine Ausgabe mit -O0



596: c=0x00;
000008A1 STD Y+2,R1 Store indirect with displacement
597: lcd_line=0x00;
000008A2 STS 0x00BF,R1 Store direct to data space
599: lcd_cpos = (c - (lcd_line * LCD_LL));
000008A4 LDS R25,0x00BF Load direct from data space
000008A6 LDI R24,0xF0 Load immediate
000008A7 MUL R25,R24 Multiply unsigned
000008A8 MOV R25,R0 Copy register
000008A9 CLR R1 Clear Register
000008AA LDD R24,Y+2 Load indirect with displacement
000008AB ADD R24,R25 Add without carry
000008AC SUBI R24,0xFF Subtract immediate
000008AD STS 0x00BE,R24 Store direct to data space


Und nu mit -O1



597: lcd_line=0x00;
00000257 STS 0x00BF,R1 Store direct to data space
599: lcd_cpos = (c - (lcd_line * LCD_LL));
00000259 LDI R24,0x01 Load immediate
0000025A STS 0x00BE,R24 Store direct to data space


In beiden Fällen kommt 1 raus, im letzten lädt er die 1 sogar einfach nur ins R24 und schreibt sie weg.
Das er beim Optimierungslauf mit O1 die Multiplikation mal eben weg spart kann ich mir ja noch erklären - aber das er das mit einer 1 ersetzt.. nicht!

Angaben zur Toolchain:
Installed Packages: Atmel AVR (8 bit) GNU Toolchain Snapshot - 3.4.2.1000
AVR Toolchain 8 Bit
Version: AVR8_Toolchain_Version:3.4.2.974 GCC_VERSION:4.7.2
Package GUID: 01BAAEB9-EC97-4398-95D1-633DB220CD77
Company: Atmel
HelpUrl:
Release Description: AVR Toolchain For 8-Bit Devices

Falls das wirklich ein Compilerfehler ist, dürfte das mehr Leute betreffen... und nicht nur RP6ler..
Ich wollte es morgen mal mit der recht neuen 6.2 Studio Beta probieren.. in der Hoffnung, das da eine neuere Toolchain mit bei ist.

Ich verstehs aber trotzdem nicht. HILFÄÄÄÄÄ


(die 3.4.3 Toolchain, welche bei Atmel angeboten wird, ändert auch nichts daran... grade noch probiert...)
Gruß

Klebwax
14.05.2014, 02:29
Bei folgendem Code.. und c=0x00;


#define LCD_LL 0x0f

static uint8_t lcd_cpos;
static uint8_t lcd_line;
c=0x00;
lcd_line = 0x00;
lcd_cpos = (c - (lcd_line * LCD_LL));


Kommt bei mir in lcd_cpos immer 1 raus.. obwohl es 0 sein muss.

Ist der Compiler defekt?
Mit Sicherheit nicht. Ein Compiler, bei dem die Integer-Multiplikation nicht funktioniert, kommt nicht durch die automatischen Regressionstests. Da braucht man nicht den Assemblercode anzuschauen. Ist Zeitverschwendung.

Wenn ich der Compiler wäre, würde ich den ganzen gezeigten Code wegoptimieren. lcd_cpos wird zwar berechnet aber nie verwendet, also braucht es nicht berechnet zu werden. Außerdem ist alles außerhalb jeder Funktion und wird daher nie ausgeführt.

Oder ernsthaft: zeig mehr von deinem Code, am besten auch die Zeile, in der der Fehler steckt;).

MfG Klebwax

RolfD
14.05.2014, 05:52
@Klebwax
Also im Prinzip stimme ich Dir ja zu... insbesondere die Aussage zu den Regressionstests.. aber Du kannst mir schon zutrauen, das ich das nicht in der Luft freihängend teste...
Der Code sieht zum testen grade so aus:


int16_t lcd_putchar(char c)
{
static bool nl_seen;
static bool cursor_seen;
uint8_t i;

if (cursor_seen) { // erstes Zeichen nach \v, Cursorposition also \v%c
//if (c <= LCD_LL) lcd_line=0;
c=0x00;
lcd_line=0x00;
//else lcd_line = c % LCD_LL; //aus kumulierter Cursorpos Zeile und Spalte berechnen
lcd_cpos = (c - (lcd_line * LCD_LL));
lcd_data(LCD_SET_DDADR + LCDLineAdr[lcd_line] + lcd_cpos, LCD_CMD);
// hier steht auch noch was code, der aber nichts zur Sache tut
cursor_seen = false; //ok es geht weiter im String
return 1; // darf nicht zur weiteren Auswertung gelangen.
} else { // wenn keine Cursorposition, dann normales Zeichen
//.. blabla.. hier gehts noch weiter

Der Code sollte eigentlich später so aus sehen:


int16_t lcd_putchar(char c)
{
static bool nl_seen;
static bool cursor_seen;
uint8_t i;

if (cursor_seen) { // erstes Zeichen nach \v, Cursorposition also \v%c
if (c <= LCD_LL) lcd_line=0;
else lcd_line = c % LCD_LL; //aus kumulierter Cursorpos Zeile und Spalte berechnen
lcd_cpos = (c - (lcd_line * LCD_LL));
lcd_data(LCD_SET_DDADR + LCDLineAdr[lcd_line] + lcd_cpos, LCD_CMD);
// hier steht auch noch was code, der aber nichts zur Sache tut
cursor_seen = false; //ok es geht weiter im String
return 1; // darf nicht zur weiteren Auswertung gelangen.
} else { // wenn keine Cursorposition, dann normales Zeichen
//.. blabla.. hier gehts noch weiter

die lcd_data(LCD_SET_DDADR + LCDLineAdr[lcd_line] + lcd_cpos, LCD_CMD);
ist definiert als void lcd_data( uint8_t data, uint8_t mode ); , LCDLineAdr[] ist ein Array aus 4 ints
Laut Breakpoints und Einzelschrittverfolgung ist vor Einsprung in lcd_data der Wert von lcd_cpos=1 wenn c=0.

Ich versuche dort, aus einer uint8 Zahl die eine cursorposition auf einem langen String (bis 80 Zeichen, enthält letztlich Reihe und Spalte in einem Display) zu berechnen. Ich würde ja mit Modulo % arbeiten aber da hat jemand das erste Zeichen auf die 0.te Display Position definiert und modulo Operationen mit 0 erzeugen schon mal Div/0 Fehler... Also suche ich einen weg um aus Angaben wie 0x14 die 2.te Zeile in der 4 Spalte zu berechnen wobei die Koordinaten dann aber leider Zeile 1, spalte 3 ist. Letzteres sind Vorgaben die ich so übernehmen muss um Code Compatibilität zu halten.

Und zur Aussage "Da braucht man nicht den Assemblercode anzuschauen." .. ich würds selbst nicht glauben wenn ich es nicht mit eigenen Augen sehen würde!
Gruß

Klebwax
14.05.2014, 07:14
Sorry, wenn ich das so sage, aber von deinem Code krieg ich Augenkrebs. Da gehen Code und Kommentar so durcheinander, nach if oder else könnte man eine neue Zeile anfangen ....


Aber zu deinem Problem mit Modulo:

#define LENGHT 20

int main() {
int i;
int xpos;
int line;

for(i = 0; i < 80; i++) {
xpos = i % LENGHT;
line = i / LENGHT;
printf("%d, %d, %d\n", i, xpos, line);
}
}

Dieser Code sollte das machen, was du beschreibst und funktioniert ohne Probleme auf meinem PC. Ich probiere C-Code gerne auf dem PC aus (ich verwende keine Atmel und hab daher das Studio nicht)

MfG Klebwax

Searcher
14.05.2014, 17:08
#define LCD_LL 0x0f

static uint8_t lcd_cpos;
static uint8_t lcd_line;
c=0x00;
lcd_line = 0x00;
lcd_cpos = (c - (lcd_line * LCD_LL));


Hat jemand eine Idee bevor ich verzweifel?

Schnell meine Anteilnahme zeigen :) Hab zwar von C kaum Ahnung; mir erscheinen aber die beteiligten Variablen nicht passend.

Eine Multiplikation mit zwei 8 Bit Variablen könnte eine 16Bit Variable füllen.
Eine Subtraktion könnte eine negative Zahl ergeben.

Geht es besser statt mit uint8_t mit int16_t oder noch größer und später lcd_cpos auf 8 Bit bringen?

Gruß
Searcher

RolfD
14.05.2014, 18:29
Also die Version von Klebwax gibt bei
lcd_cpos = c % LCD_LL;
lcd_line = c / LCD_LL;

und c=0 als Ergebnis für lcd_cpos UND lcd_line je = 255 bzw. vermutlich eher -1 aus obwohl alles uint8_t ist bzw. auf solches gecastet wurde.
So hab ich das aber auch mal gelernt...
In wie weit das mit int bzw. längeren vorzeichenbehafeten Zahlen anders wird, muss ich mir noch mal genauer ansehen.
Übrigends lässt sich der Code von mir recht gut ohne Augenkrebs lesen wenn man sich den in ein Editor mit Syntax highligtning packt, Klebwax. Und zum Angucken war die Kurze Version aus Post 1 gedacht.
Aber zu dem Progrämmchen...
LCD_LL ist bei mir 15 und das was du auf 20 gesetzt hattest.
Die Ausgabe dazu lautet:


[READY]
0, 255, 255
1, 0, 255
2, 1, 255
3, 2, 255
4, 3, 255
5, 4, 255
6, 5, 255
7, 6, 255
8, 7, 255
9, 8, 255
10, 9, 255
11, 10, 255
12, 11, 255
13, 12, 255
14, 13, 255
15, 14, 255
16, 255, 0
17, 0, 0
18, 1, 0
19, 2, 0
20, 3, 0
21, 4, 0
22, 5, 0
23, 6, 0
24, 7, 0
25, 8, 0
26, 9, 0
27, 10, 0
28, 11, 0
29, 12, 0
30, 13, 0
31, 14, 0
32, 255, 1
33, 0, 1
34, 1, 1
35, 2, 1

---3<---

78, 13, 3
79, 14, 3

Man beachte, das die erste Ziffer die koordinate -1,-1 hat, und die ganze erste Line die line-1 ist. Also so dolle getestet, wie du sagst, war das auch nicht :)
Der Weg funktioniert zwar... auch wenn da noch nicht alles auf 0 ausgeht... aber das kann man ja ggf. anpassen. Ich wollte aber explizit die Division und den Modulo Operator vermeiden wie ich auch schrieb! Allerdings kann so auch kein Div0 Fehler auftauchen wie ich befürchtete. In so fern.. deine Lösung funktioniert.
Zudem erklärt das aber nicht, warum der Compiler 0 - (0 x 15) zu 1 und nicht wie richtig, zu 0 bringt.. und zwar unabhängig von der Optimierungsstufe.
Ich denke auch nicht, das generell dem Compiler zu misstrauen ist, ich kann mir aber sehr gut vorstellen, das genau so ein Term in den regression Tests nicht getestet wird weil er eigentlich Unsinning ist. Es wäre zumindest nicht der erste Bug im gcc.
Kann ja sein das ich noch irgend ein mitwirkenden Fehler drin habe.. will ich ja garnicht ausschließen... mir wär nur halt lieber, ich hätte eine schlüssige Erklärung für das (für mich) komische Ergebnis 1.

Klebwax
14.05.2014, 19:36
Also die Version von Klebwax gibt bei
lcd_cpos = c % LCD_LL;
lcd_line = c / LCD_LL;

und c=0 als Ergebnis für lcd_cpos UND lcd_line je = 255 bzw. vermutlich eher -1 aus obwohl alles uint8_t ist bzw. auf solches gecastet wurde.
So hab ich das aber auch mal gelernt...
Da kann ich dir nicht folgen. 0 geteilt durch was auch immer außer 0 gibt 0. Also 0 / 15 = 0, simple Bruchrechnung.
So ist es auch bei modulo, das Ergebniss ist 0.

Einen Zusammenhang mit der Größe der Variablen kann ich nicht erkennen.


#define LENGHT 16

int main() {
int i;
uint8_t xpos;
uint8_t line;

for(i = 0; i < 80; i ++){
xpos = i % LENGHT;
line = i / LENGHT;
printf("%d, %d, %d\n", i, xpos, line);
}
return 0;
}

0, 0, 0
1, 1, 0
2, 2, 0
3, 3, 0
4, 4, 0
5, 5, 0
6, 6, 0
7, 7, 0
8, 8, 0
9, 9, 0
10, 10, 0
11, 11, 0
12, 12, 0
13, 13, 0
14, 14, 0
15, 15, 0
16, 0, 1
.
.
77, 13, 4
78, 14, 4
79, 15, 4
Das ganze erzeugt mit gcc. Ich hab das ganze auch mal auf einem PIC24 laufen lassen. printf() hab ich da nicht, aber auch der Debugger zeigt mir das gleiche wie oben. Der Compiler ist auch der gcc.
Ich kann dir also nicht weiter helfen

MfG Klebwax

RolfD
15.05.2014, 00:33
OK... Fehler gefunden... und er ist so blöd, das es schon fast peinlich ist.

#define LCD_LL LCD_LINE_LENGTH-0x01

Die Konstantendefinition für LCD_LL geht in die Hose denn durch die "PunktvorStrich" Regel ...
wird dann

lcd_cpos = (c - (lcd_line * LCD_LL));
zu
lcd_cpos = (c - (lcd_line * 16 - 1 ));
und damit erklärt sich die "Fehlrechnung".

Richtig wäre gewesen
#define LCD_LL (LCD_LINE_LENGTH-0x01)
...
Da hab ich mir dann doch nen kapitalen Bock geschossen :) Kommt davon wenn man im Halbschlaf irgendwas ausprobiert ohne nachzudenken. Ihr dürft mich nun alle mal auslachen :D
Gruß und Danke fürs mitdenken helfen..

oberallgeier
15.05.2014, 10:42
... Ihr dürft mich nun alle mal auslachen ...Ich jedenfalls bin nur vergnügt und beruhigt, weil solche Fehler bei mir nicht unüblich sind.

RoboHolIC
15.05.2014, 17:24
... Ihr dürft mich nun alle mal auslachen ...
Ich stelle mich dazu: Ich habe dieser Tage ebenfalls verzweifelt an der falschen Stelle einen Fehler gesucht, bis ich die Ursache in meiner Unachtsamkeit und dem RAM-Paging des MidRange-PIC fand: HIGH-Byte und LOW-Byte des ADC-Ergebnisses liegen in verschiedenen RAM-Pages ](*,)