Forum: Digitale Signalverarbeitung / DSP / Machine Learning zu langsame Programmausführung bei TMS320F2812 DSP


von Sssssss (Gast)


Lesenswert?

Hi!

Folgende Hardware aus einem Uniprojekt:
- TMS320F2812
- 50 Mhz Clock (DS1077L)
- externes Ram von cypress

Der DSP ist auf 50 Mhz geflasht, Clockprescale auf 2
(Sysclock=2/2*50=50mhz).
Im Code werden auch Berechnungen für die Baudrate durchgeführt die von
50 Mhz ausgehen - Uart funktioniert.
Auch ein 5ms Timer der per CCS ConfigureCPUTimers(....) auf 5ms
initialisiert wird funktioniert korrekt.

Wir laden das Programm nach dem erzeugen mit dem Debug-JTag auf den DSP
(es wird nicht geflasht, nur ins ram).

Nun das problem:
1
/* sehr viele initialisierungen, komplexes, wirres projekt */
2
/* ...                                                     */
3
while(1){
4
 KickDog(); //reset wdt
5
 GpioDataRegs.GPBDAT.all = 0xFFFF;
6
 GpioDataRegs.GPBDAT.all = 0x0000;
7
}

Ich lasse nun diesen Code laufen und messe mit Oszi an Pin B3.
Wenn ich aus der Länge der Low-Periode auf die Taktrate zurückrechne
komme ich darauf dass der DSP nur mit 0,5 Mhz läuft !

Der selbe Code auf dem Prototypboard (ezDSP Board, 30Mhz) läuft auch
dort
zu langsam mit 0,3Mhz.

Auch hier wieder der Faktor 100.

Wenn wir ne kleine for-schleife einbauen die nen int bis 500 zählt
während der pin high ist messen wir einige ms (!!) Ausführungszeit.

Wenn ich den ganzen Overhead aus dem Projekt rauswerfe
und nur ein Beispiel von TI (toggle) laufen lasse
bekomme ich die volle Taktrate am IO Pin.

Wir haben jetzt versuchsweise soviele Initialisierungen wie möglich
aus dem Projekt entfernt (alle (?) Interrupts aus etc).
Trotzdem noch das verhalten.

Hat jemand eine Idee was diesen 100er prescaler verursachen könnte ?
Das Projekt ist schon sher groß und wirr programmiert, können wir
nichts für,
war schon vor uns so ;)

Evtl irgendein Register das man setzen kann das sowas verursacht ?
Programmiert wird mit dem Code Composer Studio von TI.

(Da funktioniert das debuggen aber nicht richtig, das ganze Studio ist
ne Zumutung :-X)

Danke schonmal ;)

von Alex (Gast)


Lesenswert?

Schonmal in das Assembler-Listing gesehen? Kann man im CCS nicht im
Schrittbetrieb sehen, was mit jedem Takt abgearbeitet wird?

Ich kann zwar nur für AD sprechen, aber auch dort ist C-Code in meinen
Augen eine Katastrophe, weshalb ich in Assembler programmiere.

Geh einfach davon aus, dass dir der Compiler unter Umständen einen
ordentlichen Overhead erzeugt.


Alex

von Sssssss (Gast)


Lesenswert?

Hi!

Ist leider nicht ganz so einfach. Dieses Studio sollte prinzipiell
step by step durch den code debuggen können.
Geht leider nur bei einigen C Sourcen. Die anderen kann er nicht
anspringen.
(breakpoints angeblich auf ner ungültigen linie, step into meldet auch
irgendeinen fehler)

Wenn ich mir die for schleife per Hand suche sehe ich das sie ca. 10
Zeilen asm braucht pro loop.
Das erklärt aber auch den Faktor 100 nicht.
Zumal es ja in dem kleinen Testprogramm das nur aus dem nötigsten
besteht nicht auftritt.

