Phänomen tinyAVR-series(R) 0/1

OP #7341374
Lesenswert?

Beim Evaluieren und Migrieren von tinyAVR(R) 0/1 habe ich jetzt ein sehr (doofes) merkwürdiges Phänomen.

AVR-GCC Compiler Version 7.3.0

1
/* ------------------------------------------------------------
2
                          putint
3

4
     gibt einen Integer dezimal aus. Ist Uebergabe
5
     "komma" != 0 wird ein "Kommapunkt" mit ausgegeben.
6

7
     Bsp.: 12345 wird als 123.45 ausgegeben.
8
     (ermoeglicht Pseudofloatausgaben im Bereich)
9
   ------------------------------------------------------------ */
10
void putint(int16_t i, char komma)
11
{
12
  typedef enum boolean { FALSE, TRUE }bool_t;
13

14
  static uint16_t zz[]      = { 10000, 1000, 100, 10 };
15
  bool_t          not_first = FALSE;
16

17
  uint8_t    zi;
18
  int16_t    z, b;
19

20
  komma= 5-komma;
21

22
  if (!i)
23
  {
24
    my_putchar('0');
25
  }
26
  else
27
  {
28
    if(i < 0)
29
    {
30
      my_putchar('-');
31
      i = -i;
32
    }
33

34
    for(zi = 0; zi < 4; zi++)
35
    {
36
      z = 0;
37
      b = 0;
38

39
      if  ((zi== komma) && komma)
40
      {
41
        if (!not_first) my_putchar('0');
42
        my_putchar('.');
43
        not_first= TRUE;
44
      }
45

46
      while(z + zz[zi] <= i)
47
      {
48
        b++;
49
        z += zz[zi];
50
      }
51
      if(b || not_first)
52
      {
53
        my_putchar('0' + b);
54
        not_first = TRUE;
55
      }
56
      i -= z;
57
    }
58
    if (komma== 4) my_putchar('.');
59
    my_putchar('0' + i);
60
  }
61
}

putint funktioniert auf den klassischen Controllern genau so, wie es soll. Getestete Conroller waren ATmega328p, ATMega168, ATtiny44 und ATtiny2313.

Binde ich genau denselben Code nun in der tinyAVR 0/1 series ein (getestete Controller ATtiny214 und ATtiny1604), dann gibt mir putint nur Zahlen von 0..9 korrekt aus, bei Werten oberhalb von 10 "spinnt" er herum zählt einfach die Ascii-Zeichen weiter, die nach Ascii-9 kommen.

Für 10 also den Doppelpunkt, für 11 den Strichpunkt etc.

Wo liegt hier der Hund begraben?

Ich gehe schlicht davon aus, dass in meinem putint etwas "unsauber" ist, aber ich finde das nicht !

By the way:

die aufgerufene Funktion my_putchar(uint8_ch) funktioniert problemlos, einzelne Aufrufe in der Art:

1
[code]  my_putchar('0'+5);

gibt auch eine '5' aus!

Angehängte Dateien:
OP #7341518
Lesenswert?

Frank K. schrieb:

MPLABX und ein PICKIT4 oder SNAP zu nehmen und den Code im Singlestep durchzugehen ist zuviel verlangt?

Mir ist der Aufwand für die kleinen tinyAVR series 0/1 zu groß und ich werde mir hierfür kein PicKit4 zulegen (ich habe nur einen alten PicKit2 für die PIC Controller). MPLAB ist mir, wie ich in einem anderen Thread schon geschrieben hatte, zu groß und zu "schwerfällig", vor allem, wenn man sowieso nach guter alter (veralteter) Sitte sich seine Makefiles selbst zusammen bastelt und das ganze damit auch noch komplett auf der Konsole lauffähig sein soll. Im "Normalfall" bin ich eher mit STM32 unterwegs, hier dann mit einen originalen ST-Link und Debugger.

Von daher erübrigt sich die Frage nach dem zu viel verlangt sein.

