mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AT91SAM7X256: SPI nur senden über DMA ohne Empfang


Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei mir funktioniert das so einwandfrei (AT91SAM7S256, aus 
http://www.google.com/codesearch?hl=de&q=show:VEJV...
    // enable DMA transfer
    *AT91C_SPI_TPR = buff;
    *AT91C_SPI_TCR = 512;
    *AT91C_SPI_PTCR = AT91C_PDC_TXTEN;

    while(! (*AT91C_SPI_SR & AT91C_SPI_ENDTX));
    *AT91C_SPI_PTCR = AT91C_PDC_TXTDIS;
    (BYTE)( pSPI->SPI_RDR ); // it's important to read RDR here!


Siehe auch den Artikel DMA.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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... :-(

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!
    }


...

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Michael Wolf (mictronics) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> 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&pos...
Die AT91SAM7 scheinen ja ganz merkwürdige Dinger zu sein. Was bei dem 
einen Typ klappt, geht bei dem anderen nur mit Tricks...

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
RDR muss man lesen, um später an anderer Stelle keine Probleme zu haben:
Beitrag "Re: SDcard schnell beschreiben, Problem"

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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...

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.