Wenn nur der Debugger richtig arbeiten würde :(

von Alex (Gast)


Lesenswert?

Mal versuchen die Optimierung auszustellen. Vielleicht hilfts ja.

von Sssssss (Gast)


Lesenswert?

Die sollte eigentlich aus sein. Kann ich aber erst nächste Woche wieder
gucken.

von Carsten S. (carsten)


Lesenswert?

Hast du mal gemessen, wenn der das Board Stand-Alone läuft und nicht am
Debugger hängt?

von Sssssss (Gast)


Lesenswert?

Ne...
Aber ich starte das Programm ja ganz normal (run).

Ausserdem läuft ja ein anderer Testcode (nur Portdir setzen und 10 in
ner while schleife ausgeben)
unter denselben Bedingungen mit voller Geschwindigkeit.

Wenn ich unser großes Projekt nehme und dort die main schleife durch
dieselbe while(1) schleife ersetze läuft es so lahm...

Da ist bestimmt irgendein Register falsch gesetzt oder ein Interrupt
spukt die ganze zeit rum und verschwendet 90% der Rechenpower.

Dachte evtl hatte schonmal jemand das selbe Problem und könnte sagen
guck mal ob
Register xy gesetzt wird.

Gibt es einen befehl um testweise alle Interrupts auszuschalten ?
Also sowas wie cli() bei den Atmels..

von Thomas (Gast)


Lesenswert?

Wie hast du das RAM Interface initialisiert ? Wieviel Wait-States etc.
?

Gruß Thomas

von Sssssss (Gast)


Lesenswert?

Hi!

Wird das in der cmd Datei initialisiert ?

Die sieht so aus:
1
/****************************************************************************/
2
/*   rob.cmd
3
/****************************************************************************/
4
5
MEMORY
6
{
7
   PAGE 0 : BOOT(R)     : origin = 0x3f8000, length = 0x80
8
   PAGE 0 : PROG(R)     : origin = 0x3f8080, length = 0x1f80
9
   PAGE 0 : RESET(R)    : origin = 0x000000, length = 0x2
10
   PAGE 1 : XINTF6    : origin = 0x100000, length = 0x80000 /* external
11
RAM */
12
   PAGE 1 : XINTF7    : origin = 0x3fC000, length = 0x4000  /* external
13
RAM */
14
15
   PAGE 1 : M0RAM(RW)   : origin = 0x000000, length = 0x400
16
   PAGE 1 : M1RAM(RW)   : origin = 0x000400, length = 0x400
17
   PAGE 1 : L0L1RAM(RW) : origin = 0x008000, length = 0x2000
18
   PAGE 1 : ZONE2       : origin = 0x080000, length = 0x080000     /*
19
XINTF zone 2 */
20
21
   
22
}
23
 
24
SECTIONS
25
{
26
   /* 22-bit program sections */
27
   .reset   : > RESET, PAGE = 0, TYPE = DSECT
28
   .pinit   : > PROG,  PAGE = 0
29
   .cinit   : > PROG,  PAGE = 0
30
   .text    : > XINTF6,  PAGE = 1
31
   
32
33
   /* 16-Bit data sections */
34
   .const   : > M0RAM, PAGE = 1
35
   .bss     : > M1RAM, PAGE = 1
36
   .stack   : > M1RAM, PAGE = 1
37
   .sysmem  : > L0L1RAM, PAGE = 1
38
39
   /* 32-bit data sections */
40
   .ebss    : > L0L1RAM, PAGE = 1
41
   .econst  : > L0L1RAM, PAGE = 1
42
   .esysmem : > L0L1RAM, PAGE = 1
43
   .cio   : > L0L1RAM, PAGE = 1
44
   
45
   /* external ram */
46
   .frame  : > ZONE2, PAGE = 1
47
48
49
   .boot > BOOT
50
   {
51
      -lrts2800_ml.lib<boot.obj> (.text)
52
   }
53
}

Waitstates werden scheinbar nirgendwo definiert.

Gibt es zum Thema F2812 und ext Ram irgendwelche guten Manuals ?
Ich habe bis jetzt nichts wirklich brauchbares gefunden ...

Aber in unserem mini Testprogramm funktioniert das pintoggeln immer
richtig.
Egal ob  .text und .ebss im externen oder internen bereich liegen.
Dort werden auch keine Waitstates gesetzt.

von Carsten S. (carsten)


Lesenswert?

Du solltest dir wirklich den erzeugten Assemblercode mal anschauen.
Glaube nicht das dein Zugriff zu lngsam ist, sonder einfach zuviele
erzeugt werden.
Was lernen wir daraus? Wenn die Zeit stimmen muss, nimm Assembler. (hat
glaub ich mein Prof mal gesagt)

von Sssssss (Gast)


Lesenswert?

Hi!

Den Asm code hatte ich mal angesehen. Der sieht ok aus.
Auch wenn ich 10 Takte für ne Schleife bissl viel finde.

Ein simples
Portb = 0xffff;
Portb = 0x0000;
Portb = 0xffff;
Portb = 0x0000;
Portb = 0xffff;
Portb = 0x0000;
Portb = 0xffff;
Portb = 0x0000;
...
braucht auch pro Zeile 100x so lange als normal.

Extra schnell muss es nicht sein...
Aber wir würden schon gerne mehr als 0,5Mhz von dem DSP ausnutzen ;)

