Forum: Mikrocontroller und Digitale Elektronik Bit-Banging UNI/O-Bus EEPROM mit Arduino-Uno [Fehlschlag]


von Charlie2000 (Gast)


Angehängte Dateien:

Lesenswert?

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
1
#include <TimerOne.h>
2
3
#define TSTBY 605 // StandBy-Pulse 600µs + 5µs offset
4
#define TSS 15 // StartHeader setup time 10µs + 5µs offset
5
#define THDR 10 // StartHeader low pulse time 5µs + 5µs offset
6
#define TE 15 // BitPeriod time 10µs + 5µs offset
7
8
#define BUSPIN 9 // Pin to communicate with set to 9
9
#define PINSTOUT 1 // Pin State Output
10
#define PINSTIN 0  // Pin State Input
11
12
bool pinState = PINSTOUT; // pinState global
13
14
void setup()
15
{
16
  Serial.begin(9600);
17
18
  StandByPulse(); // Activate the standby-pulse
19
  StartHeaderPulse();
20
  AKNSequence(true);
21
  AdressPulse();
22
  AKNSequence(false);
23
}
24
25
void loop()
26
{
27
28
  /* add main program code here */
29
30
}
31
32
void StandByPulse()
33
{
34
  if (pinState != PINSTOUT){ pinMode(BUSPIN, OUTPUT); pinState = PINSTOUT; }  // Set bus pin to output // Set pinState global to output 
35
36
  digitalWrite(BUSPIN, HIGH); // Write high digital signal
37
  delayMicroseconds(TSTBY); // let standby-pulse time pass
38
}
39
40
void StartHeaderPulse()
41
{
42
  digitalWrite(BUSPIN, LOW); // High to Low transition for THDR
43
  delayMicroseconds(THDR); // THDR Time
44
45
  if (pinState != PINSTOUT){ pinMode(BUSPIN, OUTPUT); pinState = PINSTOUT; }  // Set bus pin to output // Set pinState global to output 
46
47
  // Low to High transition 
48
  digitalWrite(BUSPIN, HIGH); // High to Low transition escaping THDR pulse
49
50
  /* Bit Period*/
51
  delayMicroseconds(TE / 2); // Half-Bit-Period
52
  digitalWrite(BUSPIN, LOW); // Send "0"
53
  delayMicroseconds(TE / 2); // Half-Bit-Period
54
  /* Bit Period*/
55
  delayMicroseconds(TE / 2); // Half-Bit-Period
56
  digitalWrite(BUSPIN, HIGH); // Send "1"
57
  delayMicroseconds(TE / 2); // Half-Bit-Period
58
  /* Bit Period*/
59
  delayMicroseconds(TE / 2); // Half-Bit-Period
60
  digitalWrite(BUSPIN, LOW); // Send "0"
61
  delayMicroseconds(TE / 2); // Half-Bit-Period
62
  /* Bit Period*/
63
  delayMicroseconds(TE / 2); // Half-Bit-Period
64
  digitalWrite(BUSPIN, HIGH); // Send "1"
65
  delayMicroseconds(TE / 2); // Half-Bit-Period
66
  /* Bit Period*/
67
  delayMicroseconds(TE / 2); // Half-Bit-Period
68
  digitalWrite(BUSPIN, LOW); // Send "0"
69
  delayMicroseconds(TE / 2); // Half-Bit-Period
70
  /* Bit Period*/
71
  delayMicroseconds(TE / 2); // Half-Bit-Period
72
  digitalWrite(BUSPIN, HIGH); // Send "1"
73
  delayMicroseconds(TE / 2); // Half-Bit-Period
74
  /* Bit Period*/
75
  delayMicroseconds(TE / 2); // Half-Bit-Period
76
  digitalWrite(BUSPIN, LOW); // Send "0"
77
  delayMicroseconds(TE / 2); // Half-Bit-Period
78
  /* Bit Period*/
79
  delayMicroseconds(TE / 2); // Half-Bit-Period
80
  digitalWrite(BUSPIN, HIGH); // Send "1"
81
  delayMicroseconds(TE / 2); // Half-Bit-Period
82
  /* Bit Period*/
83
}
84
85
void AdressPulse()
86
{
87
  if (pinState != PINSTOUT){ pinMode(BUSPIN, OUTPUT); pinState = PINSTOUT; }  // Set bus pin to output // Set pinState global to output 
88
89
  // Low Transiton cause of NoSAK
90
  digitalWrite(BUSPIN, LOW); // Write high digital signal
91
92
  /* Bit Period*/
93
  delayMicroseconds(TE / 2); // Half-Bit-Period
94
  digitalWrite(BUSPIN, HIGH); // Send "1"
95
  delayMicroseconds(TE / 2); // Half-Bit-Period
96
  /* Bit Period*/
97
  delayMicroseconds(TE / 2); // Half-Bit-Period
98
  digitalWrite(BUSPIN, LOW); // Send "0"
99
  delayMicroseconds(TE / 2); // Half-Bit-Period
100
  /* Bit Period*/
101
  delayMicroseconds(TE / 2); // Half-Bit-Period
102
  digitalWrite(BUSPIN, HIGH); // Send "1"
103
  delayMicroseconds(TE / 2); // Half-Bit-Period
104
  /* Bit Period*/
105
  delayMicroseconds(TE / 2); // Half-Bit-Period
106
  digitalWrite(BUSPIN, LOW); // Send "0"
107
  delayMicroseconds(TE / 2); // Half-Bit-Period
108
109
  digitalWrite(BUSPIN, HIGH); // High transition to be able to make a High-To-Low again
110
  /* Bit Period*/
111
  delayMicroseconds(TE / 2); // Half-Bit-Period
112
  digitalWrite(BUSPIN, LOW); // Send "0"
113
  delayMicroseconds(TE / 2); // Half-Bit-Period
114
115
  digitalWrite(BUSPIN, HIGH); // High transition to be able to make a High-To-Low again
116
  /* Bit Period*/
117
  delayMicroseconds(TE / 2); // Half-Bit-Period
118
  digitalWrite(BUSPIN, LOW); // Send "0"
119
  delayMicroseconds(TE / 2); // Half-Bit-Period
120
121
  digitalWrite(BUSPIN, HIGH); // High transition to be able to make a High-To-Low again
122
  /* Bit Period*/
123
  delayMicroseconds(TE / 2); // Half-Bit-Period
124
  digitalWrite(BUSPIN, LOW); // Send "0"
125
  delayMicroseconds(TE / 2); // Half-Bit-Period
126
127
  digitalWrite(BUSPIN, HIGH); // High transition to be able to make a High-To-Low again
128
  /* Bit Period*/
129
  delayMicroseconds(TE / 2); // Half-Bit-Period
130
  digitalWrite(BUSPIN, LOW); // Send "0"
131
  delayMicroseconds(TE / 2); // Half-Bit-Period
132
  /* Bit Period*/
133
}
134
135
void AKNSequence(bool isMAK)
136
{
137
  if (pinState != PINSTOUT){ pinMode(BUSPIN, OUTPUT); pinState = PINSTOUT; }  // Set bus pin to output // Set pinState global to output 
138
  if (isMAK)
139
  {
140
    /* MAK */
141
    digitalWrite(BUSPIN, LOW); // Write low digital signal
142
    delayMicroseconds(TE / 2); // Half-Bit-Period
143
    digitalWrite(BUSPIN, HIGH); // Write high digital signal
144
    delayMicroseconds(TE / 2); // Half-Bit-Period
145
    /* MAK */
146
  }
147
  else if (!isMAK)
148
  {
149
    /* noMAK */
150
    digitalWrite(BUSPIN, HIGH); // Write high digital signal
151
    delayMicroseconds(TE / 2); // Half-Bit-Period
152
    digitalWrite(BUSPIN, LOW); // Write low digital signal
153
    delayMicroseconds(TE / 2); // Half-Bit-Period
154
    /* noMAK */
155
  }
156
157
  if (pinState = PINSTOUT){ pinMode(BUSPIN, INPUT); pinState = PINSTIN; }  // Set bus pin to input // Set pinState global to Input 
158
  delayMicroseconds(TE / 2); // Half-Bit-Period
159
  Serial.println(digitalRead(BUSPIN)); // Read SAK
160
  delayMicroseconds(TE / 2); // Half-Bit-Period
161
}

