1 | //******************************************************************************
|
2 | // MSP430F20xx Demo - I2C Slave Receiver / Slave Transmitter, 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 | // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz
|
7 | //
|
8 | // ***THIS IS THE SLAVE CODE***
|
9 | //
|
10 | // Slave Master
|
11 | // (msp430x20x3_usi_12.c)
|
12 | // MSP430F20x2/3 MSP430F20x2/3
|
13 | // ----------------- -----------------
|
14 | // /|\| XIN|- /|\| XIN|-
|
15 | // | | | | | |
|
16 | // --|RST XOUT|- --|RST XOUT|-
|
17 | // | | | |
|
18 | // LED <-|P1.0 | | |
|
19 | // | | | P1.0|-> LED
|
20 | // | SDA/P1.7|------->|P1.6/SDA |
|
21 | // | SCL/P1.6|<-------|P1.7/SCL |
|
22 | //
|
23 | // Note: internal pull-ups are used in this example for SDA & SCL
|
24 | //
|
25 | // R. B. Elliott / H. Grewal
|
26 | // Texas Instruments Inc.
|
27 | // February 2008
|
28 | // Built with IAR Embedded Workbench Version: 3.42A
|
29 | //******************************************************************************
|
30 |
|
31 | #include <msp430x20x3.h>
|
32 | #define Number_of_Bytes 5 // **** How many bytes?? ****
|
33 |
|
34 | void Setup_USI_Slave(void);
|
35 |
|
36 | char MST_Data = 0; // Variable for received data
|
37 | char SLV_Data = 0x55;
|
38 | char SLV_Addr = 0x90; // Address is 0x48<<1 for R/W
|
39 | int I2C_State, Bytecount, transmit = 0; // State variables
|
40 |
|
41 | void Data_RX(void);
|
42 | void TX_Data(void);
|
43 | void main(void)
|
44 | {
|
45 | WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
|
46 | if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
|
47 | {
|
48 | while(1); // If calibration constants erased
|
49 | // do not load, trap CPU!!
|
50 | }
|
51 | BCSCTL1 = CALBC1_1MHZ; // Set DCO
|
52 | DCOCTL = CALDCO_1MHZ;
|
53 | Setup_USI_Slave();
|
54 |
|
55 | LPM0; // CPU off, await USI interrupt
|
56 | _NOP();
|
57 | }
|
58 |
|
59 | //******************************************************************************
|
60 | // USI interrupt service routine
|
61 | // Rx bytes from master: State 2->4->6->8
|
62 | // Tx bytes to Master: State 2->4->10->12->14
|
63 | //******************************************************************************
|
64 | #pragma vector = USI_VECTOR
|
65 | __interrupt void USI_TXRX (void)
|
66 | {
|
67 | if (USICTL1 & USISTTIFG) // Start entry?
|
68 | {
|
69 | P1OUT |= 0x01; // LED on: sequence start
|
70 | I2C_State = 2; // Enter 1st state on start
|
71 | }
|
72 |
|
73 | switch(__even_in_range(I2C_State,14))
|
74 | {
|
75 | case 0: // Idle, should not get here
|
76 | break;
|
77 |
|
78 | case 2: // RX Address
|
79 | USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, RX address
|
80 | USICTL1 &= ~USISTTIFG; // Clear start flag
|
81 | I2C_State = 4; // Go to next state: check address
|
82 | break;
|
83 |
|
84 | case 4: // Process Address and send (N)Ack
|
85 | if (USISRL & 0x01){ // If master read...
|
86 | SLV_Addr = 0x91; // Save R/W bit
|
87 | transmit = 1;}
|
88 | else{transmit = 0;
|
89 | SLV_Addr = 0x90;}
|
90 | USICTL0 |= USIOE; // SDA = output
|
91 | if (USISRL == SLV_Addr) // Address match?
|
92 | {
|
93 | USISRL = 0x00; // Send Ack
|
94 | P1OUT &= ~0x01; // LED off
|
95 | if (transmit == 0){
|
96 | I2C_State = 6;} // Go to next state: RX data
|
97 | if (transmit == 1){
|
98 | I2C_State = 10;} // Else go to next state: TX data
|
99 | }
|
100 | else
|
101 | {
|
102 | USISRL = 0xFF; // Send NAck
|
103 | P1OUT |= 0x01; // LED on: error
|
104 | I2C_State = 8; // next state: prep for next Start
|
105 | }
|
106 | USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
|
107 | break;
|
108 |
|
109 | case 6: // Receive data byte
|
110 | Data_RX();
|
111 | break;
|
112 |
|
113 | case 8:// Check Data & TX (N)Ack
|
114 | USICTL0 |= USIOE; // SDA = output
|
115 | if (Bytecount <= (Number_of_Bytes-2))
|
116 | // If not last byte
|
117 | {
|
118 | USISRL = 0x00; // Send Ack
|
119 | I2C_State = 6; // Rcv another byte
|
120 | Bytecount++;
|
121 | USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
|
122 | }
|
123 | else // Last Byte
|
124 | {
|
125 | USISRL = 0xFF; // Send NAck
|
126 | USICTL0 &= ~USIOE; // SDA = input
|
127 | SLV_Addr = 0x90; // Reset slave address
|
128 | I2C_State = 0; // Reset state machine
|
129 | Bytecount =0; // Reset counter for next TX/RX
|
130 | }
|
131 |
|
132 |
|
133 | break;
|
134 |
|
135 | case 10: // Send Data byte
|
136 | TX_Data();
|
137 | break;
|
138 |
|
139 | case 12:// Receive Data (N)Ack
|
140 | USICTL0 &= ~USIOE; // SDA = input
|
141 | USICNT |= 0x01; // Bit counter = 1, receive (N)Ack
|
142 | I2C_State = 14; // Go to next state: check (N)Ack
|
143 | break;
|
144 |
|
145 | case 14:// Process Data Ack/NAck
|
146 | if (USISRL & 0x01) // If Nack received...
|
147 | {
|
148 | USICTL0 &= ~USIOE; // SDA = input
|
149 | SLV_Addr = 0x90; // Reset slave address
|
150 | I2C_State = 0; // Reset state machine
|
151 | Bytecount = 0;
|
152 | // LPM0_EXIT; // Exit active for next transfer
|
153 | }
|
154 | else // Ack received
|
155 | {
|
156 | P1OUT &= ~0x01; // LED off
|
157 | TX_Data(); // TX next byte
|
158 | }
|
159 | break;
|
160 |
|
161 | }
|
162 | USICTL1 &= ~USIIFG; // Clear pending flags
|
163 | }
|
164 |
|
165 | void Data_RX(void){
|
166 |
|
167 | USICTL0 &= ~USIOE; // SDA = input
|
168 | USICNT |= 0x08; // Bit counter = 8, RX data
|
169 | I2C_State = 8; // next state: Test data and (N)Ack
|
170 | }
|
171 |
|
172 | void TX_Data(void){
|
173 | USICTL0 |= USIOE; // SDA = output
|
174 | USISRL = SLV_Data++;
|
175 | USICNT |= 0x08; // Bit counter = 8, TX data
|
176 | I2C_State = 12; // Go to next state: receive (N)Ack
|
177 | }
|
178 |
|
179 | void Setup_USI_Slave(void){
|
180 | P1OUT = 0xC0; // P1.6 & P1.7 Pullups
|
181 | P1REN |= 0xC0; // P1.6 & P1.7 Pullups
|
182 | P1DIR = 0xFF; // Unused pins as outputs
|
183 | P2OUT = 0;
|
184 | P2DIR = 0xFF;
|
185 |
|
186 | USICTL0 = USIPE6+USIPE7+USISWRST; // Port & USI mode setup
|
187 | USICTL1 = USII2C+USIIE+USISTTIE; // Enable I2C mode & USI interrupts
|
188 | USICKCTL = USICKPL; // Setup clock polarity
|
189 | USICNT |= USIIFGCC; // Disable automatic clear control
|
190 | USICTL0 &= ~USISWRST; // Enable USI
|
191 | USICTL1 &= ~USIIFG; // Clear pending flag
|
192 |
|
193 | transmit = 0;
|
194 | _EINT();
|
195 |
|
196 | }
|