Ich entwickle Software für attiny88 mit der avr-gcc-Toolchain. Dies ist ein billiger Mikrocontroller mit 8kB Programmspeicher, 512B SRAM und 64B nichtflüchtigem EEPROM-Datenspeicher. Das alles ist ausreichend für die Aufgabe, die es bewältigen soll. Ich habe keinen Debugger für diesen Chip.
Das Gerät fungiert als SPI-Slave und ermöglicht dem Master das Lesen/Programmieren des EEPROM und das Lesen des Gerätestatus (Zustand einiger analoger Eingänge und digitaler Ausgänge). Das Protokoll ist einfach - das erste Datenbyte trägt die Anweisung, bei der die höchsten zwei Bits die erforderliche Aktion codieren (00-nichts, 01-EEPROM schreiben, 10-EEPROM lesen, 11-Lesezustand) und der Rest ist Adresse. Das zweite Byte ist immer Null, das dritte Byte ist der zu lesende oder zu schreibende Wert, das vierte Byte ist immer Null.
Das Problem ist, dass ich ein seltsames Verhalten vom Compiler bekomme. Es ist schwierig, genau zu sagen, was vor sich geht, deshalb werde ich nur ein paar Beispiele geben. Am auffälligsten ist, dass das Gerät ohne -Os-Optimierung nicht über SPI antwortet. Dies hat keinen der offensichtlichen Gründe - das Programm passt in den Speicher und der Stack sollte nicht in .bss/.data-Abschnitte laufen (das Programm hat ~700B, SRAM ist zwischen 0x100 und 0x2ff abgebildet, wobei .bss_end bei 0x109 liegt; der Heap ist leer; es gibt weder verschachtelte Funktionsaufrufe noch verschachtelte Interrupts).
Wenn ich die -Os-Optimierung einschalte, reagiert das Programm wie vorgesehen. Hier ist der Arbeitscode zur Handhabung der ISR:
unsigned char state[8];
volatile unsigned char data;
ISR(SPI_STC_vect)
{
switch(data>>6) {
case 0:
data = SPDR;
break;
case 1: /* write eeprom */
while(EECR & (1<<EEPE));
EECR = (0<<EEPM1)|(0<<EEPM0);
EEARL = 0;
EEDR = SPDR;
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
data = 0;
break;
case 2: /* read eeprom */
EEARL = data & 0x1f; /* with 0x3f stops working (???) */
EECR |= (1<<EERE);
SPDR = EEDR;
data = 0;
break;
case 3: /* read state */
SPDR = state[data&7];
data = 0;
break;
}
}
Das Programm wird jedoch beschädigt, wenn es semantisch anders geschrieben wird:
Wenn ich die Zeile "EEARL = data & 0x1f;" ändere zu "EEARL = data & 0x3f;", was wünschenswert ist, da es ermöglichen würde, den gesamten EEPROM-Adressraum zu adressieren, das ERPROM-Schreiben/Lesen funktioniert nicht mehr (ich brauche keine vollen 64B, also habe ich es so gelassen)
Das Lesen des Status (Fall 3) wird unterbrochen, wenn ich die Zeile „SPDR = state[data&7];“ ersetze. mit Switch-Case-Konstrukt, das den Wert des PORTD/PORTB-Registers zurückgibt, wenn die Adresse 0 bzw. 1 ist (der aktuelle Workaround besteht darin, state[0] und state[1] mit PORTB/PORTD in der Hauptschleife synchron zu halten).
Übersehe ich etwas Wichtiges? Es scheint mir, dass der Compiler durcheinander bringt, aber ich habe keine Fehlerberichte für avr-gcc oder avr-libc (newlib?) gefunden, die in die Rechnung passen würden.
Die Toolchain wurde aus dem aktuellen gcc-avr-Paket in aptitude-Repositories installiert. Das Makefile ist ziemlich einfach:
all: main.hex main.s
main.elf: main.o
avr-gcc -g -mmcu=attiny88 -o main.elf main.o
main.s: main.elf
avr-objdump -d main.elf > main.s
main.hex: main.elf
avr-objcopy -O ihex main.elf main.hex
main.o: main.c
avr-gcc -mmcu=attiny88 -Os -c main.c -Wall
UPDATE : Immer noch das gleiche Ergebnis mit den neuesten binutils, gcc und avr-libc (aus den Quellen neu kompiliert)
Sie müssen die Ausgabe von überprüfen, avr-objdump
um zu sehen, welche genauen Anweisungen für Ihren Code generiert wurden. Übrigens wäre es hilfreich, Ihren C-Code per in die Disassemblierung aufzunehmen avr-objdump -S main.elf > main.s
. 0x1F
Ich bezweifle, dass das ganze Programm anders wird, wenn Sie die Konstante durch ersetzen 0x3F
. Ihr nächster Schritt wäre, Unterschiede in der Auflistung zu isolieren und sie sorgfältig zu analysieren.
Eine solche Analyse ist so weit, wie Sie ohne geeignete Entwicklungstools kommen können. Die Anschaffung eines Debuggers oder eines Simulators würde Ihnen viel Aufwand ersparen, der erforderlich ist, wenn Sie sich auf die Analyse statischer Listen beschränken.
PS: Ich gehe hier davon aus, dass Sie beim Kompilieren keine Compiler-Warnungen erhalten. Wenn Sie welche haben, sollte deren Behebung Ihre erste Priorität sein. Moderne Compiler leisten ziemlich gute Arbeit darin, Sie über subtile Fehler zu informieren, die sonst möglicherweise schwer zu finden sind.
avr-gcc -mmcu=attiny88 -Os -S main.c
. Das sollte Adressliterale in symbolischer Form ( label_0001
usw.) belassen, sodass das Erstellen eines Diffs einfacher sein sollte.
PlasmaHH
Lundin
data
Variable? Verlassen Sie sich auf die statische Initialisierung, um Ihnen "Zero-Out" zu geben? Das ist immer eine schlechte Idee, da Mikrocontroller dort oft vom C-Standard abweichen, um einen schnelleren Start zu ermöglichen.Lundin
Student
Damien
Student
Student
Student
carloc
Student
Marcelm
while(EECR & (1<<EEPE));
, bevor Sie auch das Eeprom lesen . Beobachtung Nr. 2: Ich sehe nicht, wie das von Ihnen beschriebene 4-Byte-Protokoll mit Ihrem ISR funktioniert - Beispiel: eeprom write; das erste byte wird als befehl/adresse gelesen, das zweite (null) byte löst den eigentlichen schreibvorgang aus und schreibt 0 ins eeprom, das dritte byte (daten) wird wieder als befehl interpretiert. Das passt nicht zu deiner geschilderten Intention...Student
Student