Außerdem hoch verrückt: Nach der Installation von avr-gcc 12.2.0 macht putint das, was es soll. Also laß ich diesen Compiler installiert.


Peter D. schrieb:

Hier mal die Diskussion zu dem ATTiny26 Bug: Beitrag "Problem mit ltoa"

Danke Peda (und das Danke meine ich auch uneingeschränkt als Danke). ltoa habe ich nicht ausprobiert, aber itoa. Witzigerweise funktioniert das mit der Version 7.3.0 !!!

Aber das Problem hat sich mit der Version 12.2.0 jetzt eh erledigt. Ich hatte noch nie einen wirklich aktuellen avr-gcc installiert gehabt, weil ich mir bisher damit dann immer andere Probleme eingefangen hatte.

OP #7341795
Lesenswert?

Dank Peter mit dem Hinweis auf:

Peter D. schrieb:

Beitrag "Problem mit ltoa"

habe ich mir dort den Thread und dem Problem mit der Adressierung sehr aufmerksam durchgelesen.

Danach habe ich meinen eigenen Code genauer angesehen (und natürlich wieder verstanden was ich da gemacht habe, auch wenn es nicht kommentiert ist - ich sollte mehr sprechende Variablennamen verwenden).

Nimmt man das Array zz[] mit den Zehnerpotenzen aus der Funktion heraus und macht dieses Array global, funktioniert putint wie gewünscht auch unter avr-gcc 7.3 .

Allerdings darf das Array nicht als static definiert werden, weil auch dann dieselbe Fehlfunktion auftritt.

Deshalb hier der funktionierende Code:

1
uint16_t zz[]      = { 10000, 1000, 100, 10 };
2

3
/* ------------------------------------------------------------
4
                            putint
5
     gibt einen Integer dezimal aus. Ist Uebergabe
6
     "komma" != 0 wird ein "Kommapunkt" mit ausgegeben.
7

8
     Bsp.: 12345 wird als 123.45 ausgegeben.
9
     (ermoeglicht Pseudofloatausgaben im Bereich)
10
   ------------------------------------------------------------ */
11
void putint(int16_t i, char komma)
12
{
13

14
  typedef enum boolean { FALSE, TRUE }bool_t;
15

16
  bool_t          not_first = FALSE;
17

18
  uint8_t    zi;
19
  int16_t    z, b;
20

21
  komma= 5-komma;
22

23
  if (!i)
24
  {
25
    my_putchar('0');
26
  }
27
  else
28
  {
29
    if(i < 0)
30
    {
31
      my_putchar('-');
32
      i = -i;
33
    }
34

35
    for(zi = 0; zi < 4; zi++)
36
    {
37
      z = 0;
38
      b = 0;
39

40
      if  ((zi== komma) && komma)
41
      {
42
        if (!not_first) my_putchar('0');
43
        my_putchar('.');
44
        not_first= TRUE;
45
      }
46

47
      while(z + zz[zi] <= i)
48
      {
49
        b++;
50
        z += zz[zi];
51
      }
52
      if(b || not_first)
53
      {
54
        my_putchar('0' + b);
55
        not_first = TRUE;
56
      }
57
      i -= z;
58
    }
59
    if (komma== 4) my_putchar('.');
60
    my_putchar('0' + i);
61
  }
62
}
#7341814
Lesenswert?

Ralph S. schrieb:

Nimmt man das Array zz[] mit den Zehnerpotenzen aus der Funktion heraus und macht dieses Array global, funktioniert putint wie gewünscht auch unter avr-gcc 7.3 .

Nun, dann wird es im Initcode vor Main geladen. Innerhalb einer Funktion wird es aber erst direkt beim Eintritt geladen, d.h bei jedem Eintritt neu. Man könnte es auch per PROGMEM in den Flash legen, spart dann SRAM ein.

