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:
1 | void pioISR(void)
|
2 | {
|
3 | // reset PIO interrupt flag by reading PIO_ISR
|
4 | unsigned long int isr = AT91C_BASE_PIOA->PIO_ISR;
|
5 | if (((isr & AT91C_PA12_MISO) != 0) && ((AT91C_BASE_PIOA->PIO_PDSR & AT91C_PA12_MISO) == 0))
|
6 | {
|
7 | static unsigned char bar = 0;
|
8 | bar = !bar;
|
9 | if (bar)
|
10 | LED_GREEN_ON();
|
11 | else
|
12 | LED_GREEN_OFF();
|
13 |
|
14 | // check if transmit buffer is empty
|
15 | if ( (AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TDRE) != 0)
|
16 | {
|
17 | debugUARTSendString("w\n");
|
18 | volatile unsigned long int dummy_1 = AT91C_BASE_SPI->SPI_RDR;
|
19 | volatile unsigned long int dummy_2 = AT91C_BASE_SPI->SPI_SR;
|
20 | volatile unsigned long int dummy_3 = AT91C_BASE_SPI->SPI_RDR;
|
21 | AT91C_BASE_SPI->SPI_TDR = 0x55;
|
22 | }
|
23 | }
|
24 | }
|
25 |
|
26 |
|
27 | void initSPI(void)
|
28 | {
|
29 | debugUARTSendString("initSPI\n");
|
30 |
|
31 | // enable interrupt on DOUT/RDY on falling edge
|
32 | AT91C_BASE_AIC->AIC_IDCR = (1 << AT91C_ID_PIOA);
|
33 | AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PIOA] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE| (AT91C_AIC_PRIOR & 3);
|
34 | AT91C_BASE_AIC->AIC_SVR[AT91C_ID_PIOA] = (unsigned long int)&pioISR;
|
35 | AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_PIOA);
|
36 |
|
37 | AT91C_BASE_PMC->PMC_PCER = (1<< AT91C_ID_SPI); // enable clock
|
38 |
|
39 | AT91C_BASE_PIOA->PIO_PDR = AT91C_PA14_SPCK | AT91C_PA13_MOSI | AT91C_PA12_MISO | AT91C_PA11_NPCS0; // disable PIO function
|
40 | AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PA14_SPCK | AT91C_PA13_MOSI | AT91C_PA12_MISO | AT91C_PA11_NPCS0; // disable pullups
|
41 | 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
|
42 |
|
43 | // up to 5 MHz SPI clock, SPI mode 3 (CPOL=1, NCPHA=0)
|
44 | AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; // reset SPI
|
45 | AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN; // enable SPI
|
46 | AT91C_BASE_SPI->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED | (AT91C_SPI_PCS & (14 << 16));
|
47 | AT91C_BASE_SPI->SPI_CSR[0] = AT91C_SPI_CPOL | AT91C_SPI_CSAAT | AT91C_SPI_BITS_8 | (AT91C_SPI_SCBR & (255 << 8));
|
48 |
|
49 | AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_PIOA); // enable PIO interrupt
|
50 | AT91C_BASE_PIOA->PIO_IER = AT91C_PA12_MISO;
|
51 |
|
52 |
|
53 | // starten des SPI-Datentransfers an dieser Stelle klappt!
|
54 |
|
55 | debugUARTSendString("\\initspi\n");
|
56 | }
|
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