Hallo Forum, experimentiere seit einigen Tagen mit der DMA des TMS470 und dessen SPI. Ich möchte eine Datenübertragung aus dem internen RAM (ca. 30000 Bytes) an die SPI über die DMA realisieren, wobei die SPI nur als Master verwendet werden soll und nur Daten in Byte-Form senden soll. Über den Enable-Pin der SPI soll der SPI-Datenstrom angehalten werden können(jedoch nicht generell abgebrochen) und somit der DMA-Transfer angehalten werden. Ist der DMA-Counter auf Null, soll ein Interrupt ausgelöst werden, in dessen Routine die DMA wieder neu initialisiert werden soll und weiter arbeitet. Anbei einige Code-Fragmente: [1.] DMA-Initialisierung: void InitDMA_STA013(void) { DMAS = 0; DMAC = rDMAC; DMASA = (unsigned int)&buffer[0]; DMADA = 0xFFF7F80C; DMATC = 30000; DMACC0 = 0x00000a00; DMAGC = 0x00000000; DMAGD = 0x00000000; } mit //DMA config reg #define NCPACK (0x00 << 24) // next packet #define INTEN (1 << 15) // interrupt after compleate #define TRSIZE (0 << 13) // transfer access size #define DSTINC (0 << 11) // dest address increment #define SRCINC (1 << 9) // source address increment #define DSTMOD (0xF << 5) // dest module #define SRCMOD (0x1 << 1) // source module #define DCHN (1 << 0) // Data chaining enable #define rDMAC (0x00000000 | NCPACK | INTEN | TRSIZE | DSTINC | SRCINC | DSTMOD | SRCMOD | DCHN) [2.] in der Interrupt-Routine: void irq_handler(void) { switch ((0xFF & IRQIVEC) - 1) { case DMA_1_INT: // INT 28 InitDMA_STA013(); DMACPS = 0x00000001; //update for transfer DMACCP0 = DMA_EN2; //enable the DMA to transfer libarm_enable_irq(); break; } } [3.] SPI-Initialisierung //--- initialisiere STA013 SPI-Bus --- void InitSPI(void) { unsigned char data; int i,j; //--- init the SPI1 bus for STA013 --- SPI1CTRL1= (8 << SPI1CTRL1_LPDOUT_BIT) |// 8 bit tief (1 << SPI1CTRL1_RXDOUT_BIT); // Vorteiler = 1 SPI1CTRL2 = SPI1CTRL2_MASTER + // MasterMode SPI1CTRL2_CLKMOD + // Master Mode SPI1CTRL2_POLARITY; // Polarity FLAG gesetzt SPI1CTRL3 = 0x10; // DMA-Req-En, SPI1 Int SPI1PC6 = SPI1PC6_SOMIFUN + SPI1PC6_SIMOIFUN + SPI1PC6_CLKFUN + SPI1PC6_ENAFUN; // SOMI SIMO SPICLK ENA SPI1PC1 = //SPI1PC1_ENADIR + // EN-Pin ist GPIO SPI1PC1_SCSDIR; // CS-Pin is output for GIOP SPI1CTRL2 |= SPI1CTRL2_SPIEN; // Enable SPIs data = SPI1BUF; // Dummy Read to clear buffer } [4.] in der MAIN-Routine int main(void) { //--- initialisiere Peripherie -- InitPorts(); InitInterrupts(); InitSPI(); InitDMA_STA013(); // setup DMA and enable it __ARMLIB_enableIRQ(); DMACPS = 0x00000001; //update for transfer DMACCP0 = DMA_EN2; //enable the DMA to transfer while(1){ asm("nop"); }; } So sollte die DMA ständig den Pufferinhalt über SPI raussenden. Wird der Enable-Pin auf LOW gezogen, stoppt der Transfer, solange er auf LOW bleibt. In der Interrup-Routine wird die DMA nachgeladen und neu gestartet. Es ergaben sich nun folgende Probleme: (a) Setze ich in der Interrupt-Routine einen Breakpoint, hält der Debugger auch ordentlich an, lasse ich das Programm über RUN weiterlaufen, wird die ISR nie wieder aufgerufen; stattdessen lande ich irgendwo in der Initialisierungsroutine "InitPorts()". (b) Lasse ich den Enable der Interrupts in der ISR weg, wird die ISR nur einmal durchlaufen - danach scheint kein weiterer DMA-Transfer durchgeführt zu werden. (c) Setze ich en Enable-Pin mehrmals auf LOW und wieder auf HIGH, kann es vorkommen, dass das gleiche Ergebnis wie bei (a) entsteht. Nach einem Reset der CPU und programmstart, ergibt sich keine weitere DMA-Funktion; erst wenn ich die Spannung vom Prozessor nehme sowie den OLIMEX abklemme und anschließend alles wieder einschalte, kann ich wieder einen DMA-Zyklus laufen. Ich habe mir das Datasheet derDMA des TMS470 sowie SPNA105 angesehen; die Beispiele scheinen jedoch nicht wirklich zu laufen. Hat jemand eine Idee oder ein funktionierendes Beispiel für DMA->SPI ??? Ich wäre sehr dankbar, Michael. Ich verwende den TMS470R1B1M und für die Entwicklung CrossWorks von Rowley V1.6 Built 2 sowie den JTAG Dongle von OLIMEX. Das Board ist ein Eigenbau, der in zahlreichen anderen (nicht-DMA-Projekten) tadellos funktioniert. Die SPI funktioniert ebenfalls (ohne DNA) einwandfrei.
Hallo! Also ich würde mir erstmal Gedanken machen, warum die CPU Befehle in der InitPorts() Funktion ausführen will bzw. der Reset ausgeführt wird. Bei sowas setze ich mir Breakpoints an diese Stellen und schaue mir schrittweise die ASM Befehle an. Meistens gibt das LR Auskunft oder mit Hilfe des SP das auf dem Stack abgelegt LR ansehen. Vielleicht ist es auch ein Stack Problem. Ich weiss ja nicht wo und wie du dein Ausgabe Array angelegt hast. Was passieren könnte... Die CPU wird beim Ausführen durch einen Interrupt unterbrochen...es kommt zu einem Mode-Wechsel..die CPU retten dein großes Array auf den Stack und der platzt. Der SP zeigt dann bei der Rückkehr aus der ISR irgendwohin..Vielleicht ist dein Memory mit 0x0 initialisiert worden..so lässt sich zB ein Reset erklären. Vielleicht steht auch zufällig die Addresse der InitPort() Funktion da. Genug spekuliert, aber so ähnliche Dinge habe ich schon gesehen ;) Ich kann nur sagen, TMS470 und per DMA über SPI Daten ausgeben funktioniert. Ich kann leider keinen Beispiel Code zur Verfügung stellen.
es gibt da einges zu Beachten: 1. Ein Reset betrifft NUR den Core und cniht die Pereherie. Das heißt das DMA HET,... bei einem Reset nicht resetet werden, sondern weiterlaufen. 2. Die Perepherie muss bei der Initialierung nach dem Reset von Hand zurückgesetzt werden. 3. Bei einem Breakpoint mit Debugger ist es das gleiche. Nur der Core wird angehalten. Das hat zur Folge das bei Breakpoints und der Nutzung diverser Perepheriebaugruppen seltsame Effekte auftreten können. Mögliche Ursache für a: Das Auslesen des IRQ Registers um die IRQ Quelle festzustellen, setzt das Register zurück. Wenn jetzt in der IRQ Routine ein Breakpoint sitzt wird der Core angehalten, der DMA läuft weiter und will einen neuen IRQ auslösen. Nach RUN ist das IRQ register gelöscht aber ein IRQ per hardware ausgelöst. Die Folge ist Reset da der IRQ nicht zugeordnet werden kann. Zu b: In der IRQ wurde ein DMA transfer gestartet, und der DMA ist irgendwann damit fertig. Ist der IRQ disabled wird der DMA nicht für eine neue Übertragung initialisiert. Da das IRQ register nach einem Auslesen gelöscht ist, wird der IRQ auch nicht mehr später behandelt, da er nciht mehr im Register steht. Für einen neuen Transfer muss also der DMA von Hand getartet und die IRQ enabled werden.
Hallo Ralph, verstehe ich das richtig, dass die DMA trotz des Interrupt-Einsprunges (DMA-Counter ist dann zero) immernoch aktiv ist und läuft bzw. wenn ich direkt nach dem ISR-Einsprung (also in der ISR) alle Register nachlade und den DMA-Enable wieder starte, etwas schief zu gehen scheint?? Ist es sinnvoll, nach dem ISR-Einsprung erstmal einen DMA-Stop im DMAGD-Register durchzuführen, dann alle anderen Register der DMA zu updaten und danach den DMA-Stop zu entfernen und die DMA zu enablen?? Im Prinzip läuft nämlich die ganze Sache, jedoch gibt's irgendwo noch einen Haken... Viele Grüße, Michael.
Hallo Ralph, eine weitere Frage habe ich dann noch: In folgender AppNote (http://focus.ti.com/lit/an/spna105/spna105.pdf) habe ich eine "Andeutung von Code" für einen DMA->SPI Transfer des TMS470 gefunden. Hier wird die DMA ebenfalls in der IRQ nachgeladen (zwar in einer Sub-Routine, die aber im ISR-Handler aufgerufen wird. Hier wird kein IRQ mehr zusätzlich freigegeben - dennoch sollte das Beispiel (oder habe ich das falsch gelesen??) permanent nachladen und einen DMA-Transfer darstellen?? Michael.
Hallo Michael Es gibt zu mindestens einem TMS470 , ist aber eine Version aus dem automotive Bereich , ein älteres Errata sheet das besagt das der DMA angehalten sein muss, wenn auf die Configurationsregister schreibend zugegriffen wird. Und zwar gibt es die Flags "Halt" und "Stop", es muss das Flag "Stop" genutzt werden Also es ist auf jedenfall sinnvoll in der IRQ erst den DMA anzuhalten, dann zu konfigurieren und dann erneut zu starten. Zum IRQ enable. Für den IRQ enable sollte es eigentlich reichen wenn er 1 mal gesetzt wird, zb in der Initialisierung. Also wenn in deinem Code nicht irgendwo der IRQ disabled wird, ist es nicht notwendig , ihn in der IRQ wieder neu zu setzen.
OK. Danke Ralph, werde ich gleich mal ausprobieren. Die Möglichkeit mit dem STOP-Flag ist mir heute Nacht auch in den Sinn gekommen. Danke, Michael.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.