Ein Fehler im Chip ist weiterhin nicht auszuschließen, d.h. eine Instruktion hat einen Seiteneffekt. Der avr-gcc 12.2.0 könnte diesen Befehl anders realisiert haben, so daß der Bug sich nicht auswirkt. Ein Bug im avr-gcc 7.3 erscheint mir unwahrscheinlich, da ja ATmega168 usw. gehen.

#7341819
Lesenswert?

Probier doch mal den Code zu minimieren und schau Dir dann mal an was der Compiler daraus macht. So als Komplettwust wird das niemand verstehen können.

So als Skizze würde ich das wie folgt machen: void print_ziffer(int *zahl, const int stelle, int *print_null) { int cnt=0; while (zahl>=stelle) { cnt=cnt+1; } if ((cnt!=0) || (*print_null!=0)) { my_putchar(cnt+'0'); *print_null=1; } }

Das rufst Du dann so auf:

void print_zahl(const int zahl_) { int zahl=zahl_; int print_null=0; //keine führenden Nullen print_ziffer(&zahl, 10000, &print_null); print_ziffer(&zahl, 1000, &print_null); print_null=1; //Ab der "einer"-Stelle führende Nullen print_ziffer(&zahl, 100, &print_null); my_putchar('.'); print_ziffer(&zahl, 10, &print_null); print_ziffer(&zahl, 1, &print_null); }

Damit hast du das Problem in kleinere Teilprobleme zerlegt und kannst sehen wo was schief läuft. Nebenbei brauchst Du da auch kein LPM. Funktionsaufrufe sind auch was, dass der Compiler gut auflösen kann.

OP #7341827
Lesenswert?

Peter D. schrieb:

Nun, dann wird es im Initcode vor Main geladen. Innerhalb einer Funktion wird es aber erst direkt beim Eintritt geladen, d.h bei jedem Eintritt neu.

... das war der Sinn, weshalb ich das global gemacht habe.

Peter D. schrieb:

Man könnte es auch per PROGMEM in den Flash legen, spart dann SRAM ein.

Hm, ob sich das rentiert? Das Array belegt im SRAM 8 Byte.

OP #7341844
Lesenswert?

Christian B. schrieb:

Christian B. schrieb:

void print_ziffer(int *zahl, const int stelle, int *print_null)

...

1
 cnt=cnt+1;
1
   *zahl=*zahl-stelle; //Fehlte vorher.

}

ich werde deine Vorschläge ausprobieren und sehen, wie groß der Code wird. In einem ATtiny214 hat man nur 2 kByte Speicher, von daher bin ich da mit der Codegröße extrem geizig.

In jedem Fall werde ich die Variablennamen ändern, damit man die Funktion besser verstehen kann.

#7341952
Lesenswert?

Ralph S. schrieb:

Mir ist der Aufwand für die kleinen tinyAVR series 0/1 zu groß und ich werde mir hierfür kein PicKit4 zulegen (ich habe nur einen alten PicKit2 für die PIC Controller). MPLAB ist mir, wie ich in einem anderen Thread schon geschrieben hatte, zu groß und zu "schwerfällig", vor allem, wenn man sowieso nach guter alter (veralteter) Sitte sich seine Makefiles selbst zusammen bastelt und das ganze damit auch noch komplett auf der Konsole lauffähig sein soll.

[...]

Von daher erübrigt sich die Frage nach dem zu viel verlangt sein.

Professionell ist anders. Aber ok, die Chance, wirklich die Stelle zu finden, wo das Problem genau ist, hast Du Dir damit genommen. Ist dann wohl auch nicht so wichtig.

fchk

OP #7342054
Lesenswert?

Frank K. schrieb:

Professionell ist anders. Aber ok, die Chance, wirklich die Stelle zu finden, wo das Problem genau ist, hast Du Dir damit genommen. Ist dann wohl auch nicht so wichtig.

Na ja, ich habe die Stelle ja auch so gefunden ! Zugegeben: Mit Debugger ist vieles einfacher, auf STM32 bin ich damit auch unterwegs. Wirklich immer muß das aber nicht sein.

Außerdem: Ich bin kein professioneller Softwareentwickler

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