Datum:
Nicht jedem Otto-Normal-Endanwender von µC-Schaltungen steht ein Flashgerät oder eine serielle Schnittstelle (UART) zur Verfügung, um Daten zum Mikrocontroller zu übertragen oder gar ein Firmware-Update durchzuführen. Was aber ein jeder PC-Anwender hat, ist eine Soundkarte. Das Programmpaket SOUNDRX kann Daten mit mehr als 300 Zeichen pro Sekunde über die Soundkarte vom PC an einen ATMega übertragen. Das Paket enthält dafür ein Beispielprogramm sowohl für den µC als auch PC. Ebenso ist ein Bootloader für den µC und das dazugehörige PC-Programm vorhanden, um ATMegas mit mind. 2KB Bootloadergröße über ein simples Audiokabel zu flashen. Dieses Programmpaket ist damit für Endanwenderschaltungen gedacht, um Firmware-Updates zu ermöglichen, ohne sich direkt eine komplette Entwicklungs-Hardware anschaffen zu müssen. Die gegenwärtige Übertragungsgeschwindigkeit ist noch nicht das Optimum. An der Verbesserung der überaus simplen Emfängerschaltung wird noch gearbeitet, um die gegenwärtige Übertragungsrate von ca. 3000bd (wenn man es mit einer UART-Üertragung vergleicht) zu erhöhen. Der beigelegte Bootloader verbraucht im Moment auch noch ca. 1,6 KB an Code. Durch eine Binärübertragung kann der Speicherplatzverbrauch noch unter 1KB gedrückt werden, um den SOUNDRX-Bootloader auch für kleinere ATMegas einsetzen zu können. Im Moment wird die HEX-Datei noch im Klartext übertragen und auf dem µC interpretiert. Verlagert man diese Interpretation auf den PC, sollte sich der Bootloader auf unter 1KB drücken lassen. Näheres dazu haben wir im Artikel http://www.mikrocontroller.net/articles/SOUNDRX zusammengefasst. Gruß, Robert und Frank
Datum:
Hmm. Jeder PC hat heute eine USB-Schnittstelle. Entweder mutet man dem Endanwender zu, sich einen USB/Seriell-Wandler für 10 Euro zu besorgen, mit dem dann jeder Bootloader über die serielle Schnittstelle gefüttert werden kann... oder, man integriert in die µC-Schaltung sowieso einen FT232 bzw. ähnlichen Chip, um eine Kommunikation über USB zu ermöglichen, dann stellt sich das Problem erst gar nicht. Eine dieser beiden Lösungen ist m.E. auf jeden Fall einfacher, als ein spezielles Kabel für das Softwareupdate und entsprechende Treiber für die Soundkarte zu installieren.
Datum:
Oliver Döring schrieb: > Entweder mutet man dem Endanwender zu, sich einen USB/Seriell-Wandler > für 10 Euro zu besorgen, mit dem dann jeder Bootloader über die serielle > Schnittstelle gefüttert werden kann... > > oder, man integriert in die µC-Schaltung sowieso einen FT232 bzw. > ähnlichen Chip, um eine Kommunikation über USB zu ermöglichen, dann > stellt sich das Problem erst gar nicht. Die Schaltung mit dem LM741, kostet unter 50 Cent. Das schaffst Du nicht mit einem USB->Seriellwandler zu unterbieten. Außerdem sparst du den MAX232 in Deiner Schaltung. Stattdessen brauchst Du nur einen LM741 + 2 Widerstände + 2 100nF Kerkos + 3,5mm Klinkenbuchse > Eine dieser beiden Lösungen ist m.E. auf jeden Fall einfacher, als ein > spezielles Kabel für das Softwareupdate und entsprechende Treiber für > die Soundkarte zu installieren. Der Witz ist doch gerade, dass Du kein spezielles Kabel brauchst. Du nimmst einfach Dein Audio-Kabel, dass zu Deinem PC-Lautsprecher geht. Das Ende steckst Du einfach in die Klinkenbuchse - fertig. Ein spezieller Treiber ist auch nicht nötig, da es über den ganz normalen Windows-Soundtreiber geht, der bereits installiert ist. Achja, übrigens, wir haben gerade mal das Windows-Programm derart erweitert, dass es die HEX-Datei als WAVE-Datei speichert. Diese kann man dann mit einem beliebigen Abspielprogramm (z.B. Winamp oder auch Irfanview) an den µC schicken. Wenn man als Entwickler die Wave-Datei an den Endanwender schickt, kann dieser mit einem beliebigen Windows-/Linux-/Apple-/MP3-Player das Firmware-Update auf den µC flashen. So haben wir gerade eben mit Winamp unseren ATMega geflasht :-) Update kommt demnächst... Gruß, Frank
Datum:
Das ist doch mal eine kreative Art, µC zu flashen. Braucht man eigentlich den OPV unbedingt? Es wäre ja noch schöner, wenn man höchstens drei Widerstände zusätzlich bräuchte.
Datum:
Dennis S. schrieb: > Das ist doch mal eine kreative Art, µC zu flashen. Finde ich auch :-) Übrigens: die Idee ist eigentlich 30 Jahre alt. Damals hat man in den C64/ZX-Spectrum die Programme/Daten mit einem Kassettenrecorder geladen. Hier passiert eigentlich genau dasselbe: Die Daten werden in (hörbare) Töne gewandelt und dann an den µC übertragen. > Braucht man eigentlich den OPV unbedingt? Es wäre ja noch schöner, wenn > man höchstens drei Widerstände zusätzlich bräuchte. Der Audiosignalpegel reicht leider nicht aus, dieses ohne Verstärkung direkt auf den µC zu geben.
Datum:
Hmm, wenn das ganze jetzt noch mit Frequenzen zwischen 300-2600 Hz läuft und mit Phasendrehungen zurecht kommt gäbe es dafür evtl. noch eine interessante Anwendung. Man könnte solch ein Update über ein Telefon machen. Sprich man hat an einer Stelle einen Anrufbeantworter der das Programm als Ansage hat, und sagt der Person, dass sie einfach den Hörer auf die mit Leiterbahn gemachte Spule auf der Platine legen soll und bei der Nummer anrufen soll. Einfacher geht es wirklich nicht mehr. @odbs: Nur sehr wenige Leute sind in der Lage USB stabil zum Laufen zu bekommen. Ich gehöre nicht dazu.
Datum:
Christian Berger schrieb: > Hmm, wenn das ganze jetzt noch mit Frequenzen zwischen 300-2600 Hz läuft > und mit Phasendrehungen zurecht kommt gäbe es dafür evtl. noch eine > interessante Anwendung. Man könnte solch ein Update über ein Telefon > machen. Sprich man hat an einer Stelle einen Anrufbeantworter der das > Programm als Ansage hat, und sagt der Person, dass sie einfach den Hörer > auf die mit Leiterbahn gemachte Spule auf der Platine legen soll und bei > der Nummer anrufen soll. Einfacher geht es wirklich nicht mehr. Nette Idee. Im Moment werden Frequenzen zwischen 1200 Hz bis 6000 Hz verwendet. Diese könnte man durch Ändern der Preprozessor-Konstanten SNDRX_F_SAMMPLES von derzeit 12000 auf einen niedrigeren Wert erreichen. Die Baudrate würde dann von derzeit ca. 3000 Bd auf ca. 300 Bd sinken, also vergleichbar mit den damaligen Akkustikkopplern. Aber ich glaube, es ist trotzdem heutzutage einfacher, dem Anwender die Wave-Datei per Mail zuzusenden und ihn zu bitten, diese mit dem WinAmp oder Windows-Media-Player abzuspielen ;-) Achja: Vorher nicht vergessen: Der Lautstärke-Regler muss auf mindestens 3/4 oder besser noch auf Vollausschlag!
Datum:
Ach ja, die ATMegas in SMD haben häufig einen differentiellen Eingang für den Wandler, den man auch auf x10 und x200 schalten kann. Damit könnte man sich eventuell den Verstärker sparen.
Datum:
Christian Berger schrieb: > Ach ja, die ATMegas in SMD haben häufig einen differentiellen Eingang > für den Wandler, den man auch auf x10 und x200 schalten kann. Damit > könnte man sich eventuell den Verstärker sparen. SOUNDRX benutzt einen digitalen Pin und keinen DA-Wandler. Den meintest Du doch?
Datum:
Sehr schönes und kreatives Prinzip. Einzige Frage: Haben nicht die meisten Sound-Ausgabe-Geräte ein fest angeschlossenes Kabel, also kein Stecker-Stecker-Kabel? Was ich noch besser Fände: Sound über KondensatorMikrofon aufnehmen, Frequenzanalyse (1=10KHz 0=1KHz) und so programmieren. Also so ähnlich wie der weiter oben beschriebene Ansatz mit der Leiterschlaufe auf der Platine.. Grüße Tüftler
Datum:
Tueftler schrieb: > Haben nicht die meisten Sound-Ausgabe-Geräte ein fest angeschlossenes > Kabel, also kein Stecker-Stecker-Kabel? Ja, einige Brüllwürfel für den PC haben ein fest angeschlossenes Kabel. Dann nimmt man dann einfach das beim Monitor mitgelieferte Audiokabel. Die meisten haben ja mittlerweile integrierte Lautsprecher. Hier hat das Kabel immer an beiden Enden eine grüne 3,5mm Klinke. > Was ich noch besser Fände: Sound über KondensatorMikrofon aufnehmen, > Frequenzanalyse (1=10KHz 0=1KHz) und so programmieren. Das sollte gehen. Wenn man an den OPV ein Mikrofon anschließt und eine genügende Verstärkung da ist, müsste man das Mikro auch vor den Lautsprecher halten können. Allerdings ist das, was da am Lautsprecher über SOUNDRX ausgegeben wird, nicht gerade ohrenfreundlich. Ich würde jedenfalls dann fluchtartig den Raum verlassen ;-)
Datum:
Neue Version 1.1.0 verfügbar. Damit kann man nun mit sndtx.exe auch eine WAVE-Datei erzeugen, statt die HEX-Datei direkt "abzuspielen". Dies geht folgendermaßen: sndtx.exe -f Dateiname.hex Dateiname.wav Die erzeugte WAVE-Datei kann dann mit einem beliebigen WAVE-Player abgespielt und damit an den µC übertragen werden. Download-Datei und Artikel wurde entsprechend aktualisiert. Gruß, Robert und Frank
Datum:
Das nenne ich doch mal genial! Versuche es aufjedenfall in meinem Projekt unterzubringen :)
Datum:
Tolle Sache. Nach dem Denkanstoß von euch habe ich es mit einem Pic implementiert, jedoch nicht Modemcodiert sondern Pulscodiert. Braucht nur 1 pin, keine zusätzliche HW, und FW-Update ist mittels MP3 Player oder PC machbar. Nicht schlecht und unschlagbar Preiswert in HW.
Datum:
Die Idee ist zwar nicht neu, aber gut. Vor allem wenns auch mit nem popeligen MP3-Player funzt. Hat schon fast was von einem C64 mit Datasette. Nur halt den technischen Möglichkeiten angepasst :-)) Weiter so :-)
Datum:
Ich habe nun die OPV-Schaltung durch einen simplen Transistor + 2 Widerstände + 1 Kerko ersetzt. Erste Tests damit ergeben: 1. Signal-Empfindlichkeit ist wesentlich höher 2. Die Geschwindigkeit kann auf ca. 960 Zeichen erhöht werden, das entspricht dann ca. 9600 Bd bei einer vergleichbaren UART-Verbindung. Ich teste heute abend noch ein wenig die Grenzen aus, bevor ich ein Update des Artikels mache... Bis später, Frank
Datum:
Neue Version 1.2.0 ist online: - Neue Eingangsschaltung bestehend aus nur einem einem Kerko, drei Widerständen und einem Transistor - Geschwindigkeitserhöhung auf über 1000 Zeichen/sec. Das entspricht einer Baudrate von über 9600 Bd, wenn man die Übertragungsrate mit UARTs/RS232 vergleicht. - Bugfix in sndtx.exe beim Interpretieren der HEX-Datei (bei kurzen Zeilen) Der Artikel und die Download-Dateien wurden aktualisiert, siehe: http://www.mikrocontroller.net/articles/SOUNDRX Viel Spaß, Frank
Datum:
Hallo Frank, ein großes Lob an euch. Die Datenübertragung via Soundkarte ist auch ein Projekt, welches ich schon lange realisieren wollte. Ein Frage: Geht das ganze wirklich via MP3? Durch die Komprimierung und die verlustbehaftete Kompression kann ich mir das nicht vorstellen. Gruß, chris
Datum:
Hallo Chris, chris schrieb: > Ein Frage: Geht das ganze wirklich via MP3? Durch die Komprimierung und > die verlustbehaftete Kompression kann ich mir das nicht vorstellen. Das ist eher ein Missverständnis: man kann es mit einem MP3-Player abspielen, weil dieser in der Regel auch WAV-Dateien abspielen kann. MP3 als Datenformat wird wohl wirklich nicht funktionieren, da (wie Du schon sagtest), MP3 tatsächlich verlustbehaftet ist. Möchte man die WAV-Datei komprimieren, muss man schon ein verlustfreies Kompressionsprogramm nehmen, z.B. zip. Gruß, Frank
Datum:
Mp3 codiert geht mit bestimmten Voraussetzungen. Deshalb habe ich auch Pulscodierung verwendet. Codierung OOK z.B ein IR Protocoll wie das von Sony. Da wird nur zwischen Musik und Pause unterschieden und das lässt sich hervorragend mit Mp3 komprimieren.
Datum:
Chris schrieb: > Mp3 codiert geht mit bestimmten Voraussetzungen. Deshalb habe ich auch > Pulscodierung verwendet. Codierung OOK z.B ein IR Protocoll wie das von > Sony. Da wird nur zwischen Musik und Pause unterschieden und das lässt > sich hervorragend mit Mp3 komprimieren. SOUNDRX benutzt (wie IR-Fernbedienungen auch) ein Pulse-Distance-Protokoll, Timing siehe SOUNDRX-Artikel: http://www.mikrocontroller.net/articles/SOUNDRX Wir haben es ausprobiert: WAVE-Daei erzeugt, mit LAME nach MP3 codiert und anschließend mit WinAmp ausgegeben. Ergebnis: - WAVE-Datei geht - MP3-Datei geht nicht Jedenfalls bei 1000 Zeichen pro Sekunde. Vielleicht geht es mit niedrigeren Sampleraten. Aber was gewinnst Du dadurch? Nichts, denn die Datenmenge, die zum µC übertragen wird, bleibt dieselbe. Gruß, Frank
Datum:
Neue Version 1.3.0 ist online.
Änderungen:
- Binärübertragung für Bootloader, dadurch Verdoppelung der
Flash-Geschwindigkeit. Damit ist Geschwindigkeit vergleichbar
mit der eines üblichen ISP-Programmers.
- Neues PC-Flash-Programm sndflash.exe
- Abschalten des Ringbuffers nun möglich mit SNDRX_RINGBUFSIZE = 0
- Optimierung der ISR-Statusvariablen
Der Artikel und die Download-Dateien wurden aktualisiert, siehe:
http://www.mikrocontroller.net/articles/SOUNDRX
Viel Spaß,
Robert und Frank
Datum:
hi, nettes projekt. kann es sein, dass in dem Archiv die Bootloader-Sourcen fehlen?
Datum:
Hallo Zusammen, vielleicht ließe sich die Datenrate verdoppeln, wenn man die Bits in die Flanken kodiert. Jetzige Datenrate im Mittel: 44100/((2+2+3+5)/2)=44100/6=7350 Baud Bei Codierung in Flankenwechsel ( low=2 samples hight=4 samples ) 44100/((2+4)/2)=14700 Baud Gruß, chris
Datum:
Hi Vlad, Vlad Tepesch schrieb: > kann es sein, dass in dem Archiv die Bootloader-Sourcen fehlen? Sorry, Du hast recht. Ich habs korrigiert und sndrx-bootloader.c angefügt. Liegt jetzt als V. 1.3.1 in der Download-Datei. Uns fehlen nch ca. 70 Bytes, um den Bootloader unter 1KB zu bekommen. Vielleicht findest Du (als Tüftler) ja noch eine Optimierungstelle? ;-) Gruß, Frank
Datum:
Hallo, finde die Idee super!! Man könnte noch R3 weglassen und den internen pullup nutzen, für die Sparfüchse unter uns :) (R2 muss natürlich angepasst werden)
Datum:
chris schrieb: > vielleicht ließe sich die Datenrate verdoppeln, wenn man die Bits in die > Flanken kodiert. Du meinst, vom Puls-Distance-Protokoll auf Manchester-Codierung wechseln? > Jetzige Datenrate im Mittel: > 44100/((2+2+3+5)/2)=44100/6=7350 Baud Deine Rechnung verstehe ich nicht. Ein Byte, das gleich viele 0en und 1en hat, kostet: 4 * 4T + 4 * 7T = 16T + 28T = 44T Dann ist die Übertragungsrate im Mittel: 44100 / 44 = 1002 Bytes pro Sekunde. Das ist vergleichbar mit einer UART-Übertragungsrate von 10020 Bd, da dort noch Start- und Stopbits übertragen werden müssen (10 Bits pro Byte). Bei SOUNDRX haben die Bytes kein Start- und Stopbit, nur der ganze Datenblock hat jeweils eins. Das kann man aber bei der Rechnung vernachlässigen. Damit übertrage ich real (im Mittel) 1020 Zeichen pro Sekunde. Diesen Wert zeigt mit sndtx.exe auch an. > Bei Codierung in Flankenwechsel ( low=2 samples hight=4 samples ) > 44100/((2+4)/2)=14700 Baud Das müsstest Du mal näher ausführen - wie gesagt, habs nicht verstanden. Gruß, Frank
Datum:
Sparfuchs schrieb: > Man könnte noch R3 weglassen und den internen pullup nutzen, für die > Sparfüchse unter uns :) Stimmt, Du hast vollkommen recht! Ich werde ihn für die nächste Version "wegoptimieren" ;-) > (R2 muss natürlich angepasst werden) Der kann so bleiben, der Wert ist relativ unkritisch. Gruß, Frank
Datum:
Hallo Frank, >Jetzige Datenrate im Mittel: >44100/((2+2+3+5)/2)=44100/6=7350 Baud in meiner Rechnung ist ein kleiner "Leichtsinnsfehler" Es muss natürlich heißen: 44100/((2+2+2+5)/2)=44100/6=8018 Bit/Sekunde In der Nachrichtentechnik wird meistens die Einheit Bit/Sekunde angegeben. Die Datenübertragungsrate in Bytes/Sekunde ( ohne Protokolloverhead ) wäre dann 8018 Bit/Sekunde / 8 Bit= 1002 Byte/Sekunde >Du meinst, vom Puls-Distance-Protokoll auf Manchester-Codierung >wechseln? Nein, das würde nichts bringen. Ich mache am besten mal ein Beispiel. Es soll diese Bit-Folge codiert werden: 010110 Daraus wird --_--__- _ = Low-Pegel, - = High- Die Bit-Information liegt im Abstand der Flanken. Gruß, chris
Datum:
Ähm, Tchuldigung, der Browser stellt meine Graphik falsch dar. Also noch mal mit anderen Symbolen ( Punkt= low, Strich=High ) 010110 Daraus wird .--.--..-. Jeder Punkt und jeder Strich ist genau 2 Takte lang.
Datum:
Frank M. schrieb: > Sparfuchs schrieb: > >> Man könnte noch R3 weglassen und den internen pullup nutzen, für die >> Sparfüchse unter uns :) > > Stimmt, Du hast vollkommen recht! Ich werde ihn für die nächste Version > "wegoptimieren" ;-) Auf diese Weise lassen sich auch durch Schalten den Pins auf GND die paar Hunderd Mikroampere einsparen, die sonst durch den Pullup fließen. Dann bleibt noch der Basisstrom.
Datum:
Hallo Chris, chris schrieb: > in meiner Rechnung ist ein kleiner "Leichtsinnsfehler" > Es muss natürlich heißen: > 44100/((2+2+2+5)/2)=44100/6=8018 Bit/Sekunde Okay, das passt dann wieder, die von Dir genannten 7350 Bd erschienen mir nur zu wenig. :-) Ich habe bewusst Zeichen/Sekunde statt Bit/Sekunde angegeben, weil man sonst eine SOUNDRX-Übertragung (8 Bit/Zeichen) schlecht mit einer UART-Übertragung (10 Bit/Zeichen) vergleichen kann. 8018 Bd bei SOUNDRX sehen schlechter aus als 9600 Bd bei UART, tatsächlich schafft aber SOUNDRX mehr Zeichen pro Sekunde (1002 Zeichen/sec) rüber als ein UART (960 Zeichen/sec). Um die tatsächliche Übertragungsgeschwindigkeiten besser zu vergleichen, rechne ich lieber mit Zeichen/sec :-) > Also noch mal mit anderen Symbolen ( Punkt= low, Strich=High ) > 010110 > Daraus wird > .--.--..-. Ich versuche mal, es zu verstehen. Ich sehe da folgende Flankenabstände: 1. Bit: low - >high: Abstand 1 (ich sehe aber die Flanke "davor" nicht) 2. Bit: high -> low: Abstand 2 3. Bit: low -> high: Abstand 1 4. Bit: high -> low: Abstand 2 5. Bit: low -> high: Abstand 2 6. Bit: high -> low: Abstand 1 Okay, da kommt die Bitfolge 010110 raus. Aber was mache ich beim allerersten Bit? Da nehme ich eine virtuelle Flanke high->low an? Da bei 8 Bit pro Byte nach dem 8. bit wieder Low-Pegel gegeben ist, müsste das funktionieren :-) Für die 6 Bit brauchst Du dann 20 Takte. Ich habe nämlich beim Testen auch gelernt, dass die Soundkarte nur vernünftige Pegel liefert, wenn ich diesen mindestens für 2 Takte konstant halte. Sonst gibt das Murks am Ausgang. Das passt dann ja auch mit Deiner Aussage: > Jeder Punkt und jeder Strich ist genau 2 Takte lang. Ich brauche im Moment für die Folge 010110: 3 x 4 + 3 x 7 insgesamt 33 Takte, d.h. Deine Methode würde einen Faktor von 1,65 an Geschwindigkeit rausholen, also statt 1002 Bytes/sec wären das dann 1653 Bytes/sec. Ich glaube, das werde ich mal ausprobieren, gefällt mir :-) Gruß, Frank P.S. Es gibt noch eine andere Möglichkeit, die Geschwindigkeit nochmal zu verdoppeln: Stero statt Mono, kostet dann aber 2 Input-Pins am ATmega ;-)
Datum:
>Okay, da kommt die Bitfolge 010110 raus. Aber was mache ich beim >allerersten Bit? Da nehme ich eine virtuelle Flanke high->low an? >Da bei 8 Bit pro Byte nach dem 8. bit wieder Low-Pegel gegeben ist, >müsste das funktionieren :-) Du könntet als Startsequenz z.b. 10xNull + 1 mal Eins senden ( in Flankencodierung ). Dein Algorithmus müsste dann einfach die Zeitabstände messen: Für die 10 Nullen müssen zehn kurze Zeitabstände nacheinander auftauchen, dann der lange Abstand für die 1. Danach kannst Du den ganzen Datenstrom Senden. >Für die 6 Bit brauchst Du dann 20 Takte. Ich habe nämlich beim Testen >auch gelernt, dass die Soundkarte nur vernünftige Pegel liefert, wenn >ich diesen mindestens für 2 Takte konstant halte. Das habe ich mir fast gedacht, als ich die Beschreibung im Wiki gelesen habe. Vielleicht könnte man die Datenrate mit der Flankencodierung noch etwas erhöhen: 2 Takte für die 0 und 3 Takte für die 1. Dann käme man auf 44100/((3+2)/2)=17640 Bit/Sekunde also 2200 Byte/Sekunde.
Datum:
Angehängte Dateien:Frank M. schrieb: > > Uns fehlen nch ca. 70 Bytes, um den Bootloader unter 1KB zu bekommen. 70? bei mir (avr-gcc (WinAVR 20100110) 4.3.3) kompiliert das ding mit 1060 Bytes, also nur 36 zu viel > Vielleicht findest Du (als Tüftler) ja noch eine Optimierungstelle? ;-) Ich hab sogar recht einfach 60Bytes wegbekommen.
AVR Memory Usage ---------------- Device: atmega168 Program: 1000 bytes (6.1% Full) (.text + .data + .bootloader) Data: 45 bytes (4.4% Full) (.data + .bss + .noinit) |
Allerdings bringt das jetzt 2 Warnungen, die aber normalerweise (dazu siehe unten) ignoriert werden können
../sndrx-bootloader.c: In function 'main': ../sndrx-bootloader.c:209: warning: function declared 'noreturn' has a 'return' statement ../sndrx-bootloader.c:209: warning: 'noreturn' function does return |
was etwas unschön bei deinem Bootloader ist: er springt einfach hart nach 0x0000 ohne vorher wieder aufzuräumen. Das Anwendungsprogramm findet also eine andere Umgebung vor, als es normalerweise erwarten würde. Wenn ich es nicht auf die schnelle übersehen habe sogar mit aktiven Timerinterupt. Was ich nicht weiß und was zu überprüfen wäre, ist: was übernimmt die crt? initialisiert die Arbeitsregister oder verlässt sie sich auf die Standardregisterwerte? falls letzteres packst du mit dem Bootloader auch Daten auf den Stack, die nie wieder abgeräumt werden. Genau hier könnte aber sogar meine Attribut-definition helfen. die sagt dem Compiler, "dies ist eine Funbktion, die nie mehr verlassen wird". Dieser kann daraufhin vezichten, register oder Rückspruingadressen zu retten. edit: ok, dem stack hilft das natürlich auch nicht komplett, er ist nur eventuell etwas leerer vor allem bei den kleinen Tinys ist dieser Trick extrem nützlich, da damit meist 20-50 Bytes gespart werden können
Datum:
chris schrieb: > Das habe ich mir fast gedacht, als ich die Beschreibung im Wiki gelesen > habe. Vielleicht könnte man die Datenrate mit der Flankencodierung noch > etwas erhöhen: 2 Takte für die 0 und 3 Takte für die 1. Auch eine Idee, werde ich ausprobieren. Aber ich habe da insgesamt zur Flankencodierung noch einen Punkt als Bedenken anzumelden: Ich habe die momentanen Taktzeiten für ein mögliches Signal bewusst mit einem Abstand von 3 Takten gewählt, nämlich 4, 7, 10, 13 für "0", "1", "Stop" und "Start", damit auch ein µC ohne Quarz noch zuverlässig zwischen den einzelnen Taktzeiten unterscheiden kann. SOUNDRX erkennt nämlich: 3 bis 5 T als 4 T -> "0" 6 bis 8 T als 7 T -> "1" 9 bis 11 T als 10 T -> "Start" 12 bis 14 T als 13 T -> "Stop" SOUNDRX arbeitet also mit einer Toleranz von +/- 1T. Wenn man diese Toleranz auch bei der Flanken-Kodierung beibehalten will, sieht das nicht mehr ganz so gut aus mit der Geschwindigkeitssteigerung. Dein obiges Beispiel für 6 Bits schreibe ich mal anders, nämlich in 1T-Einheiten (kurz = 2T, lang = 4T): ..----..----....--.. = 20T Das bläht dann die Geschichte folgendermaßen auf, wenn man den 3er Abstand beibehalten will (kurz = 2T, lang = 5T): ..-----..-----.....---.. = 24T Damit liegt dann die Geschwindigkeits-Steigerung bei "nur" noch 33/24 = 1,375. Ich habe da auch noch über eine Möglichkeit der Geschwindigkeitssteigerung nachgedacht, die man eventuell dann noch mit Deiner Flankencodierung (gibt es dafür eigentlich einen Fachbegriff, unter dem man Literatur dazu findet?) kombinieren könnte. Zur Veranschaulichung meiner Idee betrachte ich erstmal das Pulse-Distance-Protokoll, denn ich finde das anschaulicher. Der Kernpunkt ist, dass ich immer direkt 2 Bits auf einmal betrachte, nämlich die Bitfolgen 00, 01, 10 und 11. Bei dem bisherigen Verfahren sind das: 00: --..--.. = 4T + 4T = 8T 01: --..--..... = 4T + 7T = 11T 10: --.....--.. = 7T + 4T = 11T 11: --.....--..... = 7T + 7T = 14T ===================================== Summe: 44T Nun codiere ich die Bitpaare wie folgt: 00: --.. = 2T + 2T = 4T 01: --..... = 2T + 5T = 7T 10: --........ = 2T + 8T = 10T 11: --........... = 2T + 11T = 13T ====================================== Summe: 34T Bei gleichmäßigem Vorkommen dieser Bitmuster "verbrate" ich pro Byte dann 34 Takte - bei gleichem Abstand der möglichen Zeiten von 3 Takten (für die Toleranz). Das entspricht einer Geschwindigkeitssteigerung von 44/34 = 1,3. Vielleicht kann man dieses Verfahren mit der Flankencodierung kombinieren... mal schauen.
Datum:
Vlad Tepesch schrieb: > 70? bei mir (avr-gcc (WinAVR 20100110) 4.3.3) kompiliert das ding mit > 1060 Bytes, also nur 36 zu viel Bei mir sind es auch 1060 Bytes, ich hatte die 70 aus dem Kopf hingeschrieben und bewusst ein "ca." davorgeknallt, weil ich den exakten Stand nach endlosen Optimierungen am Wochenende heute morgen auch nicht mehr parat hatte. > Ich hab sogar recht einfach 60Bytes wegbekommen. Klasse! Wenn ich das richtig sehe, liegt der Unterschied ledliglich bei:
int main(void) __attribute__((noreturn)); /* saves some Bytes but produces warning */ |
> Allerdings bringt das jetzt 2 Warnungen, die aber normalerweise (dazu > siehe unten) ignoriert werden können Unschön, aber vielleicht kriege ich die auch noch weg :-) Vielleicht einfach main() als void deklarieren? Probiere ich aus. > was etwas unschön bei deinem Bootloader ist: > er springt einfach hart nach 0x0000 ohne vorher wieder aufzuräumen. Muss er aufräumen? Die C-Runtime am Anfang setzt doch sowieso Stackpointer etc. wieder neu beim Start. Oder etwa nicht? Ich denke mal, dass alles zu Beginn automatisch wieder neu initialisiert wird... > Das Anwendungsprogramm findet also eine andere Umgebung vor, als es > normalerweise erwarten würde. Wenn ich es nicht auf die schnelle > übersehen habe sogar mit aktiven Timerinterupt. Die Interrupt-Vektoren werden zurückgesetzt. Aber Du hast Recht: Der Timerinterrupt muss wieder deaktiviert werden. Ist mir nicht aufgefallen, weil ich bisher Anwendungsprogramme geflasht habe, die sowieso den Timer 1 benutzen :-) > Was ich nicht weiß und was zu überprüfen wäre, ist: > was übernimmt die crt? > initialisiert die Arbeitsregister oder verlässt sie sich auf die > Standardregisterwerte? falls letzteres packst du mit dem Bootloader auch > Daten auf den Stack, die nie wieder abgeräumt werden. Glaube ich nicht. Der Stackpointer wird gewiss re-initialisiert. > Genau hier könnte aber sogar meine Attribut-definition helfen. die > sagt dem Compiler, "dies ist eine Funbktion, die nie mehr verlassen > wird". Dieser kann daraufhin vezichten, register oder > Rückspruingadressen zu retten. Eben, da hast Du vollkommen recht. Ich werde das ausgiebig testen und mir bei der Gelegenheit die Initialisierungen der C-Runtime mal näher anschauen. Vielen Dank! Frank
Datum:
Frank M. schrieb: >> Allerdings bringt das jetzt 2 Warnungen, die aber normalerweise (dazu >> siehe unten) ignoriert werden können > > Unschön, aber vielleicht kriege ich die auch noch weg :-) > Vielleicht einfach main() als void deklarieren? Probiere ich aus. auf die idee bin ich noch nicht gekommen. eine Warnung geht weg, aber es kommt eine neue dazu.
../sndrx-bootloader.c:172: warning: return type of 'main' is not 'int' ../sndrx-bootloader.c: In function 'main': ../sndrx-bootloader.c:209: warning: 'noreturn' function does return |
und man spart 4 Byte ;) Frank M. schrieb: > Klasse! Wenn ich das richtig sehe, liegt der Unterschied ledliglich bei: und ein entferntes return, sonst gibt es noch eine Warning
Datum:
Vlad Tepesch schrieb: > Allerdings bringt das jetzt 2 Warnungen, die aber normalerweise (dazu > siehe unten) ignoriert werden können Die habe ich jetzt auch wegbekommen, nämlich mit:
int main (void) { main_loop (); } |
wobei ich den Code von main() nach main_loop() geschoben habe. Das musste ich machen, weil gcc darauf beharrt, dass main() keine void-Funktion sein darf. Die Funktion main_loop habe ich dann als void main_loop (void) _attribute_ ((noreturn)); deklariert. Um dem Compiler dann klarzumachen, dass sich mainloop() wirklich nicht beendet, habe ich noch eine Endlosschleife einbauen müssen, um die letzte Warnung auch noch wegzubekommen:
void main_loop (void) { uint8_t ch; uint8_t temp; sndrx_init (); // initialize SOUNDRX #if USE_LED == 1 led_init(); // initialize LED port LED_ON; // switch LED on #endif temp = MCUCR; // set interrupt vectors to bootloader section MCUCR = temp | (1<<IVCE); MCUCR = temp | (1<<IVSEL); sei (); // enable interrupts while (1) { if (sndrx_poll (&ch, 3000) == 1 && ch == '$') // wait 3 seconds for the dollar character... { #if USE_LED == 1 LED_OFF; // got it, switch LED off #endif if (! boot_update_flash ()) // flash now { continue; } #if USE_LED == 1 LED_OFF; // switch LED off #endif } cli (); // disable interrupts temp = MCUCR; // reset interrupt vectors (set to application section) MCUCR = temp | (1<<IVCE); MCUCR = temp & ~(1<<IVSEL); asm volatile("jmp 0x0000"); } } |
Damit kann gcc erkennen, dass sich mainloop() wirklich nicht beendet. Das ergab dann nochmals eine Ersparnis von 16 Bytes, so dass wir jetzt bei 984 Bytes Code für den Bootloader sind :-) Die while-Schleife hat auch noch den Vorteil, dass der Bootloader auch dann erst die Applikation startet, wenn die Übertragung fehlerfrei geklappt hat. Bis dahin kann man immer weiter probieren, ohne den µC resetten zu müssen. Gruß, Frank
Datum:
sehr gut. Das muss ich mir unbedingt merken. Ich werde das mal hier hinzufügen: http://www.mikrocontroller.net/articles/AVR-GCC-Co...
Datum:
Vlad Tepesch schrieb: > sehr gut. Das muss ich mir unbedingt merken. Ich habe mal eben den mainloop-noreturn-Trick für ein Tiny2313-Projekt, wo ich schon immer an der 2KB-Grenze herumschrabbte, ausprobiert: 34 Byte Ersparnis. Ist zwar hier nicht soviel, aber gibt mir wieder etwas Luft für Erweiterungen :-) > Ich werde das mal hier hinzufügen: > http://www.mikrocontroller.net/articles/AVR-GCC-Co... Gute Idee.
Datum:
du könntest dir mal den Tip mit den Volatiles im Verlinkten Beitrag anschauen. da könnte es auch noch Potential geben. hab mir den Code aber nicht allzu genau angeschaut
Datum:
Vlad Tepesch schrieb: > du könntest dir mal den Tip mit den Volatiles im Verlinkten Beitrag > anschauen. > da könnte es auch noch Potential geben. Danke für den Tipp, aber vom Puffern der volatile-Variablen mach ich schon lange extensiven Gebrauch. :-)
Datum:
Ich habe noch ein paar Dutzend Bytes einsparen können: 1. In sndrx-bootloader.c:
#define SNDRX_AS_INCLUDE // bad trick: save program space by including sndrx.c so we can use static functions #include "sndrxconfig.h" #include "sndrx.h" #include "sndrx.c" |
2. In sndrx.c:
#ifdef SNDRX_AS_INCLUDE // if used as include.... #define SNDRX_STATIC static // we can declare functions as static #else // this saves program space #define SNDRX_STATIC #endif |
Dadurch konnte ich dann sämtliche sndrx-Funktionen mittels SNDRX_STATIC als static-Funktionen definieren - aber nur dann, wenn man sndrx.c mittels "#include" in das main-Modul einfügt. Beispiel: Alt:
void sndrx_init (void) { ... } |
Neu:
SNDRX_STATIC void sndrx_init (void) { ... } |
gcc kann dann die sndrx-Funktionen als inline-Funktionen weiter optimieren. Hat nochmal 20 Bytes gebracht. Durch die #defines kann sndrx.c sowohl als externes C-Modul dazugelinkt werden oder auch includiert werden. Im ersten Fall stehen dann die Funktionen als "extern" zur Verfügung, im zweiten Fall als "static". Vielleicht ist das auch noch einen Abschnitt in http://www.mikrocontroller.net/articles/AVR-GCC-Co... wert? Gruß, Frank P.S. Mittlerweile sind wieder ein paar der eingesparten Bytes für diverse Bugfixes draufgegangen (z.B. Abschalten des Timers vor Srpung in die Applikation etc.). Aber mit 1012 Bytes sind wir weiterhin unter 1KB. Das Update kann ich aber wohl erst später hochladen, im Moment ist der Upload von Dateien auf µC.net defekt...
Datum:
Frank M. schrieb: > Ich habe noch ein paar Dutzend Bytes einsparen können: > > [...] > > Dadurch konnte ich dann sämtliche sndrx-Funktionen mittels SNDRX_STATIC > als static-Funktionen definieren - aber nur dann, wenn man sndrx.c > mittels "#include" in das main-Modul einfügt. Das includieren ist nicht wirklich schön, machen wir ja aber in der wordclock auch ;) Wenn man ein Makefile manuell erstellt (ich hasse makefiles), das nicht jedes sourcefile extra compiliert (komischerweise machen das alle automatischen generatoren, die ich bisher ausprobiert habe (avrstudio 4, eclipse, jörgs mfile)), sondern alle in einen gcc-Aufruf packt kann man whole program optimization benutzen, die sollte das inlinen nur einmal gebrauchter funktionen auch gebacken bekommen, unabhängig davon, in welchem src-File sie stecken. Einziger NAchteil: wird ein File geändert, muss das ganze Projekt neu gebaut werden, was bei den kleinen Projekten aber normalerweise irrelevant ist. Vorteil: Warnungen in nicht geänderten Files erscheinen bei jedem Build.
Datum:
Vlad Tepesch schrieb: > eine Warnung geht weg, aber es kommt eine neue dazu. > ../sndrx-bootloader.c:172: warning: return type of 'main' is not 'int' > ../sndrx-bootloader.c: In function 'main': > ../sndrx-bootloader.c:209: warning: 'noreturn' function does return Ohne Warungen geht es so:
// avoid push in main int main( void ) __attribute__((OS_main)); |
Peter
Datum:
Neue Version 1.4.0 ist online. Änderungen: - Optimierung der Schaltung: Pullup-Widerstand am Transistor wegoptimiert, übernimmt nun der ATmega. - Optimierung des Bootloaders: Der Bootloader wurde von der Größe her auf unter 1KB reduziert. - Bugfix Bootloader: Timer wird nun vor Applikationsstart wieder deaktiviert - Bugfix Bootloader: Wenn die Übertragung fehlerhaft war, wird nun auf eine neue Übertragung gewartet Der Artikel, der Schaltplan und die Download-Dateien wurden aktualisiert, siehe: http://www.mikrocontroller.net/articles/SOUNDRX Gruß, Frank
Datum:
4.3.3 AVR Memory Usage ---------------- Device: atmega168 Program: 956 bytes (5.8% Full) (.text + .data + .bootloader) Data: 45 bytes (4.4% Full) (.data + .bss + .noinit) Compilerschalter: -std=gnu99 -fno-split-wide-types -fno-tree-loop-optimize -fno-move-loop-invariants -Wl,--relax --combine -fwhole-program -DF_CPU=8000000UL Ist wohl noch die alte Version gewesen: 19.07.2011 V. 1.3.1 Peter
Datum:
Hallo Frank, vielleicht lässt sich Deine Rechnung oben vereinfachen. Bei der Flankecodierung werden die Bits in zwei unterschiedliche Abstände zwischen den Flanken codiert. Hat man z.B. die Abstände 2T für low und 3T für High ergibt sich für die Übertragung von 8000-low und 8000-high Bits folgende Rechnung: 8000*2T+8000*3T=40000T mit T = 1/441000Hz ergibt sich also eine Übertragungszeit von 40000*(1/44100)=0.9 Sekunden Die 2 Kilobyte Daten werden also in unter einer Sekunde übertragen. >SOUNDRX arbeitet also mit einer Toleranz von +/- 1T. >Wenn man diese Toleranz auch bei der Flanken-Kodierung beibehalten will, >sieht das nicht mehr ganz so gut aus mit der Geschwindigkeitssteigerung. Die Flankencodierung hat eine Toleranz von +/-1T, wenn man die Zeiten low=2T und high=4 T wählt. Man erhält folgende Geschwindigkeiten für die verschiedenen Codieungsarten: 2T/3T: 44100/((2+3)/2)=17640 Bit/Sekunde= 2205 Byte/Sekunde 2T/4T: 44100/((2+4)/2)=14700 Bit/Sekunde= 1837 Byte/Sekunde Die Flankencodierung hat ähnliche Eigenschaften wie die Manchestercodierung: man kann bei jedem Flankenwechsel neu synchronisieren, dadurch wird das ganze sehr stabil gegenüber Taktschwankungen. Grüße, chris
Datum:
Peter Dannegger schrieb: > Compilerschalter: Habe mal alle durchprobiert, sowohl einzeln als auch alle auf einmal. > -fno-split-wide-types Verschlechterung: 20 Bytes > -fno-tree-loop-optimize Gewinn: 4 Bytes > -fno-move-loop-invariants Gewinn: 16 Bytes > -Wl,--relax Gewinn: 0 Bytes > --combine -fwhole-program Verschlechterung: 28 Bytes Alle auf einmal zusätzlich gesetzt: > -fno-split-wide-types > -fno-tree-loop-optimize > -fno-move-loop-invariants > -Wl,--relax > --combine -fwhole-program Gewinn: 14 Bytes Ich habe noch andere Kombinationen durchgetestet, den besten Gewinn habe ich mit > -fno-tree-loop-optimize > -fno-move-loop-invariants Dann ist der Gewinn 26 Bytes. Alle anderen Optionen sind hier kontraproduktiv bzw. bringen nichts. > Ist wohl noch die alte Version gewesen: > 19.07.2011 V. 1.3.1 Ja, ich habs mit der 1.4.0 getestet: Der Bootloader ist von 1014 Bytes auf 988 Bytes geschrumpft - sehr schön! Danke für die Tipps, Frank
Datum:
Hallo Chris, chris schrieb: > Die Flankencodierung hat eine Toleranz von +/-1T, wenn man die Zeiten > low=2T und high=4 T wählt. Nö :-) Was ist mit einem gemessenen Signal von 3T? Ist das High oder Low? Erst bei low=2T und high=5T passt es, dann ist: 1-3: low 4-6: high > Man erhält folgende Geschwindigkeiten für die verschiedenen > Codieungsarten: > > 2T/3T: 44100/((2+3)/2)=17640 Bit/Sekunde= 2205 Byte/Sekunde > 2T/4T: 44100/((2+4)/2)=14700 Bit/Sekunde= 1837 Byte/Sekunde Ich vervollständige das mal: 2T/5T: 44100/((2+5)/2)=12600 Bit/Sekunde= 1557 Byte/Sekunde > Die Flankencodierung hat ähnliche Eigenschaften wie die > Manchestercodierung: man kann bei jedem Flankenwechsel neu > synchronisieren, dadurch wird das ganze sehr stabil gegenüber > Taktschwankungen. Ja, das ist mir klar. Ich habe leider bei Flankencodierungen ähnlich wie bei Manchester so meine Abneigungen. Diese sind aber rein psychologisch bedingt. Es liegt wohl daran, dass ich damals bei der RC6-Implementierung in IRMP Blut und Wasser schwitzte, um das vernünftig erkennen zu können. Grund war ein Taktratenwechsel mitten im Frame: das Toggle-Bit wird dort lediglich mit der halben Rate gesandt als die anderen Bits. Dann bekommst Du 1-, 1,5-, 2- und 2,5-fache Taktlängen... äußerst unschön zu handlen. Das war für mich ein Kampf bis aufs Messer, bis es korrekt lief... Aber ich werde meinen inneren Schweinehund überwinden und das auf jeden Fall testen... ist so ähnlich wie für andere Leute mit Höhenangst, die an den Rand eines Wolkenkratzer-Dachs gehen... ;-) Gruß, Frank
Datum:
Frank M. schrieb: > Ja, ich habs mit der 1.4.0 getestet: Der Bootloader ist von 1014 Bytes > auf 988 Bytes geschrumpft - sehr schön! Füg mal ins *.c noch das ein:
// avoid push in main int main( void ) __attribute__((OS_main)); |
4.3.3 AVR Memory Usage ---------------- Device: atmega168 Program: 966 bytes (5.9% Full) (.text + .data + .bootloader) Data: 82 bytes (8.0% Full) (.data + .bss + .noinit) mit: -Os -fno-tree-loop-optimize -fno-move-loop-invariants -Wl,--relax --combine -fwhole-program Peter
Datum:
Peter Dannegger schrieb: > Füg mal ins *.c noch das ein: >
> // avoid push in main > int main( void ) __attribute__((OS_main)); > |
Für main: Gewinn = 0.
Für main_loop: Gewinn = 4 Bytes.
Gruß, Frank
EDIT:
Folgende Befehle sind dadurch in main_loop entfallen:
3a74: df 93 push r29
3a76: cf 93 push r28
Ich muss dazu anmerken, dass ich vorher drin hatte:void main_loop (void) __attribute__ ((noreturn)); |
Das ist dann aber nicht mehr notwendig, wenn man das OS_main-Attribut verwendet - wie ich gerade sehe. Also habe ich nun main_loop() wieder in main() umbenannt und lediglich mit dem Attribut OS_main versehen. Das bringt 8 Bytes Gewinn gegenüber dem noreturn-Attribut. Insgesamt sind es 22 Bytes Gewinn.
Datum:
Peter Dannegger schrieb: > Vlad Tepesch schrieb: >> eine Warnung geht weg, aber es kommt eine neue dazu. >> ../sndrx-bootloader.c:172: warning: return type of 'main' is not 'int' >> ../sndrx-bootloader.c: In function 'main': >> ../sndrx-bootloader.c:209: warning: 'noreturn' function does return > > Ohne Warungen geht es so: >
> > // avoid push in main > int main( void ) __attribute__((OS_main)); > |
Richtig! Für einen sauberen Reset kann man den Watchdog missbrauchen.
Datum:
Simon K. schrieb: > Richtig! > > Für einen sauberen Reset kann man den Watchdog missbrauchen. ? Was hat denn ein Reset damit zu tun, daß im Main eine Endlosschleife läuft? Man kann theoretisch das Main verlassen, landet dann aber auch in einer Endlossschleife. Es gibt auf dem AVR kein OS, wohin das Main zurück kann. Daher kann sich das Main sparen, benutzte Register zu pushen. Und genau das sagt dem Compiler dieses obige Attribut. Peter
Datum:
Peter Dannegger schrieb: > Simon K. schrieb: >> Richtig! >> >> Für einen sauberen Reset kann man den Watchdog missbrauchen. > > ? > > Was hat denn ein Reset damit zu tun, daß im Main eine Endlosschleife > läuft? Nichts. Sind doch auch zwei Absätze dazwischen! ;-) Das war als Anregung zu der Reset-Problematik mit dem jmp 0 gedacht.
Datum:
Simon K. schrieb: > Nichts. Sind doch auch zwei Absätze dazwischen! ;-) Das war als Anregung > zu der Reset-Problematik mit dem jmp 0 gedacht. Ein Reset über den Watchdog hat den Nachteil, dass dann wieder erst der Bootloader gestartet wird... und man erneut 3 Sekunden warten muss, bevor zur Applikation durchgestartet wird. Das brauche ich aber nicht nach erfolgreichem Flashen... Ausserdem kosten die wdt-Aufrufe einige Bytes an Code, den ich lieber sparen möchte ;-) Gruß, Frank EDIT: Deine Idee ist sogar noch viel schlechter: Der Watchdog würde ja immer wieder dafür sorgen, dass der Bootloader hochkommt.... in die eigentliche Applikation komme ich dann nie wieder!
Datum:
>chris schrieb: >> Die Flankencodierung hat eine Toleranz von +/-1T, wenn man die Zeiten >> low=2T und high=4 T wählt. Frank schrieb >Nö :-) doch ;-) >Was ist mit einem gemessenen Signal von 3T? Eigentlich sollte man ja 2T oder 4T messen. Mit Messfehler wäre das dann z.B. low: 1..2.9999999T high: 3T-5T
Datum:
chris schrieb: > Eigentlich sollte man ja 2T oder 4T messen. Mit Messfehler wäre das dann > z.B. > > low: 1..2.9999999T > high: 3T-5T Das geht nicht. Ich polle. Nämlich 44100 mal pro Sekunde. Der PC schickt Signale, die mindestens 2T lang sind, also nominell ändern sich die Werte bis zu 22050 mal in der Sekunde. Das heisst, ich kann genau 2 identische Werte pollen, bevor die Flanke kommt. Wenn ich zufällig ganz nahe an der Flanke des Signals polle, kann das mal kurz vor oder auch kurz danach passieren, wenn ich nicht so genau synchron bin - zum Beispiel, weil ich den internen RC-Oszillator verwende. Das Konzept hat also schon prinzipbedingt einen Fehler von +/- 1. Da dieser Fehler in beide Richtungen ausschlagen kann und mir nur ganzzahlige Messwerte 1,2,3,4,5,... vorliegen (2.99999T ist also unrealistisch), muss ich, um auf der sicheren Seite zu sein, zumindest einen Meßfehler von +/- 1 zulassen. Und das geht nur, wenn ich den Abstand beider Längen auf 3 setze.
Datum:
>Das geht nicht. Ich polle. Nämlich 44100 mal pro Sekunde.
Du kannst ja auch einen Timer verwenden. Dann geht's schneller und
genauer.
Datum:
chris schrieb: >>Das geht nicht. Ich polle. Nämlich 44100 mal pro Sekunde. > > Du kannst ja auch einen Timer verwenden. Dann geht's schneller und > genauer. Ich benutze einen Timer. Quarzgenau mit 44100 / sec. :-) Um einen Abtastfehler von +/- 1 zuverlässig zu kompensieren, muss ich auf das 3fache von 22050 hoch, also auf 66150 / sec. Dann genüge ich auch dem Abtasttheorem, dass die Abtastfrequenz mehr als das Doppelte der maximalen Signalfrequenz sein muss. Literatur dazu: http://de.wikipedia.org/wiki/Nyquist-Shannon-Abtasttheorem Ich muss mal ausrechnen, ob die 66150 / sec den µC nicht soweit dichtmachen, dass gar nichts mehr anderes läuft. Bei 120 Prozessortakten in der ISR wäre der µC jedenfalls zu 100% mit dem Abtasten beschäftigt. Das wäre nicht Sinn der Sache. Eine andere Möglichkeit wäre die Umstellung auf einen Pin-Change-Interrupt. Das würde den Prozessor wesentlich entlasten, jedoch verzichtet man dann auf einige Freiheiten, z.B. auf freie Pin-Wahl. Nicht jeder Pin eines ATmegas ist PCINT-fähig.
Datum:
Es geht auch anders. Den Timer musst Du "Full Speed" laufen lassen, dann hast Du die beste Zeiauflösungg. Hier mal Pseudo-Code warten bis flanke loop: timer starten warten bis flanke timer lesen if time>Grenzwert bit = 1 ansonsten 0 jump loop
Datum:
chris schrieb: > Es geht auch anders. Den Timer musst Du "Full Speed" laufen lassen, dann > hast Du die beste Zeiauflösungg. Hier mal Pseudo-Code Den Timer benutze ich, um 44100 mal pro Sekunde den Input-Portpin per Timer-Interrupt-Handler auszulesen. Das nenne ich "Pollen". Das passiert also im Hintergrund, während das Hauptprogramm was anderes machen kann. > warten bis flanke > loop: > timer starten > warten bis flanke > timer lesen > if time>Grenzwert bit = 1 ansonsten 0 > jump loop Ja klar, dann muss ich für "warten bis flanke" einen PCINT (Pin-Change-Interrupt) benutzen, genau das habe ich doch oben geschrieben. :-) Ich werde bestimmt nicht den Rückschritt machen, die Flanke in der Hauptfunktion zu pollen, also Deinen Pseudo-Code zu implementieren. Dann macht der µC ja nichts mehr anderes ;-) Ich denke mir das so: PCINT-Interrupt: // es kam eine Flanke Timer lesen und abspeichern if time>Grenzwert bit = 1 ansonsten 0 im Ringbuffer speichern Timer zurücksetzen Return from Interrupt // nix jump loop Fazit: Im Moment arbeitet das Pollen interruptgesteuert über Timer-Interrupt. Eine CPU-Entlastung und eine höhere Abtastauflösung lässt sich durch einen zusätzlichen Pin-Change-Interrupt erreichen. Ich werde mir mal anschauen, wieviel Arbeit das ist. Gruß, Frank
Datum:
>Ich werde bestimmt nicht den Rückschritt machen, die Flanke in der >Hauptfunktion zu pollen, also Deinen Pseudo-Code zu implementieren. Dann >macht der µC ja nichts mehr anderes ;-) Was muss Dein Code machen, außer das Flash zu programmieren?
Datum:
chris schrieb: > Was muss Dein Code machen, außer das Flash zu programmieren? das ding war ja nciht nur als bootloader gedacht
Datum:
chris schrieb: >>Ich werde bestimmt nicht den Rückschritt machen, die Flanke in der >>Hauptfunktion zu pollen, also Deinen Pseudo-Code zu implementieren. Dann >>macht der µC ja nichts mehr anderes ;-) > > Was muss Dein Code machen, außer das Flash zu programmieren? Beim Bootloader muss ich Blöcke zu je 128 Bytes (SPM_PAGESIZE) zusammensammeln und dann: 128 Bytes Flash löschen 128 Bytes wortweise in den internen PageBuffer schreiben 128 Bytes vom Pagebuffer ins Flash schreiben Der Grund ist einfach: das Flash lässt sich nicht byteweise beschreiben, sondern nur in Blöcken zu je 128 Bytes. Das kann ich nicht mal eben zwischen 2 Flanken erledigen, dafür ist die Zeit zu kurz. Es geht noch nichtmals zwischen 2 empfangenen Bytes, deshalb musste ich auch den Ringbuffer in SOUNDRX einbauen. Das habe ich alles schon getestet. Das Flashen muss "quasi-parallel" ablaufen: während ich die nächsten 128 Bytes einsammele, flasht das Ding noch im Hintergrund die letzten 128 Bytes. SOUNDRX ist aber nicht nur als Bootloader gedacht, sondern kann auch zur Informationsübertragung genutzt werden. Und auch da hat der µC noch andere Aufgaben zu erledigen als nur Bytes zu "fressen". Irgendwas muss er ja auch noch damit machen - sprich er muss die Informationen auch verarbeiten. Egal wofür... ob er empfangene Mitteilungen auf einem LCD ausgeben soll oder was weiß ich. Wenn er nichts anderes macht als Bytes über die Soundkarte empfangen, ist er ja nichts weiter als ein "schwarzes Loch"... eine Art Byte-Mülleimer. ;-) Das kanns nicht sein, oder?
Datum:
Du hast recht. Beim programmieren des Flash könnte es ein Problem geben. Ich bin mir nicht mehr sicher: muss man nicht ein Register im Flash pollen, um zu sehen, dass die Daten geflasht wurden? Wie ist das mit dem Timing, reicht die Zeit immer aus, bevor neue Daten von der Schnittstelle kommen? Was mir noch eingefallen ist: Eventuell verhalten sich die Audio-Interfaces der verschiedenen Rechner unterschiedlich. Vielleicht können alle, die es ausprobiert haben, einen Erfahrungsbericht posten, um zu sehen, ob das Verfahren bei allen Rechnern funktioniert. Die Datenübertragung vom PC zum Mikrocontroller habe ich schon mal irgendwo gesehen, aber leider finde ich die Stelle nicht mehr. Nach einiger Suche ist mir dass hier über den Weg gelaufen: http://www.eecs.umich.edu/~prabal/projects/hijack/ Wäre mal interessant zu sehen, welche Datenraten andere Leute erreichen.
Datum:
Hört sich toll an. Ich hätte da auch noch ne tolle Idee. Mann könnte dich einen SPI oder Jtag Programmer bauen der anstatt mit USB oder RS232 dann über die Soundkarte des Rechners läuft. Ich bekommme Die USB to RS232 dinger auch nicht wirklich zum laufen und das Notebook hatt leider keinen RS232 mehr.
Datum:
ATmega user schrieb: > Mann könnte dich einen SPI oder Jtag Programmer bauen der anstatt mit > USB oder RS232 dann über die Soundkarte des Rechners läuft. Wird nicht gehen, denn Du hast keinen Rückkanal. Die Informationen fließen nur in eine Richtung. > Ich bekommme Die USB to RS232 dinger auch nicht wirklich zum laufen und > das Notebook hatt leider keinen RS232 mehr. Ich benutze meist diesen hier: http://shop.myavr.de/Bauelemente%20und%20Controlle... Ist billig und braucht keinen MAX232 auf der µC-Seite, da dort direkt TTL-Pegel ankommen. Nachteil: Du kannst die Übertragungsstrecke nicht so lang machen wie bei einer RS232.
Datum:
Frank M. schrieb: >> Mann könnte dich einen SPI oder Jtag Programmer bauen der anstatt mit >> USB oder RS232 dann über die Soundkarte des Rechners läuft. > > Wird nicht gehen, denn Du hast keinen Rückkanal. Die Informationen > fließen nur in eine Richtung. Normalerweise besitzt doch fast Jede Soundkarte einen Aux-In oder einen Microphon-in. Die könnte man doch als Rückleitung benutzen.
Datum:
ATmega user schrieb: > Normalerweise besitzt doch fast Jede Soundkarte einen Aux-In oder einen > Microphon-in. Die könnte man doch als Rückleitung benutzen. Ja, daran habe ich auch schon mal gedacht. Ich hab mich damit aber noch nicht beschäftigt. Soviel ich weiß, kann ich da nur ein Recording drauf absetzen, irgendwann(?) die Aufnahme stoppen und dann auswerten. das wäre ein wenig träge, oder? ;-) Wenn das auch während der Aufnahme geht, dann könnte es klappen. Muss ich mich mal mit auseinandersetzen...
Datum:
was sollte dich darin hindern, ein Programm zu schreiben, was den AudioIn einliest und direkt verarbeitet? Nicht, dass ich das schonmal gemacht hätte, aber oich bin sicher, so schwer ist das nicht ;)
Datum:
Wir haben heute mal testweise SOUNDRX auf Flankencodierung umgestellt und das Signal per Pin-Change-Interrupt ausgewertet. Wir kommen nun auf eine mittlere Transferrate von 2205 Byte/sec. Wir werden noch diverse Tests mit dem Bootloader machen, bevor wir ein Update zur Verfügung stellen. Außerdem haben wir bemerkt, dass die Zeiten für Low und High-Signal bei diesen Geschwindigkeiten um eine Konstante differieren, die wohl aus der Schaltung oder von der Unzulänglichkeit der Soundkarte herrührt. Wir werden deshalb noch eine Art "Training" in die Sendefunktion einbauen, damit die Korrektur-Konstante vom µC dynamisch ermittelt werden kann. Im Moment steht sie noch fest im Source. Viele Grüße, Robert und Frank
Datum:
Hallo Frank, >Wir kommen nun auf eine mittlere Transferrate von 2205 Byte/sec. herzlichen Glückwunsch zur Geschwindigkeitssteigerung ;-) > Außerdem haben wir bemerkt, dass die >Zeiten für Low und High-Signal bei diesen Geschwindigkeiten um eine >Konstante differieren, die wohl aus der Schaltung oder von der >Unzulänglichkeit der Soundkarte herrührt. Ihr könnt die Schaltung auf 3 Bauteile reduzieren. Ein 10K Widerstand nach Masse, ein 10K Widerstand zur positiven Versorgung und ein 10nF als Kopplung zum Audio-Jack. Die Zeiten sind dann symmetrisch. Bei mir funktionierte es augezeichnet. Gruß, chris
Datum:
Hallo Chris, chris schrieb: > Ihr könnt die Schaltung auf 3 Bauteile reduzieren. Ein 10K Widerstand > nach Masse, ein 10K Widerstand zur positiven Versorgung und ein 10nF als > Kopplung zum Audio-Jack. Die Zeiten sind dann symmetrisch. Bei mir > funktionierte es augezeichnet. Hm. Soviel ich weiß, kommt da am Audio-Ausgang irgendwas um die 1Vss raus. Den ziehst Du nun in "die Mitte" mit den beiden Widerständen und fertig? Ich halte das ja für etwas gewagt, da Du damit eigentlich keine definierten High-/Low-Werte erzeugst. Hast Du ein Oszilloskop und kannst mal sagen, was da für Spannungen am µC-Eingang anliegen? Aber das mit dem 10nF-Kondensator (statt 100nF) werde ich mal ausprobieren. Ich vermute, dass bei der hohen Geschwindigkeit der 100nF-Kondensator zu groß (und damit zu träge) ist. Gruß, Frank
Datum:
chris schrieb: > Ihr könnt die Schaltung auf 3 Bauteile reduzieren. Ein 10K Widerstand > nach Masse, ein 10K Widerstand zur positiven Versorgung und ein 10nF als > Kopplung zum Audio-Jack. Die Zeiten sind dann symmetrisch. Bei mir > funktionierte es augezeichnet. > > Gruß, > chris wenn man dann noch den Widerstand des internen Pullups ermittelt und den Pulldown in entsprechender Größe wählt, kann man den externen Pullup auch noch weglassen ;)
Datum:
Line out ist 1vpp. Kopfhörerausgang ist generell 2Vpp.
Datum:
>Hm. Soviel ich weiß, kommt da am Audio-Ausgang irgendwas um die 1Vss >raus. Den ziehst Du nun in "die Mitte" mit den beiden Widerständen und >fertig? Ich halte das ja für etwas gewagt, da Du damit eigentlich keine >definierten High-/Low-Werte erzeugst. Soweit ich im Atmega8 Datenblatt gelesen habe, sind die digitalen Eingänge Schmitt-Trigger-Eingänge mit 0.5V Hysterese. Das passt ideal zu den 1Vss des Audiosignals, wenn man den Level richtig einstellt. In den Diagramme zu dne High-Low-Werten hatte ich eine Schwelle von ca. 1.7V bei VCC=5V abgelesen. Allerdings habe ich dann beim realen Versuch festgestellt, dass die Schaltschwellen doch bei der halben Versorgung liegen ( ok, ich hatte einen Arduino mit Atmega168 verwendet, man müsste die Datenblätter mal vergleichen ). Mittlerweile ist mir auch der Vorteil des Manchestercodes gegenüber der Flankenkodierung klarer geworden. Der Hamming-Code ist Mittelwertfrei. Bei der Flankencodierung kann es passieren, dass der mittlere Pegel abhängig vom Code ein wenig den Mittelwert wandern lässt, Das gäbe dann vermutlich leichte Zeitfehler, da die Flanken nicht wirklich rechteckig sind. >wenn man dann noch den Widerstand des internen Pullups ermittelt und den >Pulldown in entsprechender Größe wählt, kann man den externen Pullup >auch noch weglassen ;) vielleicht geht das, aber die Pullups sind vermutlich nicht so exakt. Wenn die Schwelle nicht stimmt, könnte die Signaldetektion ein Problem haben.
Datum:
chris schrieb: > Soweit ich im Atmega8 Datenblatt gelesen habe, sind die digitalen > Eingänge Schmitt-Trigger-Eingänge mit 0.5V Hysterese. Ich lese das hier im Datenblatt vom ATmega168: Input Low Voltage,Except XTAL1 and Reset pin: max. 0.3Vcc Input High Voltage, Except XTAL1 and RESET pins: min. 0.6Vcc Wenn ich das auf Vcc = 5V umrechne, erhalte ich: Low: max. 1,5V High: min. 3,0V Zwischen 1,5 und 3V ist eine nicht definierte Lücke. > Mittlerweile ist mir auch der Vorteil des Manchestercodes gegenüber der > Flankenkodierung klarer geworden. Der Hamming-Code ist Mittelwertfrei. > Bei der Flankencodierung kann es passieren, dass der mittlere Pegel > abhängig vom Code ein wenig den Mittelwert wandern lässt, Das gäbe dann > vermutlich leichte Zeitfehler, da die Flanken nicht wirklich rechteckig > sind. Ja, ich hatte auch den Verdacht, dass die Flanken nicht steil genug sind (aufgrund des Kondensators?) und deshalb der µC eine Asymmetrie sieht: Die Länge der Low-Signale unterscheidet sich um ein gutes Stück von der Länge der High-Signale. In der Summe stimmts natürlich, deshalb hatte ich bei der Pulse-Distance-Codierung bisher auch keine Probleme, weil ich immer die Summe Puls + Pause betrachtet habe. Diese Asymmetrie schwächt sich übrigens nach einem Dutzend Bits (Flanken) ab, d.h. das Ergebnis wird besser. Aber es bleibt bei einer Differenz von 10% Abweichung (anfangs sind es sogar 20%). Damit "verschmelzen" die gewählten Längen von 2T,3T,4T,5T innerhalb der Fehlergrenzen teilweise ineinander. Erst das Korrigieren von Low- und High-Zeiten um eine empirisch ermittelte Konstante brachte das Ergebnis wieder in Ordnung. Verstehe ich zwar nicht, aber das Senden von zwei Dummy-Bytes (0x00 0x00) vor dem eigentlichen Start-Bit des Blocks verbessert die Signal-Sicherheit signifikant. Diese beiden "Training-Bytes" werde ich dann wohl zukünftig zum Bestimmen der Low-/High-Längendifferenz-Korrekturwerte verwenden. Vielleicht wäre damit sogar eine Art "Autobaud-Detection" möglich - mal sehen. Aber vielleicht reicht es ja auch, den Kondensator durch 10nF zu ersetzen. Wenn dann die Asymmetrie weg ist, kann ich mir den Zinnober sparen. Zur Manchester-Codierung: Die Bits "0" und "1" wären dann zwar gleich lang, aber ich bräuchte immer 4T für ein Bit. Max. Geschwindigkeit wäre dann 1378 Bytes/sec - also ein fetter Rückschritt. > vielleicht geht das, aber die Pullups sind vermutlich nicht so exakt. > Wenn die Schwelle nicht stimmt, könnte die Signaldetektion ein Problem > haben. Ehrlich gesagt, bevorzuge ich die Transistor-Lösung. Kostet 5 Cent mehr, dafür ist man aber auf der sichereren Seite. Die Widerstand-Only-Lösung ist mir zu "abenteuerlich" ;-)
Datum:
>Ja, ich hatte auch den Verdacht, dass die Flanken nicht steil genug sind >(aufgrund des Kondensators?) Der Audioausgang ist kein Digitalausgang. Der Ausgang des DA-Wandlers dürfte mit einem Antialiasing-Filter versehen sein, dessen Grenzfrequenz je nach Filterordnung einiges unter 20kHz liegt. Das Signal bei den für diese Projekt verwendeten Pulslängen kann also gar nicht rechteckförmig sein. Die Transistorschaltung legt die Schaltschwelle irgendwo in den Sinus, deshalb erhälst Du so unterschiedliche Pulslängen.
Datum:
>Ja, ich hatte auch den Verdacht, dass die Flanken nicht steil genug sind >(aufgrund des Kondensators?) Der Kondensator macht hier das glatte Gegenteil: er verstärkt die Flanken eher, da das Ganze einen Hochpass darstellt. >Verstehe ich zwar nicht, aber das Senden von zwei Dummy-Bytes (0x00 >0x00) vor dem eigentlichen Start-Bit des Blocks verbessert die >Signal-Sicherheit signifikant Der Kondensator trennt den Gleichspannungsanteil des Signals ab. Da Du von einer Gleichspannung aus startest, dauert es eine Weile, bis sich die Ladung des Kondensators auf den Mittelwert des Signals einstellt. Wenn Du einen größeren Kondensator einsetzt, wird dieser Vorgang länger. Bei einem kleineren Kondensator geht das Einschwingen entsprechen schneller. Bei einem Nicht-Mittelwertfreien Signal gibt es auch während der Datenübertragung eine Veränderung der Schwelle. Du kannst es ausprobieren: Übertrage 100x den Wert 0xAA und danach 0xFF. Bei den 0xFF wirst Du eine Zeit lang eine Veränderung der Zeiten feststellen.
Datum:
chris schrieb: > Der Audioausgang ist kein Digitalausgang. Der Ausgang des DA-Wandlers > dürfte mit einem Antialiasing-Filter versehen sein, dessen Grenzfrequenz > je nach Filterordnung einiges unter 20kHz liegt. Das Signal bei den für > diese Projekt verwendeten Pulslängen kann also gar nicht rechteckförmig > sein. Die Transistorschaltung legt die Schaltschwelle irgendwo in den > Sinus, deshalb erhälst Du so unterschiedliche Pulslängen. Stimmt auffallend. Ich habe die Schaltung mal in LT-Spice ausprobiert. Je flacher die Rechtecke ansteigen/abfallen, desto asymmetrischer wird die Geschichte. Gruß und Dank, Frank
Datum:
chris schrieb: > Der Kondensator trennt den Gleichspannungsanteil des Signals ab. Da Du > von einer Gleichspannung aus startest, dauert es eine Weile, bis sich > die Ladung des Kondensators auf den Mittelwert des Signals einstellt. > Wenn Du einen größeren Kondensator einsetzt, wird dieser Vorgang länger. > Bei einem kleineren Kondensator geht das Einschwingen entsprechen > schneller. Stimmt, auch das habe ich mit LT-Spice getestet und verifiziert. 10nF und 100nF unterscheiden sich dabei aber bei den hier verwendeten Taktzeiten fast unmerklich. > Bei einem Nicht-Mittelwertfreien Signal gibt es auch während der > Datenübertragung eine Veränderung der Schwelle. Du kannst es > ausprobieren: Übertrage 100x den Wert 0xAA und danach 0xFF. Bei den 0xFF > wirst Du eine Zeit lang eine Veränderung der Zeiten feststellen. Das stimmt mich nicht gerade optimistisch. Bei der Puls-Distance-Codierung spielt die Asymmetrie der Signale überhaupt keine Rolle, da ich ja immer die Summe von Low+High betrachte. Bei der Flankencodierung habe ich da echt zu kämpfen. Die Signalzeiten für Bit0 = 2T und Bit1 = 3T kommen sich trotz "Training" und anschließender Korrektur um einen konstanten Wert verdächtig "nahe", weil die gemessenen Zeiten trotz Korrektur um ca. 5-10 Prozent schwanken :-( Ich werde die ganze Geschichte mal mit Bit0 = 2T und Bit1 = 4T testen. Dann sinkt zwar die mittlere Geschwindigkeit von 2205 Bytes/sec auf 1837 Bytes/sec, aber insgesamt ist mir die Übertragungssicherheit wichtiger als die Geschwindigkeit. Gruß, Frank
Datum:
>Das stimmt mich nicht gerade optimistisch. Ja, am störsichersten wäre tatsächlich der Manchestercode, weil dort der Mittelwert 0 ist. Allerdings verliert man dann natürlich den Geschwindigkeitsvorteil, weil man für jedes Bit 4T benötigt. Bei meiner Schaltung und meinem Rechner konnte ich aber auch mit kürzeren Zeiten senden. >Bei der >Puls-Distance-Codierung spielt die Asymmetrie der Signale überhaupt >keine Rolle, da ich ja immer die Summe von Low+High betrachte. Wenn Du z.B. immer die steigenden Flanke betrachtest, sollten die Zeiten tatsächlich konstant bleiben. Bei der Pulscodierung ist der Mittelwert aber auch von den übertragenen Daten abhängig, da das Puls/Pausenverhältnis ja für High- und Low-Daten unterschiedlich ist. Zumindest der Störabstand verändert sich dann ein wenig in Abhängigkeit der übertragenen Daten. > Bei der > Flankencodierung habe ich da echt zu kämpfen. Die Signalzeiten für Bit0 > = 2T und Bit1 = 3T kommen sich trotz "Training" und anschließender > Korrektur um einen konstanten Wert verdächtig "nahe", weil die > gemessenen Zeiten trotz Korrektur um ca. 5-10 Prozent schwanken :-( Versuche es doch mal mit der Spannungsteilerschaltung. Eventuell wäre ein Poti ganz gut, um die Schwelle genau auf den Mikrocontroller einzustellen. Bei der Transistorschaltung liegt die Schaltschwelle zu unsymmetrisch, so dass ungünstige Zeiten herauskommen können. Wenn Dir die Spannungsteilerschaltung nicht vertrauenswürdig erscheint, kannst Du auch den eingebauten Komparator in den Atmels verwenden. >Ich werde die ganze Geschichte mal mit Bit0 = 2T und Bit1 = 4T testen. >Dann sinkt zwar die mittlere Geschwindigkeit von 2205 Bytes/sec auf 1837 >Bytes/sec, aber insgesamt ist mir die Übertragungssicherheit wichtiger >als die Geschwindigkeit. Es könnte sein dass es bei 2T 4T noch schlechter wird, da sich der Mittelwert statt von 2/3 auf 2/4 ändert. Gruß, chris
Datum:
Angehängte Dateien:Hier ein Bild mit den Grenzen, in denen die Schaltschwellen bei der 2T/3T Codierung wandern.
Datum:
Guten Morgen Chris, chris schrieb: > Versuche es doch mal mit der Spannungsteilerschaltung. Ich werde es am Wochenende mal ausprobieren - mit Poti. Versprochen :-) > Es könnte sein dass es bei 2T 4T noch schlechter wird, da sich der > Mittelwert statt von 2/3 auf 2/4 ändert. Ich habe mit den folgenden Zeiten neu getestet: 0-Bit: 2T 1-Bit: 4T Stop: 6T Start: 8T Ich habe dabei nicht feststellen können, dass die Asymmetrie schlechter wird. Testübertragungen verliefen auch ohne Fehler. Ich werde mir bis zum Wochenende die gemessenen Werte nochmals anschauen und die Abweichungen vom Idealwert begutachten. Gruß, Frank
Datum:
Frank M. schrieb: > Der Watchdog würde ja immer wieder dafür sorgen, dass der Bootloader > hochkommt.... in die eigentliche Applikation komme ich dann nie wieder! Der Bootloader könnte als erstes die Reset-Ursache prüfen: Reset-Pin oder Power On -> Bootloader starten Watchdog -> Applikation anspringen Das kostet ein paar Bytes für den Test, spart aber auf der anderen Seite den Code, der nach erfolgreichem Flashen den Timer, Interrupt, etc. wieder abschaltet.
Datum:
R. Max schrieb: > Der Bootloader könnte als erstes die Reset-Ursache prüfen: > > Reset-Pin oder Power On -> Bootloader starten > Watchdog -> Applikation anspringen > > Das kostet ein paar Bytes für den Test, spart aber auf der anderen Seite > den Code, der nach erfolgreichem Flashen den Timer, Interrupt, etc. > wieder abschaltet. Danke, Du hast vollkommen recht. Ich werde das so einbauen.
Datum:
R. Max schrieb: > Reset-Pin oder Power On -> Bootloader starten > Watchdog -> Applikation anspringen > > Das kostet ein paar Bytes für den Test, spart aber auf der anderen Seite > den Code, der nach erfolgreichem Flashen den Timer, Interrupt, etc. > wieder abschaltet. würde ich nicht machen. Was ist wenn man in der Applikation einen weg einbauen will, den bootloader zu starten? der einzige saubere Weg ist, einen WD-Reset auszulösen (@frank: so wird es ja auch in der WC gemacht). genau damit würdest du aber nicht mehr in den Bootloader kommen.
Datum:
Vlad Tepesch schrieb: > Was ist wenn man in der Applikation einen weg einbauen will, den > bootloader zu starten? Jump auf 0x3800 sollte doch gehen, oder? > der einzige saubere Weg ist, einen WD-Reset auszulösen (@frank: so wird > es ja auch in der WC gemacht). > genau damit würdest du aber nicht mehr in den Bootloader kommen. Wieso nicht? Ein Reset über den WD würde doch genau den Bootloader wieder starten... oder hab ich da jetzt etwas verpeilt?
Datum:
Frank M. schrieb: > Ein Reset über den WD würde doch genau den Bootloader wieder starten... Ja, der würde aber nach meinem Vorschlag die Tatsache, daß der Reset vom WD ausgelöst wurde als Kriterium nehmen, direkt in die Applikation zu springen. Will man per WD in beide Richtungen springen können, braucht man zusätzlich eine Variable, die nur nach einem Power-On-Reset initialisiert wird, und dem Bootloader nach einem Watchdog-Reset mitteilt, welche Seite den Watchdog gestartet hat.
Datum:
Servus! Schade, dass da jetzt nimma weiterentwickelt wird an dem Bootloader. - Wär ne coole Sache. Wenn man den obendrein noch mit (den Funktionen von) Hagen Re's AVRootloader kombinieren könnt wär das absolut genial. ;) Leider kann ich nicht so gut programmieren, dass ich das bewerkstelligen könnte. Vielleicht schaffts von euch jemand? Wenn auch nur zumindest, dass man sich den Transistor sparen könnte und per ADC oder so das machen könnte, weils ja mim Transistor völlig asymmetrisch ist. Gruß, Stefan
Datum:
Stefan schrieb: > Schade, dass da jetzt nimma weiterentwickelt wird an dem Bootloader. - Keine Bange, es wird weiterentwickelt. Robert und ich haben uns bei der Erhöhung der Geschwindigkeit auf 2000 Zeichen/sec die letzten 2 Sonntage um die Ohren geschlagen, weil es mit bestimmten Timing-Kombinationen von 0/1-Bits partout nicht funktionieren wollte. Mittlerweile läuft es aber stabil. Jetzt muss die Dokumentation aber noch geändert werden, ca. 80% des Artikels muss neu geschrieben werden. Die neue Geschwindigkeitserhöhung auf 2000 Z/sec braucht nämlich eine neue Schaltung, nämlich entweder: - Nur ein Trimmpoti, welches durch ein extra geschriebenes Kalibrierungsprogramm exakt auf die Schaltschwelle des verwendeten ATmega eingestellt wird oder - eine neue OPV-Schaltung, die ohne Kalibrierung funktioniert. > Wenn man den obendrein noch mit (den Funktionen von) Hagen Re's > AVRootloader kombinieren könnt wär das absolut genial. ;) Ein Schritt nach dem andern, bitte. :-) > Vielleicht schaffts von euch jemand? > Wenn auch nur zumindest, dass man sich den Transistor sparen könnte und > per ADC oder so das machen könnte, weils ja mim Transistor völlig > asymmetrisch ist. Geht mittlerweile mit einem einzigen Poti - so wie es chris vorgeschlagen hatte. Wie gesagt, das Poti muss einmalig justiert werden. Update mit der neuen Software kommt spätestens am Wochenende. Gruß, Frank
Datum:
Neue Version 1.5.0 ist online. Änderungen: - Sendeformat auf flankencodiertes Protokoll umgestellt - Erhöhung der Übertragungsgeschwindigkeit auf ca. 2000 Zeichen/sec - Vereinfachung der Empfangsschaltung auf einen Kondensator + ein Poti - Kalibrierungsprogramm für die Einfachst-Schaltung - Checksums für Bootloaderübertragung eingebaut Der Artikel, der Schaltplan und die Download-Dateien wurden aktualisiert, siehe: http://www.mikrocontroller.net/articles/SOUNDRX Gruß, Frank
Datum:
Glueckwunsch zum erfolgreichen Projekt. Ich hoffe,einige Leute melden euch die Testergebnisse zurueck. Gruß, chris
Datum:
Ich versteh noch nicht so ganz, wofür man das Poti benötigt. Im Datenblatt sind die beiden Schaltschwellen für den Schmitt-Trigger-Eingang doch angegeben. Der AVR hat außerdem üblicherweise einen Analog Komparator eingebaut, der mit einem Eingang intern an die interne Referenz geschaltet werden kann. Dadurch könnte man sich die externe Beschaltung mit dem LM358 sparen.
Datum:
Simon K. schrieb: > Ich versteh noch nicht so ganz, wofür man das Poti benötigt. Im > Datenblatt sind die beiden Schaltschwellen für den > Schmitt-Trigger-Eingang doch angegeben. SOUNDRX braucht bei Flankencodierung ein symmetrisches Signal, siehe Diskussion oben und in Beitrag "Schaltschwelle bei Atmega digital Eingang" Die Schaltschwellen der digitalen(!) Eingänge sind je nach ATmega-Generation (z.B. ATmega8 vs. ATmega88) verschieden. > Der AVR hat außerdem üblicherweise einen Analog Komparator eingebaut, > der mit einem Eingang intern an die interne Referenz geschaltet werden > kann. Dadurch könnte man sich die externe Beschaltung mit dem LM358 > sparen. Der Witz ist, dass SOUNDRX keinen Analog-Eingang benötigt, sondern mit jedem digitalen Eingang zurechtkommt. Erzähl mir mal, wie Du das mit einem ATmega162 sonst machen willst ;-)
Datum:
Frank M. schrieb: > Beitrag "Schaltschwelle bei Atmega digital Eingang" > > Die Schaltschwellen der digitalen(!) Eingänge sind je nach > ATmega-Generation (z.B. ATmega8 vs. ATmega88) verschieden. OK. Aber trotzdem braucht man ja nicht zwangsläufig eine Kalibrier-Routine, wenn man einen bestimmten AVR benutzen will. Dann kann man ja die nötigen Spannungen aus dem Datenblatt entnehmen. > Der Witz ist, dass SOUNDRX keinen Analog-Eingang benötigt, sondern mit > jedem digitalen Eingang zurechtkommt. Erzähl mir mal, wie Du das mit > einem ATmega162 sonst machen willst ;-) Der Witz am Komparator wäre dann, dass man keine Kalibrier-Routine und auch keine große externe Beschaltung braucht ;-) Ansonsten eine nette Spielerei.
Datum:
Simon K. schrieb: > OK. Aber trotzdem braucht man ja nicht zwangsläufig eine > Kalibrier-Routine, wenn man einen bestimmten AVR benutzen will. Dann > kann man ja die nötigen Spannungen aus dem Datenblatt entnehmen. Ich messe keine Spannungen. Das Signal muss vom Offset her genau in der Mitte liegen, damit die High-Pegel- und die Low-Pegel-Zeiten gleich lang sind. Da nützen mir die Spannungen aus dem Datenblatt gar nichts. Ausserdem stehen dort für digitale Eingänge lediglich garantierte Mindest-Spannungen für High-Pegel und Höchst-Spannungen für Low-Pegel drin. Gerade die Grauzone dazwischen lässt Atmel bewusst offen, garantiert also für nichts. Aber genau diese Zone ist für die Lösung mit lediglich einem Poti und einem Kondensator spannend. Dass da ein Schmitt-Trigger am Digital-Eingang liegt, wird zwar im Datenblatt kurz erwähnt, aber über die eigentlichen Schwellwerte wird keine Aussage getroffen. > Der Witz am Komparator wäre dann, dass man keine Kalibrier-Routine und > auch keine große externe Beschaltung braucht ;-) Das ist richtig. Vielleicht mache ich noch eine spezielle Variante für ADC-Komparator-Eingänge, die man dann über soundrxconfig.h einstellen kann. > Ansonsten eine nette Spielerei. Jepp :-)
Datum:
Frank M. schrieb: > Gerade die Grauzone dazwischen lässt Atmel bewusst offen, > garantiert also für nichts. Aber genau diese Zone ist für die Lösung mit > lediglich einem Poti und einem Kondensator spannend. Dass da ein > Schmitt-Trigger am Digital-Eingang liegt, wird zwar im Datenblatt kurz > erwähnt, aber über die eigentlichen Schwellwerte wird keine Aussage > getroffen. Möglicherweise, weil die Schwelle in dem Bereich temperatur-, spannungs- und/oder launeabhängig ist. Die Schaltung könnte also unter bestimmten Umständen überhaupt nicht mehr funktionieren, obwohl sie mal kalibriert wurde. Sehr wackelig die Angelegenheit, finde ich. Reicht die Amplitude der Audiodatei nicht um die im Datenblatt angegebenen Grenzen zu überschreiten? Sodass man einfach (Vh+Vl)/2 als Offset einstellen kann?
Datum:
Simon K. schrieb: > Sehr wackelig die Angelegenheit, finde ich. Wenn es Dir zu wackelig ist, nimm die OpAmp-Schaltung. Die arbeitet in jedem Fall ohne Kalibrierung. > Reicht die Amplitude der Audiodatei nicht um die im Datenblatt angegebenen > Grenzen zu überschreiten? Sie sollte ausreichen, da der Kopfhörer-Ausgang einer Soundkarte in der Regel 2Vss bringt - meistens sogar mehr. Wenn Du ein Oszi hast, kannst Du das ja mal verifizieren Ich habe nämlich keins ;-) Rufe dazu http://www.kammerton.de/ auf und drehe den Lautstärkeregler Deiner Soundkarte auf mehr als 75%. > Sodass man einfach (Vh+Vl)/2 als Offset einstellen kann? Die Schaltschwelle liegt bei modernen ATmegas ziemlich genau bei Vcc/2. Eigentlich reicht es, das Poti auf die Mittenstellung einzustellen oder einfach 2 Widerstände mit gleichen Werten zu nehmen. Mit den in SOUNDRX eingebauten Toleranzen reicht das aus. Ich wollte nur auf Nummer Sicher gehen und habe mit dem Kalibrierungsprogramm bei meinem ATmega168P die Schaltschwelle bei 2,45V statt 2,5V gefunden. Auf jeden Fall sind dann die (digitalen) High-Pegel genauso lang wie die Low-Pegel bei symmetrischem Ausgangssignal der Soundkarte. Die 0,05V entsprechen aber gerade mal einer Abweichung von 2 Prozent. Das verkraftet SOUNDRX allemal. Von "wackelig" kann daher keine Rede sein. Aber wie gesagt: wem es so nicht gefällt, kann einfach die OpAmp-Schaltung nehmen.
Datum:
Frank M. schrieb: > Aber wie gesagt: wem es so nicht gefällt, kann einfach die > OpAmp-Schaltung nehmen. Alternativ könnte man einen npn- und einen pnp-Transistor in Gegentakt-Schaltung anordnen und die beiden Basen über je 10kOhm verbinden. Über einen Keramik- oder Folie-C 100nF koppelt man das Signal an den gemeinsamen Verbindungspunkt der Basiswiderstände. Die Emitter der Transistoren liefern das Signal für den µC. Auch nicht viel größer als die Einfachst-Schaltung, aber vertägt mehr Toleranzen bei den Signalpegeln.
Datum:
Hallo Frank, gerade eben habe ich mal den Bootloader für einen Atmega168 compiliert. In meinem AVR-Studio ( -OS ) erhalte ich eine Programmgröße von 1200 Bytes. Soweit ich weiß, hat der Atemga168 nur 1024 Byte für den Bootloader zur Verfügung. Hattet Ihr eine kleiner Codegröße? Gruß, chris
Datum:
chris schrieb: > gerade eben habe ich mal den Bootloader für einen Atmega168 compiliert. > In meinem AVR-Studio ( -OS ) erhalte ich eine Programmgröße von 1200 > Bytes. Soweit ich weiß, hat der Atemga168 nur 1024 Byte für den > Bootloader zur Verfügung. Das stimmt nicht. Die Bootloadergröße kann beim ATmega168 bis 2KB betragen. Eingestellt wird die Bootloadergröße über die E-Fuse. Bei der größtmöglichen Einstellung sind 1024 Words(!) möglich, das entspricht 2048 Bytes. Das Projekt ist auch so eingestellt, dass der Bootloader auf die Adresse 0x3800 compiliert wird, siehe Linker-Options: "--section-start=.text=0x3800". Somit werden die letzten 2KB für den Bootloader genutzt. Für die richtige Einstellung der Fuses ist die Seite http://www.engbedded.com/fusecalc/ sehr gut geeignet. > Hattet Ihr eine kleiner Codegröße? Ja, wir waren schon mal knapp unter 1KB, aber durch die Umstellung auf Flankencodierung und Einführung von Checksum-Übertragungen, um das ganze sicherer zu gestalten, sind wir wieder über die 1KB-Grenze gerutscht. Ich hoffe, wir können das wieder unter 1KB drücken. Im Moment muss man daher noch 2KB (= 1024 Words) einstellen. Gruß, Frank
Datum:
Knut Ballhause schrieb: > Alternativ könnte man einen npn- und einen pnp-Transistor in > Gegentakt-Schaltung anordnen und die beiden Basen über je 10kOhm > verbinden. Das klingt nicht schlecht, ich werde das mal bei Gelegenheit ausprobieren. Vielleicht malst Du mal dazu eine kleine Skizze, damit ich nichts falsch mache? ;-) Dank und Gruß, Frank
Datum:
Hi Frank, hier habe ich mich auch mal an einem Audio-Bootloader versucht: http://www.hobby-roboter.de/forum/viewtopic.php?f=... Ich habe die Manchestercodierung verwendet. Die läuft zwar nur halb so schnell, aber dafür muss man den Spannungsteiler nicht kalibrieren. Eine Auto-Detektion der Baurate ist auch drin. Das Java-Download-Programm ist etwas schlampig programmiert. Aber es funktioniert. Vielleicht gibt es hier einen Java-Experten für Oberflächen, der das Ganze etwas aufpolieren hilft. Gruß, chris
Datum:
Mit ist noch eine Idee für den minimalistischen Spannungsteilereingang gekommen: Wenn man die Portrichtung des MCs auf Ausgang schaltet und den Audiostecker an den Mikrofoneingang steckt, könnte man Daten zum PC übertragen. Wenn man den Audio PC-Ausgang an den Mikrofon Eingang des PCs anschließt und das Signal für den Mikrocontroller-Pin abzweigt, könnte man eine halbdublex Verbindung realiseren. Weiß jemand, ob der MC-Eingang des PC das 5V Signal des MCs aushält?
Datum:
Angehängte Dateien:Frank M. schrieb: > Das klingt nicht schlecht, ich werde das mal bei Gelegenheit > ausprobieren. Vielleicht malst Du mal dazu eine kleine Skizze, damit ich > nichts falsch mache? ;-) Folgendes habe ich probiert, entspricht zwar nicht ganz obiger Beschreibung, funktioniert aber hervorragend:
o Vcc
|
|
220k |
___ |<
.---|___|----| BC857C
| |\
| |
| |
Eingang ----o o--- zum µC Pin
| 220k |
| ___ |/
'---|___|----| BC847C
|>
|
|
-
(created by AACircuit v1.28.6 beta 04/19/05 www.tech-chat.de)
|
Am Controllerpin ist bei einem rechteckförmigen Eingangssignal von der Soundkarte von -20db bereits ein schönes Rechteck mit vollem Spannungshub zu sehen. Siehe Screenshot.
Datum:
chris schrieb: > Weiß jemand, ob der MC-Eingang des PC das 5V Signal des MCs aushält? Würde ich nicht drauf anlegen. Auf jeden Fall geht er stark in Sättigung, was sich auf die Signalqualität auswirkt. Besser einen Spannungsteiler 100:1 vorschalten.
Datum:
Zu oben genannter Schaltung bleibt noch anzumerken, dass man sie bei Nichtgebrauch besser abschaltbar gestaltet, da sonst etwa 3mA Ruhestrom über die Transistoren fließen.
Datum:
>Würde ich nicht drauf anlegen. Ich habe es doch mal ausprobiert, der Computer lebt und die Signale sahen gut aus. Die Manchestercodierung funktioniert ziemlich gut mit meiner Spannungsteilerversion: http://www.mikrocontroller.net/attachment/preview/120273.jpg Als Line in wird der TxD-Pin des Controllers verwendet. Wenn man ein gewöhnliches Programm hochlädt hat das den Vorteil, dass die "printf" direkt auf Line-In des PC gehen, wenn man den Anschluss dort ansteckt. Um das Signal kleiner zu machen, könnte man noch einen Widerstand vor den TxD Eingang setzen. Beim Programmieren hatte ich allerdings Schwierigkeiten einen vernünftigen Java-Treiber für Line-IN zu finden, deshalb gibt's PC seitig für den Rückkanal erst mal noch keine Software.
Datum:
Frank M. schrieb: > Übrigens: die Idee ist eigentlich 30 Jahre alt. Damals hat man in den > > C64/ZX-Spectrum die Programme/Daten mit einem Kassettenrecorder geladen. > > Hier passiert eigentlich genau dasselbe: Die gute alte Zeit! :-)
Datum:
Ähm, ok, hier das Bild noch mal etwas besser: http://www.hobby-roboter.de/forum/viewtopic.php?f=...
Datum:
Nettes Projekt! Nur ist es nun auch möglich diese Verbinung in beide Richtungen aufzubauen? zB. zwischen µC / µC oder Pc/µC






