Eigenartiges Verhalten bei Schreibzugriff auf Register (ATMega162)

Gast #2480031
Lesenswert?

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 #2480063
Lesenswert?

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 #2480090
Lesenswert?

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
...
#2480117
Lesenswert?

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 #2480128
Lesenswert?

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.

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