Forum: Mikrocontroller und Digitale Elektronik MSP430G2231 - I2C TI-Code funktioniert nicht


von Scrub (Gast)


Lesenswert?

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.
1
//******************************************************************************
2
//  MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes
3
//
4
//  Description: I2C Master communicates with I2C Slave using
5
//  the USI. Master data should increment from 0x55 with each transmitted byte
6
//  and Master determines the number of bytes recieved, set by 
7
//  the Number_of_Bytes value. LED off for address or data Ack; 
8
//  LED on for address or data NAck.
9
//  ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
10
//
11
//
12
//  ***THIS IS THE MASTER CODE***
13
//
14
//                  Slave                      Master
15
//     (msp430g2x21_usi_15.c)
16
//             MSP430G2x21/G2x31          MSP430G2x21/G2x31
17
//             -----------------          -----------------
18
//         /|\|              XIN|-    /|\|              XIN|-
19
//          | |                 |      | |                 |
20
//          --|RST          XOUT|-     --|RST          XOUT|-
21
//            |                 |        |                 |
22
//      LED <-|P1.0             |        |                 |
23
//            |                 |        |             P1.0|-> LED
24
//            |         SDA/P1.7|------->|P1.6/SDA         |
25
//            |         SCL/P1.6|<-------|P1.7/SCL         |
26
//
27
//  Note: internal pull-ups are used in this example for SDA & SCL
28
//
29
//  D. Dang
30
//  Texas Instruments Inc.
31
//  October 2010
32
//  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
33
//******************************************************************************
34
35
#include <msp430g2221.h>
36
37
38
#define number_of_bytes 5                   // How many bytes?
39
40
void Master_Transmit(void);
41
void Master_Recieve(void);
42
43
void Setup_USI_Master_TX(void);
44
void Setup_USI_Master_RX(void);
45
46
char MST_Data = 0x55;                       // Variable for transmitted data
47
char SLV_Addr = 0x90;                       
48
int I2C_State, Bytecount, Transmit = 0;     // State variable
49
void Data_TX (void);
50
void Data_RX (void);
51
void main(void)
52
{
53
  volatile unsigned int i;                  // Use volatile to prevent removal
54
55
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog
56
  if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)                                     
57
  {  
58
    while(1);                               // If calibration constants erased
59
                                            // do not load, trap CPU!!
60
  } 
61
62
  BCSCTL1 = CALBC1_1MHZ;                    // Set DCO
63
  DCOCTL = CALDCO_1MHZ;
64
65
  P1OUT = 0xC0;                             // P1.6 & P1.7 Pullups, others to 0
66
  P1REN |= 0xC0;                            // P1.6 & P1.7 Pullups
67
  P1DIR = 0xFF;                             // Unused pins as outputs
68
  P2OUT = 0;
69
  P2DIR = 0xFF;
70
71
72
73
  while(1)
74
  {
75
    Master_Transmit();
76
    //_NOP();                                 // Used for IAR
77
78
    //Master_Recieve();
79
    //_NOP();
80
 }
81
}
82
83
/******************************************************
84
// USI interrupt service routine
85
// Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14
86
// Data Recieve  : state 0 -> 2 -> 4 -> 6 -> 8 -> 14
87
******************************************************/
88
#pragma vector = USI_VECTOR
89
__interrupt void USI_TXRX (void)
90
{
91
  switch(__even_in_range(I2C_State,14))
92
    {
93
      case 0: // Generate Start Condition & send address to slave
94
              P1OUT |= 0x01;                // LED on: sequence start
95
              Bytecount = 0;
96
              USISRL = 0x00;                // Generate Start Condition...
97
              USICTL0 |= USIGE+USIOE;
98
              USICTL0 &= ~USIGE;
99
              if (Transmit == 1){
100
                USISRL = 0x90;              // Address is 0x48 << 1 bit + 0 (rw)
101
              }
102
               if (Transmit == 0){
103
               USISRL = 0x91;               // 0x91 Address is 0x48 << 1 bit 
104
                                            // + 1 for Read
105
               }
106
              USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
107
              I2C_State = 2;                // next state: rcv address (N)Ack
108
              break;
109
110
      case 2: // Receive Address Ack/Nack bit
111
              USICTL0 &= ~USIOE;            // SDA = input
112
              USICNT |= 0x01;               // Bit counter=1, receive (N)Ack bit
113
              I2C_State = 4;                // Go to next state: check (N)Ack
114
              break;
115
116
      case 4: // Process Address Ack/Nack & handle data TX
117
             
118
 if(Transmit == 1){
119
              USICTL0 |= USIOE;             // SDA = output
120
              if (USISRL & 0x01)            // If Nack received...
121
              { // Send stop...
122
                USISRL = 0x00;
123
                USICNT |=  0x01;            // Bit counter=1, SCL high, SDA low
124
                I2C_State = 14;             // Go to next state: generate Stop
125
                P1OUT |= 0x01;              // Turn on LED: error
126
              }
127
              else
128
              { // Ack received, TX data to slave... 
129
              USISRL = MST_Data++;            // Load data byte
130
              USICNT |=  0x08;              // Bit counter = 8, start TX
131
              I2C_State = 10;               // next state: receive data (N)Ack
132
              Bytecount++;
133
              P1OUT &= ~0x01;               // Turn off LED
134
              break;
135
              }
136
 } if(Transmit == 0){
137
138
               if (USISRL & 0x01)            // If Nack received
139
              { // Prep Stop Condition
140
                USICTL0 |= USIOE;
141
                USISRL = 0x00;
142
                USICNT |=  0x01;            // Bit counter= 1, SCL high, SDA low
143
                I2C_State = 8;              // Go to next state: generate Stop
144
                P1OUT |= 0x01;              // Turn on LED: error
145
              }
146
              else{ Data_RX();}             // Ack received
147
              
148
149
}
150
              break;
151
152
case 6: // Send Data Ack/Nack bit      
153
              USICTL0 |= USIOE;             // SDA = output
154
              if (Bytecount <= number_of_bytes-2)
155
              {                             // If this is not the last byte
156
                USISRL = 0x00;              // Send Ack
157
                P1OUT &= ~0x01;             // LED off
158
                I2C_State = 4;              // Go to next state: data/rcv again
159
                Bytecount++;
160
                }
161
                
162
              else //last byte: send NACK
163
              {
164
                USISRL = 0xFF;              // Send NAck
165
                P1OUT |= 0x01;              // LED on: end of comm
166
                I2C_State = 8;              // stop condition
167
              }
168
              USICNT |= 0x01;               // Bit counter = 1, send (N)Ack bit
169
              break;
170
171
      case 8: // Prep Stop Condition
172
              USICTL0 |= USIOE;             // SDA = output
173
              USISRL = 0x00;
174
              USICNT |=  0x01;              // Bit counter= 1, SCL high, SDA low
175
              I2C_State = 14;               // Go to next state: generate Stop
176
              break;
177
178
      case 10: // Receive Data Ack/Nack bit
179
              USICTL0 &= ~USIOE;            // SDA = input
180
              USICNT |= 0x01;               // Bit counter = 1, receive (N)Ack bit
181
              I2C_State = 12;               // Go to next state: check (N)Ack
182
              break;
183
184
      case 12: // Process Data Ack/Nack & send Stop
185
              USICTL0 |= USIOE;
186
              if (Bytecount == number_of_bytes){// If last byte
187
              USISRL = 0x00;
188
              
189
              I2C_State = 14;               // Go to next state: generate Stop
190
              P1OUT |= 0x01;
191
              USICNT |=  0x01;     }        // set count=1 to trigger next state
192
              else{
193
                P1OUT &= ~0x01;             // Turn off LED
194
                Data_TX();                  // TX byte
195
              }
196
              break;
197
198
      case 14:// Generate Stop Condition
199
              USISRL = 0x0FF;               // USISRL = 1 to release SDA
200
              USICTL0 |= USIGE;             // Transparent latch enabled
201
              USICTL0 &= ~(USIGE+USIOE);    // Latch/SDA output disabled
202
              I2C_State = 0;                // Reset state machine for next xmt
203
              LPM0_EXIT;                    // Exit active for next transfer
204
              break;
205
    }
206
207
  USICTL1 &= ~USIIFG;                       // Clear pending flag
208
}
209
210
211
void Data_TX (void){
212
213
              USISRL = MST_Data++;          // Load data byte
214
              USICNT |=  0x08;              // Bit counter = 8, start TX
215
              I2C_State = 10;               // next state: receive data (N)Ack
216
              Bytecount++;
217
}
218
219
void Data_RX (void){
220
  USICTL0 &= ~USIOE;                  // SDA = input --> redundant
221
        USICNT |=  0x08;                    // Bit counter = 8, RX data
222
        I2C_State = 6;                      // Next state: Test data and (N)Ack
223
        P1OUT &= ~0x01;                     // LED off
224
        }
