Forum: Projekte & Code SOUNDRX - Datenübertragung/Bootloader PC -> µC über PC-Soundkarte


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von O. D. (odbs)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Dennis S. (bzzzt)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Christian B. (casandro)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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!

von Christian B. (casandro)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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?

von Tueftler (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 ;-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Hendi (Gast)


Lesenswert?

Das nenne ich doch mal genial! Versuche es aufjedenfall in meinem 
Projekt unterzubringen :)

von Chris (Gast)


Lesenswert?

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.

von Rene B. (themason) Benutzerseite


Lesenswert?

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 :-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von chris (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Chris (Gast)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Vlad T. (vlad_tepesch)


Lesenswert?

hi, nettes projekt.

kann es sein, dass in dem Archiv die Bootloader-Sourcen fehlen?

von chris (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Sparfuchs (Gast)


Lesenswert?

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)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von chris (Gast)


Lesenswert?

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

von chris (Gast)


Lesenswert?

Ä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.

von Alex H. (hoal) Benutzerseite


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 
;-)

von chris (Gast)


Lesenswert?

>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.

von Vlad T. (vlad_tepesch)


Angehängte Dateien:

Lesenswert?

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.
1
AVR Memory Usage
2
----------------
3
Device: atmega168
4
5
Program:    1000 bytes (6.1% Full)
6
(.text + .data + .bootloader)
7
8
Data:         45 bytes (4.4% Full)
9
(.data + .bss + .noinit)

Allerdings bringt das jetzt 2 Warnungen, die aber normalerweise (dazu 
siehe unten) ignoriert werden können
1
../sndrx-bootloader.c: In function 'main':
2
../sndrx-bootloader.c:209: warning: function declared 'noreturn' has a 'return' statement
3
../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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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:
1
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

von Vlad T. (vlad_tepesch)


Lesenswert?

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.
1
../sndrx-bootloader.c:172: warning: return type of 'main' is not 'int'
2
../sndrx-bootloader.c: In function 'main':
3
../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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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:
1
int
2
main (void)
3
{
4
    main_loop ();
5
}

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:
1
void
2
main_loop (void)
3
{
4
    uint8_t     ch;
5
    uint8_t     temp;
6
7
    sndrx_init ();                                                          // initialize SOUNDRX
8
9
#if USE_LED == 1
10
    led_init();                                                             // initialize LED port
11
    LED_ON;                                                                 // switch LED on
12
#endif
13
14
    temp = MCUCR;                                                           // set interrupt vectors to bootloader section
15
    MCUCR = temp | (1<<IVCE);
16
    MCUCR = temp | (1<<IVSEL);
17
18
    sei ();                                                                 // enable interrupts
19
20
    while (1)
21
    {
22
        if (sndrx_poll (&ch, 3000) == 1 && ch == '$')                           // wait 3 seconds for the dollar character...
23
        {
24
#if USE_LED == 1
25
            LED_OFF;                                                            // got it, switch LED off
26
#endif
27
            if (! boot_update_flash ())                                               // flash now
28
            {
29
                continue;
30
            }
31
#if USE_LED == 1
32
            LED_OFF;                                                               // switch LED off
33
#endif
34
        }
35
36
        cli ();                                                                 // disable interrupts
37
38
        temp = MCUCR;                                                           // reset interrupt vectors (set to application section)
39
        MCUCR = temp | (1<<IVCE);
40
        MCUCR = temp & ~(1<<IVSEL);
41
42
        asm volatile("jmp 0x0000");
43
    }
44
}

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

von Vlad T. (vlad_tepesch)


Lesenswert?

sehr gut. Das muss ich mir unbedingt merken.

Ich werde das mal hier hinzufügen:
http://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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-Codeoptimierung

Gute Idee.

von Vlad T. (vlad_tepesch)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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. :-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich habe noch ein paar Dutzend Bytes einsparen können:

1. In sndrx-bootloader.c:
1
#define SNDRX_AS_INCLUDE    // bad trick: save program space by including sndrx.c so we can use static functions
2
#include "sndrxconfig.h"
3
#include "sndrx.h"
4
#include "sndrx.c"

2. In sndrx.c:
1
#ifdef SNDRX_AS_INCLUDE                                                                 // if used as include....
2
#define SNDRX_STATIC   static                                                           // we can declare functions as static
3
#else                                                                                   // this saves program space
4
#define SNDRX_STATIC
5
#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:
1
void sndrx_init (void)
2
{
3
   ...
4
}

