Forum: Mikrocontroller und Digitale Elektronik AT91SAM7X mit SPI und ECOS


von Rafael L. (excalibur)


Lesenswert?

Hallo Leute.....
Ich habe ein riesiges Problem und hoffe ihr könnt mir helfen.

Im Rahmen eines Projekts habe ich den AT91SAM7X bereits mit einem ECOS 
in betrieb genommen und funktioniert soweit auch alles super. Habe 
bereits folgende Schnittstellen in Betrieb: DEBUG, USART, TWI und 
CAN....

Nur die SPI_Schnittstelle macht mir richtig sorgen, die macht nämlich 
gar nichts! Versuche sie die ganze Zeit zu initialisieren und etwas zu 
senden um den Clock mit dem Oszilloskop messen zu können, so wüßte ich 
ja das die Schnittstelle initialisiert wäre aber da passiert 
nichts......

Hat zufällig jemand eine funktionierende Applikation die die 
SPI_Schnittstelle in Betrieb nimmt und irgendwas sendet???? Damit könnte 
ich zumindest schon mal meine Hardware testen und mir genauer ansehen 
wie die SPI_Schnittstelle funktioniert und wie sie reagiert.

Ich gehe jetzt nicht näher auf meinen Code ein, da ich im Moment 
wirklich keine Ahnung mehr habe was ich falsch gemacht haben könnte, ich 
habe Bereits alles ausprobiert und selbst die Register direkt 
beschrieben. Na ja vielleicht hat ja von euch einer noch eine gute Idee 
und kann mir ein paar Tips geben.....

Als anhalt für die Initialisierung habe ich folgende Schritte 
durchgeführt:
// Port-Multiplexer für SPI-Schnittstelle konf.
AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, ......);
// Clock auf SPI-Modul schalten
AT91F_SPI1_CfgPMC();
// Mode einstellen:
// ist abh. von deiner hardware
AT91F_SPI_CfgMode(AT91C_BASE_SPI1, ....);
// CS-Register init. (am besten 16bit breite einstellen
AT91F_SPI_CfgCs(AT91C_BASE_SPI1,...);
// PDC öffnen
AT91F_PDC_Open(AT91C_BASE_PDC_SPI);
// SPI-Modul aktivieren
AT91F_SPI_Enable(AT91C_BASE_SPI1);

Ist die Reihenfolge der Initialisierung irgendwie zwingend???


MFG

Rafael

von Steffen (Gast)


Lesenswert?

hier mal ein Code-Bsp. wie ich das mal gemacht habe. Das ist aber schon 
ein Jahr her.  Ich hoffe, es hilft.

#define SPI_SCKDIV  4

//-------------------------------------------------------
// Port Init
//-------------------------------------------------------

AT91F_PIO_CfgPeriph( AT91C_BASE_PIOA, // PIO controller base address
((unsigned int) AT91C_PA0_RXD0        ) | //- IRDA - RXD Peripheral A
((unsigned int) AT91C_PA1_TXD0        ),  //- IRDA - TXD Peripheral A

((unsigned int) AT91C_PA30_PCK2       ) | //- Clock-Sound // Peripheral 
B
((unsigned int) AT91C_PA23_SPI1_MOSI  ) | //- MOSI      // Peripheral B
((unsigned int) AT91C_PA24_SPI1_MISO  ) | //- MISO      // Peripheral B
((unsigned int) AT91C_PA22_SPI1_SPCK  ) | //- SCK       // Peripheral B
((unsigned int) AT91C_PA21_SPI1_NPCS0 )); //- CS_DATA   // Peripheral B

 AT91F_PIO_CfgPeriph( AT91C_BASE_PIOB, // PIO controller base address
 ( 0 ),
 ((unsigned int) AT91C_PB11_SPI1_NPCS2   ));  //- CS_SOUND // Peripheral 
B

//-------------------------------------------------------
// SPI-Init
//-------------------------------------------------------
  AT91PS_SPI     pSPI = AT91C_BASE_SPI1;
  pSPI->SPI_CR  = AT91C_SPI_SPIDIS;

  // Configure PMC by enabling SPI clock

  AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_SPI1);

  // reset and enable SPI
  pSPI->SPI_CR  = AT91C_SPI_SWRST; // SW reset
  asm("nop"); //K_Task_Wait (10);
  asm("nop");
  pSPI->SPI_CR  = AT91C_SPI_SPIEN; // SPI is enable
  asm("nop"); //K_Task_Wait (10);
  asm("nop");
  // Cfg SPI MR

  pSPI->SPI_MR = (AT91C_SPI_MSTR + AT91C_SPI_MODFDIS | AT91C_SPI_PCS );


  pSPI->SPI_CSR[SPI_CS_SOUND] = AT91C_SPI_NCPHA |
                                AT91C_SPI_CPOL  |
                              AT91C_SPI_BITS_16 |
                                (SPI_SCKDIV<<8);