225
226
227
void Setup_USI_Master_TX (void)
228
{ 
229
  _DINT();
230
  Bytecount = 0;
231
  Transmit = 1;
232
  USICTL0 = USIPE6+USIPE7+USIMST+USISWRST;  // Port & USI mode setup
233
  USICTL1 = USII2C+USIIE;                   // Enable I2C mode & USI interrupt
234
  USICKCTL = USIDIV_7+USISSEL_2+USICKPL;    // USI clk: SCL = SMCLK/128
235
  USICNT |= USIIFGCC;                       // Disable automatic clear control
236
  USICTL0 &= ~USISWRST;                     // Enable USI
237
  USICTL1 &= ~USIIFG;                       // Clear pending flag
238
  _EINT();
239
}
240
241
242
void Setup_USI_Master_RX (void)
243
{ 
244
  _DINT();
245
  Bytecount = 0;
246
  Transmit = 0;
247
  USICTL0 = USIPE6+USIPE7+USIMST+USISWRST;  // Port & USI mode setup
248
  USICTL1 = USII2C+USIIE;                   // Enable I2C mode & USI interrupt
249
  USICKCTL = USIDIV_7+USISSEL_2+USICKPL;    // USI clks: SCL = SMCLK/128
250
  USICNT |= USIIFGCC;                       // Disable automatic clear control
251
  USICTL0 &= ~USISWRST;                     // Enable USI
252
  USICTL1 &= ~USIIFG;                       // Clear pending flag
253
  _EINT();
254
255
}
256
257
void Master_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
void Master_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

von ... (Gast)


Lesenswert?

Wie es aussieht, hast du es geschafft die kalibrierten Werte
für den DCO aus der INFO-Area zu löschen.

von Scrub (Gast)


Lesenswert?

Ich weiß nicht was du meinst?

Etwa die Zeilen:
1
   BCSCTL1 = CALBC1_1MHZ;                    // Set DCO
2
   DCOCTL = CALDCO_1MHZ;

Wenn ich das Programm weiterlaufen lasse dann bleibt es immer an der 
Stelle mit dem Delay stehen:
1
__delay_cycles(10000);                  // Delay between comm cycles


Ich verstehe nicht wie der Originalcode von Texas Instruments falsch 
sein kann, die müssen das doch vorher testen?

von Scrub (Gast)


Lesenswert?

Ich habe jetzt folgende Zeilen auskommentiert:
1
 //LPM0;                                   // CPU off, await USI interrupt
2
  //__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?

von Jörg S. (joerg-s)


Lesenswert?

Wenn das Programm immer noch in der Schleife
1
  if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)                                     
2
  {  
3
    while(1);                               // If calibration constants erased
4
                                            // do not load, trap CPU!!
5
  }
steht, ist etwas faul mit den Kalibrationsdaten, die vor der Schleife 
geprüft werden.
Was in den Interrups passiert, spielt dann keine große Rolle.

von Scrub (Gast)


Lesenswert?

Nein da kommt das Programm ohne Probleme vorbei.

von Scrub (Gast)


Lesenswert?

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) ???

von Scrub (Gast)


Lesenswert?

Hat denn keiner ne Idee?

Wäre echt super, wenn mir jemand helfen könnte.

von Jörg S. (joerg-s)


Lesenswert?

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.

von Stefan (Gast)


Lesenswert?

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

von Scrub (Gast)


Lesenswert?

Aber warum bleibt das Programm zuerst in der Main stehen? Ich muss erst 
auf den Run Button clicken damit das Programm weiterläuft?

von Jörg S. (joerg-s)


Lesenswert?

Weil der Debugger so eingestellt ist das er nicht sofort losläuft. Das 
ist aber die Funktion vom Debugger und hat nichts mit dem Code zu tun.

von Scrub (Gast)


Lesenswert?

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?

von Jörg S. (joerg-s)


Lesenswert?

"Stand alone" rennt er ja sofort los. Nur der Debugger hält erst mal an.

von Scrub (Gast)


Lesenswert?

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?

von Jörg S. (joerg-s)


Lesenswert?

Wenn der Programmer abgezogen ist, sollte das so sein.
Blitzt die LED vielleicht auch nur so kurz auf das du es nicht 
mitbekommst?

von Scrub (Gast)


Lesenswert?

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
__interrupt void USI_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
105
              else{
106
                P1OUT &= ~0x01;                 // Turn off LED
107
                Data_TX();                      // TX byte
108
              }
109
              //break;
110
      }
111
112
      if (I2C_State == 14){              // Generate Stop Condition
113
              USISRL = 0x0FF;                   // USISRL = 1 to release SDA
114
              USICTL0 |= USIGE;                 // Transparent latch enabled
115
              USICTL0 &= ~(USIGE+USIOE);        // Latch/SDA output disabled
116
              I2C_State = 0;                    // Reset state machine for next xmt
117
              LPM0_EXIT;                        // Exit active for next transfer
118
              //break;
119
      }
120
    
121
122
    USICTL1 &= ~USIIFG;                           // Clear pending flag
123
}
124
125
126
void Data_TX (void){
127
128
              USISRL = MST_Data++;              // Load data byte
129
              USICNT |=  0x08;                  // Bit counter = 8, start TX
130
              I2C_State = 10;                   // next state: receive data (N)Ack
131
              Bytecount++;
132
}
133
134
void Data_RX (void){
135
  USICTL0 &= ~USIOE;                        // SDA = input --> redundant
136
    USICNT |=  0x08;                            // Bit counter = 8, RX data
137
    I2C_State = 6;                             // Next state: Test data and (N)Ack
138
    P1OUT &= ~0x01;                           // LED off
139
}

von Stefan (Gast)


Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

Komisch, was hat das denn mit dem Jumper zu tun ???

von Scrub (Gast)


Lesenswert?

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.

von Stefan (Gast)


Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

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 ???

von Stefan (Gast)


Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

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?

von Stefan (Gast)


Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

Stefan schrieb:
> Beim nächsten Interrupt wird der zum I2C_State passende case ausgeführt.

Ja, aber wie wird denn der nächste Interrupt ausgelöst ?

von Stefan (Gast)


Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

Aso,

ja cool jetzt geht es bei mir auch. Muss es jetzt halt mal mit einem 
Slave testen.

von Scrub (Gast)


Lesenswert?

Muss ich denn eigentlich einen von den mitgelieferten Quarzen einlöten,
weil ich nämlich am Ausgang kein Signal messen kann? Weder SCL noh SDA?

von Stefan (Gast)


Lesenswert?

Ein Quarz wird nicht benötigt.
Der Jumper zwischen P1.6 und LED2 muss bei beiden Launchpads entfernt 
werden.

von Scrub (Gast)


Lesenswert?

Irgendwie reagiert mein Empfängerchip nicht so richtig, also ich bekomme 
ein NACK, allein schon bei der Chip Adresse?

