Atmega32 Bitmuster senden

Gast #4312173
Lesenswert?

Hallo,

ich möchte Bitmuster z.B. 01101100 über einen GPIO des Atmega32 senden.
Der Atmega ist mit 16MHz getaktet.
Für eine logische Null möchte ich 3uS low dann 6us high an den GPIO Pin 
legen:

___------


Für eine logische Eins möchte ich 6uS low dann 3us high an den GPIO Pin 
legen:

______---


Wie bekomme ich das Timing hin?
Setze ich den Pin einfach auf high/low und arbeite dann mit delay_us()?
Oder nehem ich da besser die PWM, aber wie sende ich damit dann 
Bitfolgen?
Weil ja die PWM eigentlich ein immergleiches high/low Verhältnis sendet.

Danke für Eure Hilfe...
#4312192
Lesenswert?

Man könnte auch überlegen, ob man das Timing mit SPI hinbekommt, aber 
ohne DMA sendet SPI IMO nicht back-to-back auf AVR.

Die delay_us Methode hat großen Jitter wenn Interrupts aktiv sind, denn 
die Delay Zeit verlängert sich um die Zeit, die der µC währenddessen im 
Interrupt braucht.

Die PWM müsste man nach jedem Zyklus neu mit dem nächsten Wert laden, 
das könnte knapp passen.
#4312208
Lesenswert?

Jim M. schrieb:
> Frank M. schrieb:
>> Sonst: Timer aufsetzen und in der ISR bis 3 oder 6 zählen, dann Pegel
>> ändern.
>
> Timer Interrupt mit 1 µs Zykluszeit ist bei 16 MHz nicht mehr möglich,
> da für den Interrupt Aufruf zuviele Zyklen verwendet werden (Register
> sichern etc).

3µs könnten sich allerdings ausgehen. Bei 48 Takten hat man noch ein 
bischen Reserve. Nicht viel, aber immerhin.
(Firma: CIA) #4312225
Lesenswert?

T. Baumbach schrieb:
> Wie bekomme ich das Timing hin?

Wie bereits gefragt, soll der Controller nur seine Bitfolge senden, oder 
was anderes nebenher machen? Für eine Sequenz deines Bits zu senden 
brauchst du ca. 72 µs. Das ist relativ unkritisch und wesentlich 
schneller als in der Regel eine Ausgabe auf ein LCD Display.  Kommt 
jetzt darauf an wie oft das gesendet werden muss und wie die Toleranzen 
der Timings sind. Man kann, aber man muß es nicht mittels Timer und ISR 
machen. Ich würde es zumindest in C embeded Assembler (Externe 
Ass-Datei)  umsetzen. Aber das ist natürlich Geschmacksache.
Gast #4312231
Lesenswert?

Hi,

danke schonmal, die Genauigkeit sollte so bei +/- 150ns liegen.
Die Bitfolgen bestehen aus ca. 100-300 Bytes.
Dann ist erstmal Pause. Neue Bitfolgen sollen dann gesendet werden, wenn 
bestimmte Sensoren neue Daten liefern. Das kann mal Sekunden, mal 
Minuten dauern. Die Sensoren werden über Interrupts abgefragt.
#4312243
Lesenswert?

T. Baumbach schrieb:
> Hi,
>
> danke schonmal, die Genauigkeit sollte so bei +/- 150ns liegen.

Das wird eng.
Da kommt es auf jeden einzelnen Takt an.

> Die Bitfolgen bestehen aus ca. 100-300 Bytes.

Dann wird es noch enger. 1 Byte ausgeben wird schon knapp, aber dann 
muss ja auch noch der Nachschub rollen.

> Dann ist erstmal Pause. Neue Bitfolgen sollen dann gesendet werden, wenn
> bestimmte Sensoren neue Daten liefern. Das kann mal Sekunden, mal
> Minuten dauern.

reine Neugier:
Was hängt denn da am anderen Ende, dass du mit derart fiesen Timings 
arbeiten musst?

das ganze erinnert mich ans Bundesheer: 3/4 der Zeit hängt man rum und 
tut nichts, aber der Mülleimer muss in Lichtgeschwindigkeit ausgeleert 
werden.
#4312255
Lesenswert?

Karl H. schrieb:
> T. Baumbach schrieb:
>> Hi,
>>
>> danke schonmal, die Genauigkeit sollte so bei +/- 150ns liegen.
>
> Das wird eng.
> Da kommt es auf jeden einzelnen Takt an.

