mikrocontroller.net

Forum: Compiler & IDEs AT91SAM7S-Problem: SPI-Transfer im Interrupt starten.


Autor: Daniel J. (deejay)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

hoffentlich kann mir jemand bei meinem Problem mit dem AT91SAM7S 
weiterhelfen. Ich bin hier langsam am verzweifeln.
Folgende Situation: Ich versuche einen AD-Wandler per SPI auszulesen. 
Ein PIO-Interrupt signalisiert, dass die AD-Wandlung komplett ist und 
ein neuer Wert ausgelesen werden kann (durch eine fallende Flanke am 
Pin).
Also habe ich auf den Pin einen PIO-Interrupt gelegt, das soweit auch 
klappt (die grüne LED blinkt fröhlich, also muss der entsprechende Code 
aufgerufen werden). Das Auslesen mittels SPI klappt auch, allerdings 
nur, wenn ich es außerhalb der Interrupt-Routine starte (beispielsweise 
in der main() oder direkt in der Methode, die das SPI initialisiert...).
Wenn ich nun aber in der Interrupt-Routine vom PIO den SPI-Datentransfer 
starten will, passiert nichts.
Der Code:
void pioISR(void)
{
  // reset PIO interrupt flag by reading PIO_ISR
  unsigned long int isr = AT91C_BASE_PIOA->PIO_ISR;
  if (((isr & AT91C_PA12_MISO) != 0) && ((AT91C_BASE_PIOA->PIO_PDSR & AT91C_PA12_MISO) == 0))
  {
    static unsigned char bar = 0;
    bar = !bar;
    if (bar)
      LED_GREEN_ON();
    else
      LED_GREEN_OFF();
    
    // check if transmit buffer is empty
    if ( (AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TDRE) != 0)
    {
      debugUARTSendString("w\n");
      volatile unsigned long int dummy_1 = AT91C_BASE_SPI->SPI_RDR;
      volatile unsigned long int dummy_2 = AT91C_BASE_SPI->SPI_SR;
      volatile unsigned long int dummy_3 = AT91C_BASE_SPI->SPI_RDR;
      AT91C_BASE_SPI->SPI_TDR = 0x55;
    }
  }
}


void initSPI(void)
{
  debugUARTSendString("initSPI\n");

  // enable interrupt on DOUT/RDY on falling edge
  AT91C_BASE_AIC->AIC_IDCR = (1 << AT91C_ID_PIOA);
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PIOA] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE| (AT91C_AIC_PRIOR & 3);
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_PIOA] = (unsigned long int)&pioISR;
  AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_PIOA);
  
  AT91C_BASE_PMC->PMC_PCER = (1<< AT91C_ID_SPI);  // enable clock

  AT91C_BASE_PIOA->PIO_PDR = AT91C_PA14_SPCK | AT91C_PA13_MOSI | AT91C_PA12_MISO | AT91C_PA11_NPCS0;  // disable PIO function
  AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PA14_SPCK | AT91C_PA13_MOSI | AT91C_PA12_MISO | AT91C_PA11_NPCS0;  // disable pullups
  AT91C_BASE_PIOA->PIO_ASR = AT91C_PA14_SPCK | AT91C_PA13_MOSI | AT91C_PA12_MISO | AT91C_PA11_NPCS0;    // select peripheral A function for TWI data and TWI clock
  
  // up to 5 MHz SPI clock, SPI mode 3 (CPOL=1, NCPHA=0)
  AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;  // reset SPI
  AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;  // enable SPI
  AT91C_BASE_SPI->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED | (AT91C_SPI_PCS & (14 << 16));
  AT91C_BASE_SPI->SPI_CSR[0] = AT91C_SPI_CPOL | AT91C_SPI_CSAAT | AT91C_SPI_BITS_8 | (AT91C_SPI_SCBR & (255 << 8));
  
  AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_PIOA); // enable PIO interrupt
  AT91C_BASE_PIOA->PIO_IER = AT91C_PA12_MISO;


  // starten des SPI-Datentransfers an dieser Stelle klappt!

  debugUARTSendString("\\initspi\n");
}

Nach Aufruf der initSPI() folgt in der main() eine Endlosschleife.
Die Ausgabe des Programms sieht wie folgt aus:
initSPI
\initspi
w

Das heisst, das TDR-Register vom SPI wird einmal beschrieben, aber die 
Daten werden nicht gesendet und das Register wird nicht wieder frei... 
Der PIO-Interrupt läuft fröhlich weiter (die grüne LED blinkt).

Wenn ich den SPI-Transfer außerhalb der ISR starte, kann ich die Daten 
auf dem Oszi sehen. Wird in der PIO-ISR jedoch der Transfer gestartet, 
passiert nichts (kein SPI-Clock, nichts). Was mache ich falsch? Es muss 
doch möglich sein innerhalb der PIO-ISR den SPI-Transfer zu starten?! 
Ich habe auch schon versucht, den PIO-Interrupt abzuschalten, bevor ich 
den SPI-Transfer starte... ändert aber nichts...
Ich habe vorher auch schon versucht den SPI-Transfer mit DMA zu 
realisieren, aber das klappt auch nicht. Deswegen dachte ich, ich 
probiers erstmal ohne DMA. Aber scheinbar habe ich etwas essentiell 
wichtiges übersehen. Hat jemand eine Idee?

Das Projekt basiert auf den Beispielen von Martin Thomas, d.h. Makefile, 
Startup-Files und Linkerscripte wurden übernommen. Verwendet wird ein 
AT91SAM7S256.

MfG
  Deejay

Autor: Daniel J. (deejay)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

habe das Problem einkreisen und umgehen können. Und zwar tritt das 
Problem nur auf, wenn zwischen der Initalisierung des SPI-Moduls und dem 
SPI-Datentransfer zuviel Zeit liegt. Erfolgt das Senden sofort, klappt 
alles. Mache ich nach der Initialisierung ein kurzes Delay, wird nichts 
mehr gesendet... Seltsam.
Jetzt habe ich es so gemacht, dass ich vor dem Senden das SPI resette, 
neu konfiguriere und dann direkt die Daten schreibe... Alleine die 
SPI-Register neu zu beschreiben ohne Reset reicht nicht aus, erst der 
Software-Reset lässt es funktionieren...
Nur zur Info, falls mal jemand ähnliche Probleme hat.
Verstanden habe ich das ganze nicht, aber die Software läuft nun... 
Falls mir jemand das Verhalten erklären kann, würde ich mich natürlich 
freuen.

MfG
 Deejay

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.