Wenn eine
1
portb=0xFFFF;
2
portb=0x0000;
3
for (i=0; i<500; i++){
4
 x=x*1;
5
}
6
portb=0xFFFF;
Schleife 10 ms (!) braucht kann man den DSP so nicht wirklich nutzen
.
Das waren in asm ca 10 assembler befehle.
Sprich grob gerechnet ca 10 * 500 = 5000 Takte
-> 50Mhz -> 50.000.000 Takte pro s
-> 50.000.000/5000 = 0,0001 s = 0,1ms
Bei uns läuft also alles um den Faktor 100 zu langsam.

Damit dauert eine Reglerschleife eines einfachen PID Reglers >6ms...
Da muss irgendwas spuken, simpler asm Overhead kann das nicht sein.

Da ist ja jeder 8Mhz Atmel schneller :(

von Thomas (Gast)


Lesenswert?

Der 2812 ist schon sehr flott und die angegebene Routine sollte im
internen RAM ohne waitstates mit voller Geschwindigkeit laufen. ALso in
deinem Fall mit 20ns. Ich hab das ganze auch mit vollen 150MHz laufen
und das geht wie erwartet. Zum externen Memoryinterface schau in die
entsprechenden Datenblätter von TI. Dann hast du das Wochenende zu tun
zum lesen :o)))....

Die ensprechende Info steht in SPRU067C oder bei TI die ganzen
Handbücher auf der TMS320F2812 Seite anschauen. Das sind schon einige
MB an Datenblättern.

Das XINTF wird nicht im *.cmd file initialisiert. Dort wird nur dem
Linker mitgeteilt, wo die einzelnen Speicherbereiche liegen.

Das muss in deinem Programm passieren.

die besten Grüße und viel Erfolg
Thomas

von Sssssss (Gast)


Lesenswert?

Hi!

Wir haben das Problem gefunden ! Vielmehr waren es zwei Probleme...

1.)
Irgendeine Initialisierung sorgt für eine Verlangsamung um den Faktor
10.
Ich vermute irgendeine Initialisierung eines reserved registers.
Also bit2-15 reserved, bit0-1 soll auf 00 gesetzt werden:
register = 0x0000;
Solche Stellen haben wir einige im Code gefunden... argh...
Wo das passiert haben wir noch nicht rausbekommen. Wenn wir
die ganze anwendungsspezifische Initialisierung weglassen läuft der DSP
schneller.

So, und nun der Hauptfaktor:
2.)
Unser Programm ist zu groß für den internen Ram -> es läuft aus dem
externen Ram.
Das Speicherinterface wurde aber nirgends (!) initialisiert.
Danke für den Tipp Thomas!
Wir haben jetzt mal das run_from_xintf example modifiziert und damit
läuft es nun.
Auch dies brachte einen Faktor x10.

-> wenn beide Fehler behoben sind läuft der DSP mit seiner vollen
Geschwindigkeit :D

Danke euch allen für die Tipps ;)
Wenn wir rausgefunden haben welche Registerzuweisung den ersten /10
Faktor verursacht
werde ich das hier posten ;)

von TLA (Gast)


Lesenswert?

Hi, habe ein ähnliches Problem. Wo kann ich das das run_from_xintf
example finden?

von Sssssss (Gast)


Lesenswert?

Hi!

Ich meine es müsste hier drin sein:
http://focus.ti.com/docs/toolsw/folders/print/sprc097.html

Hab jetzt nicht reingeguckt, bei uns war es auf einer Schulungscd ;)

Gruss,
Simon

von udo (Gast)


Lesenswert?

HI leute,

ich habe auch einen 2812er. Ich habe vor eniger Zeit auch einige
Performance-Tests mit Code im internen,externen und Flash Speicher
durchgeführt. Ergebnis : ohne Initialisierung läuft der interne RAM
ohne Waitstates der Flash mit 16 waitstates und der externe RAM mit 50
oder 100(weiss ich nicht mehr ganz genau, jedenfalls sehr viele).

Da ich mir zur Zeit Code von Simulink erzeugen lasse, der den Code zum
größten Teil in den externen RAM(also via XINTF) legt, wird das Thema
für mich wieder aktuell.

Ich habe mich nie besonders ausgiebig mit den
Timing-Diagrammen/Abläufen bei Speicherzugriffen beschäftigt. Deshalb
eine Frage. Wie optimiert man den das Timing? Was ist zu beachten?

Man könnte sonst auf die Idee kommen die Waitstates(PAGE?/RANDOM?)
einfach so lange zu verringern, bis das DSP-Programm nicht mehr
vernünftig läuft. Das ist aber keine Garantie, dass bei dem gefundenen
minimalen Wert der DSP in allen Situationen korrekt operiert, denke ich
mal so.

Wäre dankbar für eine Antwort, die zeigt wie man eine solche Berechnung
sinnvoll durchführt.

Euer udo

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.