externe Konstante im Flash

Gast #2257080
Lesenswert?

Mahlzeit!
Ich hätte da gern mal ein Problem ;-)

Datei 'Const.c':
1
#include <avr/pgmspace.h>
2

3
const uint8_t K_AdresseZusatz PROGMEM = 48;
Datei 'Test.c':
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3

4
uint8_t AdressePlatine;
5
extern const uint8_t K_AdresseZusatz PROGMEM;
6

7
// const uint8_t K_AdresseZusatz PROGMEM = 48;  
8
// => so funktioniert's (ohne 'Const.c')
9
// => Liegt die Konstante (oder auch Variable) im RAM funktioniert's auch
10

11
int main()
12
{
13
 AdressePlatine=(((~PINB) & 0b11100000) >> 5) | K_AdresseZusatz;
14
}
Bei dieser Konstellation zeigt der AVR-Studio-Simulator mir im 
Überwachungsfenster zwar für die Konstante 'K_AdresseZusatz' den 
korrekten Wert an, hat aber keine Lust damit zu rechnen!?
Der ASM-Code dazu ist soweit*) korrekt, also gehe ich davon aus, dass es 
im Controller funktioniert(?):
1
 AdressePlatine=(((~PINB) & 0b11100000) >> 5) | K_AdresseZusatz;
2
  4a:  86 b3         in  r24, 0x16  ; 22
3
  4c:  90 e0         ldi  r25, 0x00  ; 0
4
  4e:  80 95         com  r24
5
  50:  90 95         com  r25
6
  52:  80 7e         andi  r24, 0xE0  ; 224
7
  54:  90 70         andi  r25, 0x00  ; 0
8
  56:  25 e0         ldi  r18, 0x05  ; 5
9
  58:  95 95         asr  r25
10
  5a:  87 95         ror  r24
11
  5c:  2a 95         dec  r18
12
  5e:  e1 f7         brne  .-8        ; 0x58 <main+0xe>
13
  60:  20 91 26 00   lds  r18, 0x0026
14
  64:  28 2b         or  r18, r24
15
  66:  20 93 60 00   sts  0x0060, r18
*) Ich habe schon mit Casts um mich geschmissen, konnte aber dem 
Compiler nicht abgewöhnen, die Operationen (Bitverknüpfungen, Schieben) 
in 16Bit zu machen. Geht das irgendwie? Außerdem: wieso 'asr r25', wenn 
alles 'uint8_t' ist?

Bitte Vorschläge, danke!
Gast #2257112
Lesenswert?

A. K. schrieb:
> Kein LPM => keine korrekten Daten.
Genau. Ist mir gerade auch aufgefallen. Das hab ich völlig übersehen. 
Die Konstante wird gar nicht berücksichtigt im ASM-Code :-(
Warum dann aber Variante 2 (nicht 'extern') funktioniert, ist mir jetzt 
auch klar: die Konstante wird nicht im Flash gespeichert, sondern gleich 
an der entsprechenden Stelle in den Code gebastelt. Muss ich mal 
'pgm_read' probieren (hoffe das braucht nicht zuviel Code!)

Bleibt noch: Warum 16Bit?
Gast #2257223
Lesenswert?

Ralf schrieb:
> konnte aber dem
> Compiler nicht abgewöhnen, die Operationen (Bitverknüpfungen, Schieben)
> in 16Bit zu machen. Geht das irgendwie? Außerdem: wieso 'asr r25', wenn
> alles 'uint8_t' ist?
Ich konnt's ihm abgewöhnen :-)
1
 AdressePlatine=(((~PINB) & 0b11100000));
2
 AdressePlatine = AdressePlatine >> 5;
3
 AdressePlatine |= pgm_read_byte(&K_AdresseZusatz);
Da gibt der Compiler sich richtig Mühe!

Trotzdem: warum erst 16Bit und 'asr r25'?
Gast #2257353
Lesenswert?

Ralf schrieb:
> Trotzdem: warum erst 16Bit und 'asr r25'?

Weil die C-Definition vorschreibt, daß bei einer Rechenoperation alle 
Operanden, die kleiner als int sind, erstmal zu int erweitert werden und 
die Rechnung dann in int durchgeführt wird. Der Compiler darf diese 
Erweiterung wegoptimieren, aber nur, wenn er garantieren kann, daß in 
jedem Fall das Ergebnis dadurch nicht beeinträchtigt wird. Jetzt ist bei 
AVR aber die native Wortgröße kleiner als int, und da dieser Fall in GCC 
eine Ausnahme darstellt, sind solche Optimierungen da nicht so 
umfassend.
#2257358
Lesenswert?

Ralf schrieb:
> Ralf schrieb:
>> konnte aber dem
>> Compiler nicht abgewöhnen, die Operationen (Bitverknüpfungen, Schieben)
>> in 16Bit zu machen. Geht das irgendwie? Außerdem: wieso 'asr r25', wenn
>> alles 'uint8_t' ist?
> Ich konnt's ihm abgewöhnen :-)
>
1
>  AdressePlatine=(((~PINB) & 0b11100000));
2
>  AdressePlatine = AdressePlatine >> 5;
3
>  AdressePlatine |= pgm_read_byte(&K_AdresseZusatz);
4
>
> Da gibt der Compiler sich richtig Mühe!
>
> Trotzdem: warum erst 16Bit und 'asr r25'?

Probier mal
1
uint8_t pin = ~PIND;
2
AdressePlatine=(( pin & 0b11100000) >> 5) | pgm_read_byte(&K_AdresseZusatz);

durch das ~ zwingst du den Compiler, den Wert auf 16 Bit aufzublasen.
Gast #2257382
Lesenswert?

@Rolf Magnus
Sozusagen: Er könnte, wenn er wollte ;-)

