Hallo,
ich muss zwischen den F1611 und den F4250 eine I2C Kommunikation
realisieren. Bedingt durch die Architektur soll der F4250 als I2C Slave
agieren. Da der F4250 aber keine hardwareseitige Implementierung hat,
muss es also durch Software realisiert werden.
Jetzt die Frage, hat jemand von euch schon mal einen I2C Slave durch
Software realisiert? Ich denke, dass dies nicht so einfach ist.
In einem anderen Thread habe ich schon mal dieselbe Frage gefunden. Hier
wurde vorgeschlagen, die SCL Leitung am Slave mit Interrupt zu handeln
und dann den Portpin entsprechen zu lesen oder zu setzen.
Mich interresiert aber, ob dies so sinnvoll ist und ob es wirklich schon
jemand in der Praxis zum Laufen gebracht hat. (Vielleicht mit ein paar
Codezeilen)
Danke Nobbie
Hallo,
ich habe den I2C Slave jetzt softwareseitig implementiert und das Lesen
und Schreiben funktioniert beim ersten Byte sauber.
Ich habe das mit dem Osziloskop getestet.
Jetzt habe ich das Problem, wenn ich mehr als 1 Datenbyte senden/lesen
möchte, geht garnichts mehr. Interressant ist, dass sich der SCL Clock
nachdem senden/lesen des ersten Datenbytes ändert (von 30kHz auf 80kHz).
Ich habe keine Ahnung warum. Wie gesagt, das Timing zwischen dem
F1611(Master) und dem F4250(Slave) funktioniert beim ersten Datenbyte
einwandfrei.
Ich poste mal kurz meinen Code. Ich bin völlig ratlos und verzweifelt,
warum sich auf einmal der SCL ändert.
Initialisierung I2C F1611 (Master)
1
voidinit_I2C(void)
2
{
3
unsignedcharadr;
4
adr=0x0048;
5
6
7
P3SEL&=~0x30;// P3.4,5 = USART0 TXD/RXD, UART0 NOT SELECT
8
P3SEL|=0x0A;// P3.1,3 = I2C, Assign I2C pins to module
9
10
U0CTL|=SWRST;
11
12
U0CTL|=I2C+SYNC;// Switch USART0 to I2C mode
13
U0CTL&=~I2CEN;// clear I2CEN bit => necessary to re-configure I2C module
case4:// clear I2CEN bit => necessary to re-configure I2C module
8
9
break;// No Acknowledge
10
11
case6:break;// Own Address
12
case8:
13
break;// Register Access Ready
14
case10:
15
RXData=I2CDRB;
16
17
break;// Receive Ready
18
case12:// Transmit Ready
19
I2CDRB=TXData;// Load I2CDRB and increment
20
21
break;
22
case14:break;// General Call
23
case16:
24
break;// Start Condition
25
}
main F1611 (Master)
1
voidmain(void)
2
{
3
volatileunsignedinti;
4
WDTCTL=WDTPW+WDTHOLD;
5
BCSCTL1=0x07;
6
BCSCTL2|=SELS;// SMCLK = XT2 (8 MHz)
7
8
//Port3 I2C und USARTs
9
P3SEL=0xFF;// UART and I2C pin option select
10
P3DIR=0xFF;// set port 3 to output direction
11
init_I2C();
12
13
U0CTL|=MST;// Master mode
14
I2CTCTL|=I2CSTT+I2CSTP+I2CTRX;// Initiate TX
15
while(I2CBB&I2CDCTL);
16
17
18
U0CTL|=MST;
19
I2CTCTL&=~I2CTRX;// Clear transmit bit
20
I2CTCTL|=I2CSTT+I2CSTP;// Restart - read from slave
Ich glaube, dass es mit dem Master zusammenhängt. Sobald ich diesem
nähmlich wieder resete, antwortet der Softwareslave(F4250) ohne
Probleme.
Was kann ich machen??????
Danke
Mal ne Frage, was kommt denn in Deinem Programm im main nach der letzten
Zeile:
I2CTCTL |= I2CSTT + I2CSTP; // Restart - read from slave
???
Poste mal bitte die komplette main-Funktion
Hallo,
erst mal danke für die Antworten.
Wie bereits gesagt, ist der Slave als softwareseitig implementiert.
Am Port sind P1.0 und P1.1 beim F4250 als I2C konfiguriert. Da der F4250
keine hardwaresetige Unterstützung für I2C hat, muss ich also eine
Softwarelösung realisieren.
Die Pins beim F4250 habe ich über Interrupts getriggert, um so die
Start, Stopcondition zu erkennen und die jeweiligen Daten- oder
Adressbits zu lesen oder zu schreiben.
Das funktioniert soweit auch alles, solange ich vom Master aus nur ein
Datenbyte lesen/schreiben möchte. Das habe ich mit dem Oszi nachgeprüft.
Das Handling funktioniert sauber. Die ACKs werden mit den entsprechenden
Taktzyklen sauber gesetzt und nach der erfolgreichen Übertragung (19.
SCL Takt) wird die StOP Condition sauber erkannt.
Wenn ich jetzt aber mehrere Datenbytes lesen oder schreiben möchte,
"bricht alles zusammen". Der SCL Takt, der ja vom Master vorgegeben
wird, verändert sich auf einmal(wird schneller).
Wie bereits im vorherigen Beitrag beschrieben, will ich statisch in der
main ein Byte schreiben und ein Byte lesen.
Ich habe das Gefühl, dass das hardwareseitige I2C handling im master
nach dem ersten Datenbyte völlig zusammenbricht. Ich weiß aber nicht
warum. Ich suche und suche und komme nicht zur Lösung. Bin echt am
verzweifeln. Sobald ich den Master resete, kann ich wieder ordnungsgemäß
ein Datenbyte übertragen, bevor die Kommunikation wieder zusammenbricht.
Danke
Nobbie
Hallo,
na, kannst du auch nicht von der Arbeit lassen??? ;-)
also hier jetz moch einmal die komplette main
1
voidmain(void)
2
{
3
4
volatileunsignedinti;
5
WDTCTL=WDTPW+WDTHOLD;
6
BCSCTL1=0x07;// XT2on, max RSEL (8 MHz)
7
BCSCTL2=SELS;// SMCLK = XT2 (8 MHz)
8
9
//Port3 I2C und USARTs
10
P3SEL=0xFF;// UART and I2C pin option select
11
P3DIR=0xFF;// set port 3 to output direction
12
init_I2C();
13
14
15
_EINT();// enable interrupts
16
17
18
//I2CNDAT = 0x01;
19
TXData=0x00;
20
for(i=0;i<2;i++)
21
{
22
23
U0CTL|=MST;// Master mode
24
I2CTCTL|=I2CSTT+I2CTRX+I2CSTP;// Initiate TX
25
while((I2CTCTL&I2CSTP)==I2CSTP);// wait until the STOP
26
// condition bit is reset
27
//while (I2CBB & I2CDCTL);
28
TXData++;
29
}
Innerhalb der main will ich zweimal ein Datenbate zum Slave senden. Da
im Slave momentan nur die 1 Byte Variante mit START/STOP Bedingung
implementiert ist, muss ich jedes einzelne Datenbyte mit START/STOP
Bedingung übertragen. Ich habe das Gefühl, dass es auf Masterseite
Schwierigkeiten beim hardwareseitigen Handling(Stopbedingung) des I2C
workflowes gibt.
Ich kann mir aber nicht erklären, warum. Das Zusammenspiel aus SCL/SDA
zwischen Master/Slave ist absolut konform mit der I2C-Spec von Phillips.
Ich könnte mir es höchstens mit einem Timingproblem auf Seiten des
Masters vorstellen.
_ _ _ _ _
SDA || |
... _ _ _ _ _ _ _ _ _ _||_ _ _ _ _ |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _
SCL | | | | | | |
... _| |_ _ _| |_ _ _| |_|
Oben habe ich dir mal die letzten Signalverläufe dargestellt. Der eine
Spike auf der SDA Leitung ist von der Busübergabe für das ACK.
Interessant ist, dass nach dem ACK der Zeitzyklus wo SCL LOW ist, viel
geringer ist. Nichts desto trotz, ist aber die STOP condition sauber zu
erkennen.
Hast du noch eine Idee?
Werde morgen mal die Masterplatine tauschen und sehen was dann passiert.
Zum jetzigen Zeitpunkt bin ich jedenfalls absolut wissenslos, was es
noch sein könnte.
Gruss Nobbie
Hiho,
erstmal eine einfache Idee. Nachdem bei Dir i==2 geworden ist,
verschwindet Dein Programm im Nirvana (while (1) im main hat manchmal
seinen Sinn...).
Es sei denn, in Deinem main kommt noch irgendwas, was ich noch nicht
kenne.
Zum zweiten,probier doch einmal den TI-Code aus (siehe auch früher
genanntes Beispiel):
U0CTL |= MST; // Master mode
I2CTCTL |= I2CSTT; // Initiate transfer
while (1)
{
if (i == 6)
{
i = 0;
TestData++;
I2CTCTL |= I2CSTP;
while (I2CTCTL & I2CSTP); // Check Stop Condition
U0CTL |= MST;
I2CTCTL |= I2CSTT;
}
i++;
_BIS_SR(CPUOFF); // Enter LPM0
P1OUT |= 0x01; // Set P1.0
if (TestData++ != RXData) break; // Test received data
P1OUT &= ~0x01; // Clear P1.0
}
while (1); // Trap CPU
}
Bevor Du am MSP und Deiner Hardware zweifelst.
Hallo allerseits,
es scheint jetzt doch an der Masterhardware zu liegen. Habe mitr noch
einmal die Eratasheets des 1611 angeschaut und die relevanten Bugs
durchgelesen. Anschließend habe ich den MSP mit einem Atmel ausgetauscht
und siehe da, der F4250 Software Slave "schnurt wie ein Kätzchen".
Es lag anscheinend wirklich daran, dass die Statemachine im master nicht
sauber funktioniert hat und nach dem ersten Datenbyte resetet hat.
Schade um das Wochenende ;-(
gruss