von Stefan (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

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?

von Scrub (Gast)


Lesenswert?

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
1
//******************************************************************************
2
//  MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes
3
//
4
//  Description: I2C Master communicates with I2C Slave using
5
//  the USI. Master data should increment from 0x55 with each transmitted byte
6
//  and Master determines the number of bytes recieved, set by 
7
//  the Number_of_Bytes value. LED off for address or data Ack; 
8
//  LED on for address or data NAck.
9
//  ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
10
//
11
//
12
//  ***THIS IS THE MASTER CODE***
13
//
14
//                  Slave                      Master
15
//     (msp430g2x21_usi_15.c)
16
//             MSP430G2x21/G2x31          MSP430G2x21/G2x31
17
//             -----------------          -----------------
18
//         /|\|              XIN|-    /|\|              XIN|-
19
//          | |                 |      | |                 |
20
//          --|RST          XOUT|-     --|RST          XOUT|-
21
//            |                 |        |                 |
22
//      LED <-|P1.0             |        |                 |
23
//            |                 |        |             P1.0|-> LED
24
//            |         SDA/P1.7|------->|P1.6/SDA         |
25
//            |         SCL/P1.6|<-------|P1.7/SCL         |
26
//
27
//  Note: internal pull-ups are used in this example for SDA & SCL
28
//
29
//  D. Dang
30
//  Texas Instruments Inc.
31
//  October 2010
32
//  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
33
//******************************************************************************
34
35
#include <msp430g2231.h>
36
37
38
39
40
void Master_Transmit(void);
41
void Master_Recieve(void);
42
43
void Setup_USI_Master_TX(void);
44
void Setup_USI_Master_RX(void);
45
46
char MST_Data = 0x55;                           // Variable for transmitted data
47
char SLV_Addr = 0x90;                       
48
49
int *Daten;
50
51
//..............................................................................................
52
//......Adressen..und..Daten....................................................................
53
//..............................................................................................
54
int preamplifier [] = {0x00, 0x00};
55
int postamplifier [] = {0x00, 0x00};
56
57
//int mux1channel1 [6];
58
//int mux1channel2 [6];
59
int mux1channel1 [] = {0x4E, 0x00, 0x00, 0x00, 0x01};
60
int mux1channel2 [] = {0x4E, 0x00, 0x00, 0x00, 0x02};
61
62
int mittelwert_stop [] = {0x00, 0x00, 0x00, 0x00, 0x00};
63
int mittelwert_start [] = {0x00, 0x00, 0x00, 0x00, 0x00};
64
//..............................................................................................
65
//..............................................................................................
66
//..............................................................................................
67
68
69
int I2C_State = 0;                    // State variable
70
int Bytecount = 0;
71
int Transmit = 0;
72
unsigned int i;                            // Use volatile to prevent removal
73
unsigned int m;
74
unsigned int zustand;
75
unsigned int number_of_bytes;
76
77
void Data_TX (void);
78
void Data_RX (void);
79
80
81
82
void main(void)
83
{
84
85
  WDTCTL = WDTPW + WDTHOLD;                     // Stop watchdog
86
  
87
  if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF){  
88
    while(1);                                   // If calibration constants erased
89
                                                 // do not load, trap CPU!!
90
  } 
91
92
  BCSCTL1 = CALBC1_1MHZ;                        // Set DCO
93
  DCOCTL = CALDCO_1MHZ;
94
95
  P1OUT = 0xC0;                                 // P1.6 & P1.7 Pullups, others to 0
96
  P1REN |= 0xC0;                                // P1.6 & P1.7 Pullups
97
  P1DIR = 0xFF;                                 // Unused pins as outputs
98
  P2OUT = 0;
99
  P2DIR = 0xFF;
100
101
102
103
  
104
      number_of_bytes = 5;
105
      Daten = mux1channel2;
106
      for (m=0; m<30000; m++){}
107
      Master_Transmit();
108
      __delay_cycles(10000);
109
      for (m=0; m<30000; m++){}
110
            
111
      /*
112
      Daten = mux1channel1;
113
      Master_Transmit();
114
      __delay_cycles(10000);
115
      for (m=0; m<300000; m++){}
116
      for (m=0; m<300000; m++){}
117
      */
118
 
119
}
120
121
/******************************************************
122
// USI interrupt service routine
123
// Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14
124
// Data Recieve  : state 0 -> 2 -> 4 -> 6 -> 8 -> 14
125
******************************************************/
126
#pragma vector = USI_VECTOR
127
__interrupt void USI_TXRX (void)
128
{
129
  switch(__even_in_range(I2C_State,14))
130
    {
131
      case 0:                     // Generate Start Condition & send address to slave
132
              P1OUT |= 0x01;                    // LED on: sequence start
133
              for(m=0;m<30000;m++){}
134
              P1OUT &= ~0x01;
135
              Bytecount = 0;
136
              USISRL = 0x00;                    // Generate Start Condition...
137
              USICTL0 |= USIGE+USIOE;
138
              USICTL0 &= ~USIGE;
139
              if (Transmit == 1){
140
                USISRL = 0x68;                  // Address is 0x48 << 1 bit + 0 (rw)
141
              }
142
              if (Transmit == 0){
143
                USISRL = 0x69;                   // 0x91 Address is 0x48 << 1 bit 
144
                                                // + 1 for Read
145
              }
146
              USICNT = (USICNT & 0xE0) + 0x08;     // Bit counter = 8, TX Address
147
              I2C_State = 2;                    // next state: rcv address (N)Ack
148
              break;
149
150
      case 2:                     // Receive Address Ack/Nack bit
151
              USICTL0 &= ~USIOE;                // SDA = input
152
              //P1DIR = 0x00;
153
              USICNT |= 0x01;                   // Bit counter=1, receive (N)Ack bit
154
              I2C_State = 4;                    // Go to next state: check (N)Ack
155
              break;
156
157
      case 4:                     // Process Address Ack/Nack & handle data TX             
158
         if(Transmit == 1){
159
                USICTL0 |= USIOE;                 // SDA = output
160
                if (USISRL & 0x01)                // If Nack received...
161
                {                   // Send stop...
162
                  USISRL = 0x00;
163
                  USICNT |=  0x01;              // Bit counter=1, SCL high, SDA low
164
                  I2C_State = 14;               // Go to next state: generate Stop
165
                  P1OUT |= 0x01;                // Turn on LED: error
166
                }
167
                else
168
                {                   // Ack received, TX data to slave... 
169
                  //USISRL = MST_Data++;            // Load data byte
170
                  USISRL = Daten[i];
171
                  i++;
172
                  USICNT |=  0x08;                // Bit counter = 8, start TX
173
                  I2C_State = 10;                 // next state: receive data (N)Ack
174
                  Bytecount++;
175
                  P1OUT |= 0x01;                 
176
                  for(m=0;m<50000;m++){}
177
                  P1OUT &= ~0x01;
178
                  for(m=0;m<50000;m++){}
179
                  P1OUT |= 0x01;
180
                  for(m=0;m<50000;m++){}
181
                  P1OUT &= ~0x01;
182
                  break;
183
                }
184
         }
185
         if(Transmit == 0){
186
        if (USISRL & 0x01)                // If Nack received
187
                {                   // Prep Stop Condition
188
                  USICTL0 |= USIOE;
189
                  USISRL = 0x00;
190
                  USICNT |=  0x01;              // Bit counter= 1, SCL high, SDA low
191
                  I2C_State = 8;                // Go to next state: generate Stop
192
                  P1OUT |= 0x01;                // Turn on LED: error
193
                }
194
                else{ Data_RX();}                 // Ack received
195
        }
196
              break;
197
198
    
199
    case 6:                     // Send Data Ack/Nack bit      
200
              USICTL0 |= USIOE;                 // SDA = output
201
              if (Bytecount <= number_of_bytes-2)
202
              {                                 // If this is not the last byte
203
                USISRL = 0x00;                  // Send Ack
204
                P1OUT &= ~0x01;                 // LED off
205
                I2C_State = 4;                  // Go to next state: data/rcv again
206
                Bytecount++;
207
              }
208
              else                   //last byte: send NACK
209
              {
210
                USISRL = 0xFF;                  // Send NAck
211
                P1OUT |= 0x01;                  // LED on: end of comm
212
                I2C_State = 8;                  // stop condition
213
              }
214
              USICNT |= 0x01;                   // Bit counter = 1, send (N)Ack bit
215
              break;
216
217
      case 8:                     // Prep Stop Condition
218
              USICTL0 |= USIOE;                 // SDA = output
219
              USISRL = 0x00;
220
              USICNT |=  0x01;                  // Bit counter= 1, SCL high, SDA low
221
              I2C_State = 14;                   // Go to next state: generate Stop
222
              break;
223
224
      case 10:                     // Receive Data Ack/Nack bit
225
              USICTL0 &= ~USIOE;                // SDA = input
226
              USICNT |= 0x01;                   // Bit counter = 1, receive (N)Ack bit
227
              I2C_State = 12;                   // Go to next state: check (N)Ack
228
              break;
229
230
      case 12:                     // Process Data Ack/Nack & send Stop
231
              USICTL0 |= USIOE;
232
              if (Bytecount == number_of_bytes){  // If last byte
233
              USISRL = 0x00;
234
              
235
              I2C_State = 14;                   // Go to next state: generate Stop
236
              P1OUT |= 0x01;
237
              USICNT |=  0x01;     }            // set count=1 to trigger next state
238
              else{
239
                P1OUT &= ~0x01;                 // Turn off LED
240
                Data_TX();                      // TX byte
241
              }
242
              break;
243
244
      case 14:                    // Generate Stop Condition
245
              USISRL = 0x0FF;                   // USISRL = 1 to release SDA
246
              USICTL0 |= USIGE;                 // Transparent latch enabled
247
              USICTL0 &= ~(USIGE+USIOE);        // Latch/SDA output disabled
248
              I2C_State = 0;                    // Reset state machine for next xmt
249
              LPM0_EXIT;                        // Exit active for next transfer
250
              break;
251
    }
252
253
    USICTL1 &= ~USIIFG;                           // Clear pending flag
254
}
255
256
257
void Data_TX (void){
258
  //USISRL = MST_Data++;                      // Load data byte
259
    USISRL = Daten[i];
260
    i++;
261
    USICNT |=  0x08;                        // Bit counter = 8, start TX
262
    I2C_State = 10;                         // next state: receive data (N)Ack
263
    Bytecount++;
264
}
265
266
void Data_RX (void){
267
  USICTL0 &= ~USIOE;                        // SDA = input --> redundant
268
    USICNT |=  0x08;                            // Bit counter = 8, RX data
269
    I2C_State = 6;                             // Next state: Test data and (N)Ack
270
    P1OUT &= ~0x01;                           // LED off
271
}
272
273
274
void Setup_USI_Master_TX (void){ 
275
    _DINT();
276
    Bytecount = 0;
277
    Transmit = 1;
278
    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST;      // Port & USI mode setup
279
    USICTL1 = USII2C+USIIE;                       // Enable I2C mode & USI interrupt
280
    USICKCTL = USIDIV_7+USISSEL_2+USICKPL;        // USI clk: SCL = SMCLK/128
281
    USICNT |= USIIFGCC;                           // Disable automatic clear control
282
    USICTL0 &= ~USISWRST;                         // Enable USI
283
    USICTL1 &= ~USIIFG;                           // Clear pending flag
284
    _EINT();
285
}
286
287
288
void Setup_USI_Master_RX (void){ 
289
    _DINT();
290
    Bytecount = 0;
291
    Transmit = 0;
292
    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST;      // Port & USI mode setup
293
    USICTL1 = USII2C+USIIE;                       // Enable I2C mode & USI interrupt
294
    //USICKCTL = USIDIV_7+USISSEL_2+USICKPL;        // USI clks: SCL = SMCLK/128
295
    USICKCTL = USIDIV_4+USISSEL_2+USICKPL;        // USI clks: SCL = SMCLK/128                      
296
    USICNT |= USIIFGCC;                           // Disable automatic clear control
297
    USICTL0 &= ~USISWRST;                         // Enable USI
298
    USICTL1 &= ~USIIFG;                           // Clear pending flag
299
    _EINT();
300
}
301
302
void Master_Transmit(void){
303
  Setup_USI_Master_TX();
304
    USICTL1 |= USIIFG;                          // Set flag and start communication
305
    LPM0;                                       // CPU off, await USI interrupt
306
    __delay_cycles(10000);                      // Delay between comm cycles
307
}
308
309
void Master_Recieve(void){
310
    Setup_USI_Master_RX();
311
    USICTL1 |= USIIFG;                            // Set flag and start communication
312
    LPM0;                                         // CPU off, await USI interrupt
313
    __delay_cycles(10000);                        // Delay between comm cycles
314
}