//-------------------------------------------------------
//
//-------------------------------------------------------
WORD spiTransfer16(WORD data)
{

  AT91PS_SPI     pSPI = AT91C_BASE_SPI1;

        // wait for transmit completion/ready
  while(!(pSPI->SPI_SR & AT91C_SPI_TDRE));
  // write data to be transmitted
  pSPI->SPI_TDR = data;

        // wait for completion
        while(!(pSPI->SPI_SR & AT91C_SPI_RDRF));
        // return received data
  return pSPI->SPI_RDR;
}

von gerhard (Gast)


Lesenswert?

hallo rafael,
meine Init. des SPI-Moduls sieht deiner sehr ähnlich.
ich würde nach dem Enable des Clock und vor dem Einstellen des Mode noch 
einen SPI-Reset ausführen, damit sollte es funktionieren.
1
// Port-Multiplexer für SPI-Schnittstelle konf.
2
AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, ......);
3
// Clock auf SPI-Modul schalten
4
AT91F_SPI1_CfgPMC();
5
// SW-Reset ausführen
6
AT91F_SPI_Reset(AT91C_BASE_SPI);
7
// Mode einstellen:
8
// ist abh. von deiner hardware
9
AT91F_SPI_CfgMode(AT91C_BASE_SPI1, ....);
10
// CS-Register init. (am besten 16bit breite einstellen
11
AT91F_SPI_CfgCs(AT91C_BASE_SPI1,...);
12
// PDC öffnen
13
AT91F_PDC_Open(AT91C_BASE_PDC_SPI);
14
// SPI-Modul aktivieren
15
AT91F_SPI_Enable(AT91C_BASE_SPI1);

wenn es das nicht war dann liegt es vermutlich an der sende-funktion.
wie sieht den die aus?

gruss
gerhard

von Rafael L. (excalibur)


Angehängte Dateien:

Lesenswert?

Hallo....

Erst mal vielen Dank für die schnellen Antworten und eure Hilfe...

@Steffen:

also alles in allem sieht mein Code deinem sehr ähnlich aber 
funktioniert trotzdem nicht! Selbst wenn ich deinen Code 1 zu 1 
übernehme und die senden Methode aufrufe:

char data = 0xFF;

while(1)
{
    spiTransfer16(data);
}

passiert bei mir auf dem Clock (mit Oszi gemessen) nichts......
Einzige was ich noch geändert habe ist das ich den Empfang auskomentiert 
habe:

//wait for completion
//while(!(pSPI->SPI_SR & AT91C_SPI_RDRF));
//return received data
//return pSPI->SPI_RDR;

@Gerhard:

ja scheinbar liegt das Problem wirklich nicht bei der Initialisierung 
bzw. weiß ich es halt nicht zu 100%. Habe alles ausprobiert und geht 
nichts.

Der Code bei mir sieht etwas komplizierter aus wegen dem ECOS aber zeige 
hier mal die beiden Funktionen die zum Senden bei mir verantwortlich 
sind als Dateianhang.

Falls mir jemand eine funktionierende Applikation geben könnte dann wäre 
das echt der Hammer, da ich echt nicht mehr weiter weiß.

MFG
Rafael

von Rafael L. (excalibur)


Angehängte Dateien:

Lesenswert?

Muss noch kurz was nachtragen was ich vorher auch noch nicht gesehen 
hatte!

Also mit dem ECOS läuft das alles über einen Interrupthändler und die 
Funktionen hatte ich vergessen.

Im Dateianhang....

Gruß
Rafael

von Steffen (Gast)


Lesenswert?

ein SPI Bsp. ist auch in der "armlib" vorhanden, die Du Dir ja mal 
anschauen kannst.

http://hubbard.engr.scu.edu/embedded/arm/armlib/index.html

von Rafael L. (excalibur)


Lesenswert?

danke Steffen!

Habe jetzt auch erste mal auf dem SPI0 ein Clock!!!!!

Der Code unten hat es möglich gemacht....

#include "lib_AT91SAM7X256.h"

#include <stdio.h>
#include <string.h>

#define SPI_SCKDIV  4

void spiInit(void)
{
  // enable clock to SPI interface
  AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_SPI0);

  // setup PIO pins for SPI bus
    *AT91C_PIOA_ASR   = 
AT91C_PA16_SPI0_MISO|AT91C_PA17_SPI0_MOSI|AT91C_PA18_SPI0_SPCK;  // 
assign pins to SPI interface
    *AT91C_PIOA_PDR   = 
