SPI per PDC auf einem ARM7

  • Themenstarter Themenstarter Gelöschtes Mitglied 16444
  • Beginndatum Beginndatum
G

Gelöschtes Mitglied 16444

Guest
Moin HABO,

ich bin, was Mikrocontroller angeht, ziemlich ins kalte Wasser geworfen worden und bekomme deshalb immer wieder Probleme, sobald es etwas komplexer wird :rolleyes: So auch dieses mal.

Ich sitze hier vor einem Problem mit meinem AT91SAM7X512, dass
ich nicht gelöst bekomme. Ich möchte über SPI pro Frame 7 mal 2
Bytes übertragen. Das ganze mit SCC/PDC. Grundsätzlich funktioniert das auch, allerdings sind die einzelnen Datenblöcke um je 2 Bytes verschoben. Das heißt wenn ich mir anschaue, was empfangen wurde, dann habe ich WERT7, WERT1, WERT2 WERT3, WERT4, WERT5, WERT6 statt WERT1, WERT2, WERT3, WERT4, WERT5, WERT6, WERT7. Ich denke ich habe da an einer Stelle noch nicht ganz durchschaut, wie das funktioniert, obwohl ich die entsprechenden Stellen im Datenblatt nun schon mehrmals gelesen habe. Hat hier vielleicht jemand einen Tipp für mich?

Code:
// Enable clock for SSC controller
*AT91C_PMC_PCER = (1 << AT91C_ID_SSC);

// SPI software reset
*AT91C_SSC_CR = AT91C_SSC_SWRST;

// Clock divider
*AT91C_SSC_CMR = 3;

// Configure receive clock
// TK Clock signal
// START: Detection of a low level on RF input
// Receive/Transmit Clock Inversion
//      The data inputs (Data and Frame Sync signals) are sampled on
//      Receive Clock rising edge. The Frame Sync signal output
//      is shifted out on Receive Clock falling edge.
*AT91C_SSC_RCMR = AT91C_SSC_CKS_TK | AT91C_SSC_START_LOW_RF | AT91C_SSC_CKI;

// Configure receive frame
*AT91C_SSC_RFMR = (6 << 8) |            // DATNB = 6 => 7 data words per frame
                  (15) |                // DATLEN = 15 => half-words are transfered (16 bit)
                  AT91C_SSC_MSBF;       // MSB first

// Enables Receive
*AT91C_SSC_CR = AT91C_SSC_RXEN;

Code:
if (*AT91C_SSC_RNCR == 0 && *AT91C_SSC_RCR == 0)
{
    *AT91C_SSC_RPR = (unsigned int)&data;
    *AT91C_SSC_RCR = sizeof(data) / 2;
    *AT91C_SSC_RNCR = 0;
    *AT91C_SSC_PTCR = AT91C_PDC_RXTEN;
}

Code:
typedef struct  _data {
  unsigned short value1;
  unsigned short value2;
  short value3;
  short value4;
  short value5;
  short value6;
  unsigned short value7;
} data, *pData;
 
ich kanns hier nicht testen, aber die empfangsseite sieht auf den ersten blick richtig aus ... bist du sicher, dass die daten in der richtigen reihenfolge auf dem bus liegen, und der fehler erst intern beim empfänger auftritt?
 
Soweit ich das beurteilen kann ja. Ich habe oben auch einen Screenshot angehängt, der die Ausgabe vom FPGA zeigt. Der erste Wert sollte eine 7000 sein und das sieht für mich soweit gut aus. In meiner Struktur landet die 7000 aber im zweiten Member.
 
Oh, ja. Dazu wurde mir von dem Entwickler, von dem ich den Code übernommen habe und dem Entwickler, der sich um den FPGA kümmert erzählt, dass es schon immer so gewesen sei, dass das erste Bit ignoriert wurde. Warum und wieso konnte sich wohl keiner erklären. Ich habe das jetzt erst mal einfach so hingenommen, da ich wie gesagt nicht wirklich viel Ahnung von der Materie habe.
Eine 7000 kommt ja auch an, auch die anderen Werte stimmen, sind aber eben verschoben, deswegen bin ich dem erst mal nicht weiter nachgegangen.

Soweit ich das für mich aus dem Datenblatt herauslesen kann stimmt der Code und du scheinst das ja zu bestätigen. Hast du vielleicht einen Tipp, was ich probieren könnte um den Fehler einzugrenzen?
 
bei näherer betrachtung von SSC_RFMR FSLEN dürfte die führende 0 als frame sync dienen ... dann fehlt mir aber irgendwie ganz hinten das letzte bit ... egal ... nehmen wir mal an dass die daten auf dem bus ok sind ...

was geht also schief? offensichtlich funktioniert der SPI part einwandfrei, da die werte sauber gelesen werden und deiner aussage nach auch alle da sind ... demnach scheint auch ssc zu tun was man von dem teil verlangt ... bleibt noch pdc als mögliche fehlerquelle beim schreiben in den speicher ... diese vermutung wird dadurch begünstigt, dass der erste wert im speicher gleichzeitig der letzte ist, der über den bus kommt ... der fehler kann also erst aufgetreten sein, nachdem der letzte wert empfangen wurde ...

ich würde demnach den fehler in dem teil suchen der sich mit dem PDC befasst ...

ich weiß nicht in welchem context dein if steht ...
Code:
if (*AT91C_SSC_RNCR == 0 && *AT91C_SSC_RCR == 0)
aber erweiter das mal um einen test ob SSC_TCR 0 ist ... evtl schreibst du zu früh auf die PDC register
 
bei näherer betrachtung von SSC_RFMR FSLEN dürfte die führende 0 als frame sync dienen

Du hast Recht :thumb_up: Auch wenn FSLEN 0 ist wird im ersten Clock-Zyklus ein Frame Sync generiert. Da dies aber vom Sender ignoriert wird, müssen die Daten desswegen wohl um ein Bit verschoben werden.

ich weiß nicht in welchem context dein if steht

Das steht in einem Interrupt Handler, der von extern jede Millisekunde ausgelöst wird.

Code:
if (*AT91C_SSC_TNCR == 0 && *AT91C_SSC_TCR == 0)
{
    if (*AT91C_SSC_RNCR == 0 && *AT91C_SSC_RCR == 0)
    {
        *AT91C_SSC_RPR = (unsigned int)&data;
        *AT91C_SSC_RCR = sizeof(data) / 2;
        *AT91C_SSC_RNCR = 0;
        *AT91C_SSC_PTCR = AT91C_PDC_RXTEN;
    }
}

Bringt keine Veränderung. Muss ich beim Auslesen von data selbst eigentlich noch etwas beachten? Also ich meine wann kann ich gefahrlos die Werte aus der Struktur auslesen? Vielleicht ist ja auch da der Fehler? Im Moment passiert dies auch in dem Interrupt - durch ein memcpy() vor dem obigen Code. Ich habe es jetzt auch einmal testweise in den if-Zweig genommen, aber das macht keinen Unterschied im Ergebnis.
 
Gute Frage, ich muss gestehen, dass ich mir darüber noch keine Gedanken gemacht habe. Das war schon so, als ich den Code übernommen habe und auf Grund meiner nicht vorhandenen Kenntnisse habe ich bisher nicht wirklich Änderungen an der Codebase vorgenommen.

Du schlägst also vor in der ISR einen neuen Buffer zu allozieren wenn eine Übertragung fertig ist und diesen für die nächste zu verwenden? Dann könnte ich den alten Buffer freigeben, sobald die darin enthaltenen Daten verarbeitet sind. Ok, das probiere ich gleich morgen einmal aus.
 
Zurück
Oben