Hallo
Die Appnote AVR310 von Atmel beschreibt, wie man das USI Interface als
I2C/TWI nutzt:
http://www.atmel.com/dyn/resources/prod_documents/doc2561.pdfhttp://www.atmel.com/dyn/resources/prod_documents/AVR310.zip
Ich habe das ganze versucht in Assembler zu übersetzen, aber bisher habe
ich noch nicht alle Fehler gefunden. Mit C-Code mit Assembler
vergleichen komme ich nicht weiter. Die Hardware ist richtig aufgebaut,
mit C funktioniert die Ansteuerung tadellos.
Ich habe leider keinen HW-Debugger zur Hand. Ich benutze UART um an die
Daten zu kommen.
Das Problem ist, dass der µC in einer Schleife festhängt (Z. 229):
1
USI_WAIT1:
2
sbis PIN_USI, PIN_USI_SCL
3
rjmp USI_WAIT1
entspricht der Übersetzung von
1
while(!(PIN_USI&(1<<PIN_USI_SCL)));// Wait for SCL to go high.
Das ist der erste Aufruf der USI_TWI_Master_Transmit Funktion in der
Hauptschleife der USI_TWI_Start_Transceiver_With_Data (Z. 162).
Laut AvrSimulator2 ist in dieser Schleife der PIN als Ausgang definiert,
ist das richtig so (bei TWI)? Normalerweise könnte sich dann PINx gar
nicht ändern.
Sieht man aus der Verhaltensweise was falsch ist/sein könnte?
Die Delay Funktion ist die aus dem Wiki (
http://www.mikrocontroller.net/articles/AVR_Assembler_Makros#Delay ).
Hello:
If you pull the I2C specification, you'll see that the SCL line is the
master clock line, which is driven by the master. From what you state,
I believe you are operating your AVR as a TWI master, yes?
What AVR? Does it have a dedicated TWI controller or a USI emulating a
TWI?
Also, be sure that you have 4K7 resistors on the SCL amd SDA lines. You
can use the weak pullups on the AVR I/O pins if only driving one or two
slaves on short lines but safer to use the external 4K7 resistors.
On porting from C to ASM. I could not find any asm code for the newer
AVR's with the TWI controller (bit-banging only). They all are written
in C now. So, I compiled Peter Fluery's TWI driver for my Mega32U4 and
just massaged the resulting ASM code contained in the LSS file. The
code uses the TWI module but it is polled, not interrupt driven.
Hope that helps!
Peace,
Scott
Jörg Wunsch schrieb:> Warum nimmst du dann nicht einfach den C-Code?
Weil ich die Software aus Platztechnischen Gründen in Assembler
schreiben möchte. Da ich das Problem bisher nicht lösen konnte (selbst
die BitBang-Methoden funktionieren nicht), habe ich in C mit einem
haufen Assembler kombiniert. Das erscheint mir jedoch noch schwerer als
reines Asm.
Scott Vitalw schrieb:> Hello:> If you pull the I2C specification, you'll see that the SCL line is the> master clock line, which is driven by the master. From what you state,> I believe you are operating your AVR as a TWI master, yes?
I use an Attiny2313 with USI-Interface as master.
> What AVR? Does it have a dedicated TWI controller or a USI emulating a> TWI?
Attiny2313
> Also, be sure that you have 4K7 resistors on the SCL amd SDA lines. You> can use the weak pullups on the AVR I/O pins if only driving one or two> slaves on short lines but safer to use the external 4K7 resistors.
In the circuit are 10k pullups. It doesn't work without them.
> On porting from C to ASM. I could not find any asm code for the newer> AVR's with the TWI controller (bit-banging only). They all are written> in C now. So, I compiled Peter Fluery's TWI driver for my Mega32U4 and> just massaged the resulting ASM code contained in the LSS file. The> code uses the TWI module but it is polled, not interrupt driven.
Something in my Asm-code had to be wrong, because it never works
(bitbanging, too).
In addition, the I2C-Slave (PCF8577) is very slowly (max. 100kHz). In C
I have to reduce the frequency (100kHz), if the clock of attiny2313 is
less than 500kHz. I don't know why.
sry for my poor english.
Samuel K. schrieb:> Weil ich die Software aus Platztechnischen Gründen in Assembler> schreiben möchte.
Naja, Du darfst nicht jede Variable als int definieren, dann braucht C
auch nur unwesentlich mehr als Assembler.
Wenn unsigned char (= uint8_t) reicht, dann nimm es auch.
Und nimm Unterfunktionen anstatt Spaghetticode.
Bei Atmel, AVRFreaks usw. findet man weitere Tips zum Vermeiden von
C-Sünden.
Typisch braucht C nur etwa 5 .. 20% mehr.
Bei größeren Programmen kann C oft sogar kompakteren Code erzeugen als
viele Assemblerprogrammierer.
Der AVR-GCC kann sogar eine über alles Optimierung vornehmen:
1
-Wl,--relax --combine -fwhole-program
Samuel K. schrieb:> (selbst> die BitBang-Methoden funktionieren nicht)
Die funktionieren sehr gut und brauchen auch nicht mehr Flash, als
HW-I2C.
Ich nehme sie sehr gerne, da sie portabel sind und jeden Pin nutzen
können.
Ein großer Vorteil von SW-I2C ist auch, daß es sich nicht verklemmen
kann bei Störungen auf dem Bus.
HW-I2C braucht immer auch einen Timeout-Handler, der es kurz mal
disabled, den Bus freitaktet und wieder enabled.
HW-I2C braucht man nur für Multimaster/Slave.
Samuel K. schrieb:> habe ich in C mit einem> haufen Assembler kombiniert. Das erscheint mir jedoch noch schwerer als> reines Asm.
Den Fehler habe ich auch ganz zu Anfang mal gemacht.
Es kostet viel Arbeit, der Nutzen ist dagegen lächerlich gering.
Seitdem kommt mir in C keine Assemblerzeile mehr rein.
Peter
Peter Dannegger schrieb:> Ein großer Vorteil von SW-I2C ist auch, daß es sich nicht verklemmen> kann bei Störungen auf dem Bus.
Das bekommst du bei Hardware-I²C aber auch hin. Du darfst nur nicht
stur überall in festen Schleifen warten (vor allem nicht auf das
Interruptflag), ohne die Wartezeit zu begrenzen. Was anderes macht
dein Software-I²C letztlich ja auch nicht in so einer Situation.
Peter Dannegger schrieb:> Naja, Du darfst nicht jede Variable als int definieren, dann braucht C> auch nur unwesentlich mehr als Assembler.
Die kleinste Variablengröße nehme ich immer, int kommt bei mir gar
nicht vor (außer als 4Byte Feld zur Argumentübergabe zu Asm).
> Wenn unsigned char (= uint8_t) reicht, dann nimm es auch.> Und nimm Unterfunktionen anstatt Spaghetticode.
Wobei Spaghetticode in Assembler meist kleiner ist.
> Bei Atmel, AVRFreaks usw. findet man weitere Tips zum Vermeiden von> C-Sünden.
Ich hab in dem C-Programm schon dauernd in die lss-Datei geschaut, viel
zu Optimieren hab ich nicht gesehen.
> Typisch braucht C nur etwa 5 .. 20% mehr.
Das Assemblerprogramm hat inzwischen dieselbe Funktionalität wie das
C-Programm braucht aber nur 1KB während C 1,5KB nutzt. Die Hauptroutinen
sind jedoch wirklich zum Spaghetticode geworden und dadurch auch sehr
kurz im Vergleich zum C-Code wo avrgcc dauernd seine Register
verschiebt.
Deutlich kürzer sind auch die ISRs. Während avrgcc haufenweise Register
sichert einschließlich r0 und r1, komme ich in Asm in der Timerisr mit 5
Registern aus. In 2 anderen Interrupts wird SREG nicht einmal gesichert,
da kein Befehl es verändert.
Durch ein globalen Pointer (Y) der auf SRAM_START zeigt, kann man sich
so ziemlich alle lds und sts Befehle sparen (diese nutzt avrgcc auch
sehr gerne).
Allgemein sind gerade komplexe Funktionen in Asm viel kleiner -
vielleicht programmiere ich auch unverständlich für den Optimierer. In
Assembler weiß man halt am Ende was man hat, wo viel Code verbraucht
wird, wie viel Ram man braucht, was langsam ist... man hat den Überblick
über sein Programm.
Samuel K. schrieb:> In 2 anderen Interrupts wird SREG nicht einmal gesichert,> da kein Befehl es verändert.
Ja, sowas hat dem C-Compiler niemand beigebracht, ist aber auch
ein ziemlicher Sonderfall, für den man bequem mit einer Assembler-
ISR arbeiten kann (denn die ISR ist dann zwangsläufig sowieso
sehr übersichtlich ;-).
> Durch ein globalen Pointer (Y) der auf SRAM_START zeigt, kann man sich> so ziemlich alle lds und sts Befehle sparen (diese nutzt avrgcc auch> sehr gerne).
Sowas erreicht man in C, indem man eine globale struct für die
Daten benutzt.
Mich würde die bit bang Lösung von Peter interessieren. Wenn die nicht
unter Verschlusssache fällt würde ich mich über die Präsentation
derselben freuen.
Eine ziemlich robust funktionierende Lösung hat etwas. Die freie Pinwahl
ist ein gewichtiges Argument finde ich.
Bei der Verwendung der avr Hardware polle ich z.B. sowiso nur, bis die
entsprechenden irq kommen - da hat man dann ja auch nichts gewonnen.
Und - die könnte der Autor auch auf asm übersetzen um Platz zu sparen.
Hier noch ein kleines Beispiel, das in Asm ziemlich klein ist, in C
aufgebläht wird. Die Funktion zeigt 2 Zeiten auf je ein Lcd an. Dabei
werden die Zeiten (in sec) erst in Stunden:Minuten bzw. Minuten:Sekunden
umgerechnet, zu BCD konvertiert und in den Displaybuffer geladen, der am
Ende mit dem Lcd-Treiber aktualisiert wird. Alles in nur ~40 Befehlen:
1
//Daten aus dem Ram laden und mit Displaybuffer aktualisieren
2
ldi temp, 60 //Divisor laden
3
mov r0, temp
4
ldi r17, 2 //=lcd: lcd1=2, lcd2=3
5
SetTime:
6
ld r24, X+ //Zeit in Sekunden laden
7
ld r25, X+
8
movw r22:r23, r0:r1 //Divisor laden
9
rcall div16u //Division ausführen
10
cpi r24, 20 //Wenn die Zeit größer als 19 Minuten ist
11
cpc r25, zero //muss nochmals durch 60 geteilt werden
Samuel K. schrieb:> Hier noch ein kleines Beispiel, das in Asm ziemlich klein ist, in C> aufgebläht wird.
Du kannst ja vieles behaupten. Dein Assemblerspaghetti ist nicht
so auf die Schnelle zu verstehen, dass man die äquivalenten Zeilen
in C hinschreiben könnte, um das überhaupt zu vergleichen.
Außerdem ist es natürlich immer einfach, sich erstmal einen händisch
gefeilten Kontext zu schaffen (diverse globale Variablen, Funktionen
mit beliebiger Aufrufsequenz) und dann festzustellen, dass ein
C-Compiler, der ja viel formaler und allgemeiner an die Lösung
rangeht, da gar nicht mithalten könne.
Wirklich vergleichen kann man folglich nur das Gesamtprojekt.
Samuel K. schrieb:> Hier noch ein kleines Beispiel, das in Asm ziemlich klein ist
Das alleine macht garnichts.
Da sind 7 Calls drin und deren Code mußt Du noch dazu zählen.
Es ist aber trotzdem ein schönes Beispiel, wie schwer Assembler zu
durchschauen und zu erweitern ist.
Schon allein die nichts sagenden Registernamen r0..r31 sind
undurchdringlich.
Ich hatte in Assembler den Registern wenigstens Namen gegeben, damit man
erkennt, was sind welche Variablen, was sind Parameter, was sind
Returnwerte, was sind Scratchpad usw.
Peter
Peter Dannegger schrieb:> Das alleine macht garnichts.> Da sind 7 Calls drin und deren Code mußt Du noch dazu zählen.
Die Calls sind in C genauso vorhanden. Die Divisionsroutinen sind in C
auch Asm-routinen.
Peter Dannegger schrieb:> Es ist aber trotzdem ein schönes Beispiel, wie schwer Assembler zu> durchschauen und zu erweitern ist.> Schon allein die nichts sagenden Registernamen r0..r31 sind> undurchdringlich.
Die Register zu numerieren hat den Vortei, dass man keine übereinander
legen kann. Bei Namen passiert das unweigerlich. Tatsächlich verwende
ich es in gemischter Form. Im Hauptprogramm verwende ich r0-r31
großteils, in Funktionen benenne ich sie.
> Ich hatte in Assembler den Registern wenigstens Namen gegeben, damit man> erkennt, was sind welche Variablen, was sind Parameter, was sind> Returnwerte, was sind Scratchpad usw.
Das hätte ich vielleicht dazusagen sollen. r24 stellt den ersten
Übergabeparameter dar, danach r25, r22 und r23. Ausnahme bildet die
Funktion SetChars, weil man dadurch ein paar Instruktionen spart. Die
Funktionen dürfen r25-r18 und Z zerstören. Davon gehe ich aber nicht
stur (wie avrgcc) aus. Wenn ein Register bei Funktion x nicht zerstört
wird sichere ich es auch nicht.
Ich denke am schwierigsten zu verstehen ist der nicht kommentierte Teil.
Um diesen zu verstehen müsste ich schon viel weiter ausholen. Allgemein
lässt er den Trennpunkt bzw. Doppelpunkt zw. den Minuten:Stunden /
Minuten:Sekunden blinken, und zwar nur bei einem bestimmten lcd.
Jörg Wunsch schrieb:> Wirklich vergleichen kann man folglich nur das Gesamtprojekt.
Ich habe derzeit in Asm mehr Funktionalitäten als im C-Projekt und
trotzdem 30% Codeersparnis. Bin ich deswegen ein miserabler
C-Programmierer?
Samuel K. schrieb:> Ich denke am schwierigsten zu verstehen ist der nicht kommentierte Teil.
Nein, wenn man als Außenstehender draufguckt, versteht man da rein
gar nichts. Die Mikro-Kommentare helfen da nicht viel, denn die
beschreiben nur das, was man in C bereits im Quellcode lesen
könnte. Was komplett fehlt ist das, was man im C-Code kommentieren
würde, also eine Überblicksbeschreibung.
> Ich habe derzeit in Asm mehr Funktionalitäten als im C-Projekt und> trotzdem 30% Codeersparnis. Bin ich deswegen ein miserabler> C-Programmierer?
Möglich, vielleicht hast du dich auch nur irgendwo ungeschickt
ausgedrückt, vielleicht sind auch die Optimierungsmöglichkeiten des
Compilers gar nicht ausgenutzt worden, kann man so nicht sagen. Was
man aber sagen kann ist, dass du einfach zu viel Zeit hast, wenn du
dir sowas noch leisten kannst. ;-)