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...
T. Baumbach schrieb: > Setze ich den Pin einfach auf high/low und arbeite dann mit delay_us()? Wenn der µC nichts anderes tun soll als diese Bitfolge auszugeben, dann spricht nichts dagegen. Sonst: Timer aufsetzen und in der ISR bis 3 oder 6 zählen, dann Pegel ändern.
:
Bearbeitet durch Moderator
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.
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).
T. Baumbach schrieb: > Wie bekomme ich das Timing hin? Die erste Frage lautet: wie genau muss es sein? Je nach Anforderung und je nachdem, was im Programm sonst noch so läuft, nimmt man eine andere Methode.
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.
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.
:
Bearbeitet durch User
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.
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.
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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
UART auf 7N1 einstellen, UBRR = 2. So passen 3 Daten-Bits in ein "UART-Byte". Diese "UART-Bytes" vorher vorbereiten, dann ist das ganze Timing ziemlich unkritisch.
Karl H. schrieb im Beitrag #4312284:
> Das Problem sind die Stoppbits.
Warum?
0 und 1 enden beide mit 3µs High. Sie unterscheiden sich nur im
"Mittelteil".
Drei Daten-Bits hintereinander sehen also so aus:
1 | L x H L x H L x H |
2 | | | |
3 | Startbit Stopbit |
:
Bearbeitet durch User
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.
:
Bearbeitet durch Moderator
Hallo, ich werde es dann wohl mal mit den delays versuchen. Danke an alle!
T. Baumbach schrieb: > kann man da evtl. mit ASM-Code innerhalb des C-Codes was machen? Nein. Bei Deinen Timing-Anforderungen mußt Du das in ASM machen. Der Rest kann dann C sein.
:
Bearbeitet durch User
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.
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.
Thomas H. schrieb: > Etwas Zeit unkrietischer wäre es > natürlich wenn du deinen Chip auf 20 MHz takten könntest. Ebenso könnte man einen DMA-fähigen µC verwenden. Dann sind das Peanuts.
1. fast PWM: Du hast 9µs = 144 Zyklen Zeit, das nächste Bit nachzuladen. Das geht in C ohne Probleme. 2. UART mit 7Bit bei 333kBaud: Damit kannst Du je UART-Byte 3 Bit senden. 3. ATmega324 nehmen und UART als gepufferten SPI-Master.
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
Sieht für mich fast nach seriellen LEDs (WS2812B) aus. Die haben ein kritisches Timing. Das Senden macht man dann per ASM und sperrt davor die Interrupts. Bei 4 MHz kritisch, bei 16 MHz locker machbar.
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.
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.
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)
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.