Im Moment seh ich nicht viele andere Möglichkeiten als tatsächlich einen 
PWM Modus zu benutzen. Zusätzlich noch einen Interrupt auf den Compare 
Match, wenn der Pin vom Timer von 1 auf 0 umgeschaltet wird. Im 
Interrupt wird dann das OCR Register jeweils nachgeladen.

Eng wird es auf jeden Fall, denn mehr als 3µs hast du im schelchtesten 
Fall nicht, um dieses Nachladen zu bewerkstelligen. Und die 300 bytes 
wollen ja auch aus dem Speicher rangekarrt werden.
#4312265
Lesenswert?

Karl H. schrieb:

> Eng wird es auf jeden Fall, denn mehr als 3µs hast du im schelchtesten
> Fall nicht, um dieses Nachladen zu bewerkstelligen. Und die 300 bytes
> wollen ja auch aus dem Speicher rangekarrt werden.

Was natürlich schon geht.
Interrupts aus und dann mit Warteschleifen die Zeit absitzen. Erfordert 
allerdings genau Abstimmung in Assembler über alles. Jeder Taktzyklus 
zählt.
Moderator Persönliche Seite #4312335
Lesenswert?

T. Baumbach schrieb:
> Hi,
>
> kann man da evtl. mit ASM-Code innerhalb des C-Codes was machen?

Solange Du parallel Interrupts laufen lässt, ist ASM auch keine Lösung.

Du hast eigentlich 2 Möglichkeiten. Beide wurden oben schon angerissen.

  1. Während des Transfers sämtliche Interrupts auschalten
     und mit Delays arbeiten, damit Dir keiner dazwischenfunkt.
     Dann bleibt jedoch noch ein kleiner Overhead, um die 300
     Bytes in einer Schleife rauszupusten. Diesen musst Du evtl. in
     die Delays mit einbeziehen.

  2. Du benutzt den UART und füllst diesen, wie Stefan es beschrieben
     hat. Hier könntest Du Interrupts dann zulassen, wenn diese
     so kurz sind, dass das Füllen des UARTs nicht abreisst, der
     UART also ununterbrochen feuert.

Ich weiß nicht, wie genau die Signale sein müssen. Hier handelt es sich 
wohl um einen asymmetrischen Biphase-Code. Wenn der Empfänger sich auf 
die Flankenwechsel neu "einschießt", also den Takt aus den Flanken 
gewinnt, kann es durchaus sein, dass größere Abweichungen (z.B. 20%) 
keine Rolle spielen.
(Firma: CIA) #4312341
Lesenswert?

T. Baumbach schrieb:
> Hi,
>
> kann man da evtl. mit ASM-Code innerhalb des C-Codes was machen?

Klar kann man, aber  Das ist meiner Meinung nach nur etwas für 
Masochisten. Ich lagere den *.s Code aus und kann so Ass  programmieren 
ohne mir das Hirn zu verbiegen.  Es wäre ein Versuch wert eine Funktion 
zum senden deiner Bitblöcke in Asseembler zu programmieren und diese am 
Stück zusenden. Das unterbricht dein Hauptprogramm circa um 22ms,  wenn 
ich mich nicht verrechnet habe.  Die zusenden und Bytes sollten in einem 
Block hintereinander im Speicher liegen, dann sollte eigentlich auch das 
Nachladen kein großes Problem sein.   Etwas Zeit unkrietischer wäre es 
natürlich wenn du deinen Chip auf 20 MHz takten könntest.
#4312346
Lesenswert?

Stefan E. schrieb:
> Karl H. schrieb im Beitrag #4312284:
>> Das Problem sind die Stoppbits.
>
> Warum?

Ich habs nach 30 Sekunden zurückgezogen. hatte die 7 in 7N1 übersehen. 
Sind zusammen mit dem Startbit 9 Bits und damit ein vielfaches von 3

> Drei Daten-Bits hintereinander sehen also so aus:
>
1
> L x H L x H L x H
2
> |               |
3
> Startbit        Stopbit
4
>

Ja.
Da hab ich zu langsam geschaltet und zu schnell getippt.
Sorry.
Gast #4312374
Lesenswert?

Man kann ja im Assembler versuchen kein Register zu benutzen mit SBI und 
CBI, dann braucht man auch keine Register zu sichern. Bei 16MHz dann 
halt
Low: 48 x "CBI PORTA,7" und 96 "SBI PORTA,7"
High:96 x "CBI PORTA,7" und 48 "SBI PORTA,7"
Oder halt ne schleife mit einem Arbeitsregister das dann noch gepusht 
und gepopt werden muß.
Ansosnten halt Timer benutzen: mit CTC Bit gesetzt und Interupt on 
Compare match und Interupthandler selber in Assembler schreiben nur 
Statusregister sichern und ein Arbeitsregister sichern und zum laden des 
Comparewertes benutzen
(Firma: CIA) #4312447
Lesenswert?

