Hallo Mikrocontroller Gemeinde,
mittels des Tutorials und der vielen Beitraege habe ich es geschafft mit
einem atMega88 mein erstes µC Projekt zu erstellen.
Die Aufgabe ist bei einem Takt von 1 MHz nach Erkennen eines Startcodes
die nachfolgenden 44 Bytes (Nibble) einzulesen. Das Einlesen der Daten
geschieht unter Ausnutzung der Taktflanke und des externen Interrupts.
Das Warten auf den Startcode führen ich durch Pollen des Portes durch.
Hierbei habe ich das Problem das das Erkennen am Anfang oder am Ende des
Startcodes liegen kann. Dadurch verliere ich ab und an einen
Einlesetakt.
Siehe Code Beispiel:
1
MAIN:
2
ldi XL,low(data_in) ; Set Adress of data_in
3
ldi XH,high(data_in)
4
LOOP_0:
5
; Wait for Initial Code (0x0F)
6
in temp, PINB
7
and temp,clrinmsk ; Clear open input pins
8
cpi temp, 0x0f ; Startsequence
9
breq CLEARINT
10
rjmp LOOP_0
11
CLEARINT:
12
; Enable INT0
13
SBI EIMSK,INT0
14
WAITINT0:
15
rjmp WAITINT0
16
EXTINT0:
17
;External interrupt store incoming data in X
18
in temp,PINB
19
st X+,temp
20
cp XL,maxdata
21
breq CODING
22
reti
23
CODING:
24
CBI EIMSK, INT0 ; Clear EXTInt 0
25
POP temp ; Clear Stack from Interrupt
26
POP temp
27
sei ;Global Interrupts Enable, switched off by Interrupt
28
29
ldi XL,low(data_in) ; Set Adress of data_in
30
ldi XH,high(data_in)
Ich suche jetzt nach einer Moeglichkeit das Erkennen des Startcodes
innerhalb der Interruptroutine oder snychron zum Takt durchzuführen.
Allerdings habe ich nur einen Takt Zeit dafür (1µS). Idealerweise dachte
ich an die Möglichkeit die Sprungadressen für den Interrupt nach
Erkennen des Startcodes zu tauschen. Oder ein Flag zu setzen, wobei
dafür und die dauernde Abfrage in der Interruptroutine die Zeit zu kurz
ist.
Achja, der Controller laueft mit 20MHz. Ein Cycle ist somit 0,05 µS. Die
Daten sollten ziemlich in der Mitte genommen werden um Verfälschungen
durch schlechte Flanken zu vermeiden.
Jegliche Hilfe ist willkommen.
Gruss
Roman
@ Roman (Gast)
>Die Aufgabe ist bei einem Takt von 1 MHz nach Erkennen eines Startcodes>die nachfolgenden 44 Bytes (Nibble) einzulesen. Das Einlesen der Daten
Die meinst ein Datenstrom mit 1 Mbit/s, richtig?
>geschieht unter Ausnutzung der Taktflanke und des externen Interrupts.
Das halte ich für gewagt. Selbst bei 20 MHz Takt hat dein uC gerade mal
20 Takte Zeit, das Datenbit einzulesen, zu verarbeiten und zu speichern.
Das ist nicht sehr viel.
>Das Warten auf den Startcode führen ich durch Pollen des Portes durch.>Hierbei habe ich das Problem das das Erkennen am Anfang oder am Ende des>Startcodes liegen kann. Dadurch verliere ich ab und an einen>Einlesetakt.
Was für eine Schnittstelle ist es den überhaupt? Wenn du zu deinen Daten
noch ein Taktsignal am Controller hast, dann solltes du das besser mit
dem SPI oder USI- Modul machen.
>Ich suche jetzt nach einer Moeglichkeit das Erkennen des Startcodes>innerhalb der Interruptroutine oder snychron zum Takt durchzuführen.
SPI oder USI. Interrupts kannst du bei DER Geschwindigkeit vergessen,
das geht nur über Polling.
MFG
Falk
Schoenen Dank fuer Deine schnelle Antwort Falk.
Die Geschwindigkeit ist richtig 1 MHz/s. Die Daten liegen parallel an
PortB bit#0-#3 an und werden nur gespeichert. Die Verarbeitung findet
spaeter statt, nachdem alle Daten gesammelt sind. SPI, USI usw. geht da
leider nicht, obwohl ich erst noch das Datenblatt an dieser Stelle
verstehen muss. Aber keine seriellen Daten, das steht schon mal fest.
Das Speichern der Daten funktioniert ja auch schon. Das Problem ist das
Erkennen der Startbedingung. Laienhaft mal so gedacht.
Takt:
Interupt bei Flanke geht high.
Holen Daten, pruefen Flag.
Gesetzt = speichern.
Anzahl erreicht?
Nein = RETI.
Ja = Verarbeitung.
Nicht gesetzt = pruefen Startbedingung
Ja = setzen Flag
Nein = RETI.
RETI
Fuer 20 Takte/Cycles etwas viel, ich weiss.
Kann ich da vielleicht mit selbstmodifizierendem Code arbeiten.
Startbedingung erfuellt = Setzen der neuen Interruptaddresse Speichern.
Verarbeitung erfolgt = Setzen der Adresse Pruefroutine.
Oder,so? Hat das schon mal jemand gemacht? Hat einer ASM Code dazu?
Gruss
Roman
@ Roman (Gast)
>Die Geschwindigkeit ist richtig 1 MHz/s. Die Daten liegen parallel an
Ahhhhh. Was ist DAS denn für eine Einheit???!!
Frequenzen haben die Einheit Hz oder MHz.
Datenübertragungen haben Bit/s oder Mbit/s.
>PortB bit#0-#3 an und werden nur gespeichert. Die Verarbeitung findet
Ach so, hab ich übersehen. Klar, dann is nix mit SPI und USI.
>Kann ich da vielleicht mit selbstmodifizierendem Code arbeiten.
Nein. Erstens weil das per se Murks ist, und zweitens weil der AVR das
ganz sicher NICHT schnell kann. Vergiss die Idee.
Um das Ganze vielleicht ein wenig zeitlich zu entspannen meine Idee.
Nimm ein 4 oder 8Bit FlipFlop (74HC273) und nimm es als Zwischenpuffer.
Die Daten werden mit der jeweils günstigen Flanke in das FlipFlop
getaktet, gleichzeitig löst der Takt einen Interrupt aus. Nun hat dein
AVR 20 Takte Zeit, die Daten zu lesen und zu verarbeiten, die kritische
Abtastung ist schon erfolgt. Das könnte man mit kompakter Programmierung
im Interrupt machen (Register nicht pop/pushen sondern exklusive
Nutzung, nur das SREG sichern). Noch besser wäre die Nutung von mehr
Lokik, entweder als TTL Bausteine oder CPLD.
Aber mal ganz grundsätzlich, was ist das denn für ne komische
Schnittstelle?
MFG
Falk
Hallo Falk,
die Taktfrequenz ist und bleibt 1 MHz / s, aber da man keinen Streit
drueber.
Das Zwischenpuffern in einem FlipFlop ist sicherlich reizvoll, aber das
Daten Speichern macht er schon recht ordentlich. Mir geht es nur darum
das Pollen des Startcodes ab zu verbessern.
Frage: Kann ich den Ausgang eines Schmitt-Triggers 40106 auf die beiden
externen INT Eingaenge legen? So ohne weiteren Widerstand dazwischen.
Wenn ich an die Digitalen Zeiten zurueckdenke sollte doch ein Ausgang
zwei Eingaenge versorgen koennen, ohne dabei in die Knie zu gehen oder
das Signal weiter zu verfaelschen?
Ich wuerde dann naemlich den Interrupt per Interupt umschalten.
Gedankensalat:
Main:
INTEXT01 = ein.
INTEXT01 = Startcode erkannt.
INTEXT01 aus.
INTEXT00 aktivieren.
RETI
INTEXT00 = Speichern der Daten bis MaxAnzahl
MaxAnzahl erreicht = INTEXT00 aus.
RET.
RETI
Verarbeitung.
RJMP Main
So sollte es doch klappen. Oder?
Gruss
Roman
@ Roman (Gast)
>die Taktfrequenz ist und bleibt 1 MHz / s, aber da man keinen Streit>drueber.
1 Hz = 1 Schwingung / s
1 Hz / s = ???
>Wenn ich an die Digitalen Zeiten zurueckdenke sollte doch ein Ausgang>zwei Eingaenge versorgen koennen, ohne dabei in die Knie zu gehen oder
Ja.
>So sollte es doch klappen. Oder?
Möglich.
MFg
Falk
Hallo Falk,
das gibt ja Anlass zur Hoffnung. Ich weiss zwar das es etwas
unkonventionell ist, aber nur so werden Ideen geboren.
Achja das Ganze ist in einer elektronischen Orgel verbaut, die
unablaessig einen Datenstrom zur Peripherie sendet. Daraus sind gezielt
die von mir genannten 44 Datenhalbytes (Nibbles) heraus zu filtern.
Also doch 1 MHz wie zuerst genannt. Na da bin ich Dir aber auf den Leim
gegangen. Die Datenrate rechne ich dann mal spaeter aus. Wie gesagt, bin
Anfaenger aber mit jeder Menge Flausen im Kopf.
Gruss und Danke
Roman
@Falk:
Hz/s sind natürlich Schwingungen / s², also eine Frequenz, die sich mit
der Zeit ändert.
@Roman:
Selbstmodifizierender Code geht bei den AVRs nicht. Sie können im RAM
keinen Code ausführen und im Normalbetrieb das Flash nicht ändern.
Selbst wenn man das Flash ändern könnte, dann würde man dieses mit
ständigen Änderungen schnell kaputt machen.
Markus
Schoenen Dank fuer die Antworten.
Ich habe das Ganze jetzt mal ins Reine geschrieben (siehe Anhang).
Ich werde den Code heute Abend mal testen. Etwas problematisch erscheint
mir das Warten auf ein Ergeignis in einer Schleife mittels RJMP. 2
Zyklen verbraucht der Sprung ohne etwas zu tun. Das kalkuiere ich mal
als Loop Delay (gestrichelte Linien)in meiner Skizze. Gibt es da
vielleicht eine bessere Loesung.
Roman
@ Roman (Gast)
>Ich werde den Code heute Abend mal testen. Etwas problematisch erscheint>mir das Warten auf ein Ergeignis in einer Schleife mittels RJMP. 2>Zyklen verbraucht der Sprung ohne etwas zu tun. Das kalkuiere ich mal>als Loop Delay (gestrichelte Linien)in meiner Skizze. Gibt es da>vielleicht eine bessere Loesung.
Ja, die Nutzung von Interrupts (externer Interrupt oder Pin Change), die
dauern zwar länger, sind aber dann konstanter in der Verzögerung.
MfG
Falk
Auf die Start Condition Interrupt gesteuert warten (Sleep).
Wenn der Interrupt ausgeführt wird alle 20 Takte das Nibble ins RAM
schaufeln (als Byte).
In ewta so
wait_for_start:
ldi zh,1
clr zl
sleep ;wait for start condition
int0:
in r16,pinb
st z+,r16 ;copy to ram 0x100
nop
nop
nop
nop
...
in r16 ,pinb
st z+,r16
...
frißt zwar wahnsinning viele bytes, ist aber dafür verdammt schnell.
Hallo Zusammen,
das mit dem Interrupt hat geklappt. Der Start ist jetzt genau definiert,
und somit auch das Einlesen. Das mit dem Sleep Modus habe ich immer als
zeitraubend verstanden. Werde es aber noch mal nach lesen.
@Falk: Da die Orgel auch noch ein drittes Manual hat(Tastenreihe) komme
ich gerne nochmal auf Deinen Vorschlag mit SPI zurueck. Die 3te
Tastenreihe muss separat abgetastet werden und der Bewegungssensor mit
einem ADC erfasst werden. Vielleicht mache ich das autonom mit einem
Tiny.?. und hole mir die Daten ueber die SPI Schnittstelle. Wie ich den
Tiny dann ansprechen muss damit er mir die Daten schickt ist mir derzeit
noch ein Buch mit sieben Siegeln. Aber es gibt ja das Forum.
Nochmals Dank an alle.
Gruss
Roman