von Dirk D. (dicky_d)


Lesenswert?

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?

von Jürgen (Gast)


Lesenswert?

Charlie2000 schrieb:
> der SCIO geht über einen Pullup
> zum Digital Pin "9" des Arduino Uno

eher ein pulldown

von franz_l (Gast)


Lesenswert?

neuerdings schraubt man die arduino boards also auf holzplatten :0
das steckbrett gibts auch als shield!

von Charlie2000 (Gast)


Lesenswert?

Jürgen schrieb:
> Charlie2000 schrieb:
>> der SCIO geht über einen Pullup
>> zum Digital Pin "9" des Arduino Uno
>
> eher ein pulldown

Ups verschrieben :)

von Charlie2000 (Gast)


Lesenswert?

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?

von Charlie2000 (Gast)


Lesenswert?

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 :(

von Karl H. (kbuchegg)


Lesenswert?

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.
1
void Zero()
2
{
3
  digitalWrite( BUSPIN, HIGH );
4
  delayMicroseconds(TE / 2);
5
  digitalWrite( BUSPIN, LOW );
6
  delayMicroseconds(TE / 2);
7
}
8
9
void One()
10
{
11
  digitalWrite( BUSPIN, LOW );
12
  delayMicroseconds(TE / 2);
13
  digitalWrite( BUSPIN, HIGH );
14
  delayMicroseconds(TE / 2);
15
}
16
17
uint8_t Mak()
18
{
19
  // ein Mak besteht aus einer logischen 1
20
  // woraufhin der Slave ebenfalls (hoffentlich)
21
  // mit einer logischen 1 antwortet
22
  One();
23
24
  pinMode(BUSPIN, INPUT);
25
26
27
  .... hier auswerten, ob der Slave eine 1 geschickt hat oder nicht
28
  .... -> Dein Bier.
29
30
  // Rückgabewert ist das, was der Slave geantwortet hat
31
  // 1 = SAK
32
  // 0 = NoSak
33
34
  return Answer;
35
}
36
37
void TransmitByte( uint8_t value )
38
{
39
  if( value & 0x80 ) One(); else Zero();
40
  if( value & 0x40 ) One(); else Zero();
41
  if( value & 0x20 ) One(); else Zero();
42
  if( value & 0x10 ) One(); else Zero();
43
  if( value & 0x08 ) One(); else Zero();
44
  if( value & 0x04 ) One(); else Zero();
45
  if( value & 0x02 ) One(); else Zero();
46
  if( value & 0x01 ) One(); else Zero();
47
}
48
49
void StartHeader()
50
{
51
  pinMode(BUSPIN, OUTPUT);
52
53
  digitalWrite(BUSPIN, LOW); 
54
  delayMicroseconds(THDR);
55
56
  TransmitByte( 0b01010101 );
57
58
  if( Mak() != 0 ) {
59
    .... mach was. Der Slave hat nicht wie erwartet geantwortet
60
  }
61
}
62
63
void StartAddress()
64
{
65
  TransmitByte( 0b10100000 );
66
67
  if( Mak() != 1 ) {
68
    .... mach was. Der Slave hat nicht wie erwartet geantwortet
69
  }
70
}


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.

: Bearbeitet durch User
von Charlie2000 (Gast)


Lesenswert?

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?

von Charlie2000 (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
27
    umschaltet.

: Bearbeitet durch User
von Charlie2000 (Gast)


Lesenswert?

...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 :)

von Karl H. (kbuchegg)


Lesenswert?

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
1
...
2
  pinMode(BUSPIN, INPUT);
3
4
  delayMicroseconds(TE / 3);
5
  firstSample = digitalRead( BUSPIN );
6
  delayMicroseconds(TE / 3);
7
  scndSample = digitalRead( BUSPIN );
8
  delayMicroseconds(TE / 3);
9
10
  if( firstSample == LOW && scndSample == HIGH )
11
    wir haben einen SAK
12
  else
13
    wir haben einen NoSAK

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Charlie2000 (Gast)


Lesenswert?

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.
1
#include <TimerOne.h>
2
3
#define TSTBY 605 // StandBy-Pulse 600µs + 5µs offset
4
#define TSS 15 // StartHeader setup time 10µs + 5µs offset
5
#define THDR 10 // StartHeader low pulse time 5µs + 5µs offset
6
#define TE 15 // BitPeriod time 10µs + 5µs offset
7
8
#define BUSPIN 9 // Pin to communicate with set to 9
9
10
int fstEdgeSample = 0;
11
int sndEdgeSample = 0;
12
13
void setup()
14
{
15
  Serial.begin(9600);
16
  pinMode(BUSPIN, OUTPUT);
17
  digitalWrite(BUSPIN, LOW);
18
  StandByPulse();
19
  StartHeaderPulse();
20
  MAK();
21
  if (isSAK()) Serial.println("SAK"); else Serial.println("NoSAK");
22
  AdressPulse();
23
  NoMAK();
24
  if (isSAK()) Serial.println("SAK"); else Serial.println("NoSAK");
25
}
26
27
void loop()
28
{
29
30
  /* add main program code here */
31
32
}
33
34
void BitOne()
35
{
36
  digitalWrite(BUSPIN, LOW);
37
  delayMicroseconds(TE / 2); 
38
  digitalWrite(BUSPIN, HIGH);
39
  delayMicroseconds(TE / 2); 
40
}
41
42
void BitZero()
43
{
44
  digitalWrite(BUSPIN, HIGH);
45
  delayMicroseconds(TE / 2);
46
  digitalWrite(BUSPIN, LOW);
47
  delayMicroseconds(TE / 2);
48
}
49
50
void MAK()
51
{
52
  BitOne();
53
}
54
55
void NoMAK()
56
{
57
  BitZero();
58
}
59
60
void TransmitByte(uint8_t value)
61
{
62
  if (value & 0x80) BitOne(); else BitZero();
63
  if (value & 0x40) BitOne(); else BitZero();
64
  if (value & 0x20) BitOne(); else BitZero();
65
  if (value & 0x10) BitOne(); else BitZero();
66
  if (value & 0x08) BitOne(); else BitZero();
67
  if (value & 0x04) BitOne(); else BitZero();
68
  if (value & 0x02) BitOne(); else BitZero();
69
  if (value & 0x01) BitOne(); else BitZero();
70
}
71
72
73
void StandByPulse()
74
{
75
  digitalWrite(BUSPIN, HIGH); // Write high digital signal
76
  delayMicroseconds(TSTBY); // let standby-pulse time pass
77
}
78
79
void StartHeaderPulse()
80
{
81
  digitalWrite(BUSPIN, LOW); // High to Low transition for THDR
82
  delayMicroseconds(THDR); // THDR Time
83
84
  TransmitByte(0b01010101);
85
}
86
87
void AdressPulse()
88
{
89
  TransmitByte(0b10100000);
90
}
91
92
bool isSAK()
93
{
94
  pinMode(BUSPIN, INPUT);
95
  delayMicroseconds(TE / 4); // Trimmed-Bit-Period
96
  fstEdgeSample = digitalRead(BUSPIN);
97
  delayMicroseconds(TE / 2); // Trimmed-Bit-Period
98
  sndEdgeSample = digitalRead(BUSPIN);
99
  delayMicroseconds(TE / 4); // Trimmed-Bit-Period
100
  pinMode(BUSPIN, OUTPUT);
101
102
  if (fstEdgeSample == LOW && sndEdgeSample == HIGH)
103
    return true;
104
  else
105
    return false;
106
}

von Peter D. (peda)


Lesenswert?

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.

von Charlie2000 (Gast)


Lesenswert?

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?

von Rudolph (Gast)


Angehängte Dateien:

Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.