ich habe gerade das Problem, dass die UART-Ausgabe eines kleinen Programms an einer Stelle hängt, wo ich mir einfach keine Ursache dafür vorstellen kann. Es handelt sich um folgende Funktion, die innerhalb einer ISR aufgerufen wird:
1
; Send 8-bit unsigned number as two hex digits.
2
; Parameter: wri0.
3
sendDbgHex:
4
push wri0
5
swap wri0
6
andi wri0, 0x0F
7
rcall sendDbgHexDigit
8
pop wri0
9
push wri0
10
andi wri0, 0x0F
11
rcall sendDbgHexDigit
12
pop wri0
13
ret
14
sendDbgHexDigit:
15
cpi wri0, 10
16
brlo sendDbgHexDigit0
17
subi wri0, -('A'-'9'-1)
18
sendDbgHexDigit0:
19
subi wri0, -'0'
20
rcall sendDbgByte
21
ret
Den vollständigen Code habe ich angehängt. Das Programm soll die ISP-Schnittstelle eines ATtiny12 simulieren (zu Testzwecken meines avrispv2-Programms). Nachdem diese Routine an anderen Stellen innerhalb der ISR problemlos ausgeführt wird, bleibt sie nach dem Aufruf in Zeile 298 von 'main.asm' nach der Ausgabe der ersten Null hängen: PuTTY zeigt "Write Program Memory, byte address 0", eigentlich müssten eine zweite Null und weitere UART-Ausgaben folgen.
Ich sitze nun schon eine ganze Weile und gehe den Code durch, aber konnte bisher nichts Verdächtiges finden. Sowas wie Stackoverflow sollte ausgeschlossen sein, da die 8KB RAM für die paar wenigen rcall-Ebenen ja dicke reichen sollten. Und Interrupts können auch nicht stören, da der Aufruf ja bereits in einer ISR erfolgt und somit das I-Flag gelöscht ist.
in einer ISR erfolgt und somit das I-Flag gelöscht ist
Das kann man so bei den AVRxt nicht sagen ...
Ah, hat sich da wohl was geändert? Dann muss ich mich damit erstmal
beschäftigen, danke für den Tipp.
Bei dieser neuen Serie(n) kann man pauschal sagen, dass die Interruptflags nicht mehr automatisch gelöscht werden. Man muss sie manuell löschen. Paar wenige Ausnahmen davon stehen im Manual. Man macht jedoch nichts falsch, wenn man pauschal die Flags selbst löscht.
Da ich kein Assembler kann, folgende Frage. Da ist nicht zufällig ein Interruptaufruf innerhalb einer ISR drin? Das darf nicht sein.
Da ich kein Assembler kann, folgende Frage. Da ist nicht zufällig ein
Interruptaufruf innerhalb einer ISR drin? Das darf nicht sein.
Was meinst du mit Interruptaufruf, einen Aufruf einer anderen ISR? Es werden nur 'normale' Routinen innerhalb der ISR aufgerufen, keine Interrupt-Routinen.
Was meinst du mit Interruptaufruf, einen Aufruf einer anderen ISR? Es
werden nur 'normale' Routinen innerhalb der ISR aufgerufen, keine
Interrupt-Routinen.
Das ist Unsinn. Innerhalb einer ISR den ISR sperren und freigeben.
Hmm, wieso? Ist nicht genau das hardwaremäßig bei den älteren AVRs passiert? Also Löschen des I-Bits beim Aufruf einer ISR und erneutes Setzen durch 'reti'. Damit eben eine ISR nicht durch (andere) Interrupts unterbrochen wird.
beim AVR wird in die ISR gesprungen, alles komplett ohne weitere Unterbrechung abgearbeitet, zurück ins Hauptprogramm, und ggf. in die nächste ISR gesprungen wenn notwendig usw. Eine Unterbrechung einer ISR durch eine andere ISR gibt es beim AVR nicht. Deswegen ist das sperren innerhalb einer ISR ohne Effekt bzw. negativen Effekt. Andererseits kann innerhalb einer ISR nichts aufgerufen werden was selbst eine ISR benötigt.
beim AVR wird in die ISR gesprungen, alles komplett ohne weitere
Unterbrechung abgearbeitet, zurück ins Hauptprogramm, und ggf. in die
nächste ISR gesprungen wenn notwendig usw.
Im Instruction Set Manual steht (Note 1, p. 113):
"In the AVRe series of devices, the Global Interrupt Enable bit is cleared by hardware once an interrupt occurs, and this bit is set when RETI is executed.
In the AVRxm and AVRxt devices, RETI will not modify the Global Interrupt Enable bit in SREG since it is not cleared by hardware while entering ISR. This bit should be modified using SEI and CLI instructions when needed."
Der letzte Satz klingt für mich danach, dass man eben die ISRs mit SEI und CLI einklammern soll, falls ISRs nicht selbst unterbrochen werden sollen.
Dann bin ich wohl, wie es aussieht, nicht der einzige, dem dieses neue "Feature" der Interruptauslösung nicht bewusst war – sondern befinde mich in bester Gesellschaft. ;·)
Dennoch scheint dies nicht die Ursache des Problems zu sein, wie ich bereits schrieb, denn das Klammern mit CLI/SEI brachte keine Abhilfe. Ich bin weiterhin auf der Suche und auf Hinweise auf mögliche Fehlerquellen gespannt.
Da sind wir zu zweit - oder besser: "waren", denn ich gebe jetzt auf, mir fällt nichts mehr ein. Zumal das Programm ohne entsprechende Umgebung schlecht zu testen ist.
Zumal das Programm ohne entsprechende
Umgebung schlecht zu testen ist.
Ja, das stimmt leider. Vielleicht sollte das hier für mich der Anlass sein, mich in die Debugging-Möglichkeiten von UPDI und MPLAB-X-IDE hineinzufuchsen.
in einer ISR erfolgt und somit das I-Flag gelöscht ist
Das kann man so bei den AVRxt nicht sagen ...
Ah, hat sich da wohl was geändert? Dann muss ich mich damit erstmal
beschäftigen, danke für den Tipp.
Bei dieser neuen Serie(n) kann man pauschal sagen, dass die
Interruptflags nicht mehr automatisch gelöscht werden.
So wie ich das lese geht's um das I-Flag im SREG, und das wird doch nach
wie vor bei IRQ-Auslösung auf 0 gesetzt? (Und bei RETI wieder auf 1
gesetzt?)
Oder hab ich da was verschlafen?
Hallo,
ähm nein, passt schon. Das I-Flag im SREG muss man selbst nicht behandeln. Deswegen ist das mit sei/cli innerhalb einer ISR sinnlos.
Manuell muss man nur das Interruptflag der auslösenden ISR löschen. Ganz pauschal bis auf sehr wenige Ausnahmen.
In the AVRxm and AVRxt devices, RETI will not modify the Global
Interrupt Enable bit in SREG since it is not cleared by hardware while
entering ISR. This bit should be modified using SEI and CLI instructions
when needed."
Der letzte Satz klingt für mich danach, dass man eben die ISRs mit SEI
und CLI einklammern soll, falls ISRs nicht selbst unterbrochen werden
sollen.
Das würde dann doch i.W. ein neues Function Attribute erfordern, damit CLI die /erste/ Instruktion in einer ISR ist und SEI die /letzte/?
Ansonsten, also wenn man das händisch macht, wird CLI erst nach dem ISR-Prolog ausgeführt, und SEI bereits for dem ISR-Epilog.
ähm nein, passt schon. Das I-Flag im SREG muss man selbst nicht
behandeln. Deswegen ist das mit sei/cli innerhalb einer ISR sinnlos.
Manuell muss man nur das Interruptflag der auslösenden ISR löschen. Ganz
pauschal bis auf sehr wenige Ausnahmen.
Sorry, aber du bist nicht mehr auf dem aktuellen Stand.
Siehe Datenblatt des AVR64DD32, S. 134; dort wird es in Satz 2 sehr deutlich:
"15.3.2.4 Interrupt Priority AVR64DD32/28
CPUINT - CPU Interrupt Controller
All interrupt vectors are assigned to one of three possible priority levels, as shown in the table below. An interrupt request from a high-priority source will interrupt any ongoing interrupt handler from a normal-priority source. When returning from the high-priority interrupt handler, the execution of the normal-priority interrupt handler will resume."
Ich denke, diese Nested Interrupts sind auch gar nicht sooo das Problem – vorausgesetzt, man ist sich darüber im Klaren und rettet z.B. alle Register (was ich ursprünglich nicht gemacht hatte, da ich eben dachte, es wäre in meinem Fall nicht notwendig). Daher habe ich auch die CLI/SEI wieder rausgenommen, nachdem ich die PUSHs/POPs ergänzt habe. Es muss an irgendwas anderem liegen.
mit dem neuen Interrupt Controller haste recht, ist mir entgangen, weil ich die Features noch nie verwendet habe. Habe nochmal nachgelesen. Nun die Frage, hast du das Priority Feature eingeschalten? Ansonsten würde er sich wie gewohnt normal verhalten. Ohne konkreten Grund würde ich das nicht aktivieren.
Pardon, ich wollte keine unnötige Diskussion lostreten, wollte nur den Satz, ganz am Anfang,
in einer ISR erfolgt und somit das I-Flag gelöscht ist
nicht unkommentiert stehen lassen.
So wie es mir schwerfällt, das TCA-Fragment im Programm nicht anzusprechen - führt alles beim eigentlichen Problem nicht weiter.
Nun
die Frage, hast du das Priority Feature eingeschalten? Ansonsten würde
er sich wie gewohnt normal verhalten.
Nein, am Interrupt Controller habe ich nichts verändert, es gelten alle Default-Werte. Somit dürften also hier eigentlich auch keine Interrupts unterbrochen werden, da alle die normale Priorität haben und nur High-Priority-Interrupts andere unterbrechen können, wenn ich das Datenblatt richtig verstanden habe.
Das soll später dazu dienen, eine verzögerte Speicherung der zu schreibenden Bytes zu realisieren, damit ich das Verhalten des Data Polling untersuchen kann. Das bisherige Grundgerüst dürfte ja erstmal nicht stören, wenn ich nichts übersehen habe, da der Timer ja noch nirgends aktiviert wird.
P.S.: Anbei noch der geänderte Code, und ich habe noch den aktuellen Stand meines 'avrispv2' hinzugefügt – der ist aber noch sehr experimentell, bisher nur schwach getestet und kann noch grobe Fehler enthalten.
Nun
die Frage, hast du das Priority Feature eingeschalten? Ansonsten würde
er sich wie gewohnt normal verhalten.
Nein, am Interrupt Controller habe ich nichts verändert, es gelten alle
Default-Werte. Somit dürften also hier eigentlich auch keine Interrupts
unterbrochen werden, da alle die normale Priorität haben und nur
High-Priority-Interrupts andere unterbrechen können, wenn ich das
Datenblatt richtig verstanden habe.
Hallo,
nein. Hier benötigt man Nerven.
Default ist, dass es keine gegenseitigen ISR Unterbrechungen gibt. Wenn zeitgleich mehrere Interrupts anstehen, wird zuerst der ausgeführt mit der höheren Priorität. Sie werden also nach Prio abgearbeitet. Dann gilt
"The lowest interrupt vector address has the highest priority." Siehe ioavr64dd32.h ab Zeile 6105.
Das heißt auch, dass nach Beendigung irgendeiner ISR die nächste ISR mit der aktuell höchsten Prio als Nächstes abgearbeitet wird. Es gibt keine wilden Sprünge innerhalb einer ISR zur nächsten ISR und zurück. Das ist Default.
Nur Frage am Rande: was ist der Grund dafür, das Blank einmal als
solches und direkt im Anschluss als '20' auszugeben?
Das war natürlich ein Fehler, danke für den Hinweis – habe es korrigiert, ebenso wie noch mehrere Fehler im Programm 'avrispv2', die sich im Zuge einer Umstrukturierung eingeschlichen hatten. Letzteres funktioniert nun wieder, getestet an einem ATmega88A (Lesen/Schreiben von Flash und EEPROM); habe es wieder mit in das ZIP-Archiv gepackt.
Ich habe nun einen AVR32DD28 mit Ihrem Programm an mein Selbstbau-Programmiergerät angeschlossen, habe im Programm die Signatur auf ATmega48PA geändert, und kann so 'schreiben', ohne Hänger; das anschließende Verify geht schief, ist ja aber erstmal nachrangig:
Ich habe nun einen AVR32DD28 mit Ihrem Programm an mein
Selbstbau-Programmiergerät angeschlossen, habe im Programm die Signatur
auf ATmega48PA geändert, und kann so 'schreiben', ohne Hänger;
Hmm, ist ja seltsam. Vielleicht stimmt auch mit meinem 64DD32 irgendetwas nicht, evtl. zu heiß geworden beim Verlöten ... Einen Moment, ich probiere es mal mit einem anderen.
15:23 Uhr: Habe das Programm jetzt auf einem anderen Exemplar laufen, und bin zunächst nun auch über das scheiternde Programming Enable gestolpert – ich hatte vergessen, das Echo des 0x53 beim dritten SPI-Byte einzubauen. Seltsamerweise hat sich das auf dem ersten 64DD32 noch nicht ausgewirkt, dort lief es ja bis zum Write Program Memory. Sehr seltsam ...
Also das Schreiben funktioniert ja ansatzweise, aber der Lesevorgang muss grundlegend überdacht werden: der Master taktet (gnadenlos) nach dem dritten Byte weiter, da muss schnellstmöglich das zu liefernde Byte im SPI bereitgestellt werden; hier aber wird erstmal, wenn ich's richtig vestehe,
1
...
2
rcall sendDbgMsg
3
...
4
rcall sendDbgHex
5
...
6
rcall sendDbgHex
7
...
8
; Load the addressed byte and move it into SPI transmit register:
Ja, das ist tatsächlich problematisch, ich hatte deshalb schon im Master, also dem avrispv2-Programm, ein Delay zwischen den SPI-Bytes von einigen Millisekunden eingefügt (gesteuert über die Konstante SPI_INTERBYTE_DELAY_MS).
So, ich habe das Programm nun auf den ATmega328P übertragen und dort zum Laufen gebracht. Zuvor habe ich noch einige Fehler gefunden, z.B. hatte ich vor dem Schreiben bzw. Lesen vom/in den SRAM vergessen, den Beginn des Arrays 'simFlash_sram' zum Z-Pointer zu addieren. Auf dem m328P funktioniert es nun; jetzt gilt es noch, das auch auf dem AVR-DD zu erreichen, dort hapert es noch an irgendetwas (momentan klappt das Programming Enable nicht, das 0x53 wird nicht zurückgegeben).
Wieso? 'sendDbgByte' ist eine andere Routine, die ein Byte an USART0
ausgibt und auch von anderen Routinen aufgerufen wird.
Aha! Etwa auch aus main()? Vermutlich ja schon. Wenn das so ist, dann ist der Fehler hier:
1
> sendDbgByte0:
2
> --------------------------------
3
> xin wri0, USART0_STATUS
4
> --------------------------------
5
> sbrs wri0, USART_DREIF_bp
6
> rjmp sendDbgByte0
7
> pop wri0
8
> xout USART0_TXDATAL, wri0
9
>
Dieser Teil des Codes ist eine "critical section", er darf nicht durch durch den Interrupt unterbrochen werden. Den tatsächlich kritischen Punkt habe ich mal durch Linien markiert. Wenn ausgerechnet während dieses Taktes bei der Ausführung in main() der Interrupt erfolgt, hast du eine klassische race condition.
Das ganze muss also "atomic" gemacht werden.
Das kostet ein zusätzliches Register, ich nenne es mal "scratch0". So lange du nichts am Standardverhalten von AVR8-Interrupts änderst (also in keiner ISR ein "sei" auftaucht und du auch die Features des neuzeitlichen Interruptcontrollers nicht nutzt), dann kannst du dieses Register global reservieren und in allen ISRs vollkommen frei nutzen, ohne es jeweils sichern und wiederherstellen zu müssen. Du darfst aber natürlich nicht davon ausgehen, dass es beim Eintritt in eine ISR bereits einen definierten Inhalt hat. Das ist allerdings für die Verwendung als "atomic"-Merker auch nicht nötig.
Der korrigierte Code würde also erst mal so aussehen:
1
> sendDbgByte0:
2
> in scratch0, CPU_SREG ;bzw. "SREG" für die klassischen AVR8
3
> cli
4
> sendDbgByte1:
5
> xin wri0, USART0_STATUS
6
> sbrs wri0, USART_DREIF_bp
7
> rjmp sendDbgByte1
8
> pop wri0
9
> xout USART0_TXDATAL, wri0
10
> out CPU_SREG, scratch0 ;bzw. "SREG" für die klassischen AVR8
11
>
Schwachsinnig bleibt der Code allerdings auch in dieser Form. Aber das ist dann schon ein anderes Thema, was da heißt: "howto implement buffered IO"...
Habe mir das Zip.file angesehen. Also mindestens 50% würde ich rauswerfen.
Die ganzen ifs und endifs zum Beispiel.
Dieses Programm ist offensichtlich "allgemein" geschrieben.
Besser wäre es, dies ganz gezielt auf das tatsächlich verwendete Target zu spezifizieren. Das ist ja - ganz nebenbei bemerkt - das Manko bei ASM. Die Portierbarkeit wird erschwert, wenn nicht gar unmöglich.
Sonst wird das eigentliche Programm durch die Varietäteneventualitäten unnötig aufgeblasen.
Ich stolpere bereits über die ersten Zeilen:
; Devices to be supported (in future):
.equ T3227 = 0
.equ A64DD32 = 1 ; not supported yet
.equ M88A = 2 ; not supported yet
und vor allem:
.nolist
.if MCU == T3227
.include "C:\Program Files\Microchip\MPLABX\v6.20\packs\Microchip\ATtiny_DFP\3.1.260\avrasm\inc\tn3227def.inc"
.else
.error "Device not supported yet."
.endif
.include "stk500v2-isp.inc"
.include "..\macros.inc"
.list
Was soll der Quatsch.
Unnötig aufgeblasen. Dient eher dazu, hinterher den Wald vor lauter Bäumen nicht mehr zu sehen
so sehen "meine" Programme aus: Etwas aufgeräumter möchte ich meinen
.nolist
.include "8535def.inc"
.list
Nachdem nun Experten mit an Bord sind, darf ich mich getrost verabschieden. Zumal ich vor der neuesten Version (von gestern abend) etwas ratlos sitze:
... das 0x53 wird nicht zurückgegeben ...
Nun sehe ich aber den ganzen Block §spiTcIsr6...9, in welchem $53 an SPI übergeben wird, auskommentiert; aber angeblich läuft es auf dem ATmega328 - wie gesagt, ich verstehe es leider nicht mehr.
Aaarghh. wollte noch was ergänzen:
Schau mal hier:
Kannst Du auf SPI umschreiben.
Ist natürlich zum besseren pädagogischen Verständnis auch "aufgeblasen".
Nope. Es gibt keine 'main()', bzw. diese besteht nur aus einer leeren Schleife:
1
loop:
2
rjmp loop
'sendDbgByte' wird nur von Subroutinen aufgerufen, die ihrerseits in einer der beiden ISRs aufgerufen werden. Es kann also keine Race Condition geben, da Interrupts ja somit immer blockiert sind, wenn diese Routine ausgeführt wird (unter den genannten Voraussetzungen hinsichtlich SEI und Interrupt Controller, die hier erfüllt sind).
Schwachsinnig bleibt der Code allerdings auch in dieser Form. Aber das
ist dann schon ein anderes Thema, was da heißt: "howto implement
buffered IO"...
Mag sein, dass du es schwachsinnig findest; für mich sollte dieses Programm nur eine "schnelle" Möglichkeit des Testens von bestimmtem Verhalten meines avrispv2-Programms im Zusammenspiel mit avrdude sein. Dass man IO puffern kann bzw. i.d.R. sollte, weiß ich auch; das war mir aber für dieses Programm unangemessen aufwendig und unnötig.
Also mindestens 50% würde ich
rauswerfen.
Die ganzen ifs und endifs zum Beispiel.
Dieses Programm ist offensichtlich "allgemein" geschrieben.
Besser wäre es, dies ganz gezielt auf das tatsächlich verwendete Target
zu spezifizieren.
Nö, das wäre meines Erachtens nach überhaupt nicht besser, weil ich dann mehrere Dateien (für jedes Device) parallel pflegen und jede Änderung am Ablauf überall vornehmen und synchron halten müsste. Das wäre viel aufwendiger als die Assembler-Direktiven.
Das ist ja - ganz nebenbei bemerkt - das Manko bei
ASM. Die Portierbarkeit wird erschwert, wenn nicht gar unmöglich.
Das ist Unsinn. Die meisten Unterschiede bestehen in den Peripherie-Einheiten der verschiedenen AVR-Serien, und diese muss man in C genauso unterschiedlich behandeln (z.B. Einrichten von UART, SPI, oder ob ein ISR-Flag manuell gelöscht werden muss oder nicht).
Was soll der Quatsch.
Unnötig aufgeblasen. Dient eher dazu, hinterher den Wald vor lauter
Bäumen nicht mehr zu sehen
Sorry, dass du es Quatsch findest. Mir dient es als Hilfe, für welche MCUs ich vorhatte, das Programm zu ergänzen, und ich selbst finde es auch nicht unübersichtlich.
Zumal ich vor der neuesten Version (von gestern abend)
etwas ratlos sitze:
... das 0x53 wird nicht zurückgegeben ...
Nun sehe ich aber den ganzen Block §spiTcIsr6...9, in welchem $53 an SPI
übergeben wird, auskommentiert; aber angeblich läuft es auf dem
ATmega328 - wie gesagt, ich verstehe es leider nicht mehr.
Mir war bewusst geworden, dass das Echo von 0x53 im dritten Byte automatisch passiert, da dieses einfach im SPI-DATA-Register verbleibt und somit wieder rausgeshiftet wird. Der auskommentierte Block ist somit überflüssig. Das Problem, welches mal beim Programming Enable vorhanden war, musste wohl ein anderes sein.
'sendDbgByte' wird nur von Subroutinen aufgerufen, die ihrerseits in
einer der beiden ISRs aufgerufen werden.
Dir ist schon bewußt, dass jede dieser beiden ISRs bei der gegebenen Implementierung das Potential besitzt, die jeweils andere quasi "endlos" zu blockieren?
Warum benutzt du nicht die Konstante SRAM_START aus 'tn4313def.inc'? Viel besser lesbar und weniger fehleranfällig und besser portierbar.
Und warum benutzt du nicht .byte-Direktiven und lässt die Adressen damit vom Assembler zuweisen? So wie es oben steht, hättest du das .dseg und .org auch weglassen können.
Und das findest du übersichtlicher als meine paar .if- und .else-Zweige?
1
ldi temp, low(ramend) ; Stackpointer setzen
2
out spl, temp
3
ldi temp, high(ramend)
4
out sph, temp
Bei den alten AVRs sollten 16-bit-Registerpaare immer mit H zuerst beschrieben werden (wobei es in diesem Fall egal ist, aber besser, man macht es immer so).
Dir ist schon bewußt, dass jede dieser beiden ISRs bei der gegebenen
Implementierung das Potential besitzt, die jeweils andere quasi "endlos"
zu blockieren?
Aber wie soll das denn passieren? Während die eine ISR ausgeführt wird, sind Interrupts gesperrt – die andere kann also gar nicht dazwischenfunken.
Mir dient es als Hilfe, für welche
MCUs ich vorhatte, das Programm zu ergänzen, und ich selbst finde es
auch nicht unübersichtlich.
Es ist jedem selbst überlassen. Aber eine allgemein übliche Maxime sollte doch lauten:
Möglichst sparsam mit Programmspeicherplatz umgehen.
Der Geiz mit Speicherplatz zeigt sich hinterher bestimmt nicht nur sondern gelegentlich auch in der Performance.
(Für Pädagogikzwecke kann davon abgewichen werden.)
; ATtiny4313 memory use summary [bytes]:
; Segment Begin End Code Data Used Size Use%
;[.cseg] 0x000000 0x00080e 2026 36 2062 4096 50.3%
;[.dseg] 0x000060 0x00007b 0 27 27 256 10.5%
;[.eseg] 0x000000 0x000000 0 0 0 256 0.0%
;Assembly complete, 0 errors. 0 warnings
oder großzügiger mit der Targetauswahl umgehen.
; ATmega32U2 memory use summary [bytes]:
; Segment Begin End Code Data Used Size Use%
; [.cseg] 0x000000 0x0005f2 1430 36 1466 32768 4.5%
; [.dseg] 0x000100 0x000112 0 18 18 1024 1.8%
; [.eseg] 0x000000 0x000000 0 0 0 1024 0.0%
; Assembly complete, 0 errors. 8 warnings
Letzteres Programm ist nicht identisch mit dem für den Attiny.
Hier muss zwingend eine Anpassung nicht nur der Ansprache der Peripherie vorgenommen werden.
Kannst Du ja selber probieren.
Insofern relativiert sich Deine Aussage oben etwas.
Das ist Unsinn. Die meisten Unterschiede bestehen in den
Peripherie-Einheiten der verschiedenen AVR-Serien, und diese muss man in
C genauso unterschiedlich behandeln
Sollte da nicht besser ein Sleep rein um Energie zu sparen?
Mit Energiesparmodi habe ich mich noch nicht befasst, da ich bisher keinen Bedarf daran hatte. Hier sollte das auch keine Rolle spielen, da es eh nur ein Testprogramm ist und ob der Controller nun ein paar Stunden lang 12 mA zieht oder nicht ...
Möglichst sparsam mit Programmspeicherplatz umgehen.
Der Geiz mit Speicherplatz zeigt sich hinterher bestimmt nicht nur
sondern gelegentlich auch in der Performance.
.if und .else und Co. sind Assembler-Anweisungen. Die entscheiden, ob der Assembler das, was dazwischen steht, assembliert oder nicht. Auf den Speicherplatz im Mikrocontroller hat das also überhaupt keine Auswirkung, weil alles, was für die Ziel-MCU nicht relevant ist, ignoriert wird.
Letzteres Programm ist nicht identisch mit dem für den Attiny.
Hier muss zwingend eine Anpassung nicht nur der Ansprache der Peripherie
vorgenommen werden.
Kannst Du ja selber probieren.
Insofern relativiert sich Deine Aussage oben etwas.
Keine Ahnung, was genau du damit meinst. Ich schrieb: "die meisten Unterschiede".
Mit Energiesparmodi habe ich mich noch nicht befasst, da ich bisher
keinen Bedarf daran hatte. Hier sollte das auch keine Rolle spielen, da
es eh nur ein Testprogramm ist
Hmm, warum schreibt man das dann in Assembler? Wenn Performance und Energieverbrauch egal sind, kann man auch C++ nehmen. Wenn man schon Assembler nutzt sollte man auch jeden letzten Takt rausquetschen, sonst ist der Aufwand umsonst...
Zumindest Performance ist mir nicht egal, da versuche ich schon immer zu optimieren, soweit ich kann.
Ich freue mich auch immer über /konstruktive/ Kritik. Voraussetzung ist natürlich, dass der Kritiker auch wirklich Ahnung von Assembler hat und nicht bloß an Dingen herummeckert, von denen er selbst nichts versteht ...
Dir ist schon bewußt, dass jede dieser beiden ISRs bei der gegebenen
Implementierung das Potential besitzt, die jeweils andere quasi "endlos"
zu blockieren?
Aber wie soll das denn passieren? Während die eine ISR ausgeführt wird,
sind Interrupts gesperrt – die andere kann also gar nicht
dazwischenfunken.
Eben!
Die aufgerufene Routine enthält eine Warteschleife. Solange die eine ISR in dieser Schleife hängt, kann die andere garantiert niemals zum Zuge kommen. Auch (und insbesondere dann) nicht, wenn sie eigentlich zeitnah ein Ereignis behandeln müsste, was mit der Debugausgabe rein garnichts zu schaffen hat.
Die aufgerufene Routine enthält eine Warteschleife. Solange die eine ISR
in dieser Schleife hängt, kann die andere garantiert niemals zum Zuge
kommen. Auch (und insbesondere dann) nicht, wenn sie eigentlich zeitnah
ein Ereignis behandeln müsste, was mit der Debugausgabe rein garnichts
zu schaffen hat.
OK, ich werde das Programm nochmal mit deaktivierter Debugausgabe assemblieren und schauen, ob das Problem dann immer noch besteht. Damit müsste sich ja ggf. sagen lassen, ob es damit zusammenhängt.
Voraussetzung ist
natürlich, dass der Kritiker auch wirklich Ahnung von Assembler hat und
nicht bloß an Dingen herummeckert, von denen er selbst nichts versteht
...
Damit war natürlich /nicht/ der darüber zitierte Niklas G. gemeint – nur um das klarzustellen.
Nachtrag: Habe gerade festgestellt, dass ich zuletzt bereits mit DEBUG=0 auf dem AVR64DD32 getestet hatte, und da hat das Programm nicht auf das Programming Enable reagiert (avrdude meldete dabei einen Fehler, mein 'avrispv2' hat wohl STATUS_CMD_FAILED zurückgeliefert, was bedeutet, dass kein 0x53 zurückkam).
.if und .else und Co. sind Assembler-Anweisungen. Die entscheiden, ob
der Assembler das, was dazwischen steht, assembliert oder nicht.
Jain. Die Funktion hast du schon richtig wiedergegeben, aber eben wegen dieser Funktion handelt es sich nicht um "Assembler-Anweisungen", sondern um "Assembler-Direktiven".
Der Unterschied ist einfach: Anweisungen sind die Dinger, die Code erzeugen, Direktiven sind die Dinger, die das eben nicht tun.
Jain. Die Funktion hast du schon richtig wiedergegeben, aber eben wegen
dieser Funktion handelt es sich nicht um "Assembler-Anweisungen",
sondern um "Assembler-Direktiven".
Ja OK, ich meinte es in dem Sinne "Anweisungen an den Assembler", aber stimmt, "Direktiven" ist die passende Bezeichnung. Der Punkt, worauf ich hinaus wollte, war ja, dass die Verwendung von .if .elif .else zur Anpassung an verschiedene Ziel-MCUs eben /nicht/ den Speicherbedarf des Programms erhöht, wie es behauptet wurde.
Dass das von mir als Denkanstoß gedachte Programm in der Praxis gekürzt und noch ausgefeilt werden kann, braucht nicht besonders betont zu werden.
Hatte ja oben extra darauf aufmerksam gemacht, indem ich schrieb:
Karl B. schrieb im Beitrag #7822170:
Ist natürlich zum besseren pädagogischen Verständnis auch "aufgeblasen".
Ein guter Cxx-Compiler übernimmt die Aufgabe schon für Dich.
Nicht umsonst will sich kaum einer mehr sich das ASM-Programmieren antun.
Hmm, warum schreibt man das dann in Assembler? Wenn Performance und
Energieverbrauch egal sind, kann man auch C++ nehmen. Wenn man schon
Assembler nutzt sollte man auch jeden letzten Takt rausquetschen, sonst
ist der Aufwand umsonst...
Weils Spaß macht?
Noch ein Tip: Debugger haben auch Macken. Nutze hier die Debug Funktion im Build and Run-Menü. Bei Studio 4. Vielleicht reden wir hier aneinander vorbei. Step for Step mit F10. Bis eine Meldung kommt.
Hat nur den Nachteil, die "Peripherie" muss physisch angeschlossen sein, die Zeitschleifen müssen angepasst werden.
ciao
gustav
Jain. Die Funktion hast du schon richtig wiedergegeben, aber eben wegen
dieser Funktion handelt es sich nicht um "Assembler-Anweisungen",
sondern um "Assembler-Direktiven".
Ja OK, ich meinte es in dem Sinne "Anweisungen an den Assembler", aber
stimmt, "Direktiven" ist die passende Bezeichnung. Der Punkt, worauf ich
hinaus wollte, war ja, dass die Verwendung von .if .elif .else zur
Anpassung an verschiedene Ziel-MCUs eben /nicht/ den Speicherbedarf des
Programms erhöht, wie es behauptet wurde.
Wie schon gesagt: die Funktion der Sache hast du vollkommen korrekt beschrieben, nur die Bezeichnung passte nicht.
Zum besseren Verständnis für die C-Only-Fraktion: .if .. .elif .. .endif des Atmel-Assemblers entspricht weitgehend dem C-Präprozessor-Konstrukt mit #if .. #elif .. #endif. Übrigens: tatsächlich kann man im Atmel-Assembler auch den C-Präprozessor verwenden.
Allerdings ist der eingebaute des Assemblers mächtiger, denn er kann Zwischenergebnisse für den zweiten Pass des Assemblers bereitstellen. Allerdings ist diese Nutzung auch sehr fehlerträchtig. Wenn man damit operiert, sollte man schon sehr genau wissen, was man tut.
Du benutzt diese erweiterten Fähigkeiten in deinem Programm aber nicht, es ist also diesbezüglich völlig unkritisch und könnte tatsächlich 1:1 durch den C-Style ersetzt werden.
Ein guter Cxx-Compiler übernimmt die Aufgabe schon für Dich.
Nicht umsonst will sich kaum einer mehr sich das ASM-Programmieren
antun.
Ich habe allerdings auch des Öfteren schon von diversen Bugs der AVR-Compiler gelesen. Für mich stellt sich dann die Frage, ob bei solch vergleichsweise "trivialen" Programmen, mit denen ich bisher gespielt habe (DCF77-Empfang, LCD-Ansteuerung, Infrarot-Kommunikation etc.) der Aufwand, der mit einem Compiler verbunden ist (Einarbeitung in MCU-spezifische Spracherweiterungen wie Interrupts etc., Kontrolle des Assembler-Outputs im Hinblick auf Nachoptimierung und evtl. Compiler-Bugs etc.) überhaupt in diesen Fällen sinnvoll die Vorteile der Hochsprache aufwiegen würde. Dass das bei komplexeren Programmen sicher der Fall ist, keine Frage.
Noch ein Tip: Debugger haben auch Macken. Nutze hier die Debug Funktion
im Build and Run-Menü. Bei Studio 4. Vielleicht reden wir hier
aneinander vorbei. Step for Step mit F10. Bis eine Meldung kommt.
Hat nur den Nachteil, die "Peripherie" muss physisch angeschlossen sein,
die Zeitschleifen müssen angepasst werden.
Ja, das mit dem IDE-gestützten Debugging habe ich mir mal vorgenommen. Wäre ja jetzt ein guter Anlass dazu, da ich mit dem UART-Debugging offensichtlich nicht weiterkomme.
Du benutzt diese erweiterten Fähigkeiten in deinem Programm aber nicht,
es ist also diesbezüglich völlig unkritisch und könnte tatsächlich 1:1
durch den C-Style ersetzt werden.
Den C-Style (insb. #define) habe ich auch schon benutzt, weil dieser im Gegensatz zu den Assembler-Direktiven auch Fließkommarechnung unterstützt (war z.B. bei meinen Infrarot-Routinen vorteilhaft für die Präprozessor-Berechnung der Zeitkonstanten).
Insgesamt muss ich übrigens sagen, dass ich den Atmel-Assembler avrasm2 sehr ausbaufähig finde. Wird ja auch nicht weiterentwickelt. Z.B. würde ich mir lokale Sprungmarken und mehr mathematische Möglichkeiten des Präprozessors wünschen. Für später habe ich mir vorgenommen, mal einen eigenen Assembler mit solchen Features zu entwickeln, dafür muss ich mich allerdings erstmal tiefer in die PC-Programmierung einarbeiten.
Insgesamt muss ich übrigens sagen, dass ich den Atmel-Assembler avrasm2
sehr ausbaufähig finde. Wird ja auch nicht weiterentwickelt. Z.B. würde
ich mir lokale Sprungmarken
Kann er. Innerhalb von Macros.
und mehr mathematische Möglichkeiten des
Präprozessors wünschen
Naja, das wird halt dadurch erschlagen, das man auch den C-Präprozessor benutzen kann.
Für später habe ich mir vorgenommen, mal einen
eigenen Assembler mit solchen Features zu entwickeln
Verschenkte Lebenszeit. Höchstens zu autodidaktischen Zwecken nützlich. Allerdings eher in Richtung "Compilerbau" als in Richtung "Assemblerpropgrammierung".
Was für letzteres nötig ist, ist bereits vollständig verfügbar. Sogar (leider) in etlichen Inkarnationen. Man braucht wahrlich nicht noch einen (wieder zu allen anderen inkompatiblen).
Echt? Wo ist das denn dokumentiert? Im AVR Assembler Manual DS40001917A finde ich nichts darüber.
Davon abgesehen fände ich es aber auch außerhalb von Macros sehr wünschenswert, um z.B. sowas schreiben zu können:
1
tst reg0
2
{ breq skip
3
mov reg0, reg1
4
skip:}
5
ldi reg2, 42
Also lokale Marken z.B. durch Klammern in der Gültigkeit beschränkt, wie lokale Variablen in C-Funktionen, damit man nicht immer einen übergeordneten Bezeichner voranstellen und nummerieren muss etc. Würde eine Menge Tipparbeit ersparen und auch die Lesbarkeit verbessern.
Verschenkte Lebenszeit. Höchstens zu autodidaktischen Zwecken nützlich.
Allerdings eher in Richtung "Compilerbau" als in Richtung
"Assemblerpropgrammierung".
Naja, Compilerbau ist mir dann doch zu hoch, ich habe nicht Informatik studiert und weiß nicht, ob ich mir die dafür nötigen Fähigkeiten jemals autodidaktisch aneignen kann. Interessieren würde es mich aber schon ...
Davon abgesehen fände ich es aber auch außerhalb von Macros sehr
wünschenswert, um z.B. sowas schreiben zu können:
1
> tst reg0
2
> { breq skip
3
> mov reg0, reg1
4
> skip:}
5
> ldi reg2, 42
6
>
Tja, sowas macht man dann halt einfach mit Makros.
1
.macro mveq
2
tst @0
3
breq skip
4
mov @0, @1
5
:skip
6
.endmacro
Aus deinem ursprünglichen Code würde dann werden:
1
mveq reg0, reg1
2
ldi reg2, 42
Übrigens gibt es bereits etliche solcher Macros fest eingebaut im Assembler. Nicht zuletzt auch "tst". Das ist keine wirkliche Anweisung, sondern nur ein Macro mit dem Body "or @0,@0".
Verlangt allerdings, sobald es über mehr als 2-3 Zeilen geht,
eine hohe Disziplin bei Programmänderungen.
Ja, und man müsste auch auf die Wortlänge der Instruktionen achten, denn es gibt ja solche aus einem und aus zwei Worten (JMP z.B.). Das wäre mir persönlich dann zu fehleranfällig.
Dann muss ich aber für jeden solcher Fälle extra ein eigenes Makro
definieren. Das macht es dann ja leider wieder ziemlich umständlich.
So what? Wenn du Assembler gewählt hast, hast du ganz bewußt auch die "Umständlichkeit" gewählt. Willst du es einfacher haben, musst du eben einen viel mächtigeren Makroassembler benutzen.
Dann muss ich aber für jeden solcher Fälle extra ein eigenes Makro
definieren. Das macht es dann ja leider wieder ziemlich umständlich.
So what? Wenn du Assembler gewählt hast, hast du ganz bewußt auch die
"Umständlichkeit" gewählt.
Naja, man kann ja einen vernünftigen Mittelweg finden, um sich das Leben nicht unnötig aufwendig zu machen. Dass andere Assemblersprachen solche lokalen Sprungmarken auch außerhalb von Makros haben (z.B. Intel-Assembler, mit einem vorangestellten Doppelpunkt, AFAIRC) deutet ja daraufhin, dass dieser Gedanke vielleicht nicht völlig abwegig ist. Und ich werde auch bei meinem Ziel bleiben, mir einen eigenen Assembler nach meinen Vorstellungen (und für meinen eigenen Gebrauch, muss sich ja sonst keiner davon stören lassen) zu implementieren, weil ich es eben für sinnvoll und nebenbei auch eine gute Programmierübung halte.
Ich habe allerdings auch des Öfteren schon von diversen Bugs der
AVR-Compiler gelesen. Für mich stellt sich dann die Frage, ob bei solch
vergleichsweise "trivialen" Programmen, mit denen ich bisher gespielt
habe (DCF77-Empfang, LCD-Ansteuerung, Infrarot-Kommunikation etc.) der
Aufwand, der mit einem Compiler verbunden ist (Einarbeitung in
MCU-spezifische Spracherweiterungen wie Interrupts etc., Kontrolle des
Assembler-Outputs im Hinblick auf Nachoptimierung und evtl.
Compiler-Bugs etc.) überhaupt in diesen Fällen sinnvoll die Vorteile der
Hochsprache aufwiegen würde. Dass das bei komplexeren Programmen sicher
der Fall ist, keine Frage.
Nunja, das hängt sicher davon ab, wo man herkommt und natürlich von der Architektur. So einfache Architekturen wie AVR8 sind auch in Asm noch sehr gut beherrschbar (wenn man halt den Assembler als Sprache perfekt beherrscht).
Ähnlich einfach sind Architekturen wie z.B. Z80, 6502, ARM-CortexM0.
Als Abgrenzung könnte man sagen: Je komplexer die im Programm zu verwendende Mathematik ist, desto geneigter wird man sein, eine Sprache zu verwenden oberhalb von Assembler.
Lustigerweise führt das aber im Umkehrschluss oft dazu: Wie weit kann ich eigentlich die (sehr oft nur scheinbar) nötige komplexe Mathematik für den konkreten Zweck vereinfachen...
Diese Überlegungen sind keinesfalls nutzlos, selbst wenn's am Ende doch ein C-Programm wird, wird es von diesen Überlegungen profitieren...
Ähnlich einfach sind Architekturen wie z.B. Z80, 6502, ARM-CortexM0.
Mich reizt tatsächlich auch die Herausforderung, mich in Cortex-M0+-Assembler für den RP2040 einzuarbeiten. Mal sehen, ob ich in absehbarer Zeit dazu komme.
Als Abgrenzung könnte man sagen: Je komplexer die im Programm zu
verwendende Mathematik ist, desto geneigter wird man sein, eine Sprache
zu verwenden oberhalb von Assembler.
Oder man hat umgekehrt sogar Spaß daran, komplexere Rechenfunktionen für einfache Architekturen in Assembler zu implementieren, um sie dort überhaupt mit akzeptabler Effizienz nutzbar zu machen; dazu gibt es gute Bücher von Manfred Schwabl-Schmidt über Fließkommaarithmetik etc. auf AVR, die habe ich schon lange im Schrank stehen und bisher nur mal durchgeblättert. Ist auch ein großes Ziel von mir, mich damit mal eingehend zu befassen. Aber dass das nicht für jeden was ist, ist mir natürlich klar.
Diese Überlegungen sind keinesfalls nutzlos, selbst wenn's am Ende doch
ein C-Programm wird, wird es von diesen Überlegungen profitieren...
Ja bestimmt, und manchmal wird ja wohl auch bei effizienzkritischen Programmteilen aus Assembler erzeugter Objektcode mit vom C-Compiler erzeugtem zusammen gelinkt. Es muss also nicht entweder–oder sein. Und wer sich mit Compilerbau beschäftigt, muss auch Assembler können, und lernen tut man das wohl nur, indem man in Assembler programmiert. Somit hat Assembler schon seine Berechtigung, auch vom reinen Spaß an der Freude mal abgesehen.
Mich reizt tatsächlich auch die Herausforderung, mich in
Cortex-M0+-Assembler für den RP2040 einzuarbeiten.
Na dann: ARM-ASM-Tutorial. Bezieht sich allerdings auf den STM32F1, welcher ein Cortex-M3 ist. Der ist aber in Assembler einfacher zu programmieren als der M0, weil der Instruction Set des M0 ziemlich limitiert ist und diverse Verrenkungen benötigt. Und nach etwas Einarbeitung auch besser programmierbar als der AVR, weil man mit 32bit einfach flüssiger arbeiten kann...
Ja bestimmt, und manchmal wird ja wohl auch bei effizienzkritischen
Programmteilen aus Assembler erzeugter Objektcode mit vom C-Compiler
erzeugtem zusammen gelinkt.
Der C-Compiler selber erzeugt bereits vielfach ein Konglomerat aus Sachen, die er wirklich aus seiner Quellsprache übersetzt und Sachen, die als Assemblermakros in seinem Bauch schlummern. Gerade auch im Mathe-Bereich stößt man ständig auf solche Asm-Fragmente. Das beweist: Den Compilerbauern selber ist absolut bewusst, wie suboptimal ihr Compiler ist.
Nur die ausschließlich biblisch besattelte "C-only-Fraktion" glaubt ernsthaft, dass es nicht so wäre und ihr Compiler schon von sich aus immer alles optimal macht.
Richtig spannend sind allerdings die Leute, die wirklich versuchen, den Compiler zu verbessern. Die lassen zwar einerseits öffentlich nix auf C/C++ kommen, kennen aber aber andererseits wenigstens selber die Schwächen und versuchen, sie zu verbessern (natürlich: auf dem einzig möglichen Weg: neue/bessere Asm-Macros).
Interessant ist das weniger aus rein technischer Sicht, sondern vor allem in Bezug auf deren Argumentation...
Einerseits müssen sie Asm verteufeln (denn damit könnte es ja jeder auch ohne den Compiler) andererseits kommen sie aber nicht darum herum, selber Asm zu benutzen, um den Compiler besser zu machen. Diese Zwangslage führt wohl zu durchaus gepaltenen Persönlichkeiten, wie man in einigen Einlassungen sehen kann.
Und ich werde auch bei meinem Ziel bleiben, mir einen eigenen Assembler
nach meinen Vorstellungen (und für meinen eigenen Gebrauch, muss sich ja
sonst keiner davon stören lassen) zu implementieren, weil ich es eben
für sinnvoll und nebenbei auch eine gute Programmierübung halte.
Ich kann nur vom Herzen empfehlen, sich gar nicht von irgendwelchen Maulhelden von diesem Weg und Ziel abbringen zu lassen, denn der 8-Bit-AVR-Assembler ist eine sehr gute Übung, von der man später bei der C-Programmierung sehr viel profitieren kann, sofern man unterm Strich wirklich eine gewisse Anzahl an Monaten intensiven, realen Schreibens damit verbracht hat. AVR mit 8-Bit ist die perfekte Umgebung dafür, denn das gewonnene Wissen und die entstandene Erfahrung wird man für sich auf jeden Fall auch bestens nutzen können – später wird man z.B. unter anderem auch sofort beurteilen können, was der Compiler für einen geschrieben hat und wie man das in C eventuell auch beeinflussen kann. Die Maulhelden dieser Welt haben oft selbst nie richtig Assembler geschrieben, sie haben oft auch nie eine richtige Leiterplatte entworfen und herstellen lassen, sie haben oft nie ein richtiges Projekt durchgezogen und zum Leben erweckt, insofern haben sie – die Maulhelden irgendwelcher Foren – nicht das Recht, andere, die es wirklich tun, zu kritisieren oder zu sagen, dass man es lieber lassen sollte. Sie „wissen” natürlich immer sofort, wie man dies und jenes „besser” machen sollte, die Maulhelden. Vom STM32-Assembler kann ich in diesem Zusammenhang nur abraten, denn hier gibt es böse Fallen und so leicht wie mit dem AVR-8-Bit-Assembler wird es leider nicht gehen.
natürlich: auf dem einzig möglichen Weg: neue/bessere Asm-Macros
Die Codegenerierung ist nur ein kleiner Teil des Compilers. Vorher muss der C/C++ Code analysiert werden, um überhaupt festzustellen welche Daten wann wohin fließen und auch um die Stellen zu finden, wo solche Snippets hin kommen können, und das ist der eigentliche Aufwand. Viele Ineffizienzen der Compiler beruhen darin, dass sie manche unnötige Instruktionen einfügen, weil sie nicht erkennen, dass sie überflüssig sind - aber nicht, dass dem Compiler zu wenige Assemblertricks bekannt wären. Ein Compiler macht eben viel mehr als nur Snippets zusammen zu stückeln.
Vom STM32-Assembler kann ich in diesem
Zusammenhang nur abraten, denn hier gibt es böse Fallen und so leicht
wie mit dem AVR-8-Bit-Assembler wird es leider nicht gehen.
Es gibt keinen "STM32-Assembler". STM benutzt zwar ARM-Kerne, hat die aber nicht erfunden. Es gibt eine riesige Vielfalt von konkurrierenden Anbietern, die zwar allesamt ebenfalls nicht den ARM erfunden haben, aber gleichermaßen benutzen.
Wenn, dann gibt es einen "ARM-Assembler". Tatsächlich gibt es deutlich mehr als einen. Das macht die Sache zunächst scheinbar etwas kompliziert. Wenn man sich aber auf CortexM0(+) beschränkt, wird es plötzlich wieder recht einfach. Ähnlich einfach wie beim AVR8. Natürlich durchaus anders (ist schließlich auch eine andere Architektur), aber prinzipiell ist es dieselbe Soße in grün. Ist eher sogar einfacher, weil es nur einen Adressraum gibt, was viel von der Komplexität der AVR8 raus nimmt. Nunja, es gibt andererseits natürlich auch Eigenschaften, die Komplexität an anderer Stelle einführen, wie etwa die sehr begrenzten Immediate-Fähigkeiten. Ist aber beherrschbar, so wie auch die AVR8 beherrschbar sind.
Mich reizt tatsächlich auch die Herausforderung, mich in
Cortex-M0+-Assembler für den RP2040 einzuarbeiten. Mal sehen, ob ich in
absehbarer Zeit dazu komme.
Da empfehle ich:
1
ARM and Thumb-2 Instruction Set
2
ARM_GNU_assembler_ref
3
ARM ThumbRefCard
4
ARM v6-M Architecture Reference Manual
5
Cortex-M0+ Technical Reference Manual
Da hast du im Grunde genommen alles, was es braucht um den RP2040 zu programmieren.
ich habe gerade das Problem, dass die UART-Ausgabe eines kleinen
Programms an einer Stelle hängt, wo ich mir einfach keine Ursache dafür
vorstellen kann.
Bevor ich hier anfange unnötig zu schreiben, vielleicht eine Frage vorab: funktioniert das nach Deinen Korrekturen mit der UART-Schnittstelle jetzt schon wie gewünscht oder besteht dieses ursprüngliche Problem weiterhin?
funktioniert das nach Deinen Korrekturen mit der
UART-Schnittstelle jetzt schon wie gewünscht oder besteht dieses
ursprüngliche Problem weiterhin?
Wenn ich das Programm 'tn12-isp-simulator' für den AVR64DD32 assembliere und flashe, funktioniert es nicht (ist aber inzwischen ein anderer Fehler, denn schon beim Programming-Enable-ISP-Befehl scheitert es dort); die angepasste Version für den ATmega328P funktioniert auf diesem hingegen einwandfrei.
Ich muss jetzt erstmal los, mache dann heute Abend weiter.
Für später habe ich mir vorgenommen, mal einen
eigenen Assembler mit solchen Features zu entwickeln
Dann würde ich die Zeit doch besser dazu nutzen, sich in C einzuarbeiten. Das beschleunigt das Programmieren um Größenordnungen.
Nebenbei erhöht das auch die Lesbarkeit, Wartbarkeit und Erweiterbarkeit drastisch.
Ich habe allerdings auch des Öfteren schon von diversen Bugs der
AVR-Compiler gelesen.
Ich kann mich nicht erinnern, daß ich mit sowas nennenswert Debugzeit verplempern mußte. Die Hauptfehlerquelle beim Programmieren sitzt immer vor dem Bildschirm.
Die Compiler sind inzwischen recht ausgereift. Viele benutzen sogar noch den alten WINAVR 2010.
Dann würde ich die Zeit doch besser dazu nutzen, sich in C
einzuarbeiten. Das beschleunigt das Programmieren um Größenordnungen.
Nebenbei erhöht das auch die Lesbarkeit, Wartbarkeit und Erweiterbarkeit
drastisch.
Nunja, wie oben schon geschrieben, macht mir das Programmieren in Assembler für solch eine vergleichsweise sehr einfache Architektur wie AVR eben einfach mehr Spaß. Ich finde es toll genau zu wissen, wie die CPU mit welchen Registern arbeitet und was wo genau im Speicher liegt.
Ich verdiene auch kein Geld mit der Programmiererei, daher steht die Effizienz des Prozesses nicht an erster Stelle, sondern es geht mehr um den Spaß an der Freude. Natürlich ist es dabei dennoch von Bedeutung, dass auch messbare Erfolge entstehen, aber die Art und Weise, wie ich diese erreiche, wähle ich eben gern selbst.
Nebenbei bemerkt habe ich auch schon in C programmiert; das war die erste Sprache, mir der ich mich so ca. als Siebtklässler beschäftigt habe, ist also schon eine Weile her, aber Grundkenntnisse sind vorhanden.
Wenn ich das Programm 'tn12-isp-simulator' für den AVR64DD32 assembliere
und flashe, funktioniert es nicht (ist aber inzwischen ein anderer
Fehler, denn schon beim Programming-Enable-ISP-Befehl scheitert es
dort); die angepasste Version für den ATmega328P funktioniert auf diesem
hingegen einwandfrei.
Ich muss jetzt erstmal los, mache dann heute Abend weiter.
– Programme immer nur in kleinen Zwischenschritten testen, korrigieren und zum Laufen bringen; einfach alles runterschreiben und erst danach nach Fehlern suchen, verursacht in der Regel mehr Arbeit, denn meistens enthält so ein runtergeschriebener Block mehrere Flüchtigkeitsfehler, oft auch Denkfehler, die die Funktionsweise des Programmablaufs betreffen; diese Vorgehensweise der kleinen Schritte gilt inbesondere dann, wenn Assembler geschrieben werden möchte, aber auch in C hilft diese sukzessive Inbetriebnahme ungemein
– wenn Peripherieteile im Projekt verwendet werden sollen, sollte man diese vorher so lange üben, bis man es geschafft hat, sie zum Laufen zu bringen, d.h.
– erstmal nur UART (ohne alles andere) richtig zum Laufen bringen, man kann dazu ein neues Projekt anlegen, um es dort bis zum Erfolg zu exerzieren
– kann man mit UART ein Byte senden, dann im nächsten Schritt das Absenden von mehreren Bytes üben und real testen - das Reinschreiben in den Sendebuffer darf immer nur mit der Flagüberprüfung erfolgen, d.h. am Ende des Prozesses sollte man auch in der Lage sein, auch längere Bytearrays per UART fehlerfrei abzuschicken
– ist auch der UART-Empfang im Projekt relevant, dann danach mit den Empfangtests beginnen und erst dann weitermachen, wenn auch das mit dem Empfang klappt
– auch alles vorher immer auf Plausibilität prüfen: CPU-Takt auf CLKOUT ausgeben und die Frequenz mit einem Oszilloskop nachmessen, genauso die UART-Baudrate z.B. anhand eines Sendebits mit dem Oszilloskop nachmessen, sobald man mit UART ein Byte senden kann; hier auch mit dem Oszilloskop schauen, ob komplette Frames versendet werden (für solche Testzwecke verwende ich oft Testzahlen wie 170 oder 85, also 01010101-Muster)
– der CCP-Mechanismus ist zeitkritisch, macht/schreibt man es falsch, wird der Befehl von der CPU regulär abgearbeitet, intern jedoch ignoriert – was man umschalten wollte, bleibt unverändert; möchte man eine Umschaltung unter CCP als Subroutine zur Laufzeit nutzen, muss man für die kritische Zeit auch die Interrupts sperren
– das UART-Senden aus der Interruptroutine heraus ist generell keine gute Sache, vor allem dann, wenn man mehrere Bytes absenden möchte und z.B. zwischendurch warten muss; es sei denn, man kann programmtechnisch sicherstellen, dass der Sendebuffer in dem Moment nicht voll ist, man dort in der ISR also etwas ohne Warterei schicken (in den Buffer schreiben) und anschließend ohne große Verzögerung aus der ISR wieder verschwinden kann
erstmal nur UART (ohne alles andere) richtig zum Laufen bringen, man
kann dazu ein neues Projekt anlegen, um es dort bis zum Erfolg zu
exerzieren
Erstmal danke für deine Tipps. Also die UART-Ausgabe hatte ja zunächst prinzipiell auch auf dem AVR-DD funktioniert (Strings und Zahlen wurden korrekt gesendet), ist nur an einer für mich unerklärlichen Stelle hängen geblieben.
Zuletzt hatte ich aber die UART-Ausgabe komplett deaktiviert (DEBUG=0 gesetzt), somit ist nun nur noch SPI aktiv, am UART kann es nicht mehr liegen.
Der allerwichtigste Tip zur Fehlersuche ist natürlich: Debugger (JTAG/SWD/debugWIRE) verwenden. Damit kann man sehr schnell und einfach eine große Zahl an Fehlern finden. Insbesondere so etwas wie "Programm bleibt stehen" - einfach im Debugger unterbrechen wenn dies passiert ist und schauen, in welchem Zustand sich das Programm befindet. Damit wäre möglicherweise dieser ganze Thread unnötig und das Problem in Minuten gelöst.
einfach alles runterschreiben und erst danach nach Fehlern suchen,
verursacht in der Regel mehr Arbeit
Finde ich nicht unbedingt. Man kann durchaus große Programmteile "runter schreiben" und dann per Debugger die Fehler finden. Man muss natürlich noch einen Überblick über den Code haben und etwas Routine im Umgang mit den Debuggingtools.
Erstmal danke für deine Tipps. Also die UART-Ausgabe hatte ja zunächst
prinzipiell auch auf dem AVR-DD funktioniert (Strings und Zahlen wurden
korrekt gesendet), ist nur an einer für mich unerklärlichen Stelle
hängen geblieben.
Solche liegengebliebenen ungeklärten Leichen sind nie gut für das eigene Verständnis und Vorankommen, denn irgendwann mal später wird man wieder genau an dieser unerklärlichen Stelle landen und wieder nicht weiterkommen. Da UART hier jetzt aber nicht relevant ist, ist es für diese Betrachtung erstmal egal.
Zuletzt hatte ich aber die UART-Ausgabe komplett deaktiviert (DEBUG=0
gesetzt), somit ist nun nur noch SPI aktiv, am UART kann es nicht mehr
liegen.
Mit der SPI-Schnittstelle sollte man prinzipiell genauso wie mit UART vorgehen – bevor irgendetwas davon in einem Projekt verwendet wird, so lange in einem Nebenprojekt exerzieren, bis es sitzt und zu 100% funktioniert. Je nach Geschwindigkeit ist auch der Gebrauch des SPI-Sendens in einer ISR als kritisch einzustufen, wenn zwischendurch gewartet werden muss.
Hast Du es noch kein einziges mal ausprobiert? Dafür ist ja die neue 1-Pin-Schnittstelle unter anderen auch gedacht worden – ich habe das auch relativ zeitnah bei der Einarbeitung in den AVR128DB ausprobiert, allerdings unter Atmel Studio 7.
Tatsächlich noch nicht - ich benutze auch sonst die Mplab X IDE lediglich zum Setzen von Fuses, ansonsten arbeite ich mit Notepad++ und der Kommandozeile bzw. Batchdateien.
ich benutze auch sonst die Mplab X IDE lediglich zum Setzen von Fuses
Ich musste diese IDE zwangsläufig auch mehrere male installieren und benutzen, um meine Snaps mit der richtigen Firmware zu flaschen – diese IDE ist mit Hintergrundthreads so überladen, dass sie schlimmer als die STM32CubeIDE lahmt und damit für meine Wahrnehmung für normales, flottes Arbeiten problematisch ist; mit einem nicht besonders schnellen PC ist das extrem nervig und quasi nicht zu gebrauchen, was die Leute sich da wieder ausgedacht haben.
diese IDE ist mit Hintergrundthreads so überladen,
Ja, aus diesen Gründen habe ich es bisher vermieden, damit zu arbeiten. Aber fürs Debugging muss es wohl sein. Leider wird das von der Performance her wesentlich bessere Studio ja nicht mehr weiterentwickelt bzw. ist nicht mehr auf dem aktuellen Stand, was neuere Devices und Tools betrifft.
Leider wird das von der Performance her wesentlich bessere Studio ja nicht
mehr weiterentwickelt bzw. ist nicht mehr auf dem aktuellen Stand, was
neuere Devices und Tools betrifft.
Die ganzen neuen AVRs sind in der Finalversion des Atmel-Studios schon drin und den Snap braucht man nur mit der entsprchenden Firmware mittels MPLAB-X-IDE flaschen – da das Atmel Studio 7 keine Updates mehr erfährt, ist es in diesem Fall für viele Jahre sogar vorteilhaft, wenn sich da nichts ändert, sonst müsste man den Snap irgendwann mal wieder mit einer neueren Firmware nachflaschen. Auch was der Compiler generiert, ist dann nach einem neuen Build immer identisch, was für mich auch vorteilhaft ist, weil ich immer den generierten Assembler-Code auch überprüfe und ggfs. über entsprechende C-Anweisungen oder -schreibweise indirekt so modifiziere. Wenn man die Optimierungsstufe des Projekts beibehält, bleibt es dann auch so – wie ich es haben wollte – erhalten. Ich habe am Anfang über viele Jahre hinweg alles selbst in Assembler für die AVR geschrieben – aus Komfort- und Zeitgründen mache ich das nicht mehr, ich weiß aber zu jedem Zeitpunkt, was der Compiler da für eine Akrobatik macht, ich weiß ebenfalls, was die Leute oft für eine komische und völlig unnötige Akrobatik in ihren präsentierten Assemblercodes machen.
Nachtrag: Screenshot angehängt – Dein AVR ist da natürlich auch drin und ein Assemblerprojekt müsste dementsprechend auch gehen
Sollte da nicht besser ein Sleep rein um Energie zu sparen?
Mit Energiesparmodi habe ich mich noch nicht befasst, da ich bisher
keinen Bedarf daran hatte. Hier sollte das auch keine Rolle spielen, da
es eh nur ein Testprogramm ist und ob der Controller nun ein paar
Stunden lang 12 mA zieht oder nicht ...
12 mA? Also mein AVR32DD28 begnügt sich mit 2.6 mA bei 5.0 V und 20 MHz (korrekt konfiguriert).
"Energie sparen" bei diesem Vorhaben? Merkwürdige Idee, unter den gegebenen Umständen ein paar mW sparen zu wollen - als Preis dafür aber eine zum Teil deutliche Verlängerung der Reaktionszeit in Kauf zu nehmen:
1
; Interruptverzoegerung:
2
; active : 9 T mit 2.6 mA @ 5.0 V
3
; idle : 16 T mit 1.7 mA @ 5.0 V
4
; standby: 45 T mit 0.6 mA @ 5.0 V
Und da ich gerade beim Thema bin:
1
.org PORTA_PORT_vect
2
jmp spiSsIsr ; SPI Slave Select ISR
3
.org TCA0_OVF_vect
4
jmp tcaOvfIsr
5
.org SPI0_INT_vect
6
jmp spiTcIsr ; SPI Transfer Complete ISR
"Zu kurz gesprungen" kann man hier wahrhaft nicht behaupten ...
"Zu kurz gesprungen" kann man hier wahrhaft nicht behaupten ...
Vorher hatte ich hier auch RJMPs, aber im Datenbuch stehen dort natürlich JMPs (bei allen Devices mit mehr als 8KB Flash), daher hatte ich das geändert. Eigentlich ist mir zwar bewusst, dass RJMPs bei der von mir gewählten Art der Notation mit den einzelnen .ORG-Direktiven dort ebenso funktionieren müssten, aber ich wollte sichergehen.
aber im Datenbuch stehen dort
natürlich JMPs (bei allen Devices mit mehr als 8KB Flash)
Aber RJMP funktioniert auch bei denen und in beide Richtungen. Nur wenn die Sprungdistanz für RJMP zu groß wird, gibt es eine Fehlermeldung und kein Hex-File wird erzeugt.
Assemblercode >8kB zu erstellen, ist schon ne Menge und dürfte Jahre dauern.
Ich habe wieder den jetzigen Stand angehängt, und versuche mich gerade am Debuggen in der MPLAB X IDE. Bisher habe ich es noch nicht geschafft, an irgendwelche nützlichen Informationen zu gelangen. Ich habe mal einen Breakpoint in Zeile 190 gesetzt, aber scheinbar wird diese überhaupt nicht erreicht. Seltsamerweise scheint die ISR gar nicht angesprungen zu werden. Keine Ahnung, woran das liegen könnte. I-Flag ist gesetzt, SPI-IE ebenso ...
Die spiSsIsr wird dagegen ausgeführt, das "SSFE" wird zweimal nacheinander gesendet, so wie es sein sollte.
– das UART-Senden aus der Interruptroutine heraus ist generell keine
gute Sache, vor allem dann, wenn man mehrere Bytes absenden möchte und
z.B. zwischendurch warten muss; es sei denn, man kann programmtechnisch
sicherstellen, dass der Sendebuffer in dem Moment nicht voll ist, man
dort in der ISR also etwas ohne Warterei schicken (in den Buffer
schreiben) und anschließend ohne große Verzögerung aus der ISR wieder
verschwinden kann
Wenn man einen Ringbuffer hat und eine Statemaschine, dann schreibt und liest in/aus dem Buffer wie man lustig ist. Dann kann bspw. der "Data Register Empty Interrupt" dafür sorgen, dass das nächste Byte aus dem Ringbuffer automatisch ins Senderegister geschoben wird. Dank Interrupt passiert das alles im "Hintergrund" ohne künstliche Wartezeiten. Es muss lauten. Man muss sicherstellen das man den Ringbuffer unter Kontrolle hat. Dann funktioniert auch der Rest.
Vorher hatte ich hier auch RJMPs, aber im Datenbuch stehen dort
natürlich JMPs (bei allen Devices mit mehr als 8KB Flash), daher hatte
ich das geändert. Eigentlich ist mir zwar bewusst, dass RJMPs bei der
von mir gewählten Art der Notation mit den einzelnen .ORG-Direktiven
dort ebenso funktionieren müssten, aber ich wollte sichergehen.
Wenn man mit '.org' oder NOPs auf den richtigen Offset achtet, ist es quasi egal, ob man relative oder absolute Sprünge nimmt, man könnte vermutlich auch eine Kombination aus NOP+RJMP oder CLI+RJMP nehmen, denn bei den AVRs handelt es sich nicht um eine echte Vektortabelle, wie man sie z.B. von dem 68000 oder der STM32 kennt, sondern nur um eine Pseudo-Vektortabelle, wo einfach der Programmcode ausgeführt wird und die normalen Befehle für das Laden des Programmcounters missbraucht werden – diese Art der Sprünge hat damals vermutlich einfach etwas Platz auf Siliziumebene gespart und man behielt es dann so bis heute bei den auch neueren Entwicklungen bei. Wenn man überhaupt keine Interrupts verwendet, kann man den eigentlichen Programmcode gleich ab Adresse 0 anfangen zu schreiben – man kann die Vektortabelle auch in eine andere Region verlegen und hat diese Möglichkeit, ab 0 direkt mit dem Programm zu beginnen, dann auch zur Verfügung.
Umgekehrt geht es aber nicht, also wo explizit RJMP verlangt wird, einfach JMP zu platzieren, allein aufgrund der doppelten Befehlsbreite ist es nicht möglich – es geht aber auch schon rein physikalisch vom Code her nicht, denn bei den AVRs mit diesem kleinen Flashspeicher fehlen (angeblich) auch die absoluten Sprungbefehle im Befehlssatz. Ob sie wirklich im Silizium nicht abgebildet worden sind, könnte man bestimmt mit einigen Tests herausfinden – ist aber nur etwas für irgendwelche Freaks, die sich gerne mit eher unnötigen oder weniger wichtigen Dingen befassen.
Die Verkleinerung der Latenz der Interruptannahme um den einen Takt ist im Normalfall eher nicht der Rede wert, wenn man weiß, dass da sowieso gleich viele PUSHs folgen werden, weil man die Register incl. Statusregister auf dem Stack retten muss. Bei ganz speziellen Anwendungen könnte diese Möglichkeit der Takteinsparung oder des CLI-Befehl-Einschubs doch wieder interessant sein – oft ist es aber sinnvoller, dann bei solchen zeitkritischen Anwendungen zu einem anderen, deutlich schnelleren µC zu greifen, wo die CPU mit z.B. 170 oder 550 MHz laufen kann und einige Register in diesem schnellen Takt auch schon selbständig auf dem Stapel ablegen tut. Wenn auch das nicht reicht, kann man Dinge auch rein kombinatorisch mit z.B. einer in einem FPGA abgebildeten Gatter-Logik realisieren und so mit der Antwort auf ein Ereignis auf die Nanosekundenebene runtergehen, sofern man dazu befähigt ist.
Läuft doch - also ich kann (mit meinem Selbstbauprogrammiergerät)
schreiben und lesen.
Hmm, das ist ja seltsam. Ich werde es später noch einmal mit einem anderen AVR64DD32 versuchen, vielleicht liegt es doch an der Hardware ...
Nachtrag: Habe dasselbe Hex gerade auf einen anderen 64DD32 geflasht und bekomme beim Programming Enable das Output "AC 53 00 00 ". Dafür wird aber die fallende Flanke an ¬SS nicht signalisiert. Sehr seltsam. Kann es vielleicht wirklich sein, dass die Hitzeeinwirkung beim Heißluftverlöten zu hoch war, sodass manche Teilfunktionen beschädigt wurden? Oder betrifft sowas immer den ganzen Chip, sodass gar nichts mehr funktionieren würde?
Gerade fällt mir noch ein, dass diese billigen Dupontkabelchen, die ich hier auch für sämtliche Verbindungen verwende, ja wohl auch teils Wackelkontakte verursachen sollen. Vielleicht liegt's auch daran. Werde heute Nachmittag noch einen Versuch mit besseren starten.
Nachtrag: Eine Platine mit 64dd28 im DIP habe ich auch noch liegen, darauf werde ich das Programm auch mal laufen lassen. Damit müsste sich ja ausschließen bzw. bestätigen lassen, dass es an den 64dd32-Exemplaren liegt.
Haben Sie keine anderen? Es ist ja eine große Familie.
Mit entsprechender CLKCTRL-Anpassung läuft es auch auf einem AVR32EA28, legt man das TCA-Fragment still auch auf einem AVR16EB28; von den DA und DB ganz zu schweigen. Und sicher klappt es auch mit einem der neueren ATtinies.
Allerdings halte ich ein Problem mit den Verbindungen oder der Stromversorgung für wahrscheinlicher.
Nachtrag: Habe dasselbe Hex gerade auf einen anderen 64DD32 geflasht und
bekomme beim Programming Enable das Output "AC 53 00 00 ". Dafür wird
aber die fallende Flanke an ¬SS nicht signalisiert. Sehr seltsam. Kann
es vielleicht wirklich sein, dass die Hitzeeinwirkung beim
Heißluftverlöten zu hoch war, sodass manche Teilfunktionen beschädigt
wurden? Oder betrifft sowas immer den ganzen Chip, sodass gar nichts
mehr funktionieren würde?
Wie ich bereits schrieb, man muss den/die Fehler in kleinen Schritten suchen – das geht auch mit einem bereits vollständig geschriebenen Programm prinzipiell genauso wie mit einem, das man in Schritten erst entstehen lässt – man legt alles unnötige durch z.B. Auskommentieren oder Überspringen lahm und lässt nur einen kleinen, zu untersuchenden Bereich des Programms für die CPU zum Abarbeiten. Wenn dieses Teil wie erwartet nachweislich und reproduzierbar funktioniert, gibt man einen weiteren Block des eigenen Codes dazu frei und prüft das dann mit der neuen Funktion bzw. mit dem zusätzlichen Code. Dupontkabel, Steckbretter, Steckverbindungen und lange Leitungen sind übrigens für Interrupteingänge etc. keine gute Wahl – damit macht man sich oft selbst unglücklich. Und externe Pull-UPs von z.B. 10kΩ können manchmal wahre Wunder vollbringen, bei manchen Anwendungen muss man mit dem Wert sogar noch weiter runtergehen. Digitalspeicheroszilloskop unbedingt benutzen, um sich das alles an den besagten neuralgischen Stellen genau anschauen zu können – das Arbeiten ohne Oszilloskop gleicht quasi der Arbeit eines Blinden, wo es darauf ankommt, zu schauen und zu sehen, was vor einem passiert.
Die Geschichte mit der Überhitzung der ICs ist sehr unwahrscheinlich, man versucht sich aber damit immer wieder zu trösten und quasi zu verdrängen, dass es an dem liegen kann, was man da selbst zusammengebastelt und als Code zusammengedichtet kann. Ich habe in den letzten 40 Jahren keinen einzigen Transistor, Diode oder IC durch Löten (mit dem Lötkolben) beschädigen können und bei mancher sehr häufiger, penetranter Hitzebearbeitung, damit das z.B. fürs Foto gut wird, hatte ich teilweise auch schon die Befürchtung, dass ich da jetzt vielleicht übertrieben habe – leider NEIN, alle µC, ICs oder sonstige Halbleiter haben danach ohne Probleme funktioniert. Das einzige, was ich bem Löten beschädigt habe, waren sogenannte intelligente SMD-LEDs WS2812 – beim Erhitzen konnte man durch das Fenster sehen, dass sie im Inneren platzten, also schlagartig undicht und so geschrottet wurden. Das waren aber vermutlich Fälschungen, die ich mal vor vielen, vielen Jahren auf Aliexpress gekauft habe, denn die Orignalteile, die ich mir später bei TME besorgt hatte, platzten nicht so beim Anlöten. Das Platzen dieser Fälschungen war übringens reproduzierbar, d.h. es war nicht nur ein IC, der bei der Herstellung zufällig einen Materialfehler erfahren hatte, sondern sie waren quasi alle so schlecht hergestellt worden.
Haben Sie keine anderen? Es ist ja eine große Familie.
Naja, auf dem mega328P läuft es ja, und auf anderen evtl. auch, aber es geht mir ja im Moment eben darum, warum es auf dem 64DD32 nicht läuft, und da hilft es mir ja nicht weiter, wenn ich noch andere Devices versuche.
Die Dupontkabel habe ich eben gegen bessere (die einzelnen von Reichelt) ausgetauscht, ohne Erfolg, und auch ein externer Pull-Up von 2 kΩ brachte keine Veränderung.
Nun bin ich gerade dabei, minimale Veränderungen für den 64DD28 vorzunehmen, und werde dann berichten, ob es auf meinem 64DD28-I/SP funktioniert.
Ich meinte auch keine AVRe, sondern AVRxt, also 'AVRmxyn', bei denen keine oder nur minimale Programmänderungen nötig sind. Und wie Sie selbst auch bemerkten, bringt der simple Wechsel von Hardware manchmal neue Erkenntnisse in einer so verfahrenen Situation wie der Ihrigen.
Vielleicht noch das: um einen Defekt an genau diesem gerade verwendeteten Chip auszuschließen, müsste man genau in die gleiche Platine und ohne irgendwelche Veränderungen einen anderen 64DD32 mit Heißluft etc. einlöten. Diese Änderungen gibt es aber allein schon aufgrund der Tatsache, dass man für den Lötvorgang z.B. irgendweche Leitungen abstecken muss. Das heißt, um das wiederum ausschließen zu können, müsste man anschließend, sofern es tatsächlich mit einem zweiten, identischen Chip fehlerfrei funktioniert, dann die Chips wieder umlöten, um zu schauen, ob es mit dem ursprünglichen IC wieder nicht geht. Damit hätte man zumindest eine gewisse Wahrscheinlichkeit dafür, dass der erste Chip eine Macke hat oder haben könnte.
Nachtrag: ich habe auch mal einen Blick ein die Errata des 64DD32 geworfen, die scheint aber extrem kurz zu sein bzw. nur sehr wenige Siliziumfehler zu enthalten, d.h. da ist kaum was drin; das sieht bei z.B. den AVR_DB und AVR_DA ganz anders aus
Sooo, ich habe endlich den Fehler gefunden: Dieser lag gar nicht beim Programm 'tn12-isp-simulator', sondern in meinem 'avrispv2', das ich zum Testen des ersteren benutzte. Dort hatte ich beim Einbau einer 1-ms-Wartezeit zwischen den einzelnen SPI-Bytes (um dem ISP-Simulator Zeit für die Verarbeitung der Bytes zu geben, bevor das nächste "geclockt" wird) das Register wri0 mit 1 geladen, und übersehen, dass dieses zum Zwischenspeichern des empfangenen SPI-Bytes diente ... Daher konnte natürlich die Erkennung des Echo-0x53 nicht mehr funktionieren.
Also Asche auf mein Haupt und Entschuldigung für die Verwirrungen ... Ich muss mir wohl eine andere Arbeitsweise angewöhnen, zu oft nehme ich zu viele Änderungen gleichzeitig an zu vielen Stellen vor, ohne einzeln zu testen, und weiß dann nicht mehr, wo die Fehler zu suchen sind ...
Und mit dem ATmega328P als Slave funktionierte alles?
Hmm, ja, das ist allerdings ein guter Einwand. Es ist möglich, dass ich die fatale Ergänzung im 'avrispv2'-Code erst danach vornahm, nachdem es mit dem 328P funktionierte; leider kann ich mich an die Abfolge nicht mehr erinnern.
Wie gesagt, ich arbeite daran, meine Arbeitsweise besser zu strukturieren, und werde nun erstmal das Interbyte-Delay in 'avrispv2' eleganter lösen, um danach mit dem Testen des ISP-Simulators fortfahren zu können. Denn die Signatur wurde soeben nicht korrekt gelesen, 'avrdude' meldete
1
Device signature = 00 01 02
2
Error: expected signature for ATtiny12 is 1E 90 05
Nebenbei bemerkt habe ich auch schon in C programmiert; das war die
erste Sprache
Das ist gut. Bei aller Liebe zu Asm: Wenn man im µC-Bereich unterwegs ist, führt eigentlich überhaupt kein Weg daran vorbei, C zumindest "lesend" zu beherrschen. Das ist mindestens genauso wichtig wie "Datenblatt-Englisch".
"Schreibend" hingegen ist deutlich komplizierter. Selbst sehr viele Leute, die ausschließlich C schreiben, können es eigentlich nicht richtig. Witzig ist, dass Assemblerkenntnisse durchaus dabei helfen können, richtigen Code in C schreiben zu können.
Fakt ist: wer (irgendeinen!) Assembler wirklich kann, wird z.B. sehr viel seltener in C Fehler der Klassen "off-by-one" oder "integer-overflow" produzieren. Einfach deshalb, weil er es von Hause aus gewohnt ist, über derartige Problematiken überhaupt nachzudenken...
Copyright see https://github.com/avrdudes/avrdude/blob/main/AUTHORS
4
5
System wide configuration file is C:\Users\Johannes\AppData\Local\Programs\avrdude\avrdude.conf
6
7
Using port : com7
8
Using programmer : avrispv2
9
AVR part : ATtiny12
10
Programming modes : ISP, HVSP
11
Programmer type : STK500V2
12
Description : Serial Atmel AVR ISP using STK500v2
13
Programmer model : AVRISP
14
HW version : 0
15
FW Version Controller : 0.00
16
SCK period : 0.1 us
17
18
AVR device initialized and ready to accept instructions
19
Device signature = 1E 90 05 (ATtiny12)
20
Auto-erasing chip as flash memory needs programming (-U flash:w:...)
21
specify the -D option to disable this feature
22
Erased chip
23
Reading 10 bytes for flash from input file 10B.hex
24
in 1 section [0, 9]: 5 pages and 0 pad bytes
25
Writing 10 bytes to flash
26
Writing | ################################################## | 100% 0.16 s
27
Reading | ################################################## | 100% 0.09 s
28
10 bytes of flash verified
29
30
Avrdude done. Thank you.
Damit ist das Eröffnungsproblem dieses Threads endlich gelöst (ursprünglich wird es sicher eine Folge des vergessenen bzw. falsch platzierten RAM-Offsets gewesen sein) und ich danke herzlich allen für die Ratschläge und Hilfe.
Nun kann ich mich weiter der Untersuchung des Flash-Value-Polling im Zusammenspiel von avrdude, STK500v2 und AVRs ohne RDY/BSY-ISP-Befehl wie ATtiny12 zur Vervollständigung meines avrispv2-Programms widmen.
Das ist gut. Bei aller Liebe zu Asm: Wenn man im µC-Bereich unterwegs
ist, führt eigentlich überhaupt kein Weg daran vorbei, C zumindest
"lesend" zu beherrschen. Das ist mindestens genauso wichtig wie
"Datenblatt-Englisch".
Ja, ich habe mir nun auch vorgenommen, mich mal in "Embedded-C" für AVRs einzuarbeiten, zunächst mit AVR-GCC oder dem Microchip XC8, da muss ich noch schauen, für was ich mich entscheide (Empfehlungen wären willkommen). Kann ja nicht schaden, auch wenn ich für AVRs mich weiterhin in Assembler vertiefen werde.
Fakt ist: wer (irgendeinen!) Assembler wirklich kann, wird z.B. sehr
viel seltener in C Fehler der Klassen "off-by-one" oder
"integer-overflow" produzieren. Einfach deshalb, weil er es von Hause
aus gewohnt ist, über derartige Problematiken überhaupt nachzudenken...
ursprünglich wird es sicher eine Folge des vergessenen
bzw. falsch platzierten RAM-Offsets gewesen sein
Na, da muss ich jetzt aber doch den Bömmel zitieren: "Mer wolle uns nix weismache" - schließlich lautet der Betreff "... UART-Ausgabe bleibt hängen ...", und zwar mitten in einer Hex-Ausgabe.
ursprünglich wird es sicher eine Folge des vergessenen
bzw. falsch platzierten RAM-Offsets gewesen sein
Na, da muss ich jetzt aber doch den Bömmel zitieren: "Mer wolle uns nix
weismache" - schließlich lautet der Betreff "... UART-Ausgabe bleibt
hängen ...", und zwar mitten in einer Hex-Ausgabe.
Ja, der Delinquent hat ziemlich sicher das eigentliche Problem nicht gefunden. Die beste Näherung war wohl:
zu oft nehme ich
zu viele Änderungen gleichzeitig an zu vielen Stellen vor, ohne einzeln
zu testen, und weiß dann nicht mehr, wo die Fehler zu suchen sind ...
Ist aber ganz grundsätzlich auch viel schwieriger, wenn es mehr als ein Programm gibt, sondern zwei auf zwei MCUs, die miteinander hakeln sollen. Da hilft nur Disziplin und Debug-Erfahrung.
Aber gewinnen kann man diese Debug-Erfahrung halt nur, indem man es tut. Ich denke, ihm ist zumindest klar geworden, dass er es unbedingt systematischer tun muss.
Ja, der Delinquent hat ziemlich sicher das eigentliche Problem nicht
gefunden.
Scheint so, denn momentan (nach dem Wechsel zurück zum 64DD32) habe ich wieder das Problem, dass beim Programming Enable nur Nullen empfangen werden (nachdem es auf dem 64DD28 funktioniert hat):
"System muß sein", schreibt Arno Schmidt an einer Stelle - und seinen Nachsatz verschweige ich jetzt lieber.
Beim Wechsel vom DIP-AVR64DD28 auf den DD32 tritt ein Problem auf? Kann doch eigentlich nicht sein, ist doch dasselbe Programm. Stromversorgung, vor allem auch die Masseverbindung, ist aber in Ordnung?
Stromversorgung,
vor allem auch die Masseverbindung, ist aber in Ordnung?
Ja, die sollte hinreichend gut sein, inzwischen habe ich drei parallele Dupontkabel als Masseverbindung zwischen den AVRs, die über SPI kommunizieren. Die werden ja hoffentlich nicht alle drei gleichzeitig Wackelkontakt haben. Bei nächster Gelegenheit werde ich mir auch Dupontkabel selbst herstellen, eine Crimpzange und Kontakte dafür habe ich mir schon besorgt, sodass ich dann sichergehen kann, dass die Quetschverbindungen dann ordentlich sind.
Stromversorgung erfolgt vom PC über einen CH340-USB-UART-Adapter (Platine von mq-pcb.de) mit 5,0 V.
Ansonsten ist mein Aufbau schon etwas improvisiert, das muss ich zugeben, aber elektrisch müsste es eigentlich OK sein. Mit dem DIP-64DD32 hat es ja auch funktioniert. Ich bin nun schon am überlegen, ob mit meinen selbst designten und von JLC gefertigten AVR-DB/DD32-Boards irgendwas nicht stimmt.
Und das haben Sie überprüft: Spannung gemessen an beiden Vdd-GND-Paaren des DD32, Spannung an VDIO2, Durchgang zwischen den GNDs der beiden uCs, immer direkt an den ICs?
Ja, ich habe mir nun auch vorgenommen, mich mal in "Embedded-C" für AVRs
einzuarbeiten, zunächst mit AVR-GCC oder dem Microchip XC8, da muss ich
noch schauen, für was ich mich entscheide.
Soweit mir bekannt, basiert xc8 für AVR auf den GNU-Tools (avr-gcc etc.), allerdings hat Microchip einige Optimierungen deaktiviert, die man per zu erwerbender Lizenz zukaufen kann...
Ich lasse mich da aber gerne eines besseren belehren.
Die Haupunterschied bei Verwendung der GNU-Tools sind:
Verwendung eines Linker/Locators zur Erstellung eines lauffähigen Programms. Zunächst werden Ojbect-Dateien erstellt (aus C/C++ oder Asm), die dann mit (Code aus) Libs wie AVR-LibC und libgcc zum ausführbaren Programm vervollständigt werden.
Und das haben Sie überprüft: Spannung gemessen an beiden Vdd-GND-Paaren
des DD32, Spannung an VDIO2, Durchgang zwischen den GNDs der beiden uCs,
immer direkt an den ICs?
Hole ich gleich noch nach ...
Vorab nur schonmal der Zwischenstand: Ich habe nun nochmal exakt dasselbe .Hex, das auf dem DD32(1) nicht funktionierte, auf den DD28 geflasht, und – dort funktioniert es einwandfrei.
Anschließend habe ich den DD32(2) (zweites Exemplar meiner selbstgelöteten Breakout-Platine) angeschlossen und nochmal das letzte .Hex geflasht – auch hier läuft es nun, wie es sein soll.
Danach habe ich das ZIP aus dem Eröffnungsbeitrag wieder heruntergeladen und darin die bekannt gewordenen Fehler (vergessenes Offset 'simFlash_sram') behoben sowie die Zeichenketten auf wenige Buchstaben gekürzt, dieses assembliert und geflasht, und auch dieses funktioniert nun auf DD32(2):
1
SSFE
2
SSFE
3
RSB 00
4
RSB 01
5
RSB 02
6
CE
7
SSFE
8
RPM 0004 00
9
RPM 0005 00
10
WPM 0000 AA
11
WPM 0001 BB
12
WPM 0002 CC
13
WPM 0003 DD
14
WPM 0004 EE
15
WPM 0005 00
16
RPM 0000 AA
17
RPM 0001 BB
18
RPM 0002 CC
19
RPM 0003 DD
20
RPM 0004 EE
21
RPM 0005 00
Somit sind wir ein ganzes Stück weiter, denn der Fehler ist damit auf die Hardware des DD32(1) eingegrenzt. Nun bleibt nur noch diese zu untersuchen, ob irgendeine Lötverbindung schlecht ist, ein Kurzschluss besteht, oder der Chip wirklich beschädigt ist.
Stromversorgung erfolgt vom PC über einen CH340-USB-UART-Adapter
(Platine von mq-pcb.de) mit 5,0 V.
Ansonsten ist mein Aufbau schon etwas improvisiert, das muss ich
zugeben, aber elektrisch müsste es eigentlich OK sein. Mit dem
DIP-64DD32 hat es ja auch funktioniert. Ich bin nun schon am überlegen,
ob mit meinen selbst designten und von JLC gefertigten
AVR-DB/DD32-Boards irgendwas nicht stimmt.
Hier noch ein Foto von meinem ersten und provisorischen Aufbau von damals mit dem AVR128DB28, um alles genau zu prüfen und sich in die neue-AVR-Familie einzuarbeiten – ich wollte hier auch wissen, ob man das alles über den Snap und mit Atmel Studio 7 betreiben kann, incl. Debugging etc. Die Adapterplatine mit dem µC habe ich direkt mithilfe von Stiftleisten in das Lochrasterfeld meiner Platine eingelötet, um keine Steckverbindungen der µC-Pins zu haben – vor allem die Quarzverbindung ist bei dieser neuen Familie sehr störanfällig. Wenn man den Quarz in die Präzisionsfassung (rechts vom Chip) einsetzt und z.B. hin und her bewegt, läuft der µC Amok oder er stürzt regelrecht ab. bzw. geht in den CFD-Notfallmodus, weil ich das auch getestet habe – durch diese Wackeldackel-Geschichte scheint diese Umschaltung in den Notbetrieb aber auch nicht immer sicher zu funktionieren. Das heißt, den Quarz muss man hier definitiv verlöten, weil durch die relativ niedrige Core-Spannung der µController und damit durch den LowPower-Betrieb der Oszillatorschaltung das ganze nicht so robust wie bei den alten AVRs mit Full-Swing-Betrieb ist – ich habe das hier mit dem Quarz steckbar gemacht, um es mit verschiedenen Quarzen zu testen, weil es ja in dem ganzen Spannungsbereich auch bis 24MHz laufen sollte und es auch tut. Richtige Evaluationsplatinen für AVR128DB128 etc. sind schon in Planung, 3/4 des Kerns habe ich schon fertig entworfen – das dauert aber bestimmt noch ein paar Wochen, bis ich sie habe, ich kann Dir aber gerne per eMail Bescheid geben, wenn es Dich interessiert, um z.B. ein paar von den ersten etwas günstiger zu bekommen.
Hier ein Foto von meinem derzeitigen sehr provisorischen Aufbau mit einem meiner ATtiny3227-Boards und zwei USB-UART-Bridges, der aber momentan gut funktioniert. Das USB-Kabel des Snaps ist mit Paketklebeband an der Tischkante befestigt, damit das Ganze nicht unkontrolliert umherwandert und evtl. noch Kurzschlüsse verursacht – einen Adapter für den Snap als 100×100-mm² große Motherboard-Platine (die hoffentlich schwer genug wird, um auf dem Tisch liegen zu bleiben – ansonsten werde ich einfach noch eine leere Platine unten drunter mit Abstandsbolzen schrauben) habe ich bereits fertigen lassen, müsste heute oder spätestens morgen bei mir ankommen.
Wenn ich schon diese Mini-Breadboards und zig zusammengestoppelte
Platinen sehe, dann weiß ich schon dass da nie was zuverlässig
funktionieren kann.
Naja, irgendwie muss man ja mal was ausprobieren und experimentieren können. Ich kann und will ja nicht für jede erdenkliche Kombination eine komplette Platine fertigen lassen. Und mit vernünftigen Dupontkabeln funktioniert das auch.
Wenn es dann wirklich zuverlässig werden soll und die endgültige Schaltung feststeht, kann man ja immer noch eine Platine dafür machen. Bis dahin muss es nicht weltraumfest sein.
Habe es heute Morgen nicht mehr geschafft, ich schreib dir dann
nachmittags.
Kein Problem, eilt ja nicht. Ach ja, falls Du auch etwas Robustes für den Snap haben möchtest, dann könnte ich Dir sogar eine unbestückte Adapterplatine von dem ersten Wurf für den Snap gratis abgeben (Foto im Anhang). Für die AVR_Dx passt dann die UDPI_v2 mit RESET, VTG, GND und UPDI, die sich in der Mitte befindet – auf den Evaluationsplatinen wird es diese Reihenfolge dann auch exakt so geben. Reset braucht man nicht unbedingt, d.h. drei Leitungen würden reichen, aber falls man es braucht, ist es da. Die UPDI_v1, die sich innerhalb der 2x3-ISP-Schnittstelle befindet, kann man natürlich auch abgreifen und nutzen, diese 2x3-Stiftleisten verwende ich auf meinen Leiterplatten aber nur für die alten AVRs, wo man über ISP programmiert. Die große Platine (Maxi) für den Snap muss ich noch machen.
Und mit vernünftigen Dupontkabeln funktioniert das auch.
Ich war auch schon am überlegen, alle Anschlüsse meiner Boards auf Schraubklemmen (im 3,5-mm-Raster oder kleiner, wenn es gibt) zu führen, und dann mit Litzenabschnitten mit Aderendhülsen zu verbinden. Wäre natürlich schöner und robuster, aber auch deutlich teurer.
Ich war auch schon am überlegen, alle Anschlüsse meiner Boards auf
Schraubklemmen (im 3,5-mm-Raster oder kleiner, wenn es gibt) zu führen,
und dann mit Litzenabschnitten mit Aderendhülsen zu verbinden. Wäre
natürlich schöner und robuster, aber auch deutlich teurer.
So ganz ohne Dupont wird es beim schnellen, günstigen Prototypen nicht gehen – ich mache es in der Regel so, dass alles, was verlötet werden kann oder muss, dazu gehören z.B. VCC und GND, auch verlötet wird. Wenn VCC+GND nicht verlötet wird, dann habe ich selbstgemachte Krokodilklemmen-Leitungen, wo es an der Krokodilklemme verlötet ist und der Querschnitt der Leitung zumindest 100mA ohne nennenswerten Spannungsabfall durchlässt. Mit diesen Krokodilklemmen kann man relativ sicher an Stiftleisten andocken – Wackelkontakte gibt es hier nicht, wenn man mit der Klemme gleich zwei Stiftleisten schnappt. Diese günstigen, dünnen, fertiggekauften Krokodilklemmen-Leitungen sind dafür nicht geeignet – wie dünn die Leitung ist, sieht man, wenn man sie abschneidet oder sie nach intensivem Gebrauch von alleine abbricht. Taster, LEDs und UART-Verbindung kann man mit frischen (nicht ausgeleierten) Dupontkabel anbinden, Schnittstellen wie I2C oder SPI verbinde ich nicht gerne über Dupontkabel bei Tests, aber für einen kurzen Test geht es auch. Bei dedizierten Interrupteingängen muss man anders vorgehen – „Antennen” aller Art sind hier extrem kontraproduktiv. µController verlöte ich in der Regel immer, selbst die Adapterplatine, auf der sie verlötet wurden, wird wiederum auch verlötet (so wie hier bei dem AVR128DB28 in SO28), nur bei PDIP nehme ich auch mal Sockel, allerdings nur Präzisionsfassungen, weil diese einfachen Federkontakte sehr schnell Kontaktprobleme bereiten können. Ich habe jetzt auch einen Fall, wo ich eine PLCC-Fassung verwenden werde – diese Fassungen sind aber ziemlich sicher und robust, insofern auch OK. In ganz speziellen Fällen verwende ich Zerokraftsockel und dann dafür entsprechend auf Adapterplatinen aufgelötete ICs mit Stiftleisten im 2,54mm-Raster für den großen oder auch kleinen Sockel – hier gibt es dann definitiv keine Wackelkontakte (zwei Fotos im Anhang). Diese Nullkraftsockel sind natürlich ziemlich teuer, dafür bekommt man aber die Sicherheit, dass es keine Wackeldackel gibt. Steckbretter benutze ich wegen dieser genannten Gründe überhaupt nicht – das ist ja quasi eine Ansammlung von Wackelkontakten und parasitären Kapazitäten, die man sich da auf den Tisch stellt; wenn etwas provisiorisch aufgebaut werden muss, dann wird es zumindest auf Lochrasterplatinen ordentlich verlötet (wie ich es z.B. mit dem AVR128 gemacht habe).
PS: Schraubklemmen gibt es auch im 2,54mm-Raster, sind aber auch relativ teuer und diese verkleinerte Konstruktion ist entsprechend filigran
@ Johannes,
https://www.mikrocontroller.net/attachment/660229/IMG_20250205_080120.jpg
bei deinem Foto sieht man unten 2 Folien die mindestens dort nichts zu suchen haben.
Die hellere rötliche könnte Antistatisch sein.
Die untere größere silbrige ist Antistatisch.
Antistatische Folie macht zwar keinen direkten satten Kurzschluss, aber es bedeutet eine gewisse Leitfähigkeit. Das zusammen mit hochohmigen Eingängen ... Sowas hat unter Leiterplatten im Betrieb definitiv nichts zu suchen.
Antistatische Folie macht zwar keinen direkten satten Kurzschluss, aber
es bedeutet eine gewisse Leitfähigkeit. Das zusammen mit hochohmigen
Eingängen ... Sowas hat unter Leiterplatten im Betrieb definitiv nichts
zu suchen.
Antistatische Folien haben Ableitwiderstände im Gigaohmbereich pro mm Abstand. Das bestätigt auch der Test mit zwei Messspitzen, in geringstmöglichem Abstand voneinander auf die Folie gedrückt, ein Multimeter zeigt bei mir OL im 200-MΩ-Bereich. Ich bezweifle, dass sich das bei den Schaltungen, mit denen ich hantiere, auswirken könnte.
Anbei ein Foto meines Snap-Adapters, den ich seit heute Nachmittag in Benutzung habe. Die 90°-Stiftleiste ist eine Ausführung mit extra langen THT-Beinchen (Samtec TSW-108-09-L-S-RA), die hier wegen der Abstandshalter unter dem Snap notwendig ist (und die sind sicher auch vorteilhaft, damit keine Kurzschlüsse der Beinchen der Snap-Buchsenleiste zur Massefläche bzw. Leiterbahnen des Motherboards entstehen).
Nichts für ungut, sorry dass meine Antwort negativ rüber kam, war nicht so gemeint. Ich kann mir halt nur nicht vorstellen, dass diese sehr geringe Leitfähigkeit dieser ESD-Oberflächen in diesem Fall etwas ausmacht. Vielleicht irre ich mich auch, kenne mich auch nicht genau damit aus. Hatte die Tütchen auch als Unterlage vorhin direkt entfernt und durch Papier ersetzt.
Ich habe übrigens noch drei dieser Snap-Motherboards übrig und würde sie zum Selbstkostenpreis abgeben, falls jemand Bedarf hat.
Glückwunsch dazu, denn reale Erfolge sind wichtig fürs Weiterkommen –
damit sollten aber auch die Probleme mit dem Klebeband jetzt beseitigt
sein : )
Vielen Dank :·) Ist ja ein sehr einfaches Layout, aber das Board erfüllt seinen Zweck, der Snap bzw. die Verbindung USB-Kabel/-Buchse ist mit dem Kabelbinder um das USB-Kabel auch gut darauf fixiert.
Das Kabel habe ich dennoch auch wieder an der Tischkante angeklebt, damit das Board nicht auf dem Tisch umherwandert, getrieben durch etwaige Bewegungen des recht starren Kabels.
Das Kabel habe ich dennoch auch wieder an der Tischkante angeklebt,
damit das Board nicht auf dem Tisch umherwandert, getrieben durch
etwaige Bewegungen des recht starren Kabels.
Ja, das schwarze USB-Kabel für den Snap scheint auch etwas dick zu sein – ich verwende hierfür ein einfaches, dünnes Kabel, das auch für meine Smartfones verwendet werden kann, um sich mit dem PC zu verbinden. Ich habe im Laufe der Jahre auf dem „Hauptarbeitsplatz” auch ein System der Anordnung der Kabel entwickelt bzw. es hat sich halt in diese Richtung entwickelt, wo die Spannungsquelle (Netzteil) links steht und dementsprechend auch von links an meine Leiterplatten angeschlossen werden kann und die Signalkabel wie USB oder µC-Programmieranschlüsse in der Regel von rechts in die Platinen gesteckt werden können, weil auch der PC auf der rechten Seite steht und sie von dort kommen. Auch das Oszilloskop steht auf der rechten Seite. Dieses Konzept versuche ich jetzt bei mir (auf allen Arbeitsplätzen) beizubehalten – es muss aber schon jeder selbst für sich herausfinden oder herauskristallisieren, was ihm am besten zusagt. Bei einem meiner Kunden kann das auch genau umgekehrt und deshalb problematisch sein – aber so ist halt das Leben, man kann und wird es nicht allen Recht machen können und irgendwo muss man dann auch einen Punkt machen und das ganze einheitlich festlegen bzw. durchziehen. Problematisch und chaotisch wird es nur dann, wenn es jedesmal anders ist, weil man bei den eigenen Entwürfen gar nicht auf die Ausrichtung der Stecker und Buchsen achtet – aber auch damit muss dann schon jeder selbst irgendwie klarkommen oder sich arrangieren.
Ja, das schwarze USB-Kabel für den Snap scheint auch etwas dick zu sein
– ich verwende hierfür ein einfaches, dünnes Kabel,
Ja das stimmt, es ist recht dick, aber ich dachte immer, dass das für höhere Qualität spricht - evtl. bessere Abschirmung - kann aber auch ein Trugschluss sein.
Leider hat der SNAP keine USB-C-Buchse, denn dafür habe ich bessere i.S.v. flexiblere Kabel.
Dieses Konzept versuche ich jetzt bei mir (auf allen Arbeitsplätzen)
beizubehalten – es muss aber schon jeder selbst für sich herausfinden
oder herauskristallisieren, was ihm am besten zusagt.
Hmm, ich hatte bisher immer die Anschlüsse so platziert, wie es fürs Layout am günstigsten war - aber stimmt, wenn ich die Platinen nun doppelseitig fertigen lasse, habe ich da natürlich mehr Freiheiten und kann auch an die praktischen Aspekte denken.
Ja das stimmt, es ist recht dick, aber ich dachte immer, dass das für
höhere Qualität spricht - evtl. bessere Abschirmung - kann aber auch ein
Trugschluss sein.
Bei der moderaten Übertragungsgeschwindigkeit, die der Snap nutzt, muss hier kein Supa-Dupa-Kabel verwendet werden, auch von der Strombelastbarkeit bzw. vom Spannungsabfall her gesehen ist das ziemlich egal, denn die USB-Spannung der Buchse wird ausschließlich für die Snap-Schaltung verwendet, weil das VTG-Konzept des Snaps so gedacht ist, dass VTG eine separate, externe Spannung sein soll, die gleichzeitig auch die vielen kleinen Levelshifter, die da am Ende der IOs verbaut sind, versorgt. Das ist auch besser so, dass man es so explizit getrennt hat, denn jeder Kurzschluss oder zu hoher Strombedarf, der durch die Targetschaltung verurascht werden könnte, würde auch Auswirkungen auf die Stromversorgung des Snaps haben und womöglich zu irgendwelchen Funktionsstörungen oder Restarts führen – das sollte auch jeder bedenken, der auf Teufel komm raus die Spannung dieser USB-Buchse nutzen möchte. Der µC des Snaps wird auch handwarm, aber bei 300 MHz als Takt (oder womit auch immer der µC da in dieser Größenordung läuft) ist das ganz normal und bedeutet nicht, dass hier extrem viel Strom fließt – 100mA reichen bei 3,3V völlig aus, um die Wärmeentwicklung am IC-Gehäuse mit der Hand deutlich zu spüren. Die alten 8751, 68000, die noch nicht in CMOS hergestellt wurden, wurden bei 5V und 170-200mA mit nur 12 bzw. 8 MHz alt Takt schon richtig heiß.
Habe soeben alle Füßchen des betreffenden AVR64DD32 mit viel Flussmittel und Lötkolben nachgelötet, die Lötstellen sehen alle m.E.n. gut aus, nichts auffälliges zu sehen. Trotzdem funktioniert er nach wie vor nicht, dasselbe Programm auf einem anderen DD32 auf baugleicher Platine dagegen schon. Ich verbuche den ersten DD32 nun einfach als defekt, vielleicht hat er auch irgendwie ESD-mäßig mal was abbekommen, obwohl ich darauf eigentlich immer achte.
Wie auch immer, so langsam vergeht mir die Lust auf die Suche nach der exakten Ursache, ich werde den Fall jetzt ad acta legen, dieser Thread kann damit als erledigt betrachtet werden. Vielen aufrichtigen Dank an alle für die hilfreichen Antworten.