@Karl Heinz Buchegger
Ich hatte mir extra den ASM-Code angeschaut, mit meinen Kenntnissen 
könnte ich da nichts verbessern (in Assembler hätte ich das genauso 
gemacht, außer: r30 gleich als Ziel für lpm zu verwenden, hätte ich mich 
nicht 'getraut'):
1
 AdressePlatine=(((~PINB) & 0b11100000));
2
  4a:  86 b3         in  r24, 0x16  ; 22
3
 AdressePlatine = AdressePlatine >> 5;
4
 AdressePlatine |= pgm_read_byte(&K_AdresseZusatz);
5
  4c:  e6 e2         ldi  r30, 0x26  ; 38
6
  4e:  f0 e0         ldi  r31, 0x00  ; 0
7
  50:  e4 91         lpm  r30, Z+
8
  52:  80 95         com  r24
9
  54:  82 95         swap  r24
10
  56:  86 95         lsr  r24
11
  58:  87 70         andi  r24, 0x07  ; 7
12
  5a:  e8 2b         or  r30, r24
13
  5c:  e0 93 60 00   sts  0x0060, r30
('swap + lsr' fand ich gut, dass er das im Sortiment hat :-) Bei der 
'16Bit-Variante' war das ja noch eine Schleife!)
Gast #2257879
Lesenswert?

@Karl Heinz Buchegger
Hatte gestern keine Gelegenheit mehr das zu probieren. Mit deinem 
Zweizeiler ist das ganze wieder etwas übersichtlicher.
-----
Karl Heinz Buchegger schrieb:
> durch das ~ zwingst du den Compiler, den Wert auf 16 Bit aufzublasen.

Rolf Magnus schrieb:
> Weil die C-Definition vorschreibt, daß bei einer Rechenoperation alle
> Operanden, die kleiner als int sind, erstmal zu int erweitert werden und
> die Rechnung dann in int durchgeführt wird.

Kann man sowas als Laie wissen? Dann habe ich das immer überlesen. 
Vielleicht, weil es auf dem PC nicht so wichtig ist...
Persönliche Seite #2257908
Lesenswert?

Ralf schrieb:

> int main()
> {
>  AdressePlatine=(((~PINB) & 0b11100000) >> 5) | K_AdresseZusatz;
> }
> [/c]
> [...]
> *) Ich habe schon mit Casts um mich geschmissen, konnte aber dem
> Compiler nicht abgewöhnen, die Operationen (Bitverknüpfungen, Schieben)
> in 16Bit zu machen. Geht das irgendwie?

Der Cast muss an der richtigen Stelle sein:
1
AdressePlatine = ((((uint8_t) ~PINB) & 0b11100000) >> 5) | K_AdresseZusatz;

> Kann man sowas als Laie wissen?

Naja, eine Sprachfestlegung nimmt keine Rücksicht darauf, ob man Laie 
ist oder nicht.
Gast #2257953
Lesenswert?

Johann L. schrieb:
> Der Cast muss an der richtigen Stelle sein:
> AdressePlatine = ((((uint8_t) ~PINB) & 0b11100000) >> 5) | K_AdresseZusatz;

Ich glaube, das war die einzige Stelle, die ich nicht probiert habe. So 
ein Port hat ja nun sowas von 8Bit...
Aber: 'Wie wir jetzt wissen' ;-)
Karl Heinz Buchegger schrieb:
> durch das ~ zwingst du den Compiler, den Wert auf 16 Bit aufzublasen.
Persönliche Seite #2258086
Lesenswert?

Ralf schrieb:
> Johann L. schrieb:
>> Der Cast muss an der richtigen Stelle sein:
>> AdressePlatine = ((((uint8_t) ~PINB) & 0b11100000) >> 5) | K_AdresseZusatz;
>
> Ich glaube, das war die einzige Stelle, die ich nicht probiert habe.

Freilich geht aus sowas:
1
void foo2()
2
{
3
    AdressePlatine = (PINB >> 5) ^ K_AdresseZusatz;
4
}

indem du in K_AdresseZusatz die unteren 3 Bits setzt. Ist ja eh ne 
Konstante, und da tut das nicht weh :-)
Gast #2258623
Lesenswert?

Johann L. schrieb:
> Freilich geht aus sowas:void foo2()
> {
>     AdressePlatine = (PINB >> 5) ^ K_AdresseZusatz;
> }
> indem du in K_AdresseZusatz die unteren 3 Bits setzt. Ist ja eh ne
> Konstante, und da tut das nicht weh :-)
>
Kann ich nachvollziehen :-)
Das ist natürlich mal was. Wäre ich nie drauf gekommen.

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