Salut,
ich möchte eine gepufferte SPI Ausgabe schreibe. damit ich nicht jedes
Mal im Program auf des SPIF warten muss. Nun bin ich schon eine Weile am
rumdoktern und der Verzweiflung nahe, weiol es nicht so läuft, wie
gewünscht. Ich benutze Ringpuffer mit schreib und Lesezeiger und
Statusflag, ob er leer ist oder etwas drin steht. Wenn der Puffer leer
ist, schreibe ich in der spi_putc(byte) direkt ins SPDR ansonsten in den
Puffer. In der ISR wird dann geguck, ob noch was im Puffer zu senden
ist. Quellcode siehe. Wenn jemand ein offensichtliche Dummheit entdeckt,
möge er sie mir doch bitte verraten.
Danke, Alex
void spi_masterinit(void) {
spi_out_wr = 0;
spi_out_rd = 0;
spi_buf_sts = 0;
DDRB |= (1<<DDB7)|(1<<DDB5)|(1<<DDB4);
SPCR |= (1<<SPIE)|(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);
}
char spi_putc(char send_byte) {
if(spi_buf_sts == 0) SPDR = send_byte;
else {
spi_out_buf[spi_out_wr ++] = send_byte;
if(spi_out_wr == SPI_BUFLENGTH) spi_out_wr = 0;
}
return (send_byte);
}
ISR(SPI_STC_vect) {
if(spi_out_wr != spi_out_rd) {
SPDR = spi_out_buf[spi_out_rd ++];
if(spi_out_rd == SPI_BUFLENGTH) spi_out_rd = 0;
spi_buf_sts = 1;
}
else spi_buf_sts = 0;
}
Was geht denn denn nicht?
Auf jeden Fall solltest du während der spi_putc-Routine die Interupts
sperren, sonst ist Datenmüll vorprogrammiert. Fällt nicht sofort durch
Fehler auf, kommt aber irgendwann :-)
Hi,
wenn ich dreimal direkt hintereinander spi_putc aufrufe, wird nur einmal
gesendet, auch die ISR wird nur einmal angesprungen.
Das mit der Interrupt-Sperre probiere ich direkt mal aus..
Feddback in einigen Minuten.
Alex
Jetzt nicht direkt ein Fehler, aber ein Problem: Du prüfst nicht, ob
noch Platz im Puffer ist, wenn du die zu sendenden Daten reinschreibst.
Ein weiters Problem: Was passiert, wenn der Interrupt kommt, während du
gerade spi_putc ausfürhrst ?
Sagen wir mal der Puffer wäre leer, dann setzt die Interruptroutrine
spi_buf_sts auf 0, obwohl direkt danach Daten in den Puffer geschrieben
werden. Diese werden erst gesendet, wenn das nächste Byte mit spi_putc
geschrieben wird.
Ansonsten sehe ich jetzt eigentlich keine Fehler, wiso das Programm
nicht funktionieren sollte.
der Puffer ist 32 byte groß, in meinem Programm werde ich nie 32 Byte in
Folge senden. Ein überlauf ist also quasi ausgeschlossen. Das andere
Problem werde ich wohl noch überdenken müssen. Vielleicht lässt es sich
ja mit dem Vorschlag deines Vorredners lösen.
Danke, Alex
Den Interrupt wärend spi_putc zu sperren, hat das Problem nicht gelöst.
Ich hab noch mal mit dem Oszi geschaut, es wird nur das erste
ausgegeben, die anderen beiden...? Werde wohl noch etwas rumprobieren
müssen. Hat noch jemand 'nen vorschlag, wie man sie 'ner Lösung annähern
könnte?
Alex
ich habe noch ein busy-flag eingeführt, was immer dann gesetzt wird,
wenn das SPDR beschrieben wird und gelöscht wird, wenn das letzte byte
gesendet, das heißt, die ISR augerufen und der Buffer leer vorgefunden
wurde. Ohne dieses Flag, schreibt die spi_putc, so wie sie oben steht
jedes mal direktt in SPDR, weil der spi_buf_sts noch auf null steht,
weil der erste Interrupt noch gar nicht erfolgt ist und somit
spi_buf_sts noch nicht gesetzt wurde.
Yippi, ich könnte feiern ;-)
Codeschnipsel:
char spi_putc(char send_byte) {
SPCR &= ~(1<<SPIE);
if(spi_buf_sts == 0 && spi_busy == 0) {
spi_busy = 1;
SPDR = send_byte;
}
else {
spi_out_buf[spi_out_wr ++] = send_byte;
if(spi_out_wr == SPI_BUFLENGTH) spi_out_wr = 0;
}
SPCR |= (1<<SPIE);
return (send_byte);
}
ISR(SPI_STC_vect) {
PORTC ^= (1<<7);
if(spi_out_wr != spi_out_rd) {
spi_buf_sts = 1;
SPDR = spi_out_buf[spi_out_rd ++];
if(spi_out_rd == SPI_BUFLENGTH) spi_out_rd = 0;
}
else {
spi_buf_sts = 0;
spi_busy = 0;
}
}
Meines Erachtens lohnen sich SPI interrupts nicht wenn man mit hohen
Bitraten arbeitet. Bei Bitrate = Clock ist ein byte nach 8 clocks
draussen, Da kann ich grad mal 2, 3 bytes pushen und popen. Dann kann
man's gleich im Polling betrieb laufen lassen.
Mag sein, aber manchmal muss es eben langsamer auch vernünftig und ohne
große Wartezeiten im Programmablauf gehen. Außerdem freue ich mich ja
nur, dass ich's gelöst habe.
Alex