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:
1 | DMA_InitTypeDef DMA_InitStructure; |
2 | |
3 | |
4 | RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); |
5 | /* DMA1 channel1 configuration ----------------------------------------------*/
|
6 | DMA_DeInit(DMA1_Channel1); |
7 | DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(GPIOA->IDR); |
8 | DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&myResultArray; |
9 | DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; |
10 | DMA_InitStructure.DMA_BufferSize = 1000; |
11 | DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; |
12 | DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; |
13 | DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; |
14 | DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; |
15 | DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // will repeat automatically |
16 | DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; |
17 | DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; |
18 | DMA_Init(DMA1_Channel1, &DMA_InitStructure); |
19 | /* Enable DMA1 channel1 */
|
20 | DMA_Cmd(DMA1_Channel1, ENABLE); |
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
Jup darauf wollte ich auch hinaus (CPLD) als ich fragte ob er vier SPI parallel betreiben möchte.
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.