Hallo Leute!
Ich habe vor kurzem mal nachgefragt wie ich einen UNI/O-Bus gesteuerten
EEPROM über den Arduino Uno ansteuern kann. Mir wurden Begriffe wie
Bit-Banging aber auch fertige Libraries zur Verfügung gestellt. Da ich
gerne selber etwas versuche um bei dem Versuch immer wieder was an
Wissen mitzunehmen, stelle ich Euch hier meinen Fehlversuch vor :D
Ich würde euch bitte mal über den Code zu schauen und mir vielleicht
dabei zu helfen das Ganze zum laufen zu bringen. Ich versuche euch alle
relevanten Informationen dazu bereit zu stellen.
Bevor ich das mache, möchte ich aber ein paar Begrifflichkeiten nennen
die Ihr mir nicht nennen braucht, da ich mich mit diesen schon befasst
habe oder diese einfach nicht gebrauchen konnte :D
Dazu gehört:
- Die Arduino Timer1-Libary
- I²C und SPI Bus Modi (Ich benötige keine Alternativen)
- Bibliotheken die das Thema schon gelöst haben, ich möchte selber auf
den Nenner kommen und mich nicht an der Arbeit Anderer bedienen :D
- Ein Oszilloskopf zur Freq. Prüfung ist aufm Weg!
Ich komme nun einmal zum Abbild meines Arduino und dem EEPROM (Bitte
nicht lachen, ich hatte nur ein 8-SO Package, vor einer Woche kannte ich
den Unterschied noch nicht - ein PDIP Package ist auf dem Weg :) )
Das 20150724_173242.jpg zeigt meinen "Zusammenbau". Ich habe mehrmals
geprüft das die Anschlüsse sinnig sind. der SCIO geht über einen Pullup
zum Digital Pin "9" des Arduino Uno.
Ich gehe mal davon aus, dass die Verkabelung passt und dort der Fehler
nicht liegt. Darum fahre ich nun mit dem Code fort. Ich habe vieles
einfach nur stumpf gehackt. Ich packe erst Kram in Funktionen wenns auch
funktioniert.
Habe den Code jetzt step-by-step mit folgendem DataSheet verglichen:
http://ww1.microchip.com/downloads/en/DeviceDoc/22076D.pdf
Dort unter Kategorie 10.0 Device Address Polling. Ich möchte halt durch
das Polling ein erstes Debugging machen. Insofern ich die richtige
Adresse des Slave-Device erwische bekomme ich ein SAK zurück. Das
bedeutet nicht nur das ich einen Device mit der Adresse erreicht habe -
sondern auch, dass die Frequenzen und die Kommunikation soweit
funktioniert.
Die Device Adresse besteht aus dem Family Nibble : 0101 und dem Device
Nibble 0000 - welche soweit ich überall lese default ist. Da ich im
status register auch nix was Adresse angeht umschreiben kann - glaube
ich somit erstmal das ich mit 0000 richtig liege insofern ich keinen
zweiten Device anpappe.
(Bitte nehmt mir keine sinnfreien Comments übel - war n doofes
copy-paste Gefummel)
Ich danke Jedem für die Mühe sich meinen Kram hier durchzulesen und
sogar zu helfen!
gruß Charlie
Dicky D. schrieb:> Ohne zu wissen was für ein Bauteil da in der Luft schwebt,> stolpere ich> grade über deinen Aufbau, was macht der Widerstand rechts im Bild?
Der sichert meine Angst vor Probleme ab. Da ich ein Anfänger in der
Elektronik bin war ich der Meinung es wäre ne gute Idee dort n
Widerstand reinzuklemmen. Könnte dieser Probleme darstellen?
Edit:
Ich entschuldige mich für den großen Post ohne das Problem überhaupt zu
verdeutlichen!!!
Es handelt sich um folgenden EEPROM:
http://ww1.microchip.com/downloads/en/DeviceDoc/20002122B.pdf
Nun zum Problem selbst:
Ich sollte bei der zweiten AKN-Sequenz ein SAK einlesen. Leider lese ich
wiederum nur eine 0 ein. Das liegt entweder, dass Frequenzgemäß
irgendwas falsch mache oder die Schaltung an sich garnicht auf den
EEPROM ansetzt.
Leider bin ich sehr schlecht im debuggen von Master to Slave Geschichten
im µC-Bereich :(
Charlie2000 schrieb:> Ich habe vieles> einfach nur stumpf gehackt. Ich packe erst Kram in Funktionen wenns auch> funktioniert.
Du würdest dir viel leichter tun, wenn du diese Attitüde ablegen
würdest.
Soviel ich dem Datenblatt entnehmen kann, wird JEDE Byteübertragung
mit einer MAK abgeschlossen. Wo ist die bei dir zb beim Header.
Deine Umschalterei der Port Pin Richtung ist auch unlogisch. Wenn du den
Start HEader beginnst, musst du den Pin auf Low ziehen. Dazu muss aber
die Ausgaberichtung schon auf Output gestellt sein. Diese Absicherung
mit der pinState Variable kannst du dir sparen. Wenn der Pin schon auf
Output sein sollte, passiert nichts weiter wenn du ihn nochmals auf
OUTPUT stellst.
Ach Hack.
Teil doch den Code erst mal vernünftig in Funktionen ein. Da sieht man
ja vor lauter digitalWrites überhaupt nichts mehr in deinem Code. Du
ertränkst doch die eigentliche Logik in den Low-Level Details wie Pin
setzen.
Wie gesagt: Lass diesen Blödsinn mit "Ich schreib Funktionen erst wenn
es funktioniert". Derartige Protokolle lassen sich normalerweise super
in einzelne Funktionsgruppen aufteilen, die es sich verdient haben, in
eigene Funktionen gesteckt zu werden.
das ist dann auch viel einfacher zu debuggen. Und vor allen Dingen muss
man nicht Unmengen Code absuchen, ob sich nicht doch irgendwo ein
Copy&Paste Tippfehler eingeschlichen hat.
Karl H. schrieb:> Charlie2000 schrieb:>>> Ich habe vieles>> einfach nur stumpf gehackt. Ich packe erst Kram in Funktionen wenns auch>> funktioniert.>> Du würdest dir viel leichter tun, wenn du diese Attitüde ablegen> würdest.
Gut ich werds mal anständig machen. Denke mal dann wird einiges
schlüssiger.
>> Soviel ich dem Datenblatt entnehmen kann, wird JEDE Byteübertragung> mit einer MAK abgeschlossen. Wo ist die bei dir zb beim Header.
StandByPulse(); // Activate the standby-pulse
StartHeaderPulse();
AKNSequence(true);
AdressPulse();
AKNSequence(false);
Nach dem Header kommt doch eine AKNSequence-Funktion? Dort wird ein MAK
gesendet. Oder was meinst du?
Nochwas - habe den Pull-Down Resi zu nem Pull-Up Resi geändert. Da ein
NoSAK ja kein low-to-high oder high-to-low ist gibt mir das einlesen ja
immer den vom Pullup manipulierten Wert wieder. Das heisst selbst wenn
was nicht stimmt und anstelle eines SAK ein NoSAK kommt - bekomme ich ja
auch nur ne 1. Ist dementsprechend ein Pull-Down sinnvoller (Auch wenn
ich bei google mehr Leute finde die PullUps nutzen) ? Denn somit wäre
ich wenns schief geht mit ner "0" bedient und könnte damit eher sicher
stellen das was nicht funktioniert hat.
gruß Charlie
Charlie2000 schrieb:> Nach dem Header kommt doch eine AKNSequence-Funktion? Dort wird ein MAK> gesendet. Oder was meinst du?
Das man in deinem Code vor lauter digitalWrite's nichts anderes mehr
sieht.
1
if(pinState=PINSTOUT){pinMode(BUSPIN,INPUT);pinState=PINSTIN;}// Set bus pin to input // Set pinState global to Input
2
delayMicroseconds(TE/2);// Half-Bit-Period
3
Serial.println(digitalRead(BUSPIN));// Read SAK
4
delayMicroseconds(TE/2);// Half-Bit-Period
das klappt aber so nicht.
Theoretisch (wenn die Anweisungen mehr oder weniger in 0 Zeit ablaufen
würden), hättest du dich mit dem delay auf genau die Umschaltflanke
'positioniert'. Ob du den Pin dann als Low oder als High einliest, ist
mehr oder weniger Zufall und hängt davon ab, in welcher Femtosekunde du
nachsiehst.
Du willst wissen, ob es einen Low-High Übergang einen High-Low Übergang
oder irgendwas anderes gab.
Dazu siehst du (nach Stabilisierung der Leitung, zb nach 1/3 der Bitzeit
)sofort nach, wartest dann zb 2/3 der Bitzeit, zumindest aber so lange
bis die Flanke auf jeden Fall schon durch sein müsste, wenn es eine gab,
und siehst nochmal nach. Aus dem Vergleich der beiden male nachsehen
kannst du erschliessen, ob da eine Flanke war und wenn ja welche.
1
Wenn 1. Mal nachsehen 2. mal nachsehen -> Schlussfolgerung
2
3
Low Low keine Flanke, Pin durchgehend low
4
Low High steigende Flanke
5
High Low fallende Flanke
6
High High keine Flanke, Pin durchgehend High
Du willst also den Pinzustand, zu diesen Zeitpunkten wissen
1
Begin der
2
Bitzeit
3
v
4
------|--------+
5
|
6
|
7
+-------|--
8
^
9
Ende der Bitzeit
10
11
^ ^
12
| |
13
Hier, zu diesen Bitzeiten siehst du dir
14
den Eingang an. Weit weg von den Flanken an denen der
15
Baustein den Pegel umschalten könnte und es daher
16
auf Milliardstel Sekunden darauf ankommen würde
17
wer schneller ist: dein Programm oder der Baustein.
18
19
20
Du willst aber den Eingangspin *NICHT* zu diesen
21
22
^ ^ ^
23
| | |
24
25
Zeitpunkten abfragen. Denn zu diesen Zeitpunkten läufst du
26
Gefahr, dass just in diesem Moment der Baustein den Pin
...Wow...
Kann man dich irgendwie mieten? Hab selten so gute und schlüssige
Erklärungen gesehen O_o
Danke Dir !
Ich werde erstmal alles gesagte anwenden und mit einem perfekt
funktioniereden Code wiederkehren (...also niemals) ;)
Danke Allen für die Hilfe!
Ich nerve jetzt erstmal nicht und bastel dran rum :)
Charlie2000 schrieb:> Nochwas - habe den Pull-Down Resi zu nem Pull-Up Resi geändert. Da ein> NoSAK ja kein low-to-high oder high-to-low ist gibt mir das einlesen ja> immer den vom Pullup manipulierten Wert wieder. Das heisst selbst wenn> was nicht stimmt und anstelle eines SAK ein NoSAK kommt - bekomme ich ja> auch nur ne 1. Ist dementsprechend ein Pull-Down sinnvoller (Auch wenn> ich bei google mehr Leute finde die PullUps nutzen) ?
Ist völlig wurscht.
Denn der Hersteller hat mitgedacht
Entweder du kriegst in der Antwortzeit eine Flanke auf deinem Eingang
(dann muss das auch eine steigende Flanke sein) oder du kriegst eben
keine. Ob der Eingangspin dann die ganze Zeit auf 0 oder die ganze Zeit
auf 1 war spielt keine Rolle: keine Flanke ist das Zeichen für NoSAK
Edit: Im Datenblatt steht:
A NoSAK is defined as any sequence that is not a valid SAK
d.h. theoretisch könnte es eine Flanke geben, nur dass das dann eine
fallende Flanke wäre und keine steigende. Ob der Baustein das auch
generieren kann, steht auf einem anderen Blatt. Für dich aber gilt: Wenn
in der Antwortzeit eine Flanke detektiert wird UND das eine steigende
Flanke ist, dann hast du einen SAK. In allen anderen Fällen hast du
einen NoSAK
Karl H. schrieb:> Ist völlig wurscht.
D.h. ganz wurscht ist es nicht.
Nehmen wir den Fall, dass am Bus überhaupt kein Baustein angeschlossen
ist, der Pullup aber da ist und es aus irgendeinem Grund Kapazitäten am
Bus gibt.
D.h. wenn dein Code den Pin auf 0 zieht, dann wird der Pullup eine
gewisse Zeit brauchen um die Leitung wieder auf High zu ziehen. Wenn nun
die Zeitkonstante dieses Vorgangs lang genug ist, dann könnte man das
mit einer steigenden Flanke verwechseln. Der Code detektiert einen SAK
wo keiner ist.
Hat man umgekehrt einen Pulldown (und wieder die Kapazität), dann könnte
es passieren, dass die letzte Aktion ausgabeseitig die war, dass die
Leitung auf 1 gezogen wurde. So weit so gut. Auch hier braucht dann der
Pulldown eine gewisse Zeit um die Leitung wieder auf 0 zu bringen. Aber:
eine 1->0 Flanke ist kein gültiger SAK
D.h. wenn ein Baustein angeschlossen ist, dann ist es egal
Wenn kein Baustein angeschlossen ist UND der Mond richtig steht, dann
könnte es mit einem Pullup zu Fehlinterpretation kommen, mit einem
Pulldown aber nicht.
Hallo nochmal!
Habe nun den Code abgewandelt - er ist nun fein lesbar. Ich habe
abermals drüber geschaut und bin mir eigentlich sehr sicher, dass es nun
funktionieren müsste. Insofern das Problem nicht woanders liegt.
Leider bekomme ich nur NoSAK Signale zurück. Das Adress Polling versagt
somit. Auch bei der Device Adresse bin ich mir sicher - welche bei dem
Prefix Nibble 0101 für EEPROMS und 0000 für das default hard-wired
adress Feld liegt.
Hier nochmal der Versuch den ich unternehme als Screenshot
http://puu.sh/jdoZg/f3ce2d8e1d.png
Address Polling ist, denke ich, die beste Art erst einmal zu debuggen
und zu schauen ob ich überhaupt zum EEPROM durchstoßen kann.
Der Code der dank Karl Heinz weitaus lesbarer geworden ist!
Also wie gesagt ich bekomme kein anständiges Feedback vom EEPROM und
mein großes Problem ist halt, dass ich nicht anständig nach dem Fehler
debuggen kann.
Ich hab mir nicht das ganze Datenblatt angeschaut, aber das sieht
äußerst komplex aus.
Im Gegensatz zu anderen bidirektionalen Bussen (1-Wire, I2C) muß eine
extra Richtungsumschaltung erfolgen und ich hab nicht rausgefunden, wann
genau.
Es scheint auch kein festes Timing zu geben, sondern der Slave muß sich
erst an den Master adaptieren oder umgekehrt?
Da ist ja USB fast noch einfacher.
Hey!
Also ich habe mir das UNI/O Bus Datenblatt zweimal komplett durchgelesen
- wo erkennst du denn das mit der Richtungsumschaltung? Oder meinst du
das Einlesen des SAK (Slave Aknowledge Bit) ? Also das ich ab der Stelle
einlesen anstatt ausgeben muss?
Ein festes Timing gibt es auch nicht. Via Start Header Pulse
synchronisiert der Slave mit dem Master über ein Byte (0101 0101) dort
holt sich der Slave den Takt raus. Ich denke das meintest du?
Hi,
ich spiele auch gerade mit einem 11AA02E48T EEPROM von Microchip rum das
diese UNI/O Schnittstelle hat.
Mein Ziel ist einfach die ID aus dem Chip auszulesen.
Beim Code habe ich im wesentlichen die Funktionen benutzt die oben
stehen, angepasst AVR-GCC und PORTA5 als I/O.
Am anfang meines Programmes habe ich diese Sequenz:
1
DDRA|=(1<<PA5);// PA5 zum Ausgang machen
2
PORTA&=~(1<<PA5);
3
_delay_us(10);
4
5
StandByPulse();
6
7
_delay_us(TSS);
8
9
StartHeader();
10
MAK();
11
12
DDRA&=~(1<<PA5);// PA5 zum Eingang machen
13
PORTA&=~(1<<PA5);
14
_delay_us(50);
15
16
StartAddress();
17
NoMAK();
18
19
DDRA&=~(1<<PA5);// PA5 zum Eingang machen
20
PORTA&=~(1<<PA5);
21
_delay_us(50);
Das Ergebnis sieht man an den beiden Scope-Bildern.
Was vom Controller ausgeht ist alles da, Low-High Wechsel am Anfang,
600µs Standby-Puls, THDR Low-Puls, Start-Header, MAK.
Nur, da wo mittendrin der Pegel wegschmiert, das ist die Stelle an der
der Pin auf Eingang umgeschaltet wird, sollte da nicht der Chip mit
einem Impuls auf der Leitung antworten? NoSAK?
Und am Ende fehlt auch ein Impuls vom EEPROM - SAK?
Was mache ich falsch?
Alternativ könnte auch der Chip kaputt sein, aber der ist korrekt
eingelötet und die Pins haben auch wirklich Kontakt und auch zum
richtigen I/O Pin.
Über die Bus-Leitung bekommt man den Chip auch nicht kaputt, der ist
intern Strom-begrenzt.