von Jörg S. (joerg-s)


Lesenswert?

1
USISRL = Daten[i];
Wieso i und nicht Bytecount? Und wo wird i initialisiert?

Und warum sind deine Daten alle Integer wo du immer nur byte bzw. char 
senden kannst?

von Scrub (Gast)


Lesenswert?

i wir oben als
1
unsigned int i
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?

von Jörg S. (joerg-s)


Lesenswert?

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.

von Stefan (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

Kann es sein, dass die Warteschleifen in case 4 bei mir Probleme 
bereiten ?

von Scrub (Gast)


Lesenswert?

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:
1
//******************************************************************************
2
//  MSP430G2x31 Demo - ADC10, Sample A1, AVcc Ref, Set P1.0 if > 0.5*AVcc
3
//
4
//  Description: A single sample is made on A1 with reference to AVcc.
5
//  Software sets ADC10SC to start sample and conversion - ADC10SC
6
//  automatically cleared at EOC. ADC10 internal oscillator times sample (16x)
7
//  and conversion. In Mainloop MSP430 waits in LPM0 to save power until ADC10
8
//  conversion complete, ADC10_ISR will force exit from LPM0 in Mainloop on
9
//  reti. If A1 > 0.5*AVcc, P1.0 set, else reset.
10
//
11
//                MSP430G2x31
12
//             -----------------
13
//         /|\|              XIN|-
14
//          | |                 |
15
//          --|RST          XOUT|-
16
//            |                 |
17
//        >---|P1.1/A1      P1.0|-->LED
18
//
19
//  D. Dang
20
//  Texas Instruments Inc.
21
//  October 2010
22
//  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
23
//******************************************************************************
24
#include "msp430g2231.h"
25
26
int mem1;
27
int mem2;
28
29
void main(void)
30
{
31
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
32
  ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
33
  ADC10CTL1 = INCH_1;                       // input A1
34
  ADC10AE0 |= 0x02;                         // PA.1 ADC option select
35
  P1DIR |= 0x01;                            // Set P1.0 to output direction
36
  mem1 = 0;
37
  mem2 = 0;
38
39
  for (;;)
40
  {
41
    ADC10CTL1 = INCH_1;
42
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
43
    ADC10MEM = mem1;
44
    ADC10CTL0 &= ~ADC10SC;
45
    
46
    ADC10CTL1 = INCH_2;
47
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
48
    ADC10MEM = mem2;
49
    ADC10CTL0 &= ~ADC10SC;
50
    __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
51
    if (ADC10MEM < 0x1FF)
52
      P1OUT &= ~0x01;                       // Clear P1.0 LED off
53
    else
54
      P1OUT |= 0x01;                        // Set P1.0 LED on
55
  }
56
}
57
58
// ADC10 interrupt service routine
59
#pragma vector=ADC10_VECTOR
60
__interrupt void ADC10_ISR(void)
61
{
62
  __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
63
}

von Scrub (Gast)


Lesenswert?

Sory, hier der verbesserte Code:
1
#include "msp430g2231.h"
2
3
int mem1;
4
int mem2;
5
6
void main(void)
7
{
8
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
9
  ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
10
  ADC10CTL1 = INCH_1;                       // input A1
11
  ADC10AE0 |= 0x02;                         // PA.1 ADC option select
12
  P1DIR |= 0x01;                            // Set P1.0 to output direction
13
  mem1 = 0;
14
  mem2 = 0;
15
16
  for (;;)
17
  {
18
    ADC10CTL1 = INCH_1;
19
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
20
    ADC10MEM = mem1;
21
    ADC10CTL0 &= ~ADC10SC;
22
    
23
    ADC10CTL1 = INCH_2;
24
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
25
    ADC10MEM = mem2;
26
    ADC10CTL0 &= ~ADC10SC;
27
    __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
28
    if (mem1 < mem2)
29
      P1OUT &= ~0x01;                       // Clear P1.0 LED off
30
    else
31
      P1OUT |= 0x01;                        // Set P1.0 LED on
32
  }
33
}
34
35
// ADC10 interrupt service routine
36
#pragma vector=ADC10_VECTOR
37
__interrupt void ADC10_ISR(void)
38
{
39
  __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
40
}

von Stefan (Gast)


Lesenswert?

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!

von Scrub (Gast)


Lesenswert?

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.
1
//******************************************************************************
2
//  MSP430G2x31 Demo - ADC10, Sample A1, AVcc Ref, Set P1.0 if > 0.5*AVcc
3
//
4
//  Description: A single sample is made on A1 with reference to AVcc.
5
//  Software sets ADC10SC to start sample and conversion - ADC10SC
6
//  automatically cleared at EOC. ADC10 internal oscillator times sample (16x)
7
//  and conversion. In Mainloop MSP430 waits in LPM0 to save power until ADC10
8
//  conversion complete, ADC10_ISR will force exit from LPM0 in Mainloop on
9
//  reti. If A1 > 0.5*AVcc, P1.0 set, else reset.
10
//
11
//                MSP430G2x31
12
//             -----------------
13
//         /|\|              XIN|-
14
//          | |                 |
15
//          --|RST          XOUT|-
16
//            |                 |
17
//        >---|P1.1/A1      P1.0|-->LED
18
//
19
//  D. Dang
20
//  Texas Instruments Inc.
21
//  October 2010
22
//  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
23
//******************************************************************************
24
#include "msp430g2231.h"
25
26
int mem1 = 0;
27
int mem2 = 0;
28
29
void main(void)
30
{
31
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
32
  ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
33
  //ADC10CTL1 = INCH_2;                       // input A1
34
  ADC10AE0 |= 0x06;                         // PA.1 ADC option select
35
  P1DIR |= 0x01;                            // Set P1.0 to output direction
36
37
  for (;;)
38
  {
39
    ADC10CTL1 = INCH_1;
40
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
41
    __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
42
    mem1 = ADC10MEM;
43
    
44
    ADC10CTL1 = INCH_2;
45
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
46
    __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
47
    mem2 = ADC10MEM;
48
    
49
    if (mem1 < mem2)
50
      P1OUT &= ~0x01;                       // Clear P1.0 LED off
51
    else
52
      P1OUT |= 0x01;                        // Set P1.0 LED on
53
  }
54
}
55
56
// ADC10 interrupt service routine
57
#pragma vector=ADC10_VECTOR
58
__interrupt void ADC10_ISR(void)
59
{
60
  __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
61
}

von Stefan (Gast)


Lesenswert?

Hast du die Spannung an den Portpins mit einem Voltmeter überprüft?
Hast du den TXD und den RXD Jumper gezogen?

von Scrub (Gast)


Lesenswert?

Die Spannungen habe ich überprüft, passt.

Aber die Jumper stecken noch !?!

von Scrub (Gast)


Lesenswert?

Hi,

hab`s jetzt. Die Jumper stecken noch.

Bevor man die Ports definiert muss man jeweils die Zeile
1
ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
 einfügen.

Also komplett:
1
#include "msp430g2231.h"
2
3
unsigned int mem1 = 0;
4
unsigned int mem2 = 0;
5
int i;
6
7
void main(void)
8
{
9
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
10
  //ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
11
  //ADC10CTL1 = INCH_2;                       // input A1
12
  ADC10AE0 |= 0x06;                         // PA.1 ADC option select
13
  P1DIR |= 0x01;                            // Set P1.0 to output direction
14
15
  for (;;)
16
  { 
17
    ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
18
    ADC10CTL1 = INCH_2;
19
    for (i=0; i<10; i++){
20
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
21
    __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
22
    //mem2 = ADC10MEM;
23
    }
24
    mem2 = ADC10MEM;
25
    
26
    ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
27
    ADC10CTL1 = INCH_1;
28
    for (i=0; i<10; i++){
29
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
30
    __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
31
    //mem1 = ADC10MEM;
32
    }
33
    mem1 = ADC10MEM;
34
    
35
    if (mem1 < mem2)
36
      P1OUT &= ~0x01;                       // Clear P1.0 LED off
37
    else
38
      P1OUT |= 0x01;                        // Set P1.0 LED on
39
      
40
  }
41
}
42
43
// ADC10 interrupt service routine
44
#pragma vector=ADC10_VECTOR
45
__interrupt void ADC10_ISR(void)
46
{
47
  __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
48
}

von Stefan (Gast)


Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

Danke.

Ich hab jetzt 6 Felder initialisiert:
1
//..............................................................................................
2
//......Adressen..und..Daten....................................................................
3
//..............................................................................................
4
int preamplifier [] = {0x00, 0x00};
5
int postamplifier [] = {0x00, 0x00};
6
7
int laut [] = {0x09, 0x00, 0x00, 0x00, 0xC0};
8
int leise [] = {0x09, 0x00, 0x00, 0x00, 0x00};
9
10
int mittelwert_stop [] = {0x1F, 0x00, 0x00, 0x00, 0x00};
11
int mittelwert_start [] = {0x1F, 0x00, 0x00, 0x01, 0x5D};
12
//..............................................................................................
13
//..............................................................................................
14
//..............................................................................................

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?

von Stefan (Gast)


Lesenswert?

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?

von Scrub (Gast)


Lesenswert?

Hab jetzt ein paar Variablen eingespart und jetzt geht`s.

von Scrub (Gast)


Lesenswert?

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
1
CCTL0 &= ~CCIE;
geht es nicht.
Hier der gesamte Code.
1
//******************************************************************************
2
//  MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes
3
//
4
//  Description: I2C Master communicates with I2C Slave using
5
//  the USI. Master data should increment from 0x55 with each transmitted byte
6
//  and Master determines the number of bytes recieved, set by 
7
//  the Number_of_Bytes value. LED off for address or data Ack; 
8
//  LED on for address or data NAck.
9
//  ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
10
//
11
//
12
//  ***THIS IS THE MASTER CODE***
13
//
14
//                  Slave                      Master
15
//     (msp430g2x21_usi_15.c)
16
//             MSP430G2x21/G2x31          MSP430G2x21/G2x31
17
//             -----------------          -----------------
18
//         /|\|              XIN|-    /|\|              XIN|-
19
//          | |                 |      | |                 |
20
//          --|RST          XOUT|-     --|RST          XOUT|-
21
//            |                 |        |                 |
22
//      LED <-|P1.0             |        |                 |
23
//            |                 |        |             P1.0|-> LED
24
//            |         SDA/P1.7|------->|P1.6/SDA         |
25
//            |         SCL/P1.6|<-------|P1.7/SCL         |
26
//
27
//  Note: internal pull-ups are used in this example for SDA & SCL
28
//
29
//  D. Dang
30
//  Texas Instruments Inc.
31
//  October 2010
32
//  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
33
//******************************************************************************
34
35
#include <msp430g2231.h>
36
37
void Master_Transmit(void);
38
//void Master_Recieve(void);
39
40
void Setup_USI_Master_TX(void);
41
//void Setup_USI_Master_RX(void);
42
43
char SLV_Addr = 0x90;                       
44
45
int *Daten;
46
47
//..............................................................................................
48
//......Adressen..und..Daten....................................................................
49
//..............................................................................................
50
int preamplifier [] = {0x00, 0x00};
51
int postamplifier [] = {0x00, 0x00};
52
53
int laut [] = {0x09, 0x00, 0x00, 0x00, 0xC0};
54
int leise [] = {0x09, 0x00, 0x00, 0x00, 0x00};
55
56
int mittelwert_stop [] = {0x1F, 0x00, 0x00, 0x00, 0x00};
57
int mittelwert_start [] = {0x1F, 0x00, 0x00, 0x01, 0x5D};
58
59
int I2C_State = 0;                    // State variable
60
int Bytecount = 0;
61
int Transmit = 0;
62
//unsigned int i;                            // Use volatile to prevent removal
63
unsigned int m = 1;
64
unsigned int zustand;
65
unsigned int number_of_bytes;
66
67
//unsigned int mem1 = 0;
68
unsigned int mem2 = 0;
69
int k;
70
71
void Data_TX (void);
72
//void Data_RX (void);
73
74
75
76
void main(void)
77
{
78
79
  WDTCTL = WDTPW + WDTHOLD;                     // Stop watchdog
80
81
  
82
  ADC10AE0 |= 0x06;                         // PA.1 ADC option select
83
  //P1DIR |= 0x01;                            // Set P1.0 to output direction
84
  
85
  if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF){  
86
    while(1);                                   // If calibration constants erased
87
                                                 // do not load, trap CPU!!
88
  } 
89
90
  BCSCTL1 = CALBC1_1MHZ;                        // Set DCO
91
  DCOCTL = CALDCO_1MHZ;
92
93
  P1OUT = 0xC0;                                 // P1.6 & P1.7 Pullups, others to 0
94
  P1REN |= 0xC0;                                // P1.6 & P1.7 Pullups
95
  P1DIR = 0xFF;                                 // Unused pins as outputs
96
  P2OUT = 0;
97
  P2DIR = 0xFF;
98
  
99
  //Setup the Timer
100
  CCTL0 = CCIE;                             // CCR0 interrupt enabled
101
  TACCR0 = 5000;
102
  TACTL = TASSEL_1 + MC_1;                  
103
104
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
105
106
107
108
  while(1){
109
    
110
    ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
111
    ADC10CTL1 = INCH_2;
112
    for (k=0; k<10; k++){
113
      ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
114
      __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
115
    }
116
    mem2 = ADC10MEM;
117
    
118
    ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
119
    ADC10CTL1 = INCH_1;
120
    for (k=0; k<10; k++){
121
      ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
122
      __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
123
    }
124
    //mem1 = ADC10MEM;
125
    
126
    if(ADC10MEM < mem2){              //Audio größer als Schwelle
127
      if (zustand == 0){
128
        number_of_bytes = 5;
129
        Daten = mittelwert_stop;
130
        Master_Transmit();
131
        __delay_cycles(10000);
132
        
133
        Daten = laut;
134
      Master_Transmit();
135
      zustand = 1;
136
        __delay_cycles(10000);
137
      }
138
      
139
      m = 1;
140
    }
141
    
142
    /*
143
    if (mem1 < mem2)
144
      P1OUT &= ~0x01;                       // Clear P1.0 LED off
145
    else
146
      P1OUT |= 0x01;                        // Set P1.0 LED on
147
    */  
148
  }     
149
 
150
}
151
152
/******************************************************
153
// USI interrupt service routine
154
// Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14
155
// Data Recieve  : state 0 -> 2 -> 4 -> 6 -> 8 -> 14
156
******************************************************/
157
#pragma vector = USI_VECTOR
158
__interrupt void USI_TXRX (void)
159
{
160
  switch(__even_in_range(I2C_State,14))
161
    {
162
      case 0:                     // Generate Start Condition & send address to slave
163
              P1OUT |= 0x01;                    // LED on: sequence start
164
              for(m=0;m<30000;m++){}
165
              P1OUT &= ~0x01;
166
              Bytecount = 0;
167
              USISRL = 0x00;                    // Generate Start Condition...
168
              USICTL0 |= USIGE+USIOE;
169
              USICTL0 &= ~USIGE;
170
              if (Transmit == 1){
171
                USISRL = 0x68;                  // Address is 0x48 << 1 bit + 0 (rw)
172
              }
173
              USICNT = (USICNT & 0xE0) + 0x08;     // Bit counter = 8, TX Address
174
              I2C_State = 2;                    // next state: rcv address (N)Ack
175
              break;
176
177
      case 2:                     // Receive Address Ack/Nack bit
178
              USICTL0 &= ~USIOE;                // SDA = input
179
              //P1DIR = 0x00;
180
              USICNT |= 0x01;                   // Bit counter=1, receive (N)Ack bit
181
              I2C_State = 4;                    // Go to next state: check (N)Ack
182
              break;
183
184
      case 4:                     // Process Address Ack/Nack & handle data TX             
185
         if(Transmit == 1){
186
                USICTL0 |= USIOE;                 // SDA = output
187
                if (USISRL & 0x01)                // If Nack received...
188
                {                   // Send stop...
189
                  USISRL = 0x00;
190
                  USICNT |=  0x01;              // Bit counter=1, SCL high, SDA low
191
                  I2C_State = 14;               // Go to next state: generate Stop
192
                  P1OUT |= 0x01;                // Turn on LED: error
193
                }
194
                else
195
                {                   // Ack received, TX data to slave... 
196
                  //USISRL = MST_Data++;            // Load data byte
197
                  USISRL = Daten[Bytecount];
198
                  USICNT |=  0x08;                // Bit counter = 8, start TX
199
                  I2C_State = 10;                 // next state: receive data (N)Ack
200
                  Bytecount++;
201
                }
202
         }
203
              break;
204
205
      case 10:                     // Receive Data Ack/Nack bit
206
              USICTL0 &= ~USIOE;                // SDA = input
207
              USICNT |= 0x01;                   // Bit counter = 1, receive (N)Ack bit
208
              I2C_State = 12;                   // Go to next state: check (N)Ack
209
              break;
210
211
      case 12:                     // Process Data Ack/Nack & send Stop
212
              USICTL0 |= USIOE;
213
              if (Bytecount == number_of_bytes){  // If last byte
214
              USISRL = 0x00;
215
              
216
              I2C_State = 14;                   // Go to next state: generate Stop
217
              P1OUT |= 0x01;
218
              USICNT |=  0x01;     }            // set count=1 to trigger next state
219
              else{
220
                P1OUT &= ~0x01;                 // Turn off LED
221
                Data_TX();                      // TX byte
222
              }
223
              break;
224
225
      case 14:                    // Generate Stop Condition
226
              USISRL = 0x0FF;                   // USISRL = 1 to release SDA
227
              USICTL0 |= USIGE;                 // Transparent latch enabled
228
              USICTL0 &= ~(USIGE+USIOE);        // Latch/SDA output disabled
229
              I2C_State = 0;                    // Reset state machine for next xmt
230
              LPM0_EXIT;                        // Exit active for next transfer
231
              break;
232
    }
233
234
    USICTL1 &= ~USIIFG;                           // Clear pending flag
235
}
236
237
238
void Data_TX (void){
239
  USISRL = Daten[Bytecount];
240
    //i++;
241
    USICNT |=  0x08;                        // Bit counter = 8, start TX
242
    I2C_State = 10;                         // next state: receive data (N)Ack
243
    Bytecount++;
244
}
245
246
247
void Setup_USI_Master_TX (void){ 
248
    _DINT();
249
    Bytecount = 0;
250
    Transmit = 1;
251
    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST;      // Port & USI mode setup
252
    USICTL1 = USII2C+USIIE;                       // Enable I2C mode & USI interrupt
253
    USICKCTL = USIDIV_7+USISSEL_2+USICKPL;        // USI clk: SCL = SMCLK/128
254
    USICNT |= USIIFGCC;                           // Disable automatic clear control
255
    USICTL0 &= ~USISWRST;                         // Enable USI
256
    USICTL1 &= ~USIIFG;                           // Clear pending flag
257
    _EINT();
258
}
259
260
261
262
void Master_Transmit(void){
263
  Setup_USI_Master_TX();
264
    USICTL1 |= USIIFG;                          // Set flag and start communication
265
    LPM0;                                       // CPU off, await USI interrupt
266
    __delay_cycles(10000);                      // Delay between comm cycles
267
    
268
    P1OUT |= 0x01;                          // LED on: sequence start
269
}
270
271
272
// ADC10 interrupt service routine
273
#pragma vector=ADC10_VECTOR
274
__interrupt void ADC10_ISR(void)
275
{
276
  __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
277
}
278
279
/******************************************************
280
// Timer interrupt service routine
281
******************************************************/
282
#pragma vector=TIMERA0_VECTOR
283
__interrupt void Timer_A (void)
284
{
285
  if(m!=1){
286
    number_of_bytes = 5;
287
    Daten = leise;
288
    Master_Transmit();
289
    zustand = 0;
290
    __delay_cycles(10000);
291
    
292
    Daten = mittelwert_start;
293
    Master_Transmit();
294
    __delay_cycles(10000);
295
  }
296
  m = 0;
297
}

von Stefan (Gast)


Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

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
1
BCSCTL3 = LFXT1S_2
 eigentlich?

von Stefan (Gast)


Lesenswert?

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

von Scrub (Gast)


Lesenswert?

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?

von Scrub (Gast)


Lesenswert?

Ich denke, dass ich den Timer for einer warte-Schleife ersetzten werde.
Ist nicht so elegant, würde aber trotzdem gehen oder?

von Scrub (Gast)


Lesenswert?

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.
1
//******************************************************************************
2
//  MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes
3
//
4
//  Description: I2C Master communicates with I2C Slave using
5
//  the USI. Master data should increment from 0x55 with each transmitted byte
6
//  and Master determines the number of bytes recieved, set by 
7
//  the Number_of_Bytes value. LED off for address or data Ack; 
8
//  LED on for address or data NAck.
9
//  ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
10
//
11
//
12
//  ***THIS IS THE MASTER CODE***
13
//
14
//                  Slave                      Master
15
//     (msp430g2x21_usi_15.c)
16
//             MSP430G2x21/G2x31          MSP430G2x21/G2x31
17
//             -----------------          -----------------
18
//         /|\|              XIN|-    /|\|              XIN|-
19
//          | |                 |      | |                 |
20
//          --|RST          XOUT|-     --|RST          XOUT|-
21
//            |                 |        |                 |
22
//      LED <-|P1.0             |        |                 |
23
//            |                 |        |             P1.0|-> LED
24
//            |         SDA/P1.7|------->|P1.6/SDA         |
25
//            |         SCL/P1.6|<-------|P1.7/SCL         |
26
//
27
//  Note: internal pull-ups are used in this example for SDA & SCL
28
//
29
//  D. Dang
30
//  Texas Instruments Inc.
31
//  October 2010
32
//  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
33
//******************************************************************************
34
35
#include <msp430g2231.h>
36
37
void Master_Transmit(void);
38
//void Master_Recieve(void);
39
40
void Setup_USI_Master_TX(void);
41
//void Setup_USI_Master_RX(void);
42
43
char SLV_Addr = 0x90;                       
44
45
char *Daten;
46
47
//..............................................................................................
48
//......Adressen..und..Daten....................................................................
49
//..............................................................................................
50
char preamplifier [] = {0x00, 0x00};
51
char postamplifier [] = {0x00, 0x00};
52
53
char laut [] = {0x09, 0x00, 0x00, 0x00, 0xC0};
54
char leise [] = {0x09, 0x00, 0x00, 0x00, 0x00};
55
56
char mittelwert_stop [] = {0x1F, 0x00, 0x00, 0x00, 0x00};
57
char mittelwert_start [] = {0x1F, 0x00, 0x00, 0x01, 0x5D};
58
59
int I2C_State = 0;                    // State variable
60
int Bytecount = 0;
61
//unsigned int i;                            // Use volatile to prevent removal
62
unsigned int m = 1;
63
unsigned int zustand;
64
unsigned int number_of_bytes;
65
66
//unsigned int mem1 = 0;
67
unsigned int mem2 = 0;
68
long k = 0;
69
70
void Data_TX (void);
71
//void Data_RX (void);
72
73
74
75
void main(void)
76
{
77
78
  WDTCTL = WDTPW + WDTHOLD;                     // Stop watchdog
79
80
  
81
  ADC10AE0 |= 0x06;                         // PA.1 ADC option select
82
  //P1DIR |= 0x01;                            // Set P1.0 to output direction
83
  
84
  if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF){  
85
    while(1);                                   // If calibration constants erased
86
                                                 // do not load, trap CPU!!
87
  } 
88
89
  BCSCTL1 = CALBC1_1MHZ;                        // Set DCO
90
  DCOCTL = CALDCO_1MHZ;
91
92
  P1OUT = 0xC0;                                 // P1.6 & P1.7 Pullups, others to 0
93
  P1REN |= 0xC0;                                // P1.6 & P1.7 Pullups
94
  P1DIR = 0xFF;                                 // Unused pins as outputs
95
  P2OUT = 0;
96
  P2DIR = 0xFF;
97
  
98
  //Setup the Timer
99
  CCTL0 &= ~CCIE;                             // CCR0 interrupt enabled
100
  TACCR0 = 5000;
101
  TACTL = TASSEL_1 + MC_1;                  
102
  //_BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
103
  
104
  P1OUT &= ~0x01;
105
//  for(k=0;k<40000;k++);  P1OUT ^= 0x01;
106
//  for(k=0;k<40000;k++);  P1OUT ^= 0x01;
107
//  for(k=0;k<40000;k++);  P1OUT ^= 0x01;
108
//  for(k=0;k<40000;k++);  P1OUT ^= 0x01;
109
//  for(k=0;k<40000;k++);  P1OUT ^= 0x01;
110
//  for(k=0;k<40000;k++);  P1OUT ^= 0x01;
111
112
113
  while(1){
114
    
115
    CCTL0 &= ~CCIE;
116
    ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
117
    ADC10CTL1 = INCH_2;
118
    //for (k=0; k<1; k++){
119
      
120
      ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
121
      __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
122
      //CCTL0 = CCIE;
123
    //}
124
    mem2 = ADC10MEM;
125
    
126
    ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
127
    ADC10CTL1 = INCH_1;
128
    //for (k=0; k<1; k++){
129
      //CCTL0 &= ~CCIE;
130
      ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
131
      __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
132
    //}
133
    //mem1 = ADC10MEM;
134
    CCTL0 = CCIE;
135
    
136
    if(ADC10MEM < mem2){              //Audio größer als Schwelle
137
      if (zustand == 0){
138
        number_of_bytes = 5;
139
        Daten = mittelwert_stop;
140
        Master_Transmit();
141
        __delay_cycles(10000);
142
        
143
        Daten = laut;
144
      Master_Transmit();
145
      zustand = 1;
146
        __delay_cycles(10000);
147
      }
148
      
149
      m = 1;
150
    }
151
    //for(k=0;k<40000;k++);
152
    /*
153
    if (mem1 < mem2)
154
      P1OUT &= ~0x01;                       // Clear P1.0 LED off
155
    else
156
      P1OUT |= 0x01;                        // Set P1.0 LED on
157
    */  
158
  }     
159
 
160
}
161
162
/******************************************************
163
// USI interrupt service routine
164
// Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14
165
// Data Recieve  : state 0 -> 2 -> 4 -> 6 -> 8 -> 14
166
******************************************************/
167
#pragma vector = USI_VECTOR
168
__interrupt void USI_TXRX (void)
169
{
170
  CCTL0 &= ~CCIE;
171
  switch(__even_in_range(I2C_State,14))
172
    {
173
      case 0:                     // Generate Start Condition & send address to slave
174
//              P1OUT |= 0x01;                    // LED on: sequence start
175
//              for(m=0;m<30000;m++){}
176
//              P1OUT &= ~0x01;
177
              Bytecount = 0;
178
              USISRL = 0x00;                    // Generate Start Condition...
179
              USICTL0 |= USIGE+USIOE;
180
              USICTL0 &= ~USIGE;
181
              
182
                USISRL = 0x68;                  // Address is 0x48 << 1 bit + 0 (rw)
183
              
184
              USICNT = (USICNT & 0xE0) + 0x08;     // Bit counter = 8, TX Address
185
              I2C_State = 2;                    // next state: rcv address (N)Ack
186
              break;
187
188
      case 2:                     // Receive Address Ack/Nack bit
189
              USICTL0 &= ~USIOE;                // SDA = input
190
              //P1DIR = 0x00;
191
              USICNT |= 0x01;                   // Bit counter=1, receive (N)Ack bit
192
              I2C_State = 4;                    // Go to next state: check (N)Ack
193
              break;
194
195
      case 4:                     // Process Address Ack/Nack & handle data TX             
196
         //if(Transmit == 1){
197
                USICTL0 |= USIOE;                 // SDA = output
198
                if (USISRL & 0x01)                // If Nack received...
199
                {                   // Send stop...
200
                  USISRL = 0x00;
201
                  USICNT |=  0x01;              // Bit counter=1, SCL high, SDA low
202
                  I2C_State = 14;               // Go to next state: generate Stop
203
                  //P1OUT |= 0x01;                // Turn on LED: error
204
                }
205
                else
206
                {                   // Ack received, TX data to slave... 
207
                  //USISRL = MST_Data++;            // Load data byte
208
                  USISRL = Daten[Bytecount];
209
                  USICNT |=  0x08;                // Bit counter = 8, start TX
210
                  I2C_State = 10;                 // next state: receive data (N)Ack
211
                  Bytecount++;
212
                }
213
         //}
214
//         
215
              break;
216
217
//    case 6:                     // Send Data Ack/Nack bit      
218
//              USICTL0 |= USIOE;                 // SDA = output
219
//              if (Bytecount <= number_of_bytes-2)
220
//              {                                 // If this is not the last byte
221
//                USISRL = 0x00;                  // Send Ack
222
//                P1OUT &= ~0x01;                 // LED off
223
//                I2C_State = 4;                  // Go to next state: data/rcv again
224
//                Bytecount++;
225
//              }
226
//              else                   //last byte: send NACK
227
//              {
228
//                USISRL = 0xFF;                  // Send NAck
229
//                P1OUT |= 0x01;                  // LED on: end of comm
230
//                I2C_State = 8;                  // stop condition
231
//              }
232
//              USICNT |= 0x01;                   // Bit counter = 1, send (N)Ack bit
233
//              break;
234
//
235
//      case 8:                     // Prep Stop Condition
236
//              USICTL0 |= USIOE;                 // SDA = output
237
//              USISRL = 0x00;
238
//              USICNT |=  0x01;                  // Bit counter= 1, SCL high, SDA low
239
//              I2C_State = 14;                   // Go to next state: generate Stop
240
//              break;
241
242
      case 10:                     // Receive Data Ack/Nack bit
243
              USICTL0 &= ~USIOE;                // SDA = input
244
              USICNT |= 0x01;                   // Bit counter = 1, receive (N)Ack bit
245
              I2C_State = 12;                   // Go to next state: check (N)Ack
246
              break;
247
248
      case 12:                     // Process Data Ack/Nack & send Stop
249
              USICTL0 |= USIOE;
250
              if (Bytecount == number_of_bytes){  // If last byte
251
              USISRL = 0x00;
252
              
253
              I2C_State = 14;                   // Go to next state: generate Stop
254
              P1OUT |= 0x01;
255
              USICNT |=  0x01;     }            // set count=1 to trigger next state
256
              else{
257
                P1OUT &= ~0x01;                 // Turn off LED
258
                Data_TX();                      // TX byte
259
              }
260
              break;
261
262
      case 14:                    // Generate Stop Condition
263
              USISRL = 0x0FF;                   // USISRL = 1 to release SDA
264
              USICTL0 |= USIGE;                 // Transparent latch enabled
265
              USICTL0 &= ~(USIGE+USIOE);        // Latch/SDA output disabled
266
              I2C_State = 0;                    // Reset state machine for next xmt
267
              LPM0_EXIT;                        // Exit active for next transfer
268
              break;
269
    }
270
271
    USICTL1 &= ~USIIFG;                           // Clear pending flag
272
    CCTL0 = CCIE;
273
}
274
275
276
void Data_TX (void){
277
  USISRL = Daten[Bytecount];
278
    //i++;
279
    USICNT |=  0x08;                        // Bit counter = 8, start TX
280
    I2C_State = 10;                         // next state: receive data (N)Ack
281
    Bytecount++;
282
}
283
284
/*
285
void Data_RX (void){
286
  USICTL0 &= ~USIOE;                        // SDA = input --> redundant
287
    USICNT |=  0x08;                            // Bit counter = 8, RX data
288
    I2C_State = 6;                             // Next state: Test data and (N)Ack
289
    P1OUT &= ~0x01;                           // LED off
290
}
291
*/
292
293
void Setup_USI_Master_TX (void){ 
294
    _DINT();
295
    Bytecount = 0;
296
    //Transmit = 1;
297
    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST;      // Port & USI mode setup
298
    USICTL1 = USII2C+USIIE;                       // Enable I2C mode & USI interrupt
299
    USICKCTL = USIDIV_7+USISSEL_2+USICKPL;        // USI clk: SCL = SMCLK/128
300
    USICNT |= USIIFGCC;                           // Disable automatic clear control
301
    USICTL0 &= ~USISWRST;                         // Enable USI
302
    USICTL1 &= ~USIIFG;                           // Clear pending flag
303
    _EINT();
304
}
305
306
/*
307
void Setup_USI_Master_RX (void){ 
308
    _DINT();
309
    Bytecount = 0;
310
    Transmit = 0;
311
    USICTL0 = USIPE6+USIPE7+USIMST+USISWRST;      // Port & USI mode setup
312
    USICTL1 = USII2C+USIIE;                       // Enable I2C mode & USI interrupt
313
    //USICKCTL = USIDIV_7+USISSEL_2+USICKPL;        // USI clks: SCL = SMCLK/128
314
    USICKCTL = USIDIV_4+USISSEL_2+USICKPL;        // USI clks: SCL = SMCLK/128                      
315
    USICNT |= USIIFGCC;                           // Disable automatic clear control
316
    USICTL0 &= ~USISWRST;                         // Enable USI
317
    USICTL1 &= ~USIIFG;                           // Clear pending flag
318
    _EINT();
319
}
320
*/
321
322
void Master_Transmit(void){
323
  Setup_USI_Master_TX();
324
    USICTL1 |= USIIFG;                          // Set flag and start communication
325
    LPM0;                                       // CPU off, await USI interrupt
326
    __delay_cycles(10000);                      // Delay between comm cycles
327
    
328
    P1OUT |= 0x01;                          // LED on: sequence start
329
}
330
/*void Master_Recieve(void){
331
    Setup_USI_Master_RX();
332
    USICTL1 |= USIIFG;                            // Set flag and start communication
333
    LPM0;                                         // CPU off, await USI interrupt
334
    __delay_cycles(10000);                        // Delay between comm cycles
335
}
336
*/
337
338
// ADC10 interrupt service routine
339
#pragma vector=ADC10_VECTOR
340
__interrupt void ADC10_ISR(void)
341
{
342
  __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
343
}
344
345
/******************************************************
346
// Timer interrupt service routine
347
******************************************************/
348
#pragma vector=TIMERA0_VECTOR
349
__interrupt void Timer_A (void)
350
{
351
  P1OUT ^= 0x01;
352
  if(m!=1){
353
    
354
    number_of_bytes = 5;
355
    Daten = leise;
356
    Master_Transmit();
357
    zustand = 0;
358
    __delay_cycles(10000);
359
    
360
    Daten = mittelwert_start;
361
    Master_Transmit();
362
    __delay_cycles(10000);
363
  }
364
  m = 0;
365
}

von Scrub (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Scrub (Gast)


Lesenswert?

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?

von Scrub (Gast)


Lesenswert?

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?

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.