Hallo, ich möchte, in Assembler, mit möglichst wenig Instruktionen ein Bit von PB2 in "data"(Register) übernehmen, jedoch darf data nicht komplett überschrieben werden. [\avrasm] SBIC PINB,2 ORI data,0x01 Frage: Geht dies auch mit weniger Instruktionen? Eleganter? Danke Mathias
Weniger als ein Befehl? Das dürfte sportlich werden. Vielleicht könntest Du einen Tipp zum verwendeten Prozessor geben. Meine Glaskugel ist nämlich immer noch in der Werkstatt.
Hallo, sorry. Der µC ist Atmel Attiny 13A. Ich shifte das Datenbit, lese dann PB2 ein, setze das Bit (0/1), vergleiche, wieviele Schiebeoperationen ich hatte und breche bei 8 ab. 1. LSL data ; Datenbyte linkshift 2. SBIC PINB,2 ; Überspringe nächste, wenn PIN PB2 = 0 3. ORI data,0x01 ; wert setzen 4. INC counter ; Counter erhöhen 5. CPI counter,8 ; Counter auf max-wert prüfen 6. BRNE ....etc..pp Das ganze wollte ich gerne (Durchlaufzeit) etwas "Kompakter" haben !!! Mathias
Hi Eleganter? Keine Ahnung, aber was ist, wenn PINB nicht "1" ist? Vieleicht setzt du noch vor deine Anweisung ein ANDI data,0xFE Sonst bleibt ein einmal gesetztes Bit für immer und ewig "1" Aber mal eine Frage, wieso willst du bei ca. 3 Takten noch "eleganter" werden? Gruß oldmax
Hallo, wenn PB2 nicht 1 ist, ist er automatisch null (da shift vorher). Dann wird gezählt. Routine dient zum seriellen einlesen. Mit jedem Shift rückt das datenbyte nach links, bis 8 "voll" sind. Ich wollte nur die Zählerei kürzer machen, hab aber noch keine idee ! Mathias
Wenn Du schon schiebst... Ein paar Schiebebefehle schubsen das oberste/unterste Bit ins Carry-Bit. Dieses kann als Sprungbedingung verwendet werden.
Mathias schrieb: > Ich shifte das Datenbit, lese dann > PB2 ein, setze das Bit (0/1), vergleiche, wieviele Schiebeoperationen > ich hatte und breche bei 8 ab. Start: Datenbyte mit 1 laden Schleife: Schieben + Testen, aber ohne counter Endetest: Wenn deine am Anfang geladene 1 im Carrybit auftaucht, sind automatisch 8 Durchläufe fertig. :)
:
Bearbeitet durch User
@Ralf Geht! ...aber 1 x LSR = 1 x DEC 1 x LDI = 1 x LDI (1/8) 1 x BRCS = BREQ als Schleifenbegrenzung also gleichwertig
Hallo, gibt es einen "Trick" um den PB2 (und nur das Bit von PB2) direkt mit Data zu verknüpfen, ohne es vorher explizit in ein register einzulesen? Mathias
Amateur schrieb: > ...aber 1 x LSR = 1 x DEC > 1 x LDI = 1 x LDI (1/8) > 1 x BRCS = BREQ Hmm. Wenn, dann wird nach links geschoben und getestet ob das Carry-Flag noch nicht gesetzt ist:
1 | ldi r16, 1 |
2 | input: |
3 | lsl r16 |
4 | sbic PINB, 2 |
5 | ori r16, 1 |
6 | brcc input |
... wäre jetzt so mein Gedanke. Edit: Vielleicht müsste noch ein 'clc' vor die Schleife zur Sicherheit?
:
Bearbeitet durch Moderator
@ Mathias Soweit mir bekannt ist, hat der AVR keinen Befehl um unter Angabe einer Bitnummer, oder auch einer Bitmaske und einer Speicheradresse (oder auch eines Registers, dass eine Speicheradresse enthält) ein Bit an dieser Speicheradresse zu beeinflussen. http://www.atmel.com/images/Atmel-0856-AVR-Instruction-Set-Manual.pdf Wenn das in data zu beeinflussende Bit an der selben Position sitzt, wie in Port, dann ist diese Befehlsfolge
1 | ANDI data,(0xFF-0x04) |
2 | SBIC PINB,2 |
3 | ORI data,0x04 |
die kürzeste die mir einfällt. (Wobei "data" ein Register ist). Nebenbei: Ich verstehe nicht, zu welchem Zweck Du diese Schiebeoperationen machst. Kannst Du das mal erklären, bitte?
:
Bearbeitet durch Moderator
Wenn PINB eher als dünn besetzt zu erwatzen ist, könntest du folgenden Ansatz in Betracht ziehen.
1 | .DEF tmp = r16 |
2 | .DEF tmp2= r17 |
3 | .DEF data= r1 |
4 | |
5 | |
6 | .CSEG |
7 | .ORG 0 |
8 | startup: |
9 | ldi tmp,0xff |
10 | out portb,tmp |
11 | |
12 | in tmp,pinb |
13 | loop: |
14 | breq end |
15 | mov tmp2,tmp |
16 | neg tmp2 ;mask rightmost 1 |
17 | and tmp2,tmp |
18 | eor tmp,tmp2 ;clear bin in pinb |
19 | rjmp loop |
20 | end: |
21 | rjmp end |
Mit der Bitmaske kann, logo, auch was mit dem data-register gemacht werden
Mathias schrieb: > 1. LSL data ; Datenbyte linkshift > 2. SBIC PINB,2 ; Überspringe nächste, wenn PIN PB2 = 0 > 3. ORI data,0x01 ; wert setzen > 4. INC counter ; Counter erhöhen > 5. CPI counter,8 ; Counter auf max-wert prüfen > 6. BRNE ....etc..pp = 55 Takte > Das ganze wollte ich gerne (Durchlaufzeit) etwas "Kompakter" haben !!!
1 | IN tmp, PINB |
2 | BST tmp, 2 |
3 | BLD data, 7 |
4 | IN tmp, PINB |
5 | BST tmp, 2 |
6 | BLD data, 6 |
7 | IN tmp, PINB |
8 | BST tmp, 2 |
9 | BLD data, 5 |
10 | IN tmp, PINB |
11 | BST tmp, 2 |
12 | BLD data, 4 |
13 | IN tmp, PINB |
14 | BST tmp, 2 |
15 | BLD data, 3 |
16 | IN tmp, PINB |
17 | BST tmp, 2 |
18 | BLD data, 2 |
19 | IN tmp, PINB |
20 | BST tmp, 2 |
21 | BLD data, 1 |
22 | IN tmp, PINB |
23 | BST tmp, 2 |
24 | BLD data, 0 |
= 24 Takte
Ah. Moment. Willst Du eine "Folge von 8 Bits von PINB2" in "data" übernehmen?
Ein Port-Register zu verschieben ist nicht sinnvoll. Außer dem SBI?-Befehl gibt es nicht viele Möglichkeiten. ... aber manche Programmierer haben, aus Geschwindigkeitsgründen ein Register welches konstant mit Null belegt ist. also weit außerhalb Deiner Schleife gibt es dann einmalig ein LDI Rx,0 oder wie auch immer Du löschst. ... XOR Rz,Rz ; Lösche Ergebnisregister (1 Takt) MOV Ry,PINB ; Port lesen (1 Takt) LSR Ry ; Abfragebit [1] nach [0] (1 Takt) LSR Ry ; Abfragebit [0] nach [C] (1 Takt) ADC Rz,Rx ; Rz = 0 oder 1 je nach B2 (1 Takt)
Lese gerade, dass es -nur- um PB2 geht. Dann ist es natürlich unnötig, sich um den ganzen PINB zu kümern... Tschuldigung mein Fehler ich habe hier gar nicht mehr weitergelsen, ich hab mich etwas in avrasm eingelesen schnell, das ist Jahre her, dass ich damit gespielt habe. Wie gesagt: sorry
@Bedienungsanleitungssucher (Gast) 2-Wire in Software, bei jedem Takt an PB1 lese ich PB2 ein, shifte bis 8 bit voll->Flag setzen und verarbeiten! Mathias
Mathias schrieb: > @Bedienungsanleitungssucher (Gast) > > 2-Wire in Software, bei jedem Takt an PB1 lese ich PB2 ein, shifte bis 8 > bit voll->Flag setzen und verarbeiten! > > Mathias Aha. Danke. Und das ist tatsächlich ein Protokoll mit byteweisem Takt? Kenne ich gar nicht. Nun gut. Ich kenne nicht alles, was es gibt. Hast Du da mal einen Link auf die Protokollbeschreibung?
Ah jetzt habe ich es auch begriffen. War bischen Salami. Aber du gibts doch gar keinen Takt aus. Wo spielt denn da der Takt?
An PB1 liegt die Taktleitung. Bei jedem Takt wird ein Bit (0/1) übernommen und weitergeschoben. Link zu Protokoll wird schwierig, da Eigenbau! Mathias
Mathias schrieb: > An PB1 liegt die Taktleitung. Bei jedem Takt wird ein Bit (0/1) > übernommen und weitergeschoben. Link zu Protokoll wird schwierig, da > Eigenbau! > > Mathias Aha. Dankeschön. Hmm. Naja. Auch bei selbst definierten Protokollen ist eine Beschreibung zweckmäßig, denke ich. Aber gut. Deine Sache. Im übrigen ist dann I2C das ähnlichste Protokoll. Nur berücksichtigt der Code oben, wenn ich das richtig sehe, den Takt nicht. Weder die von den Antwortern (die das ja nicht wissen konnten) noch Dein eigener. Es wird einfach, so schnell wie möglich eingelesen und geschoben.
Eigentlich schmeckt Salami ganz gut. Aber Informationen Scheibchenweise sind aber nicht der Wahre Mathias.
Amateur schrieb:
1 | XOR Rz,Rz ; Lösche Ergebnisregister (1 Takt) |
2 | MOV Ry,PINB ; Port lesen (1 Takt) |
3 | LSR Ry ; Abfragebit [1] nach [0] (1 Takt) |
4 | LSR Ry ; Abfragebit [0] nach [C] (1 Takt) |
5 | ADC Rz,Rx ; Rz = 0 oder 1 je nach B2 (1 Takt) |
Abgesehen davon, dass es in statt mov heißen muss, fehlt da doch ein lsr Ry.
Ein paar Randbedingungen fehlen aber immer noch. Ist, bezogen auf den Takt, das Datenbit während der ansteigenden Flanke gültig; während er high oder low ist; oder während der abfallenden Flanke? Und was vielleicht nicht ganz unwichtig ist: Wie schnell Tickst Du? Aber vielleicht fallen Dir ja noch ein paar Randbedingungen ein, die das alles umwerfen.
@Mathias Hast du schon eine funktionierende Lösung und willst das ganze nur noch schneller/ sparsamer machen? Falls nicht, ist das jetzt noch nicht der richtige Zeitpunkt um über solche Details nachzudenken... Mathias schrieb: > Link zu Protokoll wird schwierig, da > Eigenbau! Mach mal eine ordentliche Beschreibung von dem Protokoll. Wenn da noch der Takt berücksichtigt werden soll, wird das nix mit 'ner Schleife bzw. der schnellen, 'aufgerollten' von Stefan.
@S. Landolt Stimmt, mein Editor hat aber nicht gemeckert;)
An der funktionierenden Lösung bastele ich zur Zeit noch. Der Loop läuft durch, sobald über INT0 die Taktflanke erkannt wurde. Wenn 8 bit durch sind, setze ich ein Flag und arbeite das in der Hauptschleife ab. Die Routine muß so schnell sein, um den AVR aus dem Sleep aufzuwecken, Bit speichern und wieder schlafen legen zu können ! Und ja, sobald das ganze bidirektional läuft, werde ich eine ausführliche Beschreibung machen !
Wie willst Du eigentlich den "Anfang" finden? Eine kleine Störung reicht da schon aus. Ich weiß, ich bin ein Spielverderber...
Amateur schrieb: > Stimmt, mein Editor hat aber nicht gemeckert;) Es reicht ja, wenn der Landolt meckert. > Wie willst Du eigentlich den "Anfang" finden? Und wie die Mitte des abzutastenden Bits? > Ich weiß, ich bin ein Spielverderber... Da sind wir schon zu zweit, das ist m.E. sehr schwer bis unmöglich.
Mathias schrieb: > Die Routine muß so schnell sein, um den AVR aus dem Sleep aufzuwecken, > Bit speichern und wieder schlafen legen zu können ! Hmm. Bit speichern? Da brauchst du ja keine Schleife. Trotzdem, wenn ich jetzt mal für die Verarbeitung des Bits 4 Takte ansetze (nicht nachgerechnet!), du möchtest eine Datenübertragung in Software mit F_CPU/4? Und wenn du jetzt sagst: "Alles ganz anders"... Mathias schrieb: > Und ja, sobald das ganze bidirektional läuft, werde ich eine > ausführliche Beschreibung machen ! ... lieber gleich!
Ich glaube zwar nicht, dass es weiterhilft, aber hier eine Lösung mit 1+16 Takten:
1 | .def tmp = r16 |
2 | ldi tmp,0 |
3 | sbic PINB,2 |
4 | ori tmp,(1<<7) |
5 | sbic PINB,2 |
6 | ori tmp,(1<<6) |
7 | . |
8 | . |
9 | sbic PINB,2 |
10 | ori tmp,(1<<0) |
> sobald über INT0 die Taktflanke erkannt wurde > Die Routine muß so schnell sein, um den AVR aus dem Sleep > aufzuwecken, Bit speichern und wieder schlafen legen zu können! Bit? Ich dachte Byte. Das ist so direkt nur bei relativ langsamer Übertragung machbar. Wenn aber der Sender dem eigentlichen Byte einen Startimpuls im Abstand von etwa 10-15 Takten vorausschickt, dann sollte eine Übertragung mit f_CPU/4 machbar sein, vielleicht auch /3.
@Amateur: Takt ist 128KHz über WD-oszi Datenbit ist während der ansteigenden Flanke des Taktsignals gültig Sender schickt Taktsignal, um Empfänger zu wecken, Überträgt 3x8bit und geht in Empfang/Sleep
128 K ist ganz schön ziemlich. Ich hoffe, dass Dein µP, zwischenzeitlich, in der Wachperiode, genügend Zeit hat sich die Daten auch anzusehen. Datenübertragung ist ja kein Selbstzweck. Vor allem das erste Bit (Takt) hat's in sich. Ausgehend von "S. Landolt"'s Sequenz brauchst Du, netto, 128K * 16 Takte zum Empfangen. Da bleibt kaum zum Speichern Zeit, geschweige etwas anderes zu machen.
Mathias schrieb: > @Amateur: Takt ist 128KHz über WD-oszi Ist der Watchdog-Oszi nicht ziemlich ungenau? Wenn man dann, ohne weitere Takt-Synchronisierung, frei laufend 8 Datenbits einlesen will... ?
:
Bearbeitet durch User
Hier mal ein erprobtes Protokoll in C: Beitrag "mehrere MC seriell über Datenbus verbinden (1Draht)"
Wow! ich wusste nicht, daß es schon so viele (und bessere) Ansätze gab.....
Wow! Auch erscheinen mir die in Peters Artikel genannten Zeiten/Geschwindigkeiten viel realistischer.
Zum Protokoll: Prinzipiell steuere ich den Empfänger an, wie ich ein Schieberegister ansteuere, die Idee ist entstanden, als ich eine 7seg ANzeige angesteuert habe, dachte ich mir: so könnte das auch von µC zu µC funktionieren. Mathias
Mathias schrieb: > so könnte das auch von µC zu µC > funktionieren. Ja. Ich würde mich aber zur Sicherheit von der Geschwindigkeit im Verhältnis zum CPU-Takt verabschieden. Muss der tiny unbedingt mit 128kHz getaktet werden? Alternative zum Vorschlag von Stefan Ernst:
1 | .dseg |
2 | |
3 | data: .BYTE 24 ; 3x8 Byte |
4 | |
5 | .cseg |
6 | |
7 | ldi XL, low(data) |
8 | ldi XH, high(data) |
9 | |
10 | in r16, PINB |
11 | st X+, r16 |
12 | |
13 | ; usw. |
Alle drei Bytes können ohne 'Registerwechsel' hintereinander übertragen werden. (Wenn ich wüsste, was ein 'AVR8L based device' ist, könnte das sogar noch schneller sein.) Hinterher gemütlich auswerten. ---- Mathias schrieb: > Prinzipiell steuere ich den Empfänger an, wie ich ein Schieberegister > ansteuere, Von der Einlesegeschwindigkeit würde ich mich allerdings, wie gesagt, trennen. Bitweise Syncronisation in einer Schleife oder im Interrupt bei deutlich höherer F_CPU wäre meine Wahl.
:
Bearbeitet durch User
Hallo, also der 128KHz Takt kommt, da der Tiny u.a. über einen 0.22F Kondensator betrieben wird. Mehr "Power" F_CPU kann ich nicht rausnehmen, sonst bin ich nach 30sek schon am Ende.
Mathias schrieb: > also der 128KHz Takt kommt, da der Tiny u.a. über einen 0.22F > Kondensator betrieben wird. Wie machst Du das? > Mehr "Power" F_CPU kann ich nicht > rausnehmen, sonst bin ich nach 30sek schon am Ende. Von "rausnehmen" war nicht die Rede, Ralf sprach von einem deutlich "höheren" CPU-Takt.
Supercap lädt auf - ab 1,6/1,8V springt der Tiny an. Im Versuch läuft der Tiny mit 600KHz aktuell gerade mal ca. 15 min bei 1,8 V . Da ich ungefähr alle 10-15 min eine kurze "Ladephase" bekomme, muß der Tiny die magere Zeit überbrücken können. Bei 1,2MHz saugt der µC den Cap zu schnell leer
Mathias schrieb: > Im Versuch läuft der Tiny mit 600KHz aktuell gerade mal ca. 15 min bei > 1,8 V . Hmm. Irgendjemand hat da aber jetzt einen Denkfehler drin :-/ 600kHz -> 15min - Hat der in der Zeit richtig zu tun? 9Mhz -> 1min was machen, den Rest schlafen. Okay, wird nicht ganz linear sein... Achso: Jetzt sind wir wieder beim Protokoll für die Datenübertragung: kann das auch deutlich langsamer gehen?
:
Bearbeitet durch User
Mathias schrieb: > Prinzipiell steuere ich den Empfänger an, wie ich ein Schieberegister > ansteuere Also SPI. Wenn du dir einen Gefallen tun willst: ersetz' die popeligen ATtiny13 durch pinkompatible ATtiny25. (Die DIL-Version ist bei Reichelt sogar billiger als der '13, die SOIC gleich viel.) Die haben eine USI, die dich bei der Implementierung eines seriellen Protokolls in Hardware unterstützt. Energieverbrauchsmäßig nehmen sich die beiden auch nichts. Mathias schrieb: > also der 128KHz Takt kommt, da der Tiny u.a. über einen 0.22F > Kondensator betrieben wird. Milchmädchenrechnung. Schnellerer Takt und längere Schlafphasen sind energieverbrauchsmäßig nicht schlechter als ein durchtickernder langsamer Takt. Voraussetzung: Betrieb vom RC-Oszillator, damit er in wenigen Takten aufwacht und nicht erst einen Quarz ankurbeln muss.
Hatte das ganze mit 1,2MHz laufen, jedoch schaffe ich die Abarbeitung der Daten dann nicht (Look-up table etc..), da der Cap dann zu schnell unter die 1,8V (benötigt für 1,2MHz) druntergeht. Ich komme von der Energie gerade so über 1,6 - 1,8V raus, d.h. bei 1,2 Mhz gibt es viele Zyklen, bei denen er garnicht mehr "anspringt", daher kam die Idee mit 128KHz zu arbeiten! Mit 128Khz könnte ich an der 1,6V Grenze länger "arbeiten"
Tiny 25 verwenden ist eine Idee wert, glaube ich langsam.....
Mathias schrieb: > Mit 128Khz könnte ich an der 1,6V Grenze länger "arbeiten" Betrieb völlig jenseits der Grenzwerte, ojeh. Wenn du keinen Brownout-Detektor aktivierst, garantiert dir aber auch keiner, dass da überhaupt noch sinnvolles Zeug aus dem Flash gelesen wird und nicht mal irgendwann beim Auslesen ein gekipptes Bit drin ist, sodass die Firmware kompletten Humbug veranstaltet.
Mathias schrieb: > An PB1 liegt die Taktleitung. Bei jedem Takt wird ein Bit (0/1) > übernommen und weitergeschoben. Link zu Protokoll wird schwierig, da > Eigenbau! Das hört sich ziemlich nach SPI an. Warum nimmst du nicht einfach SPI?
weil tiny13A keinen SPI hat, deshalb ist glaube ich wechsel zu Tiny25 sinnvoll, wenn der Preisunterschied so marginal ist
Mathias schrieb: > weil tiny13A keinen SPI hat, deshalb ist glaube ich wechsel zu > Tiny25 > sinnvoll, wenn der Preisunterschied so marginal ist Entweder du suchst dir einen Controller, der mit <=1,6V spezifiziert ist oder du spendierst deiner Schaltung eine vernünftige Spannungsversorgung. Und sag nicht: "Das geht nicht." Einen Controller ausserhalb der Spezifikation zu betreiben, geht gar nicht. Ob der 25er in deiner jetzigen Schaltung überhaupt läuft, steht ohnehin in den Sternen. Die 25/45/85 gehören nämlich noch zur alten Garde. Bis 1,8V runter gehen nur die V-Typen. Bei denen dürfte das Preisargument gegenüber dem 13A allerdings nicht mehr greifen. mfg.
Thomas E. schrieb: > Bei denen dürfte das Preisargument gegenüber dem 13A allerdings nicht > mehr greifen. Ja, weil es sie nicht als A-Typen gibt. Wenn die Baugröße keine so große Geige spielt: ATtiny24A.
Falls der nicht zu groß ist und vor allem der Wirkungsgrad noch passt: ATtiny43U
Mathias schrieb: > da der Tiny u.a. über einen 0.22F Kondensator betrieben wird. Mathias schrieb: > Im Versuch läuft der Tiny mit 600KHz aktuell gerade mal ca. 15 min bei 1,8V. Mal so gerechnet: Kondensator 0.22F = 220mAs -> 900s Akku 300mAh -> milchmädchenmäßige ~1200h (~50d) Warum nimmst du keinen Akku? Mathias schrieb: > Da ich ungefähr alle 10-15 min eine kurze "Ladephase" bekomme, Wie kurz? -> Vorwiderstand ermitteln für ordentlich 'Saft auf den Akku', so dass der sich noch wohlfühlt.
Akku-> Nicht möglich, da Energy Harvesting Lösung angestrebt ist. 0,22F ist eigentlich zu viel, es sollten eher <0,1 sein, aber ich muß im Prototypenstadium den µC ja auch zum laufen kriegen....paar minuten
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.