Frank M. schrieb:
> Ebenso könnte man einen DMA-fähigen µC verwenden. Dann sind das Peanuts.

Klar und ohne Frage. Es gäbe noch unzählige Lösungen. Sind aber alle 
unnötig inclusive 20 Mhz, wenn er seine ISR's stoppen könnte für die 
25ms, wozu er sich aber noch nicht geäußert hat. Den Assemblercode für 
das Rausschieben von ein paar Bytes zu erstellen ist unter der 
Zuhilfenahme des Simulators (um das Timing zu kontrollieren) zudem eine 
Anfängeraufgabe.
#4312474
Lesenswert?

uwe schrieb:
> Interupthandler selber in Assembler schreiben

Bei 144 Zyklen Interruptrate ist Assembler völlig unnötig.
Da muß man sich schon sehr dumm anstellen, um in C über 100 Zyklen zu 
verbrauchen.
Die Daten sollten aber schon gepuffert vorliegen, d.h. der Interrupt hat 
einen Zähler 0..7 für das Rotieren der 8 Bits und einen Pointer auf das 
zu sendende Datenbyte.
Gast #4312554
Lesenswert?

T. Baumbach schrieb:

> ich möchte Bitmuster z.B. 01101100 über einen GPIO des Atmega32 senden.
> Der Atmega ist mit 16MHz getaktet.
> Für eine logische Null möchte ich 3uS low dann 6us high an den GPIO Pin
> legen:
>
> ___------
>
>
> Für eine logische Eins möchte ich 6uS low dann 3us high an den GPIO Pin
> legen:
>
> ______---
>
>
> Wie bekomme ich das Timing hin?

Z.B. mit den Dingern, die sich schon rein vom Namen her für solche 
Sachen anbieten, mit Timern.

> Oder nehem ich da besser die PWM, aber wie sende ich damit dann
> Bitfolgen?

Indem du in der ISR den OCR-Wert für das nächste Bit einstellst.

> Weil ja die PWM eigentlich ein immergleiches high/low Verhältnis sendet.

Nicht, wenn du den OCR-Wert änderst...

Das müßtest du hier alle 9µs tun, was bei 16MHz Takt noch kein 
nennenswertes Problem ist, schließlich kann der AVR in 9µs bei 16MHz 
genau 144 Takte lang Code abarbeiten. Natürlich hast du etwas 
Interrupt-Overhead, aber in einer gediegenen Programmiersprache bleiben 
trotzdem reichlich Takte in der ISR über, um den Job zu erledigen, den 
sie erledigen muß.



Allerdings gibt es eine noch effizientere Lösung, wenn man eine 
SPI-masterfähige USART zur Verfügung hat. Dein Problem kann man dann 
nämlich auch damit lösen und dadurch die Interrupt-Rate auf fast ein 
Drittel senken (in jedem gesendeten Byte stecken 2 2/3 encodierte 
Nutzbits. Leider ist aber die Komplexität des Nutzcodes selber dann 
deutlich höher, im Vergleich von hochoptimierten Asm-Implementierungen 
der beiden Ansätze ergibt sich dadurch dann nur noch ein relativ kleiner 
Vorteil für die USART-SPI-Lösung.
Aber in Stümper-C mit seinem hoch-ineffizienten Interrupthandling wiegt 
die Ersparnis bei der ISR-Rate deutlich schwerer, hier lohnt der Ansatz 
durchaus.


Noch besser ist übrigens im konkreten Fall eine USART in ihrer ganz 
normalen Betriebsart, allerdings im 7N1-Modus. Da bekommt man dann 
nämlich
volle drei Nutzbits in einem Sende-"Byte" (nur 7 Bit lang) encodiert, 
drittelt also die nötige ISR-Rate, da zufällig die Level von LL-RS232- 
Start- und Stopbits in's gewünschte Encodier-Schema passen. Das 
vereinfacht dann den Nutzcode in der ISR so weit, dass es auch in Asm 
wieder sehr attraktiv wird. (In C sowieso, die Gülle profitiert hier 
gleich doppelt, sowohl vom trivialeren ISR-Code als auch von der 
weiteren Absenkung der ISR-Rate)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren