Hallo,
ich habe mir das Launchpad mit dem MSP430G2231 von TI besorgt, um damit
über I2C Schnittstelle andere Chips zu steuern. Habe dazu unten
stehenden Originalcode von TI meinen bedürfnissen angepasst, was leider
nicht geklappt hat. Daher dachte ich ich, dass der Fehler bei mir und
meinen Änderungen im Originalcode liegt und dachte mir, dass ich erst
mal mit dem Originalcode versuche, was auch nicht funktioniert hat.
USICNT|=USIIFGCC;// Disable automatic clear control
251
USICTL0&=~USISWRST;// Enable USI
252
USICTL1&=~USIIFG;// Clear pending flag
253
_EINT();
254
255
}
256
257
voidMaster_Transmit(void){
258
Setup_USI_Master_TX();
259
USICTL1|=USIIFG;// Set flag and start communication
260
LPM0;// CPU off, await USI interrupt
261
__delay_cycles(10000);// Delay between comm cycles
262
}
263
voidMaster_Recieve(void){
264
Setup_USI_Master_RX();
265
USICTL1|=USIIFG;// Set flag and start communication
266
LPM0;// CPU off, await USI interrupt
267
__delay_cycles(10000);// Delay between comm cycles
268
}
Das programm bleibt zunächst einmal in der Zeile, wo ich den Watchdog
ausschalte stehen, daher dachte ich, dass es am Watchdog liegt und habe
ihn angeleassen, wo er dann ganz einfach in der nächsten Zeile
stehengeblieben ist.
Wäre toll wenn mir jemand helfen könnte.
Vielleicht schaffe ich es auch einfach nicht das Programm auf das Board
zu spielen?
Grüße
//__delay_cycles(10000); // Delay between comm cycles
Und jetzt passiert folgendes:
Das Programm kommt in Switch/Case Verzweigung rein, sagt aber, dass er
ein Ack empfangen hat, obwohl ich noch gar nichts an das Board
angeschlossen habe und es somit gar nicht möglich ist etwas zu
empfangen?
Ehrlich gesagt verstehe ich auch gar nicht wie denn überhaupt ein
Interrupt auftreten kann, um in die Switch/Case Verzweigung
einzutreten???
Also wie wird der USI Interrupt überhaupt eingeleitet (USI_TXRX) ???
Scrub schrieb:> Also wie wird der USI Interrupt überhaupt eingeleitet (USI_TXRX) ???
Ich denke mal entweder duch Pegelwechseln am Port-Pin oder durch ein TX
Interrupt, also leeres Ausgangregister.
Scrub schrieb:> Also wie wird der USI Interrupt überhaupt eingeleitet (USI_TXRX) ???
Durch das Setzen des USIIFG in Master_Transmit():
USICTL1 |= USIIFG; // Set flag and start
communication
Aha...
Jetzt mal ne blöde Frage:
Wenn ich das Programm nicht debuggen, sondern direkt auf das Board
spielen und live testen will, wie mache ich das dann? Ich habe ja hier
keinen Run button mehr?
Ich verstehe das nicht ganz. Wenn ich das Board nach dem debuggen vom
Strom gtrenne und erneut verbinde dann, dann müsste ja wie beim
debugging irgendwann auch die Error-LED leuchten, das tut sie aber
nicht?
Ja Jörg S. du hast recht, sie blitzt kurz auf.
So jetzt kann ich mein Problem vlt eingrenzen. Ich denke nämlich, dass
das Problem in der switch/case Verzweigung liegt.Wenn ich in einem Case
die Auswerte-Variable I2C_State ändere, dann denn bekommt dann reagiert
die switch Verzweigung gar nicht darauf. Sie macht der Reihe nach
weiter, es sei denn eine break Anweisung kommt, dann verlässt sie die
swicht Verzweigung komplett. Die Variable I2C_State wird aber korrekt
verändert.
Jetzt habe ich es so gemacht, dass ich switch/case Verzweigung durch if
erstzt habe und das Programm eigentlich richtig läuft, jedoch wenn es in
I2C_State==12 auf DataTX() zugreift kehrt sie halt nicht mehr wie
vorgesehen in I2C_State==10 zurück, d.h. es müsste eigentlich an dieser
Stelle noch ein Interrupt ausgelöst werden.
Hier der betroffene Teil des Codes:
1
#pragma vector = USI_VECTOR
2
__interruptvoidUSI_TXRX(void)
3
{
4
if(I2C_State==0){// Generate Start Condition & send address to slave
5
P1OUT|=0x01;// LED on: sequence start
6
Bytecount=0;
7
USISRL=0x00;// Generate Start Condition...
8
USICTL0|=USIGE+USIOE;
9
USICTL0&=~USIGE;
10
if(Transmit==1){
11
USISRL=0x90;// Address is 0x48 << 1 bit + 0 (rw)
12
}
13
if(Transmit==0){
14
USISRL=0x91;// 0x91 Address is 0x48 << 1 bit
15
// + 1 for Read
16
}
17
USICNT=(USICNT&0xE0)+0x08;// Bit counter = 8, TX Address
18
I2C_State=2;// next state: rcv address (N)Ack
19
//break;
20
}
21
22
if(I2C_State==2){// Receive Address Ack/Nack bit
23
USICTL0&=~USIOE;// SDA = input
24
USICNT|=0x01;// Bit counter=1, receive (N)Ack bit
25
I2C_State=4;// Go to next state: check (N)Ack
26
//break;
27
}
28
29
if(I2C_State==4){// Process Address Ack/Nack & handle data TX
30
if(Transmit==1){
31
USICTL0|=USIOE;// SDA = output
32
if(USISRL&0x01)// If Nack received...
33
{// Send stop...
34
USISRL=0x00;
35
USICNT|=0x01;// Bit counter=1, SCL high, SDA low
36
I2C_State=14;// Go to next state: generate Stop
37
P1OUT|=0x01;// Turn on LED: error
38
}
39
else
40
{// Ack received, TX data to slave...
41
USISRL=MST_Data++;// Load data byte
42
USICNT|=0x08;// Bit counter = 8, start TX
43
I2C_State=10;// next state: receive data (N)Ack
44
Bytecount++;
45
P1OUT&=~0x01;// Turn off LED
46
//break;
47
}
48
}
49
if(Transmit==0){
50
if(USISRL&0x01)// If Nack received
51
{// Prep Stop Condition
52
USICTL0|=USIOE;
53
USISRL=0x00;
54
USICNT|=0x01;// Bit counter= 1, SCL high, SDA low
55
I2C_State=8;// Go to next state: generate Stop
56
P1OUT|=0x01;// Turn on LED: error
57
}
58
else{Data_RX();}// Ack received
59
}
60
//break;
61
}
62
63
if(I2C_State==6){// Send Data Ack/Nack bit
64
USICTL0|=USIOE;// SDA = output
65
if(Bytecount<=number_of_bytes-2)
66
{// If this is not the last byte
67
USISRL=0x00;// Send Ack
68
P1OUT&=~0x01;// LED off
69
I2C_State=4;// Go to next state: data/rcv again
70
Bytecount++;
71
}
72
else//last byte: send NACK
73
{
74
USISRL=0xFF;// Send NAck
75
P1OUT|=0x01;// LED on: end of comm
76
I2C_State=8;// stop condition
77
}
78
USICNT|=0x01;// Bit counter = 1, send (N)Ack bit
79
//break;
80
}
81
82
if(I2C_State==8){// Prep Stop Condition
83
USICTL0|=USIOE;// SDA = output
84
USISRL=0x00;
85
USICNT|=0x01;// Bit counter= 1, SCL high, SDA low
86
I2C_State=14;// Go to next state: generate Stop
87
//break;
88
}
89
90
if(I2C_State==10){// Receive Data Ack/Nack bit
91
USICTL0&=~USIOE;// SDA = input
92
USICNT|=0x01;// Bit counter = 1, receive (N)Ack bit
93
I2C_State=12;// Go to next state: check (N)Ack
94
//break;
95
}
96
97
if(I2C_State==12){// Process Data Ack/Nack & send Stop
98
USICTL0|=USIOE;
99
if(Bytecount==number_of_bytes){// If last byte
100
USISRL=0x00;
101
102
I2C_State=14;// Go to next state: generate Stop
103
P1OUT|=0x01;
104
USICNT|=0x01;}// set count=1 to trigger next state
Bei mir läuft das Programm aus dem ersten Beitrag wenn der Jumper
zwischen P1.6 und LED2 entfernt ist.
Ich habe nur ohne Slave getestet, weiss daher nich ob die Kommunikation
wirklich funktioniert. An P1.6 und P1.7 konnte ich aber mit dem
Oszilloskop Clock und Datensignale sehen die sich regelmäßig
wiederholten.
Habe jetzt den Jumper herausgenommen und alles ist beim Alten.
Bei einer break-Anweisung verlässt er die switch-Verzweigung, wenn ich
die breaks auskommentiere dann geht er jeden case nach der Reihe durch,
Änderungen der Variable I2C_State bewirken gar nichts.
Scrub schrieb:> Komisch, was hat das denn mit dem Jumper zu tun ???
Im Beispielprogaremm wird P1.6 als I2C SDA genutztz.
Auf dem Launchpad ist P1.6 über den Jumper mit LED2 verbunden.
Mit gesetztem Jumper kann ich weder an P1.6 noch an P1.7 irgendwelche
Signale beobachten, ohne Jumper wird regelmäßig eine Datenübetragung
gestartet die aber wegen des fehlenden Slaves abbricht.
Ich kenn mich mit dem I2C Protokoll kaum aus, aber die über den Jumper
angeschlossene LED scheint zu stören. Wenn ich die Zeit dafür finde
versuche ich morgen mal ein zweites Launchpad als I2C Slave mit dem I2C
Master zu verbinden.
Cool Danke.
Bei mir sagt er ja, dass er ein ACK, also eine Bestätigung vom Slave,
bekommen hat, obwohl kein Slave angeschlossen ist. Aber, ich glaube das
liegt daran, dass der Pin einfach offen ist und in der Luft hängt.
Ist es nicht so, dass bei einer break-Anweisung die switch_Verzweigung
komplett verlassen wird ???
Ohne angeschlossenen Slave bekomm ich nie ein ACK, ich lande immer im
"If Nack received.." Teil von case 4.
Der Pin hängt nich in der Luft weil für die SDA und SCL Pis die internen
Pullups aktiviert sind.
Und ja, mit einem break wird die switch-Verzweigung verlassen. Der
I2C_State wird für den nächsten Interrupt gespeichert.
Mit dem TI-Beispielprogramm msp430g2x21_usi_12.c auf einem Launchpad als
Master und einem zweiten Launchpad mit msp430g2x21_usi_15.c als Slave
scheint die Kommunikation zu funktionieren. Ich hatte erst einige
Probleme weil die Beschreibung der Verbindung in den TI-Beispielen
falsch ist.
P1.6 des Masters muss mit P1.6 des Slaves verbunden werden und P1.7 mit
P1.7.
Stefan schrieb:> Und ja, mit einem break wird die switch-Verzweigung verlassen. Der> I2C_State wird für den nächsten Interrupt gespeichert.
Dann muss es doch aber so sein, dass zum Beispiel nach jedem case durch
das break die switch-Verzweigung verlassen wird und dann durch einen
erneuten Interrupt die, je nach I2C_State, darauf folgende case
ausgeführt wird, oder?
Beim nächsten Interrupt wird der zum I2C_State passende case ausgeführt.
Noch eine kleine Ergänzung bzw. Korrektur zu meinen vorigen Beiträgen:
P1.6 ist SCL und P1.7 ist SDA.
In jedem case, mit Ausnahme des letzten welches die Übertragung beendet,
wird USICNT auf die Anzahl der zu übertagenen Bits gesetzt. Während die
Bits übertragen werden wird USICNT heruntergezählt. Wird Null erreicht
sind alle Bits übertragen und der nächste Interrupt wird ausgelöst.
Hast du die beiden Launchpads richtig miteinander verbunden, P1.6 des
Masters mit P1.6 des Slaves und P1.7 mit P1.7?
Mit den Originalprogrammen, bei denen ich nur beim Master die Anzahl der
zu übertragenen Bytes auf 2 gesetzt und die Pausenlängen verändert habe,
erhalte ich das im Anhang gezeigte Ergebnis.
Ich verbinde ein MSP430G2231 (Master) mit einem DSP von National. Die
Anschlüsse sind aber richtig.
Der DSP hat eine eigene Software mit der ich I2C-Daten über USB senden
kann, das klappt auch. Ich schließe zusätzlich SDA und SCL und GND vom
MSP an. Den USB-STecker kann ich nicht rausstecken, da sonst die
Versorgung weg ist.
Kann es sein, dass es Probleme gibt, weil ich USB und MSP gleichzeitig
angeschlossen habe, obwohl ja extra Pins da sind für I2C?
So jetzt habe ich einige Pobleme lösen können aber nicht alle.
Unzwar habe ich das ganze mit einem Empfängerboard getestet. Ich sende
die Chipadresse und bekomme ein ACK. So dann habe ich ein Feld mit
meiner Registeradresse und den Daten. Die Elemente des Feldes werden
nacheinander versendet, ich bekomme auch ein Ack. Jedoch sendet der MSP
nicht die Daten die ich in das Feld reingeschrieben habe, sondern immer
E2.
Was ist denn das Problem?
Hier mein Testcode
initialisiert.
Hast aber Recht, ich könnte genau so gut bytecount nehmen.
Was hat es aber mit byte und char zu tun, dass das Programm einfach
irgendetwas sendet? Warum macht int Probleme?
Scrub schrieb:> i wir oben als unsigned int i initialisiert.
Ja, aber wo wird der Wert von i gesetzt?
> Was hat es aber mit byte und char zu tun, dass das Programm einfach> irgendetwas sendet?
Vermutlich nichts, wundert mich nur.
Scrub,
bei mir scheint dein letzter Testcode die richtigen Daten zu senden.
Ich habe nur in case 0 die Slave-Adresse auf 0x90 geändert um es mit
meinem zweiten Launchpad als Slave testen zu können und die
Warteschleifen aus case 4 entfernt um das Ergebnis auf dem Oszilloskop
besser abbilden zu können.
Auch ohne explizite Initialisierung wird bei mir i anscheinend auf 0
gesetzt.
Beim ersten Stop des Debuggers in der Zeile in der der Watchdog gestoppt
wird steht am RAM Speicherplatz von i 0, wenn das Programm beendet ist
steht dort 5.
Hi,
ja jetzt geht`s lag doch an den for - Schleifen.
Warum kann ich eigentlich den Speicher ADC10MEM des ADC nicht auslesen?
Ich hatte nämlich vor den zwei Ports zu verglichen und zu schauen welche
Spannung größer ist, aber das funktioniert nicht so richtig:
Zusätzlich zum A1 Eingang musst du auch den A2 ADC-Eingang freigeben,
also ADC10AE0 |= 0x06 statt ADC10AE0 |= 0x02.
Nach dem ersten und dem zweiten Start der Wandlung musst du jeweils den
uC mit __bis_SR_register(CPUOFF + GIE) schlafen legen. Nach dem
Interrupt läuft der uC wieder und du kannst das Ergebnis per memx =
ADC10MEM abfragen.
Mit ADC10CTL0 &= ~ADC10SC wird die Wandlung abgebrochen und du erhälst
ein ungültiges Ergebnis - lösch die beiden Zeilen!
Vielen Dank. Funktioniert jetzt einigermaßen.
Aber das Problem ist, das die ADCs nicht richtig wandeln.
An einem Port hab ich 0,5V und am anderen hab ich 1V und als Wert in
ADC10MEM habe ich manchmal sogar gleiche Werte.
Ich vermute das es an meinen Variablen mem1 und mem2 liegt.
Ich bin jetzt endlich auch dazu gekommen das mal auszuprobieren.
Scrub schrieb:> Bevor man die Ports definiert muss man jeweils die Zeile> ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled> einfügen.
Wenn man den Eingangskanal wechseln will scheint man vorher das Enable
conversion Bit löschen zu müssen, was die Zeile auch macht.
Es reicht aber auch ein ADC10CTL0 &= ~ENC vor jedem
Eingangskanalwechsel.
Bekomme eine Fehlermeldung:
Severity and Description Path Resource Location Creation Time Id
run placement fails for object ".stack", size 0x32 (page 0). Available
ranges: RAM size: 0x80 unused: 0x32 max hole:
0x32 I2CTest line 0 1304333311531 2838
Wenn ich 2 Bytes in irgendeinem Element lösche, dann ist der Fehler weg
???
Es kann doch nicht sein, dass mein Speicher nicht ausreicht, oder?
128 Byte RAM sind verdammt wenig. Wenn davon dann 50 Byte für den Stack
reserviert werden wirds sehr schnell eng.
Jörg S. schrieb:> Und warum sind deine Daten alle Integer wo du immer nur byte bzw. char> senden kannst?
Ich habe nun die Einzelteile meines Programms (Timer, ADC, I2C) zu einem
Ganzen zusammengesetzt und wie zu erwarten war funktioniert es nicht.
Ich denke es liegt am Timer, der springt ja immer in die ISR, auch beim
Datensenden, d.h. ich müsste die Interrupts vorher ausschalten.
mit
Was soll dein Programm denn eigentlich machen?
Jedesmal wenn der Timer abläuft 2 ADC-Kanäle auslesen und abhängig von
den Ergebnissen etwas über I2C senden?
Wenn ja, dann könntest du in der Timer ISR das gleiche machen wie in der
ADC ISR: nur den Controller aufwecken. Schlafen legen müsstest du ihn
dann in der while(1) Schleife und nicht davor.
Wenn du dann noch die Warteschleifen aus den ISRs entfernst und das
Timer Intervall länger ist als die I2C Datenübertragung dauert könnte
das Programm vielleicht ungefähr das machen was es soll auch ohne
zwischendurch Interrupts sperren zu müssen.
Hast du eigentlich den Quarz aufgelötet?
Wenn nicht, dann solltest du den VLO zu ACLK-Generierung über BCSCTL3 =
LFXT1S_2 einschalten bevor du den Timer startest.
Ja so ähnlich.
Aber:
Die Adc sollen "immer" auslesen. Beide ADCs werden miteinander
verglichen und wenn FALL1 (der Einfachheit pro nenne ich das jetzt so)
eintrifft dann sende ich was über I2C der mir einen Kanal auf einem
anderen Board öffnet.
Das schließen soll aber eben nur in den Timer-Interrupts erfolgen.
Was macht
Das mit dem Kanal öffen und schließen versteh ich nicht ganz.
Wenn jederzeit geöffnet werden kann aber nur im Timer Interrupt
geschlossen dann kann da beliebig wenig Zeit zwischen vergehen.
Was BCSCTL3 = LFXT1S_2 macht findest du im MSP430x2xx Family User's
Guide, Abschnitt 5.3.4 BCSCTL3, Basic Clock System Control Register 3
LFXT1Sx Bits 5-4 Low-frequency clock select and LFXT1 range select.
These bits select between LFXT1 and VLO ...
00 32768-Hz crystal on LFXT1
01 Reserved
10 VLOCLK (Reserved in MSP430x21x1 devices)
11 Digital external clock source
Was ich nicht verstehe ist ganz einfach, wenn ich den Timer interrupt
einschalte, dann springt er immer wieder in die ISR, als ob der Timer
einfach zu kurz wäre, obwohl ich die Zeit erhöht habe?
Das mit der for-Schleife ging natürlich auch nicht.
Also mein Programm soll,
je nach ADC Zuständen ein anderes Board ein- und ausschalten
(laut/leise). Einschalen soll es immer sofort und ausschalten immer zu
Timer-Interrupts.
Ich habe meinen Code noch etwas abgeändert, siehe unten. Das Problem
ist, dass der Teil in der while(1), in der ich den Timer-Interrupt
enable einfach zu kurz ist. Also öfters nicht ausgelöst werden kann. Wie
kann ich das umgehen.
Ich habe jetzt meinen Code "verbessert" und es funktioniert trotzdem
nicht. Ich bin mir sicher, dass es etwas mit dem Timer zu tun hat.
Wenn ich einmal im Timer drin bin dann komme ich da nicht mehr raus,
d.h. ich durchlaufe die Timer ISR immer wieder.
Also noch eigenartiger kann ein Fehler doch nicht sein, oder?
Wenn ich das Pogramm auf das Board spiel und auf "run" klicke, dann
funktionert alles.
ABER, wenn ich es dann neu starte (also USB raus und wieder rein) dann
gehts nicht, d.h. ich komme gar nicht in die Interrupt Service Routine
vom Timer.
Woran kann denn das liegen?
Das lag an der Clocksource, ich hatte ACLK gewählt und muss MCLK/SMCLK
auswählen, dann funktioniert es.
Was mir aber aufgefallen ist: an meinem ADC-Eingang habe ich, ohne das
was angeschlossen ist, 3,5V anliegen, also die Versorgungsspannung vom
Chip?