Forum: Mikrocontroller und Digitale Elektronik Port schnell in SRAM schreiben


von Tobias (Gast)


Lesenswert?

Hallo,
stehe vor folgender Aufgabe:
Ich will in einer Interruptroutine über einen Zeitraum von 300µs 600 
Messwerte von einem parallelen 8Bit A/D-Wandler, der an einem Port des 
ATMega1284p hängt ins SRAM schieben um diese anschließend 
weiterzuverarbeiten. Der Interrupt wird nur etwa alle 80ms ausgelöst, so 
dass ich zwischen den Interrupts genügend Zeit habe die Daten 
weiterzuverabeiten. Ich programmiere üblicherweise in C.

Meine Frage:
Kann man die Aufgabe mit C oder Inline-Assembler bewältigen? AVR läuft 
mit 16MHz. Somit hätte ich pro Sample 8 Takzyklen Zeit. Bin in Assembler 
nicht wirklich fit, hab mir aber gerade mal die Instruktiontable 
angesehen und komme zu folgendem Resultat:

loop:
IN Rd, A   --> 1 Zyklus
ST Z+, Rr  --> 2 Zyklen
CPI Z, 800 --> 1 Zyklun
BRNE loop  --> 1,2 Zyklen

Also gesamt 5-6 Zyklen. Damit könnte ich 2,67MSps in den SRAM schieben, 
ist das korrekt?

Danke.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

CPI Z, 800 ist wohl etwas umfangreicher.
Ein CPIW gibt es nicht.

INIT Z
MOV Rcount,200
loop:
IN Rd, A   --> 1 Zyklus
ST Z+, Rr  --> 2 Zyklen
IN Rd, A   --> 1 Zyklus
ST Z+, Rr  --> 2 Zyklen
IN Rd, A   --> 1 Zyklus
ST Z+, Rr  --> 2 Zyklen
IN Rd, A   --> 1 Zyklus
ST Z+, Rr  --> 2 Zyklen
DEC Rcount --> 1 Zyklus
BRNE loop  --> 1,2 Zyklen

14 Zyklen pro 4 Bytes. (3,5 per Byte)

mov rH, HIBYTE(800)
loop:
IN Rd, A   --> 1 Zyklus
ST Z+, Rr  --> 2 Zyklen
CPI ZL,LOBYTE(800)  --> 1 Zyklus
CPC ZH,rH --> 1 Zyklus
BRNE loop  --> 1,2 Zyklen

6 Zyklen pro 1 Byte.

Die Methode nennt sich entrollen von Schleifen.

von FelixW (Gast)


Lesenswert?

Tobias schrieb:
> loop:
> IN Rd, A   --> 1 Zyklus
> ST Z+, Rr  --> 2 Zyklen
> CPI Z, 800 --> 1 Zyklun
> BRNE loop  --> 1,2 Zyklen
>
> Also gesamt 5-6 Zyklen. Damit könnte ich 2,67MSps in den SRAM schieben,

Löse die Schleife auf. Kostet Flash, ist aber deutlich schneller. Die 
Anzahl der Werte kannst über die Einsprungadresse berechnen

PC = loop_n + (loop_nm1-loop_n) *(n-x)

loopn:
IN Rd, A   --> 1 Zyklus
ST Z+, Rr  --> 2 Zyklen
loop_nm1:
IN Rd, A   --> 1 Zyklus
ST Z+, Rr  --> 2 Zyklen
...
IN Rd, A   --> 1 Zyklus
ST Z+, Rr  --> 2 Zyklen
tue was anderes

von chris (Gast)


Lesenswert?

Hallo,

Tobias schrieb:
> Ich will in einer Interruptroutine über einen Zeitraum von 300µs 600
das heißt alle 500ns stehen neu Daten an wie wird denn das 
synchronisiert?

nach 80ms kommt der int und dann werden für 300µs 600bytes aufgenommen?

keine Ahnung wie das in C aufgerufen wird oder beendet wird (InlineAsm)
Das mit dem CPI Z,800 geht so nicht da CPI nur 8bit breit vergleichen 
kann...
rein in asm:

.equ Datastart = $0060            ;speicherpunkt/zelle

Einsprung vom C
rcall    init_ZPOINTER
loop:
IN      RD,A                                   ;1 Zyk
ST      Z+,Rr                                 ;2 Zyk
CPI    ZL,LOW(DataStart+600)   ;1 Zyk
BRNE  loop                                  ;1-2 Zyk
CPI    ZH,High(DataStart+600)   ;1 Zyk
BRNE loop                                  ;1-2 Zyk =
Rücksprung zu C

init_ZPOINTER:
ldi  zh,high(DataStart)
ldi  zl,low(DataStart)
ret

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

Für die 600 Meßwerte steht genug RAM zur Verfügung.
Der Quarz sollte dann eine passende Frequenz (20 MHz z.B.) haben um mit 
NOP die entrollte Schleife vom Timing her zu frisieren.
Hauptproblem wird die Verzögerung durch den Interrupteinstieg sein.
Und die Verarbeitunggeschwindigkeit.

von Tobias (Gast)


Lesenswert?

Hallo,

vielen Dank für die Antworten. 6 Zyklen / Sample sollte also möglich 
sein. Dann gehe ich das Thema so an.

chris schrieb:
> das heißt alle 500ns stehen neu Daten an wie wird denn das
> synchronisiert?
Für die Synchronisierung mit dem ADC würde ich einen vom CPU-Takt 
abgeleiteten Takt generieren und über die Output Compare Unit ausgeben. 
Am Anfang der Interruptroutine will ich dann ebenfalls in Assembler das 
sampling der Daten auf den den Takt synchronisieren.

chris schrieb:
> nach 80ms kommt der int und dann werden für 300µs 600bytes aufgenommen?
Korrekt. Die Daten werden anschließend verrechnet. Bei den Messwerten 
handelt es sich um einen Zündspannungsverlauf. Es sollen die 
Zündspannung, die Brenndauer und die Brennspannung sowie Anomalien des 
Signals vermessen werden.

Dennis Heynlein schrieb:
> Hauptproblem wird die Verzögerung durch den Interrupteinstieg sein.
Da sehe ich in meiner Anwendung kein Problem, da die ersten 5µs des 
Signals für mich uninteressant sind. Starten will ich das Sampling über 
eine eigene Komparatorschaltung ebenfalls Interruptgesteuert. Ein 
zeitlicher Versatz eines gesampleten Datenblocks zum nächsten um ein 
paar µs spielt keine Rolle.

Dennis Heynlein schrieb:
> Und die Verarbeitunggeschwindigkeit.
80ms reichen mir hier auch mit Weiterverarbeitung in C völlig aus.

von Peter D. (peda)


Lesenswert?

Dennis Heynlein schrieb:
> CPI Z, 800 ist wohl etwas umfangreicher.

Ach komm, CPI + CPC kostet gerade mal einen Zyklus mehr als bei 8Bit.
Sind dann 7 Zyklen, also ist noch ein NOP nötig, um auf 8 zu kommen.

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.