Neu:
1
SNDRX_STATIC void sndrx_init (void)
2
{
3
   ...
4
}

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-Codeoptimierung

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...

von Vlad T. (vlad_tepesch)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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:
1
// avoid push in main
2
int main( void ) __attribute__((OS_main));


Peter

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von chris (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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:
1
// avoid push in main
2
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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> Füg mal ins *.c noch das ein:
>
1
> // avoid push in main
2
> int main( void ) __attribute__((OS_main));
3
>

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:
1
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.

von Simon K. (simon) Benutzerseite


Lesenswert?

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:
>
1
> 
2
> // avoid push in main
3
> int main( void ) __attribute__((OS_main));
4
>

Richtig!

Für einen sauberen Reset kann man den Watchdog missbrauchen.

von Peter D. (peda)


Lesenswert?

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

von Simon K. (simon) Benutzerseite


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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!

von chris (Gast)


Lesenswert?

>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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von chris (Gast)


Lesenswert?

>Das geht nicht. Ich polle. Nämlich 44100 mal pro Sekunde.

Du kannst ja auch einen Timer verwenden. Dann geht's schneller und 
genauer.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von chris (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von chris (Gast)


Lesenswert?

>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?

von Vlad T. (vlad_tepesch)


Lesenswert?

chris schrieb:
> Was muss Dein Code machen, außer das Flash zu programmieren?

das ding war ja nciht nur als bootloader gedacht

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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?

von chris (Gast)


Lesenswert?

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.

von ATmega user (Gast)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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%20Controller/myUSBtoUART.htm?sp=article.sp.php&artID=200024

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.

von ATmega user (Gast)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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...

von Vlad T. (vlad_tepesch)


Lesenswert?

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 ;)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von chris (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Vlad T. (vlad_tepesch)


Lesenswert?

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 ;)

von Chris (Gast)


Lesenswert?

Line out ist 1vpp. Kopfhörerausgang ist generell 2Vpp.

von chris (Gast)


Lesenswert?

>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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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" ;-)

von chris (Gast)


Lesenswert?

>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.

von chris (Gast)


Lesenswert?

>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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von chris (Gast)


Lesenswert?

>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

von chris (Gast)


Angehängte Dateien:

Lesenswert?

Hier ein Bild mit den Grenzen, in denen die Schaltschwellen bei der 
2T/3T Codierung wandern.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von R. M. (rmax)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Vlad T. (vlad_tepesch)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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?

von R. M. (rmax)


Lesenswert?

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.

von Stefan (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von chris (Gast)


Lesenswert?

Glueckwunsch zum erfolgreichen Projekt. Ich hoffe,einige Leute melden 
euch die Testergebnisse zurueck.

Gruß,
chris

von Simon K. (simon) Benutzerseite


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 ;-)

von Simon K. (simon) Benutzerseite


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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 :-)

von Simon K. (simon) Benutzerseite


Lesenswert?

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?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

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.

von chris (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

von chris (Gast)


Lesenswert?

Hi Frank,

hier habe ich mich auch mal an einem Audio-Bootloader versucht:
http://www.hobby-roboter.de/forum/viewtopic.php?f=4&t=127&p=530

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

von chris (Gast)


Lesenswert?

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?

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Angehängte Dateien:

Lesenswert?

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:
1
                                          o Vcc
2
                                          |
3
                                          |
4
                               220k       |
5
                                ___     |<
6
                           .---|___|----|   BC857C
7
                           |            |\
8
                           |              |
9
                           |              |
10
               Eingang ----o              o---  zum µC Pin
11
                           |   220k       |
12
                           |    ___     |/
13
                           '---|___|----|   BC847C
14
                                        |>
15
                                          |
16
                                          |
17
                                          -
18
(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.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

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.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

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.

von chris (Gast)


Lesenswert?

>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.

von A.N. (Gast)


Lesenswert?

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! :-)

von chris (Gast)


Lesenswert?

Ähm, ok, hier das Bild noch mal etwas besser:
http://www.hobby-roboter.de/forum/viewtopic.php?f=4&t=128

von Simon A. (testnetz)


Lesenswert?

Nettes Projekt!

Nur ist es nun auch möglich diese Verbinung in beide Richtungen 
aufzubauen?
zB. zwischen µC / µC oder Pc/µC

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.