Ich versuche gerade SPI mit DMA zum laufen zu bringen. Der
DMA2_IRQHandler wird zwar aufgerufen, es ist aber nie ein "DMA_IT_TC".
Die Base Adress im Register wird auch nicht inkrementiert, obwohl ich es
auf DMA_MemoryInc_Enable gestellt habe.
Hiermit initialisiere ich DMA:
Aufgerufen wird er, der breakpoint am if wird aufgerufen. Aber zum
Clearflag und zum printf kommt es nie.
Aus SPI1 kommen auch keine Daten, das Oszilloskop zeigt nur das Rauschen
an (0V+-20mV), das auf GND liegt.
Das GPIO ist richtig konfiguriert, da das SPI selbst funktioniert, wenn
ich es manuell ansteuere. Genutzt wird das STM32F4-Discovery Board
Um das Verhalten des Controllers nachzuvollziehen, wäre es schön zu
wissen, warum die ISR aufgerufen wird.
Ein Transfer Complete Interrupt ist wohl nicht die Ursache. Welches Flag
ist denn gesetzt?
Leon Loeser schrieb:> dmaInitStruct.DMA_BufferSize = 288; //192*12bit
das sieht ungewöhnlich aus! sollte aber nicht die fehlerquelle sein.
wie sind denn deine Daten im Speicher abgelegt? nicht im 16-bit Raster?
Leon Loeser schrieb:> nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 0;> nvicInitStruct.NVIC_IRQChannelSubPriority = 0;
Es ist auch ungewöhnlich, dem DMA die höchste Priorität zu geben. Sollte
geändert werden, muss aber auch nicht die Fehlerquelle sein
Hallo,
versuch doch mal mit geringerer SPI-Geschwindigkeit. Hatte gerade ein
ähnliches Problem, was ich auch noch nicht genauer eruiert habe. Aber ab
und zu wurde der IRQ nicht mehr aufgerufen, die DMA "hatte sich
aufgehängt".
Seitdem ich die SPI-Baudrate verringert habe funktioniert es fehlerfrei.
Nur mal so zu Eingrenzen des Problems...
Grüße, Brt
Sorry, ich blicke es spontan nicht. Vielleicht hilft der Hinweis:
> Der RX Interrupt wird ausgelöst, sobald das letzte Byte empfangen> wurde, der gesamte SPI Transfer also abgeschlossen ist. Jetzt kann> die Chip Select Leitung wieder auf high gelegt werden. TX sollte in> keinem Fall für diesen Zweck genutzt werden, weil dieser zu früh> mit der Arbeit fertig ist.http://www.diller-technologies.de/stm32.html
Sorry, falls ich daneben liege.
das mit den 12 byte ist anders gemeint. im speicher liegen 288 bit rum.
die sind für den TLC 5941, es sind also 12*24 bit. Das wären 36 byte,
aber es sind 8 tlcs, also 288 byte. Habe das wohl etwas missverständlich
kommuniziert^^
Es liegt aber im zusammengeschobenen format im Speicher vor^^
Ich würde vor der Initialisierung die DMA Register in einen definierten
Zustand bringen z.B. mit
DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_FEIF3 | DMA_FLAG_DMEIF3 |
DMA_FLAG_TEIF3 | DMA_FLAG_HTIF3 | DMA_FLAG_TCIF3);
/* Disable DMA2 Stream3 */
DMA_Cmd(DMA2_Stream3, DISABLE);
/* Deinit DMA2 Stream3 */
DMA_DeInit(DMA2_Stream3);
und dann zwischen init und cmd noch die transfer complete Unterbrechung
sowie die flow control freischalten z.B. mit
DMA_ITConfig(DMA2_Stream3, DMA_IT_TC, ENABLE);
DMA_FlowControllerConfig(DMA2_Stream3, DMA_FlowCtrl_Peripheral);
Ich habe jetzt mal das deInit und flowcontrol eingefügt. Aktuell zeigt
er mir im statusregister während dem interrupt an, dass Transfer
Complete, Half Complete und FiFo-Error auf 1 gesetzt sind.
Interessant, dass das FIFO Error Flag gesetzt ist, obwohl du den FIFO
ausgeschaltet hast...
Leon Loeser schrieb:> DMA_Cmd(DMA2_Stream3, ENABLE);
setze das mal ganz ans ende, nachdem tatsächlich ALLES initialisiert
ist.
Dies startet nämlich die DMA übertragung.
Momentan startest du die Übertragung zu einem Zeitpunkt, an dem der
SPI_DMA_Request noch nicht aktiviert ist. KANN probleme machen, MUSS
aber nicht.
Ich erwarte natürlich, dass du zuerst den SPI initialisierst, dann den
DMA.
Leon Loeser schrieb:> dmaInitStruct.DMA_Memory0BaseAddr = (uint32_t) tlcValues;
Ich gehe hier davon aus, dass tlcValues ein Array oder Pointer ist.
Zusätzlich kannst du noch Probieren, dmaInitStruct.DMA_FIFOThreshold auf
einen definierten Wert zu setzen. Sollte für die Hardware kein
Unterschied machen, da der FIFO ja deaktiviert ist, aber vieleicht zickt
die Init-Routine dabei rum, und du merkst es nicht.
Siehe
in der Init Routine des DMA. Dann wäre dein DMA nicht initialisiert.
Ich habe auch schon viel über den DMA geflucht, der Fehler liegt meist
im Detail. Vieleicht helfen dir diese Ideen.
~Lil B
Es wahr wohl wirklich die reihenfolge der Aufrufe.
der IRQHandler sieht dann so aus:
1
voidDMA2_Stream3_IRQHandler(){
2
if(DMA_GetFlagStatus(DMA2_Stream3,DMA_IT_TCIF3)){
3
DMA_Cmd(DMA2_Stream3,DISABLE);
4
DMA_SetCurrDataCounter(DMA2_Stream3,288);
5
DMA_ClearFlag(DMA2_Stream3,DMA_IT_TCIF3);
6
DMA_Cmd(DMA2_Stream3,ENABLE);
7
DMA_ClearITPendingBit(DMA2_Stream3,DMA_IT_TC);
8
}
9
}
Ich glaube da habe ich die ganze Zeit die Flags und IT Bits verwechselt.
Der Interrupt startet momentan nur die Übertragung neu (proof of
concept). Das wird dann bald mit einem Timer verbunden. Gedacht ist es,
um TLC5941 mit daten für nen RGB LED Cube zu füllen^^
Eine Frage hätte ich noch:
All diese Utility Funktionen haben dieses assert_param(...) in sich. Ist
das für den Compiler? oder wird das während dem Programmablauf
aufgerufen? Ich frage, da ich auch direkte Registermanipulation nutzen
würde, falls das schneller ist...
Achja: Ist es möglich, die MemoryAdress zu ändern, ohne das ganze
initStruct zu nutzen? also einfach ins register schreiben oder so?
Leon Loeser schrieb:> All diese Utility Funktionen haben dieses assert_param(...) in sich. Ist> das für den Compiler?
Nein.
> oder wird das während dem Programmablauf> aufgerufen?
Ja.
> Ich frage, da ich auch direkte Registermanipulation nutzen> würde, falls das schneller ist...
Das ginge schneller.
> Achja: Ist es möglich, die MemoryAdress zu ändern, ohne das ganze> initStruct zu nutzen? also einfach ins register schreiben oder so?
Ja, aber vorher den DMA stoppen und anschließend wieder starten.