Hallo,
Ich möchte gern nur senden, ohne etwas zu empfangen (d.h. die
empfangenen Bytes interessieren nicht).
Wenn ich es so mache:
....
// Enable DMA
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
// Set DMA pointers and length
AT91C_BASE_SPI0->SPI_RPR = (unsigned int)dummy;
AT91C_BASE_SPI0->SPI_RCR = sizeof(buff);
AT91C_BASE_SPI0->SPI_TPR = (unsigned int)buff;
AT91C_BASE_SPI0->SPI_TCR = sizeof(buff);
// Wait until DMA complete
while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXBUFE));
while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY));
// Disable DMA
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
....
funktioniert es, aber mich stört dabei dieser Dummy Buffer, in dem Daten
landen, die ich gar nicht brauche.
wenn ich es aber so versuche:
....
// Enable DMA
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTEN;
// Set DMA pointers and length
AT91C_BASE_SPI0->SPI_TPR = (unsigned int)buff;
AT91C_BASE_SPI0->SPI_TCR = sizeof(buff);
// Wait until DMA complete
while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXBUFE));
while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY));
// Disable DMA
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTDIS;
....
funktioniert es nicht :(
Weiss jemand von euch vielleicht, was ich falsch mache?
Danke im Voraus,
--> Peter
Noch ein Versuch, diesmal mit der lib_AT91SAM7X256_H, brachte auch
keinen Erfolg.
Das hier:
...
AT91F_PDC_Open (AT91C_BASE_PDC_SPI0);
AT91F_PDC_SendFrame (AT91C_BASE_PDC_SPI0, (char*)buff, 512, 0,0);
AT91F_PDC_ReceiveFrame (AT91C_BASE_PDC_SPI0, (char*)dummy, 512,
0,0);
while (!AT91F_PDC_IsTxEmpty(AT91C_BASE_PDC_SPI0 ));
while (!AT91F_PDC_IsRxEmpty(AT91C_BASE_PDC_SPI0 ));
AT91F_PDC_Close (AT91C_BASE_PDC_SPI0);
...
funktioniert, aber das:
...
AT91F_PDC_Open (AT91C_BASE_PDC_SPI0);
AT91F_PDC_SendFrame (AT91C_BASE_PDC_SPI0, (char*)buff, 512, 0,0);
while (!AT91F_PDC_IsTxEmpty(AT91C_BASE_PDC_SPI0 ));
AT91F_PDC_Close (AT91C_BASE_PDC_SPI0);
...
funktioniert nicht :-(
wieso lässt sich der PDC nicht so konfigurieren, dass er empfangene
Bytes einfach wegwirft?
Hallo Andreas,
Danke für deine Antwort.
Ich kenne den Code und den Artikel, so hatte ich es als erstes probiert,
aber es ging leider nicht. Jetzt habe ich es mal so gemacht:
...
// enable DMA transfer
AT91C_BASE_SPI0->SPI_TPR = (unsigned int)buff;
AT91C_BASE_SPI0->SPI_TCR = 512;
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTEN;
while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXBUFE));
while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY));
while(! (AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_ENDTX));
...
und es geht !?!??
sobald ich aber eins von den 'while's weglassen, funktioniert es nicht,
dann rauscht er zu schnell durch, so als hätten die schleifen keine
wirkung.
ich kann mir das nicht erklären... :-(
Hallo,
Ich habe mich jetzt entschlossen, ein wenig RAM zu verschwenden, also
meinen ursprünglichen Code zu verwenden.
Der Code von Andreas lief nur sehr unzuverlässig auf meinem SAM7X256,
die Version mit dem unnützen Empfangsbuffer dagegen läuft sehr stabil.
Es sieht jetzt so aus:
...
// Enable DMA
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
// Set DMA info
AT91C_BASE_SPI0->SPI_RPR = (unsigned int)dummy_rx_buffer;
AT91C_BASE_SPI0->SPI_RCR = 512;
AT91C_BASE_SPI0->SPI_TPR = (unsigned int)buff;
AT91C_BASE_SPI0->SPI_TCR = 512;
// Wait until DMA complete
while (AT91C_BASE_SPI0->SPI_RCR != 0);
// Disable DMA
AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
...
Die Sendefunktion (benutzt ebenfalls DMA) und sieht fast identisch aus.
@Andreas: Es würde mich trotzdem interessieren...
Ich weiss nicht, warum deine Funktion nicht bei mir funzt.
Wieso machst du am Schluss den Lesezugriff auf das RDR-Register?
Ist diese Vorgensweise irgendwo dokumentiert?
Danke,
--> Peter
>>Ist diese Vorgensweise irgendwo dokumentiert?
Im Datenblatt, unter SPI Master Mode Operations. Aber man muss halt
lesen.
Unbedingt zu beachten sind auch die Errata zum SPI und DMA Mode wenn du
mehrere Channels mit unterschiedlichen Geschwindigkeiten benutzen
willst.
>> Im Datenblatt, unter SPI Master Mode Operations. Aber man muss halt lesen.
Also ich kann nirgends finden, dass man das RDR lesen muss nach einem
PDC Transfer.
Hier scheint einer ein ähnliches Problem zu haben:
http://www.at91.com/phpbb/viewtopic.php?t=2001&postdays=0&postorder=asc&highlight=spi+dma&start=15
Die AT91SAM7 scheinen ja ganz merkwürdige Dinger zu sein. Was bei dem
einen Typ klappt, geht bei dem anderen nur mit Tricks...
> RDR muss man lesen, um später an anderer Stelle keine Probleme zu haben
Ach deshalb, ja, wenn man die übliche RX/TX-Weise benutzt, indem man
TDRE und RDRF abfragt.
UINT8 SPI_RxTx (UINT8 out)
{
while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TDRE));
AT91C_BASE_SPI0->SPI_TDR = out;
while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_RDRF)); // Könnte zu früh
gesetzt sein!!!
return (UINT8)(AT91C_BASE_SPI0->SPI_RDR);
}
...aber man kann natürlich auch gleich beides in einem haben ;-)
UINT8 SPI_RxTx (UINT8 out)
{
AT91C_BASE_SPI0->SPI_TDR = out;
while (!( AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY)); // Danach hat
RDR immer den aktuellen Wert.
return (UINT8)(AT91C_BASE_SPI0->SPI_RDR);
}
Das TXEMPTY-Bit wird gesetzt, wenn der Vorgang komplett abgschlossen
ist, also gesendet und empfangen wurde. In dem Fall dürfte ein fehlendes
'Read' von SPI_RDR im DMA-Code nichts ausmachen...
Trotzdem würde mich immer noch brennend interessieren, warum der Code
von Andreas bei mir streikt.
Ich habe schon eine ganze Weile herumgesucht, konnte aber nirgends was
finden, das auf irgendwelche Unterschiede zwischen den beiden
AT91SAM7-Typen hinweist...