AT91C_PA16_SPI0_MISO|AT91C_PA17_SPI0_MOSI|AT91C_PA18_SPI0_SPCK;
    *AT91C_PIOA_PPUER = 
AT91C_PA16_SPI0_MISO|AT91C_PA17_SPI0_MOSI|AT91C_PA18_SPI0_SPCK;  // set 
pullups
  // setup PIO pins for SPI chip selects
  //AT91C_BASE_PIOA->PIO_ASR = AT91C_PA11_NPCS0|AT91C_PA31_NPCS1;
  //AT91C_BASE_PIOA->PIO_PDR = AT91C_PA11_NPCS0|AT91C_PA31_NPCS1;
  //AT91C_BASE_PIOA->PIO_OER = AT91C_PA11_NPCS0|AT91C_PA31_NPCS1;

  // reset and enable SPI
    AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN | AT91C_SPI_SWRST;
  AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN;

  // set master mode with:
  //  - SPI master
  //  - no mode fault
  //  - variable peripheral chip select
  AT91C_BASE_SPI0->SPI_MR = AT91C_SPI_MODFDIS | AT91C_SPI_PS_VARIABLE | 
AT91C_SPI_MSTR;
//  *AT91C_SPI_MR = AT91C_SPI_MODFDIS | AT91C_SPI_PS_FIXED | 
AT91C_SPI_MSTR | (0x0E<<16);

  // setup data transfer format and rate for device 0-3 => 8bits, 
CPOL=0, NCPHA=1
  AT91C_BASE_SPI0->SPI_CSR[0] = 
AT91C_SPI_NCPHA|AT91C_SPI_BITS_8|(SPI_SCKDIV<<8);
  AT91C_BASE_SPI0->SPI_CSR[1] = 
AT91C_SPI_NCPHA|AT91C_SPI_BITS_8|(SPI_SCKDIV<<8);
  AT91C_BASE_SPI0->SPI_CSR[2] = 
AT91C_SPI_NCPHA|AT91C_SPI_BITS_8|(SPI_SCKDIV<<8);
  AT91C_BASE_SPI0->SPI_CSR[3] = 
AT91C_SPI_NCPHA|AT91C_SPI_BITS_8|(SPI_SCKDIV<<8);
}

char spiTransferByte(char data)
{
  // wait for transmit completion/ready
  while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TDRE));
  // write data to be transmitted
  AT91C_BASE_SPI0->SPI_TDR = data;
  // wait for completion
  while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_RDRF));
  // return received data
  return AT91C_BASE_SPI0->SPI_RDR;
}



int main()
{


  spiInit();

  char data = 0xFF;

    while(1){

      spiTransferByte(data);
    }

    return 0;
}

Leider hatte die SPI1_Schnittstelle nicht so funktioniert.....

Nun gut jetzt das ganze noch mit dem ECOS zum laufen bekommen und dann 
mal schauen.....

Danke euch!

Gruß
Rafael

von Rafael L. (excalibur)


Lesenswert?

So Leute.....

Jetzt habe ich nochmal eine weitere Frage.

Gibt es bei dem AT91SAM7X einen unterschied zwischen den beiden 
SPI-Schnittstellen??? Also zwischen SPI0 und SPI1????

Gem. Datenblatt liegt der einzige Unterschied den ich erkennen konnte, 
darin das SPI0 Peripheral A ist und SPI1 Peripheral B ist.

Ich frage deshalb, weil mit dem o.a. Code konnte ich die 
SPI0-Schnittstelle ansprechen aber wenn ich den Code soweit geändert 
habe das die SPI1-Schnittstelle angesprochen wird (AT91C_BASE_SPI0 auf 
AT91C_BASE_SPI1 geändert, alle Pins von SPI0 auf SPI1 usw.) dann konnte 
ich wieder keinen Clock messen.

Hätte ich am Code noch etwas anderes ändern müssen??? Funktioniert die 
SPI1_Schnittstelle des AT91 nicht korrekt???? Oder hatte jemand auch 
schon mal ein ähnliches Problem????

Wäre auch hier wieder für eure Hilfe sehr dankbar, ich muss nämlich die 
SPI1-Schnittstelle in betrieb nehmen.

MFG
Rafael

von Rafael L. (excalibur)


Lesenswert?

Habe den Fehler gefunden.....

Hier ist das AT91C_PIOA_ASR bzw. das AT91C_PIOA_BSR Register 
verantwortlich. Je nachdem ob man halt Peripheral A oder Peripheral B 
haben möchte...

Gruß
Rafael

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
Noch kein Account? Hier anmelden.