-
Notifications
You must be signed in to change notification settings - Fork 0
/
Demo7_Slave_alternative.c
147 lines (136 loc) · 6.35 KB
/
Demo7_Slave_alternative.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* MSP430FR2355 as slave on I2C bus. Runs in a timed loop to blink green LED.
Receipt of 3-byte sequence 0x00 0x01 0x02 from master, halts the loop, latches
the red LED, and enters LPM4. The 3-byte sequence 0x04 0x05 0x06 restarts the
loop and clears the red LED. Interrupt to clear I2C bus if it hangs.
P1.2 SDA on UCB0
P1.3 SCL on UCB0
*/
#include <msp430.h>
#include <stdint.h>
volatile uint8_t RxData[3], RxCount, reg_reset;
volatile uint8_t *PRxData; // Pointer to receive buffer
void main(void) {
WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer
PM5CTL0 &= ~LOCKLPM5; //Unlock GPIO
P1SEL0 |= BIT2 + BIT3; //Set I2C pins; P1.2 UCB0SDA; P1.3 UCB0SCL
P1DIR |= BIT0 + BIT1 + BIT4 + BIT5 + BIT6 + BIT7; //Set these pins to outputs
P6DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7; //Set these pins to outputs
P1OUT &= ~BIT0; //LEDs off
P6OUT &= ~BIT6;
CSCTL4 = SELA__VLOCLK; //Set ACLK to VLO at 10 kHz
/* MC_1 to count up to TB0CCR0, set to ACLK (VLO) and divide it by 8.
The measured frequency is 1.2 kHz NOT 1.25 kHz. */
TB0CTL |= MC_1 + TBSSEL__ACLK + TBCLR;
TB0EX0 |= TBIDEX_7;
TB0CCTL0 = CCIE; //Enable the Timer B interrupt
UCB0CTLW0 = UCSWRST; // Software reset enabled
UCB0CTLW0 |= UCMODE_3 + UCSYNC; // I2C mode, sync mode (Do not set clock in slave mode)
UCB0CTLW1 |= UCCLTO_3; //34 ms I2C bus timeout
UCB0I2COA0 = 0x77 | UCOAEN; // Slave address is 0x77; enable it
UCB0CTLW0 &= ~UCSWRST; // Clear reset register
UCB0IE |= UCRXIE0 + UCSTPIE + UCCLTOIE; // Enable receive, stop, and timeout I2C interrupts
__enable_interrupt(); //Enable global interrupts.
RxCount =0;
//Main loop follows
while(1)
{
TB0CCR0 = 1100; //Looping period
TB0CTL |= TBCLR; //Clear the timer counter
LPM0; //Wait in low power mode for timeout
P6OUT |= BIT6; //Flash green LED
TB0CCR0 = 100;
TB0CTL |= TBCLR;
LPM0;
P6OUT &= ~BIT6; //Flash LED
if (RxCount == 0) ;
else if (RxCount == 3)
{
PRxData = (uint8_t *)RxData; // Point PRxData to start of RxData
if ((*PRxData == 1) && (*PRxData+1 == 2) && (*PRxData+2 == 3))
{
//Stop loop
RxCount=0;
P1OUT|= BIT0; //Red LED on
TB0CTL = MC_0; //Stop the timer
LPM4;
//Rx flag is raised. Need some time to read the I2C bus
__delay_cycles(100);
//Check for correct 3 byte string
while(1)
{
if (RxCount == 3)
{
PRxData = (uint8_t *)RxData; // Point PRxData to start of RxData
if ((*PRxData == 4) && (*PRxData+1 == 5) && (*PRxData+2 == 6)) //Re-start slave loop
{
RxCount=0;
P1OUT &= ~BIT0; //Clear red LED
TB0CTL |= MC_1 + TBSSEL__ACLK + TBCLR; //Restart timer
break;
}
else //Incorrect 3-byte command; go back to sleep
{
RxCount=0;
LPM4; //Wait in LPM4 for master data
__delay_cycles(100);
}
}
else //Need to receive 3 bytes to re-start loop
{
RxCount=0;
LPM4; //Wait in LPM4 for master data
__delay_cycles(100);
}
}
}
else RxCount=0;
}
else RxCount=0; //Byte count != 0 or !=3; reset count
} //end of main loop
}
#pragma vector=TIMER0_B0_VECTOR //This vector name is in header file
__interrupt void Timer_B (void)
{
LPM0_EXIT;
}
#pragma vector = USCI_B0_VECTOR
__interrupt void USCIB0_ISR(void)
{
switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
{
case USCI_NONE: break; // Vector 0: No interrupts
case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG
case USCI_I2C_UCNACKIFG:break; // Vector 4: NACKIFG
case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG
case USCI_I2C_UCSTPIFG: // Vector 8: STPIFG
UCB0IFG &= ~UCSTPIFG;
LPM4_EXIT;
break;
case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3
case USCI_I2C_UCTXIFG3: break; // Vector 14: TXIFG3
case USCI_I2C_UCRXIFG2: break; // Vector 16: RXIFG2
case USCI_I2C_UCTXIFG2: break; // Vector 18: TXIFG2
case USCI_I2C_UCRXIFG1: break; // Vector 20: RXIFG1
case USCI_I2C_UCTXIFG1: break; // Vector 22: TXIFG1
case USCI_I2C_UCRXIFG0: // Vector 24: RXIFG0
/* I2C data will load into the buffer when in low power modes.
Exiting from LPM must take place inside the interrupt. */
RxCount++;
*PRxData++ = UCB0RXBUF;
break;
case USCI_I2C_UCTXIFG0: break; // Vector 26: TXIFG0
case USCI_I2C_UCBCNTIFG: break; // Vector 28: BCNTIFG
case USCI_I2C_UCCLTOIFG: // Vector 30: clock low timeout. Try to reset I2C bus
reg_reset = UCB0IE; // Save current IE bits
P1SEL0 &= ~(BIT2); // Generate NACK by releasing SDA
P1SEL0 &= ~(BIT3); // then SCL by disconnecting from the I2C
UCB0CTLW0 |= UCSWRST; // Reset
UCB0CTLW0 &= ~UCSWRST;
P1SEL0 |= (BIT2|BIT3); // Re-connect pins to I2C
UCB0IE = reg_reset; // Reset interrupt register
UCB0IFG &= ~UCCLTOIFG; //Clear interrupt flag
break;
case USCI_I2C_UCBIT9IFG: break; // Vector 32: 9th bit
default: break;
}
}