Eigenartiges Verhalten bei Schreibzugriff auf Register (ATMega162)

Gast #2480031
Hallo!

Ich hab hier ein Problem, an dem ich fast verzweifele...
Ich möchte eine Matrixtastatur an meinen ATMega162 an PORT A 
anschließen. Dafür will ich mir eine Funktion bauen, die die aktuell 
gedrückte Zahl ausgeben soll. Momentan erkenne ich nur die Zeile:
1
#define MATRIX_NOKEY  12
2
#define MATRIX_INVALID  13
3

4
#define nop() \
5
  __asm__("nop\n\t"  \
6
    "nop\n\t")
7

8

9
uint8_t matrix_poll_number() {
10
  uint8_t number = MATRIX_NOKEY;
11
  uint8_t input_value = 0;
12

13
  // Zeile herausbekommen
14
  DDRA = 0b10000111;                // Zeilen als Eingänge konfig.
15
  PORTA = 0b01111000;                // Pull-Ups aktivieren, Spalten auf GND ziehen
16
  nop();
17
  input_value = PINA;
18

19
  if (input_value == 0b01111000) number = MATRIX_NOKEY;
20
  else if (input_value == 0b00111000) {
21
    // Vierte Zeile
22
    number = 24;
23
  }
24
  else if (input_value == 0b01011000) {
25
    // Dritte Zeile
26
    number = 23;
27
  }
28
  else if (input_value == 0b01101000) {
29
    // Zweite Zeile
30
    number = 22;
31
  }
32
  else if (input_value == 0b01110000) {
33
    // Erste Zeile
34
    number = 21;
35
  }
36
  else number = MATRIX_INVALID;
37

38
  DDRA = 0b11111000;
39
  PORTA = 0b00000111;
40

41
  return number;
42
}

Die Funktion wird im Hauptprogramm periodisch ca. alle 500ms aufgerufen 
und der Rückgabewert wird auf dem UART ausgegeben.

Das komische ist nun folgendes: Wenn ich eine oder beide der vorletzten 
Anweisungen der Funktion, also DDRA = 0b11111000; und PORTA = 
0b00000111; auskommentiere, funktioniert alles wie erwartet.
Wenn aber beide Anweisungen drin sind kommt immer MATRIX_INVALID als 
Rückgabewert. Wie kann das denn sein, wenn zum Zeitpunkt der beiden 
Anweisungen der Inhalt der Variable number schon feststeht?

Kann mir da jemand helfen?
Gast
Ok, mit _delay_us(1); funktionierts. Aber nicht etwa, weil die 2 nops zu 
schnell waren, sondern wegen der Codeoptimierung. Aus welchen Grund auf 
immer hat der Compiler die beiden Schreibzugriffe auf das Register 
vorgezogen (vor die Abfrage von PINA). Fragt sich nur, warum...
Gast
Weil du eine Optimierungsstufe angegeben hast, bei der ein Umordnen von 
Anweisungen erlaubt ist und durch die Umordnung ein schnellerer oder 
kleinerer (je nach Optimierungsvorgabe) Code entstanden ist.

Der Compiler weiss nicht, dass das Setzen der I/O-Pins und das Abfragen 
logisch und physikalisch zusammen gehören

Um das Problem zu umgehen, könnte man versuchen eine Funktion für diese 
Anweisungen zu verwenden ggf. auch als inline Funktion.

1
static inline uint8_t get_PINA(void)
2
{
3
  // Zeile herausbekommen
4
  DDRA = 0b10000111;  // Zeilen als Eingänge konfig.
5
  PORTA = 0b01111000; // Pull-Ups aktivieren, Spalten auf GND ziehen
6
  nop();
7
  return PINA;
8
}
9

10
uint8_t matrix_poll_number() {
11
  uint8_t number = MATRIX_NOKEY;
12
  uint8_t input_value = get_PINA();
13
...
Alex schrieb:

> Ok, mit _delay_us(1); funktionierts. Aber nicht etwa, weil die 2 nops zu
> schnell waren, sondern wegen der Codeoptimierung. Aus welchen Grund auf
> immer hat der Compiler die beiden Schreibzugriffe auf das Register
> vorgezogen (vor die Abfrage von PINA). Fragt sich nur, warum...

Kannst du das belegen? Das wäre ein ernster Compilerfehler.
Gast
A. K. schrieb:
> Alex schrieb:
>
>> Ok, mit _delay_us(1); funktionierts. Aber nicht etwa, weil die 2 nops zu
>> schnell waren, sondern wegen der Codeoptimierung. Aus welchen Grund auf
>> immer hat der Compiler die beiden Schreibzugriffe auf das Register
>> vorgezogen (vor die Abfrage von PINA). Fragt sich nur, warum...
>
> Kannst du das belegen? Das wäre ein ernster Compilerfehler.

Nein, kann ich nicht, da ich mich dabei getäuscht habe (sorry, hab was 
verwechselt.) Das Problem scheint zwar durch Codeoptimierung 
hervorgerufen zu werden, aber die Schreibzugriffe werden nicht 
verschoben.
Eben. Die NOPs wurden verschoben oder vielleicht auch ganz einkassiert, 
weil nicht volatile. Daher stimmte das Timing nur, wenn die Pullups 
vorher schon aktiv waren. Ohne die beiden Zeilen blieben sie aktiv und 
es funktionierte.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.