Auf einem ziemlich frisch installierten Linux-System, noch ohne Bildbearbeitung:
rschaten% gimp bild.jpg
zsh: correct gimp to vim ? ([Y]es/[N]o/[E]dit/[A]bort)
Also Postscript habe ich schon mit VI bearbeitet, aber das geht dann sogar mir zu weit…
Auf einem ziemlich frisch installierten Linux-System, noch ohne Bildbearbeitung:
rschaten% gimp bild.jpg
zsh: correct gimp to vim ? ([Y]es/[N]o/[E]dit/[A]bort)
Also Postscript habe ich schon mit VI bearbeitet, aber das geht dann sogar mir zu weit…
Das ist cool: da macht jemand gut klingende (wenn man auf 8-Bit-Sound steht) Musik, und wenn man die Audiokanäle an ein zweikanal-Oszilloskop anschliesst sieht man quasi das Musikvideo. Im Original sieht man nur eine Simulation, aber es gibt eine Menge Videos von echten Oszis. Ich bin schwer amüsiert!
Ich nutze den Blog mal um eine Frage in die Runde zu stellen. Hier lesen ja einige Elektronik-Bastler, vielleicht kann mir einer einen Tip geben.
Ich bin wieder einmal dabei eine Schaltung zu planen. Nichts kompliziertes. Wieder was mit USB, basierend auf einem ATmega8. Die Herausforderung: das Ergebnis sollte möglichst klein sein. Den Controller habe ich im TQFP-32-Gehäuse. Da würde ich gerne auf den ISP-Stecker zum programmieren verzichten. Auf dem Controller kann man auch einen Bootloader unterbringen, so dass ich den später per USB programmieren können sollte.
Die Frage ist: wie kriege ich den Bootloader elegant auf den Controller?
Ich habe Gestern schon probiert ob ich so ein Klemmen-Kabel vom Bus Pirate oder vom Logic Sniffer an den Controller anschließen kann. Also bevor der eingelötet ist. Sieht nicht nach einer guten Methode aus: getestet habe ich das nicht, aber ich glaube dass ich mit den Klemmen nicht nur einen einzelnen Pin erwische. Außerdem ist die Gefahr ziemlich hoch die Pins damit abzubrechen.
Ich habe gesehen dass es Adapter mit ZIF-Sockel für TQFP-Gehäuse gibt, das ist wohl der professionelle Weg. Die kosten aber auch professionell — zwischen 130 und 200 Euro. Selbst wenn ich sowas per eBay direkt in China bestelle sind es noch 30 Euro, das ist reichlich wenn ich nur zwei Controller damit versorgen will. Und dann könnte ich immer noch nur die eine Gehäuseform damit verarbeiten, wenn ich mal einen Tiny programmieren will stehe ich wieder vor dem Problem.
Also:
Oder wie? Ich bin für jeden Tip dankbar…
Nachdem ich mich seit Monaten über einen Wackelkontakt in der Stromzufuhr meines treuen Notebooks (Thinkpad T43) geärgert habe hat es mich Heute davon überzeugt dass das so nicht weitergeht. Komplett entladen, keine Chance mehr es aufzuladen.
Naja, kaputt ist es eh. Also mal den Schraubenzieher angesetzt. Um zur Strombuchse zu kommen muss man das Teil fast bis auf die letzte Schraube zerlegen. Zwischendurch habe ich an mir gezweifelt und beim Händler meines Vertrauens nachgefragt was es kostet wenn der mir das repariert. 140 Euro, lohnt nicht für den antiken Rechenschieber. Für 150 kriege ich da schon das Nachfolgemodell (T60), für 300 sogar das Modell mit dem ich schon lange liebäugel (X61t mit großer Auflösung). Also weitermachen…
Wie gesagt: ich musste das Ding fast komplett auseinander nehmen. Habe ich bei einem Notebook noch nie gemacht. Da waren am Rumpf glaube ich nur noch drei oder vier Schrauben die ich nicht lösen musste. Ich hatte echte Bedenken das wieder zusammen puzzlen zu können, und das obwohl ich das Tablet meiner Einzigen neben mir liegen hatte das mir das Hardware Maintenance Manual praktisch vorgelesen hat.
Hat aber geklappt. Insgesamt hat die Aktion fast drei Stunden gedauert. Diesen Text schreibe ich von besagtem T43, der Akku ist mittlerweile auch schon wieder bei 32%.
Ach ja, die Strombuchse: entgegen meiner Erwartung war es nicht so dass da Lötstellen auf dem Mainboard gebrochen sind. Das Teil ist sinnvollerweise gar nicht auf dem Board aufgelötet, das ist mit dem Gehäuse verschraubt und liefert den Saft per Kabel ans Board. Der Hohlstecker (bzw. die Buchse) war einfach nur ausgenudelt. An strategisch korrekter Stelle dremeln und die Lasche innen drin zurückbiegen hat Wunder gewirkt.
Ich hatte mir ja vor einiger Zeit einen Bus Pirate gekauft (und damit dann mein OLED befeuert). Gerade bin ich über einen Clone gestolpert der vielleicht gerade für AVR-Bastler — der originale Pirate basiert auf PIC — interessant sein könnte: Bus Ninja.
Q. Why is it called Bus Ninja?
A. Because Ninjas are better than Pirates and Yarrrrrduino sounds silly.
Das sollte also auf einem Arduino funktionieren, den hat vielleicht der eine oder andere eh rumliegen. Wenn ich jetzt spontanen Bedarf hätte könnte ich mir mit den Teilen die ich habe was passendes zusammenstellen.
Allerdings habe ich aktuell keinen Bedarf: den Piraten habe ich ja schon, und der wird mir auch weiter gute Dienste leisten. Bin immer noch überzeugt von dem Ding, der Ninja nur nach einer interessanten Alternative.
Vielleicht wäre die Firmware auch für den USBprog portierbar. Der ist halbwegs verbreitet, und das würde den meiner Meinung nach nochmal deutlich aufwerten. Meinen USBprog wollte ich ursprünglich auch als Logic Sniffer benutzen, das habe ich aber nie vollständig befriedigend hingekriegt. Dafür habe ich mittlerweile den OBLS, seitdem ist der USBprog nur noch Programmer — und als solcher eigentlich zu schade…
Webseite: „This new wire is a great step up from my previous efforts, and allow the „sould“ of the original Cynosure to stay intact, while allowing the cable to be even more quiet than before, and reveal even more inner details.“
Ich: „Aehm… USB ist digital…“
Webseite: „Locus Design was one of the first, if not the first, to come out with an „audiophile“ USB cable.“
Ich: „Aber… aeh… digital?“
Webseite: „Everything about the Cynosure is custom, the connectors, the wire, the way I damp and shield it, and even how I terminate it with the best Mundorf solder and a special adhesive material that not only does not negatively impact the sound, but makes the ends very strong and durable.“
Ich: „Mundorf… was!? DIGITAL!“
Webseite: „Starting at $3549 for 3FT.“
Ich: *krampf* *zuck* *umfall*
Diesen Text habe ich erst 2015 aus dem alten CMS übernommen, der war 2011 noch nicht im Blog.
Ich habe noch nicht viele Mikrokontroller-Projekte gemacht, aber mehr als eines beinhaltete die Steuerung von LEDs mittels Pulsweitenmodulation (PWM). Mit einer oder mehr LEDs ist das eine Sache die den kleinen Controller schon halbwegs stresst, aber wenn der Controller neben dem Dimmen von LEDs auch noch andere mehr oder weniger komplizierte Aufgaben hat geht einem schnell das Timing in die Brüche mit denen die LEDs angesteuert werden. Ganz zu schweigen vom Programmcode, der mit jeder weiteren Aufgabe unleserlicher wird die ‚zur gleichen Zeit‘ ablaufen soll.In meinem nächsten Projekt muss ich wieder LEDs faden, daher habe ich nach einem einfacheren Weg gesucht das zu machen. Das Projekt umfasst das Lesen von Speicherkarten, Kommunikation mit einer Echtzeituhr und die Ausgabe von Text auf einem LCD-Display, also bin ich fast sicher dass ich es nicht hinkriegen würde fünf Kanäle zuverlässig zu steuern. Und so viele werden es wohl mindestens werden.
Der erste Plan war, einen fertigen Chip dafür zu benutzen. Ich habe mich umgesehen und das beste was ich fand war ein Teil von Philips (PCA-irgendwas, ich habe die Nummer vergessen), das über einen I2C-Bus gesteuert werden kann. Das Teil kann bis zu acht LEDs ansprechen, aber neben ‚an‘ und ‚aus‘ gibt es nur zwei Helligkeiten die man den Ausgängen zuweisen kann. Diese sind dann wiederum variabel, aber trotzdem kann man so nicht einen Kanal mit 20%, einen mit 50% und einen mit 80% belegen. Außerdem gibt es das Teil nur als SMD, und meine Fähigkeiten am Lötkolben reichen für die Verarbeitung so kleiner Teile leider nicht aus.
Also wuchs der Plan, einen separaten Controller für die Ansteuerung der LEDs zu nehmen, der von einer Art ‚Hauptprozessor‘ angesprochen wird — idealerweise mittels I2C-Bus, da ich ja später noch mehrere andere Geräte benutzen möchte die an den gleichen Bus kommen könnten. Also habe ich einen ATtiny2313 in mein Breadboard gesteckt, den mit einem 20MHz-Quarz getaktet, und wir haben versucht so viele LEDs wie möglich zu steuern…
Die Helligkeitssteuerung von LEDs wird üblicherweise mit Pulsweitenmodulation gemacht. Ich habe das auch schon in mehreren Projekten benutzt.
Bis jetzt habe ich immer alle LEDs eingeschaltet die eine Helligkeit grösser als 0 annehmen sollten, abgewartet bis die erste LED ausgeschaltet werden muss, die LED ausgeschaltet, auf die nächste gewartet, und so weiter. Nach einer bestimmten Zeit sind alle LEDs aus und ich fange von vorne an.
Ich versuche mal, das an einem kleinen Bild zu verdeutlichen:
1 2 3 4 5 6 |
. . . . .| . . 1 *************************************************|************************ 2 *************************************** |************************ 3 ********* |********** 4 | 5 ***************************** |************************ |
In diesem Beispiel dauert ein kompletter Durchlauf des PWM-Zyklus 50 Zeiteinheiten. Die erste LED ist die ganze Zeit durch eingeschaltet (100%), die zweiter für 40 von 50 Zeiteinheiten (80%), die dritte für zehn (20%) und die fünfte für 30 Zeiteinheiten (60%). Die vierte LED ist aus (0%). Man sieht, dass der PWM-Zyklus nach 50 Zeiteinheiten von vorn beginnt.
Ein Nachteil dieser Technik ist, dass sie langsam ist. Und sie wird mit jedem weiteren Kanal den man ansteuern möchte langsamer. Wir haben es versucht, aber wir waren auf diese Weise nicht in der Lage mehr als fünf LEDs anzusteuern ohne dass sie sichtbar anfingen zu flackern.
Wir haben auch versucht, alle Zustände der Pulsweitenmodulation in einem Array abzulegen, so dass der Algorithmus nur noch durch das Array wandern und die jeweiligen Werte darstellen muss. Das ging aber auch nicht, weil unser Controller nicht über genügend RAM verfügt um so ein Array abzulegen.
Nach einigen Tests die mehr oder weniger schlechte Ergebnisse brachten hatte Thomas eine großartige Idee wie man die PWM implementieren könnte. Sie arbeitet auch mit einem Array für alle Zustände, allerdings werden die Zustände nicht gleich lange dargestellt. Der erste Status wird nur für eine Zeiteinheit angezeigt, der zweite für zwei Einheiten, der dritte für vier, und so weiter. Auf die Weise werden die LEDs zwar während eines PWM-Zyklus‘ mehr als nur einmal an- und ausgeschaltet, aber das tut niemandem weh.
Ich versuche mich noch einmal an einem Bildchen:
1 2 3 4 5 6 7 8 9 10 |
. . . . . . | . .. . . . . |.. . . 1 * |* 2 ** | ** 3 *** |*** 4 **** | **** 5 * **** |* **** 6 ****** | ****** 7 ******* |******* 8 ******** | **** |
Hier sehen wir also eine Pulsweitenmodulation mit acht Kanälen, die bis zu 64 verschiedene Helligkeiten annehmen können. Kanal 1 wird nur für eine Zeiteinheit eingeschaltet, Kanal 2 für zwei Einheiten, und so weiter. Interessant ist der fünfte Kanal: die LED wird für eine Zeiteinheit ein-, dann für zwei Einheiten aus-, und dann wieder für vier Einheiten eingeschaltet.
Wir sehen uns mal ein komplexeres Beispiel an — in dem auch hellere LEDs vorkommen:
1 2 3 4 5 6 7 8 9 10 |
. . . . . . | . .. . . . . |.. . . 1 * *******************************|* 2 ** **************** | ** 3 ******* **************** |******* 4 *******************************| 5 * **** **************** |* **** 6 *************************************************************| ********** 7 **************************************************************|*********** 8 ************************ | **** |
Die Kanäle 1 bis 8 zeigen die Helligkeiten 33, 18, 23, 32, 21, 63, 64 und 24.
Der Vorteil dieser Technik ist, dass man sich einerseits nur eine begrenzte Anzahl von Zuständen merken muss (sechs in diesem Beispiel), und andererseits die Schleife durch die Zustände sehr einfach ist: Status n wird an die Ausgänge geschickt, dann wird für 2^(n-1) Zeiteinheiten gewartet, dann folgt der nächste Zustand.Jeder Zustand wird durch ein Bitmuster dargestellt, das im jeweiligen Schritt an die Ausgänge geschickt wird. Mit anderen Worten: eine Spalte die im obigen Bild am Anfang einer Wartezeit steht. In diesem Beispiel haben wir also sechs Zustände: 01010101, 01100110, 01110100, 11100000, 11110110 und 01101001. Der erste wird für eine Zeiteinheit dargestellt, der zweite für zwei Einheiten, der dritte für vier, und so weiter…
Ein weiterer Vorteil dieser Technik ist, dass die Anzahl der Ausgänge fast unerheblich für die Systemlast ist. Nur wenn neue Helligkeiten angefordert werden muss der Algorithmus die Zustände neu berechnen, aber das ist schnell gemacht. Mit diesem Algorithmus ist es also möglich, unterschiedliche Helligkeiten auf allen freien Pins eines Controllers anzuzeigen. Für einen ATtiny2313 heisst das, dass man 13 LEDs faden kann während man immer noch in der Lage ist mittels I2C mit anderen Geräten zu kommunizieren!
I2C zu sprechen ist zwar keine Raketenwissenschaft, aber da das eine Menge mit Bit-Shifterei zu tun hat wenn man es implementieren will habe ich da eine fertige Bibliothek benutzt.
Genommen habe ich die Bibliothek von Donald R. Blake, er hat die freundlicherweise unter die GPL gestellt und sie auf avrfreaks.net veröffentlicht. Man findet das originale Posting im Thread ‚8 bit communication between AVR using TWI‚, und einige Nachträge in ‚I2C Slave on an ATtiny45‚.
Danke für die Arbeit, Donald! Und dafür dass Du eine freie Lizenz benutzt hast.
Da sein Paket nur als Attachment im Forum erhältlich zu sein scheint, und ich mir nicht sicher bin für wie lange das der Fall sein wird, habe ich es in den Tarball dieses Projektes mit aufgenommen.
Man sollte dieses Gerät benutzen können wie jeden anderen I2C-Slave auch:
Die folgenden Pins des Controllers müssen mit der Schaltung verbunden werden:
Die I2C-Daten und -Taktleitungen sollten mit 4,7k-Widerständen terminiert werden um die Leitungen auf VCC hoch zu ziehen. An alle übrigen Pins können LEDs angeschlossen werden. Die Anordnung ist wie folgt:
In meinen Tests habe ich einen ATmega8 mit der I2C-Bibliotkek von Peter Fleury (http://jump.to/fleury — auch an Ihn Dank für die freie Lizenz!) als I2C-Master benutzt.
Eine typische Funktion um den Dimmer anzusprechen sieht wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#define I2C_FADER 0x10 void sendi2cBytes(uint8_t address, uint8_t brightness) { // address: number of the LED to set (0..12) // brightness: value between 0 and 127 // start the communication... i2c_start_wait((I2C_FADER < < 1) + I2C_WRITE); // write a byte with the address. we want the highest bit of the // address to be 1, so the slave can be sure that this is an address. i2c_write(address | 0x80); // calculate the actual duration the LED should light up. we could do // this on the slave's side, but we assume that the device is more // flexible when it is done on the master side. uint16_t duration = (brightness + 1) * (brightness + 1) - 1; // calculate the low- and the high-byte and send it. note that we split // the duration into 7-bit-values, not 8 bit! in this way the highest // bit of the transferred bytes is always low, allowing the slave to // recognize the transmitted bytes as values, not as addresses. i2c_write(duration & 0x7f); // low byte i2c_write((duration >> 7) & 0x7f); // high byte // stop the communication... i2c_stop(); } |
Hier sieht man alle LEDs in verschiedenen Geschwindigkeiten faden.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
void sendi2cBytes(uint8_t address, uint8_t brightness) { i2c_start_wait((I2C_FADER << 1) + I2C_WRITE); i2c_write(address | 0x80); uint16_t duration = (brightness + 1) * (brightness + 1) - 1; i2c_write(duration & 0x7f); // low byte i2c_write((duration >> 7) & 0x7f); // high byte i2c_stop(); } void fadeall(void) { uint8_t i = 0; int16_t brightness[13]; int16_t speed[13]; for (i = 0; i < 13; i++) { brightness[i] = 64<<8; speed[i] = random() & 0xff + 0x40; } while (1) { for(i= 0; i < 13; i++){ sendi2cBytes(i, brightness[i]>>8); brightness[i]+= speed[i]; if(brightness[i]>>8 > 127 || brightness[i]>>8 < 0){ brightness[i]-= speed[i]; speed[i] = -speed[i]; } } timerPause(1); } } |
Hier sieht man das Signal einer LED, die von 0 bis 127 fadet. Leider hat mein Oldtimer-Oszilloskop im mittleren Teil Probleme korrekt zu triggern.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void sendi2cBytes(uint8_t address, uint8_t brightness) { i2c_start_wait((I2C_FADER < < 1) + I2C_WRITE); i2c_write(address | 0x80); uint16_t duration = (brightness + 1) * (brightness + 1) - 1; i2c_write(duration & 0x7f); // low byte i2c_write((duration >> 7) & 0x7f); // high byte i2c_stop(); } void fade(void) { uint8_t i; for(i= 0; i < = 127; i++){ sendi2cBytes(0, i); timerPause(100); } } |
Bis jetzt hat das Teil in allen getesteten Situationen prima funktioniert. Alles läuft wie geplant.
Ich schätze, dass dieser Dimmer im Vergleich zu fertigen Controller-ICs etwas langsam ist. Ich kann zwar kein Flackern in den LEDs erkennen, da sie immer noch ziemlich schnell geschaltet werden (etwa einmal alle 6ms, also ein Flackern mit 166Hz — zu schnell für mich).
Wieder mal geht mein besonderer Dank an Thomas Stegemann. Er hatte die tolle Idee für den PWM-Algorithmus, und ich bin immer wieder beeindruckt von der Geduld mit der er mir eine dermaßen kranke Sprache wie C näher bringt…
Dieses Projekt steht unter der GNU General Public License (GPL). Eine Kopie der GPL liegt dem Paket in der Datei License.txt bei.
Irgendwann will ich mal selbst eine Platine zusammenbraten auf der ein echtes Linux läuft. Ohne einen besonderen Einsatzzweck, einfach nur weil es geht. Inspiration in die Richtung bietet Gnublin. Im Prinzip ist das schon alles, und sogar komplett Open Source. Einschließlich des Schaltplans. Nur der ARM-Controller lässt sich nicht von Hand löten…