Sorry, das mit dem INTERRUPT hätte ich natürlich sehen sollen. Ja,
INTERRUPT statt SIGNAL in einer UART-ISR ist komplett tödlich. Sofort
nach dem SEI im Prolog der ISR (das in diesem Falle bereits vom
Compiler erzeugt wird) löst die Hardware einen neuen Interrupt aus,
sodass diese verschachtelt werden ad nauseum. Das hängt damit
zusammen, dass das hardwareseitige `interrupt pending' flag nicht
(wie
teilweise bei anderen Interrupts üblich) bereits beim Eintritt in die
ISR gelöscht wird sondern erst beim Lesen (bzw. Schreiben beim
Sender-Interrupt) von UDR.
> Was heißt volatile, bzw. was bewirkt es?
Die genaue Definition lässt sich im C-Stanard nachlesen. Effektiv
bewirkt es, dass Zugriffe auf eine derart gekennzeichnete Variable
nicht mehr optimiert werden, sondern immer ausgeführt. In deinem
Falle manipulierst du eine der Indexvariablen in einer ISR, aber die
Codeflussanalyse im Hauptprogramm merkt natürlich davon nichts.
Folglich könnte sie Zugriffe auf diese Variable u. U. komplett
optimieren (bspw. aus Schleifen herausziehen), da sich die Variable
nach Meinung des Optimizers ja ohnehin nicht ändern kann.
Das hat natürlich auch einen negativen Seiteneffekt. Die Variable
wird dann wirklich jedesmal von ihrer Speicherstelle eingelesen,
auch innerhalb der ISR, wo sich ihr Wert ja wirklich nicht geändert
haben kann. Besser als Deine Version wäre dann das Cachen in einer
temporären Variable innerhalb der ISR (das wird dann typisch ein
Register sein):
SIGNAL(SIG_UART_RECV)
{
uint8_t buf_write_local = buf_write;
// Hier ggf. auf Pufferüberlauf testen
buffer[buf_write_local] = UDR;
if (++buf_write_local >= MAXBUFFER) buf_write_local = 0;
buf_write = buf_write_local;
}
> Bist du DER Jörg Wunsch?
Ganz bestimmt. Wer denn sonst? :-) DIE Jörg Wunsch jedenfalls
nicht. ;-)
> Der (Mit)Entwickler von AVR-libc?
*Mit*Entwickler, ja, wohl mittlerweile. Der Entwickler der avr-libc
war/ist Marek Michalkiewicz, auch wenn er mittlerweile nicht mehr ganz
so aktiv ist.