Hallo!
Bei meinem aktuellen Projekt kommuniziert der ATmega168PA über EINEN
digitalen Pin mit einer Gegenstelle.
Konkret wird ein Polling-Signal vom ATmega (Pin ist OUTPUT) gesendet und
danach antwortet die Gegenstellen mit den Daten (Pin ist INPUT). Beide
Kommunikations-Richtungen erfolgen über den selben PIN.
Das Polling-Signal wird bereits richtig erzeugt. Wenn der Pin
anschließend als Input konfiguriert wird, funktioniert keine weitere
Ausgabe (Polling-Signal) mehr. Dies lässt sich am Logic Analyzer gut
beobachten -> nach einem Reset des ATmega kommt das Polling-Signal
einmal und dann nie mehr.
Hier ein Auszug aus dem Assembler Code (Kommunikation über PB0):
1
LDI R16,0b00100001
2
OUT DDRB,R16 ; define PB 0 and 5 as output
3
4
SBI PORTB,0 ; initalize HIGH
5
6
; generate polling-signal here
7
8
9
LDI R16,0b00100000
10
OUT DDRB,R16 ; define PB 0 as input for Response --> Ab dieser Zeile wird kein Polling-Signal mehr ausgegeben.
Mein erster Verdacht war, dass ich beim Wechseln eine Zwischenschritt
benötigte wie in der Doku beschrieben:
[Doku]
Switching Between Input and Output
When switching between tri-state ({DDxn, PORTxn} = 0b00) and output high
({DDxn, PORTxn}
= 0b11), an intermediate state with either pull-up enabled {DDxn,
PORTxn} = 0b01) or output
low ({DDxn, PORTxn} = 0b10) must occur. Normally, the pull-up enabled
state is fully acceptable,
as a high-impedance environment will not notice the difference between a
strong high
driver and a pull-up. If this is not the case, the PUD bit in the MCUCR
Register can be set to disable
all pull-ups in all ports.
Switching between input with pull-up and output low generates the same
problem. The user
must use either the tri-state ({DDxn, PORTxn} = 0b00) or the output high
state ({DDxn, PORTxn}
= 0b11) as an intermediate step.
[/Doku]
Daran scheint es aber nicht zu liegen. Hab die genannten
Zwischenschritte testweise implementiert gehabt.
Was mache ich hier falsch?
Danke schon vorab!
Andreas schrieb:> Was mache ich hier falsch?
Du hast vergessen, zuerst mal ein ein brauchbares Protokoll zu designen
und statt dessen einfach sinnlos und planlos losprogrammiert.
Ein Eindraht-Bus (auch wenn's nur P2P ist) ist so ziemlich das
anspruchsvollste für ein Protokolldesign, was man sich vorstellen kann,
jedenfalls wenn man Wert darauf legt, dass die Kommunikation dauerhaft
zuverlässig läuft.
Das fängt bereits bei der Wahl geeigneter Hardware an. Zwei (zumindest
potentiell) gegeneinander arbeitende PushPull-Ausgänge sind absolut
ungeeignet dafür. Deswegen benutzen Eindraht-Busse praktisch immer
Konstrukte mit OpenDrain-Ausgängen und Pullup-Widerständen.
Danke für deine Antwort!
Das Protokoll musste ich nicht designen. Konkret möchte folgendes
Projekt (PIC) auf einen ATmega realisieren:
http://www.pieter-jan.com/node/10
Derzeit habe ich das generierte Signal nur mit einem Logic-Analyzer
geprüft. Mir ist weiterhin unklar, warum das Polling-Signal nur einmal
ausgegeben wird? Dies scheint ein Problem in der Programmierung zu sein.
Parallel ergibt sich mir aus deiner Antwort eine weitere Frage:
Der PIC hat doch auch nur einen Push-Pull Ausgang? Entgeht mir hier ein
wichtiges Detail?
Andreas schrieb:
> Dies scheint ein Problem in der Programmierung zu sein.
Scheint mir auch so.
Mit einer eingehenderen Analyse anhand dieses fünf-Zeilen-Schnipsels bin
aber nicht nur ich, sondern offenbar sogar Fähigere überfordert.
> Derzeit habe ich das generierte Signal nur mit einem> Logic-Analyzer geprüft. Mir ist weiterhin unklar,> warum das Polling-Signal nur einmal ausgegeben wird?
" nur "? Könnte es sein, dass der ATmega auf eine Antwort wartet, ein
Logic-Analyzer diese aber nicht liefert?
Andreas schrieb:> Das Protokoll musste ich nicht designen. Konkret möchte folgendes> Projekt (PIC) auf einen ATmega realisieren:> http://www.pieter-jan.com/node/10
Da war jemand am Werk, der ungefähr genausowenig Ahnung hat wie du
selber. Zum Glück waren allerdings wenigstens die Entwickler des N64
richtige Ingenieure und haben deswegen auch alles richtig gemacht...
> Derzeit habe ich das generierte Signal nur mit einem Logic-Analyzer> geprüft. Mir ist weiterhin unklar, warum das Polling-Signal nur einmal> ausgegeben wird? Dies scheint ein Problem in der Programmierung zu sein.
Natürlich. Aber das ist nur ein Folgeproblem...
> Parallel ergibt sich mir aus deiner Antwort eine weitere Frage:> Der PIC hat doch auch nur einen Push-Pull Ausgang? Entgeht mir hier ein> wichtiges Detail?
Ja, natürlich. Sowohl beim PIC als auch beim Atmel kann man die Ausgänge
auch als Open-Drain benutzen und sogar ggf. interne Pullups hinzu
schalten. Wobei es je nach Länge der Signalleitung u.U. sinnvoller ist,
nicht die internen Pullupszu benutzen, sondern einen externen,
wesentlich niederohmigeren.
Vielen Dank für eure Antworten!
> Mit einer eingehenderen Analyse anhand dieses fünf-Zeilen-Schnipsels bin> aber nicht nur ich, sondern offenbar sogar Fähigere überfordert.
Ok, hier der gesamte Code:
1
.DEF mp = R16
2
.DEF lifetick = R28
3
.DEF numbZeros = R29
4
.DEF numbOnes = R30
5
.DEF numbCycles = R31
6
7
RJMP main
8
9
main:
10
; ###### send polling signal #######
11
12
SBI PORTB,0 ; initalize HIGH
13
LDI mp,0b00100001
14
OUT DDRB,mp ; define PB 0 as output
15
16
LDI numbZeros, 7
17
LDI numbOnes, 2
18
19
zero:
20
CBI PORTB,0 ;16,1
21
LDI numbCycles,15 ;2
22
23
zeroFalseLoop: ; 14 * 3 ICs + 1 * 2 IC = 44
24
DEC numbCycles ;3
25
BRNE zeroFalseLoop ;4,(5)
26
27
NOP
28
SBI PORTB,0 ;LAST,1
29
LDI numbCycles,3 ;2
30
31
zeroTrueLoop: ; 2 * 3 ICs + 1 * 2 IC = 8
32
DEC numbCycles ;3
33
BRNE zeroTrueLoop ;4,(5)
34
35
NOP
36
NOP
37
38
DEC numbZeros ;2
39
BRNE zero
40
41
42
43
one:
44
LDI numbCycles,5 ;2
45
CBI PORTB,0
46
47
oneFalseLoop: ; 4 * 3 ICs + 1 * 2 IC = 14
48
DEC numbCycles ;3
49
BRNE oneFalseLoop ;4,(5)
50
51
SBI PORTB,0
52
LDI numbCycles,14
53
54
oneTrueLoop: ; 13 * 3 ICs + 1 * 2 IC = 41
55
DEC numbCycles ;3
56
BRNE oneTrueLoop ;4,(5)
57
58
DEC numbOnes
59
BRNE one
60
61
62
; ########## receive controller signal #########
63
64
;CBI PORTB,0
65
LDI mp,0b00100000
66
OUT DDRB,mp ; define PB 0 as input and PB 5 as output for LED
67
68
;CBI PORTB,0
69
70
; ########## Wait for data - approx. 3 sec #############
71
72
LDI R18,255
73
delayOutOuter:
74
LDI R17,255
75
delayOuter:
76
LDI numbCycles,255
77
delayInner:
78
DEC numbCycles
79
BRNE delayInner
80
DEC R17
81
BRNE delayOuter
82
DEC R18
83
BRNE delayOutOuter
84
85
; ######### lifetick - toggle onboard LED #########
86
87
SBI PINB, 5
> " nur "? Könnte es sein, dass der ATmega auf eine Antwort wartet, ein> Logic-Analyzer diese aber nicht liefert?
Das kann ausgeschlossen werden, da am Beginn des Main Programmes immer
(zyklisch) das Polling Signal gesendet wird.
> Natürlich. Aber das ist nur ein Folgeproblem...
Wie meinst du das? Sobald ich nachfolgenden Zeilen im Code
auskommentiere, ist am Ausgang wieder das zyklische Polling-Signal
messbar:
>
1
> LDI R16,0b00100000
2
> OUT DDRB,R16 ; define PB 0 as input for Response --> Ab dieser Zeile wird kein Polling-Signal mehr ausgegeben.
3
>
> Ja, natürlich. Sowohl beim PIC als auch beim Atmel kann man die Ausgänge> auch als Open-Drain benutzen und sogar ggf. interne Pullups hinzu> schalten. Wobei es je nach Länge der Signalleitung u.U. sinnvoller ist,> nicht die internen Pullups zu benutzen, sondern einen externen,> wesentlich niederohmigeren.
Wenn ich dich richtig verstehe, wäre bei Verwendung von Open-Drain
(Ausgang) und Pullups (Eingang) (elektrisch) alles sauber?
Wenn das Programm danach wieder von vorne beginnen soll, dann solltest
du das auch hinschreiben.
Zur Zeit ist das Verhalten nach deinem letzten Befehl offiziell
undefiniert. Im der Praxis gehts zwar tatsächlich irgendwann von vorne
los, was allerdings zwischenzeitlich passiert, ist offen.
Sind Sie sicher, dass das kein Messfehler ist?
Also wenn ich noch vor dieses "Wait for data - approx. 3 sec" ein "rjmp
0" setze, dann sehe ich mit meinem alten Analogoszilloskop auf PB0 eine
hübsche Impulskette.
Danke für Eure Antworten und Tipps!
Ich habe am Ende des Codes nun noch die Zeile "RJMP main" ergänzt und
nun funktioniert es!
Komischerweise funktionierte der zyklische Aufruf OHNE "RJMP main"
solange, bis die Data Direction des Pins (mit DDRB Register) einmal
geändert wurde.
Danke für Eure Unterstützung!
(Dann hatten Sie uns also doch nicht den gesamten Code gezeigt)
Nach dem "SBI PINB, 5" holpert das Programm weiter, bis es auf den
Bootloader trifft, und dieser reagiert offenbar verschieden auf die
unterschiedlichen Port-Konfigurationen.
Ohne Bootloader funktioniert es nämlich ohne das "rjmp main", auch wenn
es schlechter Programmierstil ist, ich hatte es ausprobiert.
Ergänzung: es muss nicht mal der Bootloader selbst sein, da können ja
noch irgendwelche Reste im Programmspeicher stehen; im Gegensatz zum
direkten Brennen, bei welchem zuerst komplett gelöscht wird.
Andreas schrieb:> Ja, nach SBI PINB, 5 kommt kein Code mehr. Wieso ins Leere?> Danach beginnt die Abarbeitung der Befehle wieder von vorne.
<facepalm/> Wie kommst du auf dieses schmale Brett?
Andreas schrieb:> Ich habe am Ende des Codes nun noch die Zeile "RJMP main" ergänzt und> nun funktioniert es!
Unglaublich! Jetzt wirst du sicher gleich noch behaupten, daß es nachts
dunkel wird.