Hi, ich habe folgendes Problem: Die Ausfürungszeit eines Befehl (Assemblerbefehls) benötigt anscheinend 7 Taktzyklen. Umgebung: Testboard von Olimex für TMS320F28016 60 MHz Systemtakt Entwiscklungsugebung CCS4.0 Ich habe folgendes Testprogramm: startLabel: GpioDataRegs.GPASET.bit.GPIO0 = 1; GpioDataRegs.GPACLEAR.bit.GPIO0 = 1; goto startLabel; Mit dem Oszi benötigt das Signal zwischen den beiden Kommandos ca. 117 ns, also ca. 7 Taktzyklen. Das Programm habe ich im Flash, für den ich bereits mit InitFlash() bereits das Pipelining und die WaitStates angepasst habe (hoffentlich richtig). Ich habe das Programm bereits ohne JTAG-Emulator direkt vom FLASH gestartet -> gleiches Verhalten Ich hoffe auf gute Ratschläge.
Marc Bergdolt schrieb: > startLabel: > GpioDataRegs.GPASET.bit.GPIO0 = 1; > GpioDataRegs.GPACLEAR.bit.GPIO0 = 1; > goto startLabel; Der Compiler (ich benutze noch CCS33) erzeugt ziemlich üblen Assemblercode für solch Bitgefrickel. Schau Dir mal den Assemblercode an, da dürfte das Verbesserungspotential leicht zu finden sein.
Ist dass eine Art High-Level-Assembler oder C? Wenn es C ist, dann fehlt zur Bewertung der Ursache Laufzeit der Assembler-Code.
stimmt. Ist das so richtig, dass jedes Kommando diese 7 Taktzyklen benötigt? In der Dokumentation von TI steht bei den Assemberlbefehlen jeweil die Cycle-Anzahl. Die diesem Testprogramm müssten das (OR-Befehl) 1 Zyklus sein, also eine Ausführungszeit von 16.67 ns. Bei mir sind es aber 7 Zyklen. Was könnte ich falsch gemacht haben?
Sorry, hatte den Post ("wo ist die Frage?") gelöscht, weil ich die Frage mittlerweile erraten hatte. Nun kenne ich die TMS320er nicht und DSPs habe teilweise sehr spezielle Befehlssätze, insofern ist der Assembler-Code schwer zu erraten. Viele Prozessoren benötigen mehrere Takte für scheinbare einfache C Statements, sei es weil komplexe Befehle länger dauern, sei es weil mehrere Befehle erzeugt werden. Bei ARMs beispielsweise wird aus IOport = 1; eine Sequenz von 3 Befehlen, darunter ein langsamer Ladebefehl aus dem Flash. 7 Takte wären dafür völlig normal. > Was könnte ich falsch gemacht haben? Es auf Hochsprachen-Ebene zu analysieren.
Also wenn der Code aus dem Flash ausgeführt wird, dann sind eindeutig Waitstates im Spiel. Aus dem SRAM sollte es schneller gehen. Wenn der TMS320F28016 zu langsam ist, dann sollte man es ansonsten mal mit dem TMS320F2801(100Mhz) versuchen.
Zur Ausführung aus dem internen RAM noch eine Bemerkung. Ich habe es gerade nochmals probiert. Bei der Ausführung vom RAM dauert es genauso lange, also ebenfalls 7 Taktzyklen. die 60MHz würden für meine App schon ausreichen.
A. K. schrieb: > Ist dass eine Art High-Level-Assembler oder C? Wenn es C ist, dann fehlt > zur Bewertung der Ursache Laufzeit der Assembler-Code. Dem ist nichts hinzuzufügen :-)
Anbei noch der komplette Assembler-Code aus dem Disassembler: C$L1: GpioDataRegs.GPASET.bit.GPIO0 = 1; MOVW DP,#0x01BF OR @2,#0x0001 GpioDataRegs.GPACLEAR.bit.GPIO0 = 1; OR @4,#0x0001 goto startLabel; SB C$L1,UNC
Servus Ich benutze auf der Arbeit den TMS320F28335. Wir haben so etwas Ähnliches auch versucht. Das liegt nicht an dem Assembler, sondern du kannst den Ausgangsport nicht mit 60MHz umladen. Die Treiber sind einfach nicht schnell genug. Die Pins haben ja eine kleine Kapazität und dann sind an den Ausgängen noch Schutzdioden. Also nochmal Kapazität. Da müsste der TMS einen riesigen Strom zum umladen treiben können. Das kann er aber nicht. Aber intern kann er mit dem Takt rechnen. Gruß, Jens
Hi Jens, stimmt. Ich habe zwischen den beiden Kommandos zum Ausgang setzen/rücksetzen drei andere Kommandos gesetzt. Ich bekomme dann die selbe Zeit am Oszi angezeigt. Vielen Dank! Vielen Dank auch an alle anderen!
Ich denke nicht, dass die Pinkapazitäten eine Rolle spielen. Wohl aber die Busstrukturen. Auch hier will ich mangels Kenntnis der TMS320 ein Beispiel aus dem ARMs bringen: Dort finden sich immer mehrere interne Busse. Sehr schnelle innerhalb des Cores und zwischen Core und Caches/Speichern, mässig schnelle zwischen Core/Cache und performanten Funktionsblöcken (AHB) und eher gemächlich arbeitende Busse zu den weniger performanten Periphierieeinheiten (APB). Solche langsameren Peripheriebusse sind oft nicht in der Lage, mit dem Tempo des Prozessors mitzuhalten. So kann ein solcher Bus u.U. nur alle paar Takte eine neue Operation ausführen. Je nach Befehl, Konfiguration und Bauart kann dies einen Prozessorbefehl direkt abbremsen (bei Leseoperation unvermeidlich), oder die Busoperation wird angestossen und arbeitet dann autark weiter (bei Schreiboperation möglich), wobei dann der nächste Befehl evtl. verzögert wird, wenn er den Bus anspricht und zu früh kommt. Es kann deshalb auch vorkommen, dass ein paar NOPs zwischen solchen Befehlen den Ablauf nicht verzögern. Darüber ist beispielsweise NXP gestolpert. Die ersten LPC2000 hatten grottenlangsamen Portzugriff. In nachfolgenden Versionen wurden deshalb die Ports vom langsamen APB an den schnellen AHB verlegt. Mit der Folge, dass diese neueren Modelle in dieser Frage sehr schnell sind, schneller als eine Konkurrenz, deren Ports weiterhin am APB hängen.
@ Tim Ich möchte mit den ePWMs eine Takterzeugung für Schrittmotoren erzeugen. (4 Achsen, interpolierte Fahrt in 2D, 3D, 4D und Geschwindigkeitsoverride) Das mit den GPIOs war nur zwischendrin mal ein Test, ob die CPU richtig läuft, weil ich den Eindruck hatte, dass mein bisher geschriebener Code doch etwas langsam ist. Ich habe mir nun aber den Assemblercode angeschaut und unter Berücksichtigung der Tatsache, dass Sprungbefehle etc. mehrere Taktzyklen benötigen, kommt das wohl schon hin. Ich hatte die letzten Jahre unter Windows Software geschrieben und mache jetzt seit längerer Zeit mal wieder was hardwarenahes. Daran muss man sich erst wieder gewöhnen.
Ah interessant. Ich persönlich würde größere DSPs von Ti empfehlen. Z.B. den 2808 oder 2809. Für die Entwicklung sind sie eleganter, da sie nicht so schnell an Ihren Speichergrenzen kommen. Zunächst habe ich auf einem 2808 entwickelt und erst später den Code optimiert und reduziert für den 2801(100Mhz). Allgemein ist die C2000 Serie recht elegant und nach einer gewissen Erfahrung leicht zu händeln. Meist kann man den Code 1:1, bzw. mit geringen Anpassung, von einem 2801 zu einem TMS320F28335 bringen. Die Serie 2801 bis 2809 ist Pin-Kompatibel, dem 28016 fehlt ein SPI Kanal. Aber ich schweife etwas ab... Außerdem ist zukünftig die Piccolo Serie recht interessant, da dieser DSP/DSC mit einer Versorgungsspannung auskommt. Sprich es gibt keinen Aufwand mehr mit der Initialisierung der Versorgungsspannung -> ca. 3€ kann man dadurch sparen. Der interne Oszillator ist aber nicht das Gelbe von Ei, aber was will man schon verlangen ;) Zu den GPIOs: Anscheinend hast du dich schon mit der Dokumentation beschäftigt, da du die Register-Anweisung Set und Clear benutzt. Den typischen Fehler hast du also umgangen. Für die Mitleser hier: Das DAT Register ist nicht zum setzen der GPIOs gedacht. Allgemein wird der Code recht gut optimiert. Allerdings wird richtig großer Assembler-Code erzeugt, wenn: + Große Switch-Case Anweisungen genutzt werden + For Schleifen (Also wie immer) + Besonders For Schleifen, die 32Bit Variablen bearbeiten / berechnen + Jeglicher Zugriff auf dem Flash oder bei größeren DSPs Adress- und Datenbus. + IF Bedingung mit zu vielen Vergleichen - besonders bei 32Bit Variablen
Äh, mal eine Frage: 7 Takte ist für eine komplette Periode oder jeweils zwischen zwei Flanken?? Das kann eigentlich nicht sein, da eine Jump im Programmcode dazu füren müsste, dass die Zeiten für high und low Pegel unterschiedlich sind. Hast Du gelesen, dass die maximale Togglefrequenz für GPIOs 25MHz beträgt? Ich verstehe dass so, dass man nur ein 12,5MHz Rechtecksignal erzeugen kann.
Hi mischu, Die Zeit (7 Takte) hatte ich zwischen zwei Flanken gemessen. Ich vermute, dass das mit dem internen Bus zwischen CPU und GPIOs zusammenhängt. Wenn ich zwischen die beiden Kommandos andere Befehle schreibe (ich glaube, bis zu 4 oder 5), dann wird die Zeit zwischen den Flanken nicht länger. Ich habe inzwischen auch schon in der Dokumentation eines anderen Prozessors gelesen, dass bei der Adressierung der Periphiereinheiten Wartezyklen eingelegt werden. Bezüglich dem TMS320 habe ich das jetzt nicht mehr genau verfolgt. Ich habe inzwischen herausgefunden, dass für die Division bei den TMS320 keine Hardwareeinheit zur Verügung steht. Das kommt mir sehr ungelegen... Daher bin ich inzwischen auf der Suche nach einer anderen CPU. (Favorit momentan: PIC32) Das mit den 25 MHz hatte ich nicht gelesen.
Ich bin vielleicht nicht mehr auf dem neuesten Stand. Welcher Prozessor hat denn in der Klasse eine Divisions-Einheit? Selbst die Sharc DSPs von AD hatten nur eine einfache fixpoint - divisionseinheit (Stand vor 3 Jahren). Wofür benötigst Du die Division überhaupt?
Ja stimmt. Eine vorhandene Divisionseinheit bedeutet noch nicht eine Division in einem Takt. Das hatte ich fälschlicherweise angenommen. Vorteil der Divisionseinheit ist allerdings, dass sie zur Laufzeit die Anzahl der Durchläufe reduziert (Je nachdem, welches das höchste gesetzte Bit ist.) Ich benötige die Division für die Berechnung der folgenden Schrittgeschwindigkeiten. Bei einer Beschleunigungsrampe muss ich von Schritt zu Schritt diese Rechnung wiederholen. Deine Frage 'Wofür benötigst Du die Division überhaupt?' macht mich inzwischen etwas stutzig, ob ich mich mit der uC-Arithmetik und alternativen Rechenmöglichkeiten noch auseinandersetzen muss. Ich hatte mich bisher nur auf Vorberechnungen konzentriert. Aber die bringen eigentlich nur sehr geringe Einspareffekte.
Deine bruchstückhafte Erklärung bringt nicht wirklich Licht in dein Projekt. Ohne etwas genauere Erklärung, was genau du machen möchtest und welche Umsetzung dir derzeit vorschwebt, ist keine weitere Hilfe möglich. Zum Thema Division: Die ist immer blöd auf einem DSP. Da gibt es nur eine goldene Regel: Vermeide sie!! - Alles was zur Compilezeit an Divisionen berechnet werden kann als Konstanten definieren. - Alle abhängigen Parameter zur Laufzeit, die nur selten geändert werden am Besten nur bei Initialisierung / Änderung berechnen und in zusätzlichen Variablen speichern. - Alle zur Laufzeit regelmäßig veränderten Werte so umformen, das man jeden Divisor nur einmal ausrechnet und dann mit allen anderen Werten per Multiplikation an den gewünschten Stellen verwenden. Tipp: - Wenn Du langsam veränderliche Werte misst aus denen Du den Kehrwert bilden musst, wäre es übertrieben diese mit einer hohen Abtastrate aufzunehemn und die Division zu bilden. D.h. du kannst Eigenheiten deines Systems ausnutzen, um die tatsächlich notwendige Anzahl Divisionen zu realisieren. - Je nach Auflösung kann auch eine Lookup-tabelle helfen (< 10Bit) - Analog Devices z.B. verwendet für ihre Float Division eine Funktion, die nur einen 8Bit Kerhwert erzeugt. Anschließend wird das Ergebnis per Polynom bis auf ein LSB interpoliert. - Man kann gezielt unterabtasten / Werte länger verwenden und diese zwischen mehreren Berechnungen extra / interpolieren. Du siehst, der Möglichkeiten sind keine Grenzen gesetzt. Welche Lösung in Deinem Fall klappt... ist ohne weiteren Input nicht feststellbar. Gruß 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.