Hallo Zusammen,
ich habe eine Frage an ARM-Assembler-Spezialisten:
Fuer das Einlesen der Daten von vier schnellen (4 x 40 Mbit pro Sek.)
1-bit-ADC moechte ich, wenn moeglich, die GPIOs einer ARM-Cortex-M3-MCU
nutzen (z.B. Silabs Precision 32, coreclockmax = 80 Mhz).
Ist es mit dieser MCU moeglich, die an einem GPIO-Port anliegenden Daten
in maximal zwei Taktzyklen einzulesen und in das MCU-RAM zu schreiben?
Das Assembler-Programm stelle ich mir wie folgt vor:
Pseudocode:
GPIO Port 1 einlesen, byte oder word nach RAM-Speicherplatz 1 schreiben
GPIO Port 1 einlesen, byte oder word nach RAM-Speicherplatz 2 schreiben
GPIO Port 1 einlesen, byte oder word nach RAM-Speicherplatz 3 schreiben
GPIO Port 1 einlesen, byte oder word nach RAM-Speicherplatz 4 schreiben
...
GPIO Port 1 einlesen, byte oder word nach RAM-Speicherplatz 1000
schreiben
- Maximal 2000 Taktzyklen sollte die ARM-MCU fuer die Ausfuehrung dieses
Codes benoetigen
- 1000 bits am Stueck einlesen ist fuer meine Anwendung ausreichend
Danke!
Gruesse
Mac
Ohne jetzt großartig in ARM-Assembler programmiert zu haben, denke ich,
dass das nicht wird. Es existieren im im Thumb2 keine Befehle um
Speicher in Speicher zu kopieren. Also muss man den Umweg über ein
CPU-Register machen. Das könnte folgendermaßen aussehen:
:sample
Wert von GPIO in Register laden (1 Takt)
Register wegspeichern (indirekte Addr.) (1 Takt)
Pointerregister inkrementieren (1 Takt)
Pointerregister mit Endaddresse vergleichen (1 Takt)
Sprung zu sample wenn ungleich (1 Takt)
Das wären schon mindestens 5 Takte. Du wolltest 2.
Gruß Oliver
Könnte aber mit DMA gehen. Als Quelladresse den GPIO, als Zieladresse
den RAM mit inkrement. Mit dem ADC klappt das gut, mit dem GPIO hab ichs
noch nicht probiert.
Sowas in der Art:
Am besten machst Du sowas per DMA. Schau also nach einem Controller der
DMA hat und bei dem das auch für die GPIOs funktioniert.
Aber auch damit ist die Geschwindigkeit der GPIOs normal begrenzt und
nicht der volle CPU-Takt. Wie schnell Du auf die GPIOs zugreifen kannst
ist leider nicht immer ganz einfach aus den Datenblättern rauszulesen...
> Silabs Precision 32, coreclockmax = 80 Mhz
Die GPIOs hängen bei diesen µCs IIRC am APB, der kann nur 40 MHz max.
Dann wird das mit 40MBit schon recht eng, selbst mit DMA.
> Fuer das Einlesen der Daten von vier schnellen (4 x 40 Mbit pro Sek.)> 1-bit-ADC moechte ich, wenn moeglich, die GPIOs ...
Du hast also 4 x einen 40Mbit/s ADC mit seriellem Interface (z.B. SPI) ?
Du möchtest also vier serielle SPIs parallel betreiben jeden mit
40Mbit/s ?
Schreib mal die Mega Sampels pro Sekunde hin und welches Interface die
Dinger haben.
Vielen Dank für eure Antworten!
In Sachen DMA habe ich vor kurzem mal bei Micro Energy nachgefragt. Die
haben mir mitgeteilt, dass der DMA-Transfer bei den Gecko-MCUs ca. 12-15
Takte benötigen würde, zumindest bezogen auf die SPI-Schnittstelle. Eine
DMA-Lösung habe ich deshalb nicht weiter verfolgt. Aber ich werde mal
versuchen aus einem STM32-Datenblatt Angaben dazu herauszulesen.
Oliver, wenn ich Deinen Assemblercode richtig verstehe, dann hast Du
eine kurze Schleife mit Abbruchbedingung dargestellt.
Müssten die ersten zwei Zeilen eintausend Mal hintereinander kopiert
dann nicht zum gewünschten Ergebnis in jeweils zwei Takten führen? :
Wert von GPIO in Register laden (1 Takt)
Register wegspeichern (RAM-Adresse 1) (1 Takt)
Wert von GPIO in Register laden (1 Takt)
Register wegspeichern (RAM-Adresse 2) (1 Takt)
Wert von GPIO in Register laden (1 Takt)
Register wegspeichern (RAM-Adresse 3) (1 Takt)
...
Wert von GPIO in Register laden (1 Takt)
Register wegspeichern (RAM-Adresse 1000) (1 Takt)
Grüße
Mac
Mac schrieb:> Oliver, wenn ich Deinen Assemblercode richtig verstehe, dann hast Du> eine kurze Schleife mit Abbruchbedingung dargestellt.> Müssten die ersten zwei Zeilen eintausend Mal hintereinander kopiert> dann nicht zum gewünschten Ergebnis in jeweils zwei Takten führen? :>> Wert von GPIO in Register laden (1 Takt)> Register wegspeichern (RAM-Adresse 1) (1 Takt)> Wert von GPIO in Register laden (1 Takt)> Register wegspeichern (RAM-Adresse 2) (1 Takt)> Wert von GPIO in Register laden (1 Takt)> Register wegspeichern (RAM-Adresse 3) (1 Takt)> ...> Wert von GPIO in Register laden (1 Takt)> Register wegspeichern (RAM-Adresse 1000) (1 Takt)
Wie willst du denn in einem Thumb2-Befehl eine 32 Bit Addresse codieren?
Das geht also wieder über indirekte Adressierung. Und dafür musst du
nach jedem Transfer das Pointerregister erhöhen.
Außerdem brauchen Load- und Store-Befehle 2 Takte (eben nachgeschaut):
Wert von GPIO in Register laden (2 Takte)
Register wegspeichern indirekt über
Pointerregister (2 Takte)
Pointerregister := Pointeregister + 1 (1 Takt )
Gruß Oliver
Hallo Uwe, die ADC haben 4 x 40 40Mbit/s und ein serielles Interface. Im
Datenblatt wird das Interface zwar nicht SPI genannt, es scheint aber
technisch völlig identisch zu sein. Die ADCs laufen übrigens mit der
gleichen clock wie der ARM.
Zu Megasamples kann ich im Moment keine Aussage machen, soweit ich das
einschätzen kann sollte das aber in Bezug auf das Interface nicht
relevant sein, zumindest nicht in Bezug auf meine Problemstellung.
Zuerst habe ich übrigens nach ARM-Controllern mit schneller(n)
SPI-Schnittstelle(n) gesucht, ich habe aber keine ARM-MCU mit
40Mbit/s-SPI-Interface gefunden.
Grüße
Mac
Oliver J. schrieb:> Wie willst du denn in einem Thumb2-Befehl eine 32 Bit Addresse codieren?> Das geht also wieder über indirekte Adressierung. Und dafür musst du> nach jedem Transfer das Pointerregister erhöhen.>> Außerdem brauchen Load- und Store-Befehle 2 Takte (eben nachgeschaut):> Wert von GPIO in Register laden (2 Takte)>> Register wegspeichern indirekt über> Pointerregister (2 Takte)>> Pointerregister := Pointeregister + 1 (1 Takt )
Ah, ok. Ich hab von Thumb2 leider keine Ahnung. Dann kann ich diese
Lösungsmöglichkeit wohl abschreiben.
Vielen Dank!
Grüße
Mac
Oliver J. schrieb:> Mac schrieb:>> Hallo Uwe, die ADC haben 4 x 40 40Mbit/s> Welche ADCs sind das denn?
So doof es auch ist, ich darf leider nicht ins Details gehen, wegen NDA
und Arbeitgeber.
Grüße
Mac
man könnte auch die 4 bits des adc stapeln, also 4 bit ins high-nibble
und 4-bit ins low-nibble, mit ein paar externen ICs solltes gehn, is aba
hald mehraufwand, vmtl. wär mehr takt billiger oder in sonderfällen eine
CPLD, die lacht dann auch bei 100 MHz noch...
Man muss sich ja nicht auf einen Wert pro Schleifendurchlauf
beschränken. Bei mehreren kann man STM mit Post-Inkrement verwenden, das
ist günstiger als einzelne ST. Etwa:
1
ldr r0,[r7]
2
ldr r1,[r7]
3
ldr r2,[r7]
4
ldr r3,[r7]
5
ldr r4,[r7]
6
ldr r5,[r7]
7
stmia r6!,{r0,r1,r2,r3,r4,r5}
(So sind ausschließlich 16 Bit Opcodes verwendet.)
Ich hab aber nicht nachgeschaut, ob das von den Zyklen wirklich
günstiger ist.
> SPI-Schnittstelle(n) gesucht, ich habe aber keine ARM-MCU mit> 40Mbit/s-SPI-Interface gefunden.LPC1769 müsste in die Richtung kommen. Die Schnittstellen heissen da
SSP, das sind schnelle SPI Schnittstellen (die legacy SPI braucht 12
Clockzyklen bei diesem µC und fällt damit aus). Mit den SSPs ist SPI als
Master bis CCLK/2 möglich; Die Port Pins gehen IIRC aber nur bis 50MHz.
Die sind auch DMA fähig.
Vielen Dank für die weiteren Hinweise!
Max, durch Deinen CPLD-Hinweis habe ich mal in diese Richtung und FPGA
gegoogelt und bin dann bei IGLOO Nano hängengeblieben. Da die Teile ev.
geeignet und auch verfügbar sind, werde ich in dieser Richtung wohl
erstmal weitermachen.
Jim, der LPC1769 klingt auch interessant. I.S. Gehäusegröße trifft er
zwar nicht ganz meine Anforderungen, aber ev. gibts da auch noch
kleinere Brüder.
Grüße
Mac