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?
Bei mir funktioniert das so einwandfrei (AT91SAM7S256, aus http://www.google.com/codesearch?hl=de&q=show:VEJV2SrvXxc:uXNEDD2Kg9A:a4I1dNTs21E&sa=N&ct=rd&cs_p=svn://mikrocontroller.net/mp3dec/trunk&cs_f=fatfs/mmc.c):
1 | // enable DMA transfer
|
2 | *AT91C_SPI_TPR = buff; |
3 | *AT91C_SPI_TCR = 512; |
4 | *AT91C_SPI_PTCR = AT91C_PDC_TXTEN; |
5 | |
6 | while(! (*AT91C_SPI_SR & AT91C_SPI_ENDTX)); |
7 | *AT91C_SPI_PTCR = AT91C_PDC_TXTDIS; |
8 | (BYTE)( pSPI->SPI_RDR ); // it's important to read RDR here! |
Siehe auch den Artikel DMA.
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... :-(
nachtrag, vom code fehlte etwas ... // 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)); // disable DMA AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTDIS; { volatile BYTE xx = (BYTE)( AT91C_BASE_SPI0->SPI_RDR ); // it's important to read RDR here! } ...
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: Beitrag "Re: SDcard schnell beschreiben, Problem"
> 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...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.