-
Notifications
You must be signed in to change notification settings - Fork 9
/
i2c.c
129 lines (106 loc) · 4.79 KB
/
i2c.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
//code adapted from http://www.43oh.com/forum/viewtopic.php?f=9&t=139
//Kerry D. Wong
//http://www.kerrywong.com
#include <msp430.h>
#include <legacymsp430.h>
#include "i2c.h"
#include "pins.h"
void i2c_init(void)
{
P1DIR |= SCL | SDA; // Set SCL, SDA and LED as Output
// Set Pull-Ups on SCL and SDA
P1REN |= SCL | SDA;
P1OUT |= SCL | SDA;
// enable SDA, SCL, SCLK, i2c mode, MSB, output enabled, hold in reset
USICTL0 = USIPE7 | USIPE6 | USIMST | USIOE | USISWRST;
// USICTL0 Upper 8bit Register of 16bit USICTL Register
// USIPE7 = P1.7 USI Mode, i2c SDA enabled
// USIPE6 = P1.6 USI Mode, i2c SCL enabled
// USIPE5 = P1.5 USI Mode, i2c Clock Input? (Not Set)
// USILSB = LSB Mode (Not Set = MSB)
// USIMST = Master Mode
// USIGE = Output Latch (Not Set = Clock Controlled)
// USIOE = Data Output Enable
// USISWRST = USI Software Reset (Set to allow changing settings)
// SMCLK / 4, and Reverse Clock Polarity
USICKCTL = USIDIV_7 + USISSEL_2 + USICKPL;
// USICKCTL 8bit USI Clock Control Register
// USIDIVx = Clock Divider (Bit7-5, USIDIV_2 = Divide by 4)
// USISSELx = Clock Source (For Master Mode, Bit4-2, USISSEL_2 = SMCLK)
// USICKPL = Clock Polarity (0 = Inactive Low, 1 = Inactive High)
// USISWCLK = Software Clock State
// I2C Mode
USICTL1 = USII2C;
// USICTL1 Lower 8bit Register of 16bit USICTL Register
// USICKPH = Clock Phase (0 = Data Changed, then Captured, 1 = Data Captured, then Changed)
// USII2C = I2C mode
// USISTTIE = START condition Interrupt
// USIIE = USI Counter Interrupt
// USIAL = Arbitration Lost Notification
// USISTP = STOP condition Notification
// USISTTIFG = START condition Int. Flag
// USIIFG = USI Counter Int. Flag
// release from reset
USICTL0 &= ~USISWRST;
}
void i2c_start(void)
{
//P1OUT |= LED; // Turn P1.0 Led on
// Send i2c START condition
USISRL = 0x00; // Load USISRL Lower Byte Shift Register MSB with 0 for i2c START
USICTL0 |= USIGE | USIOE; // Force Output Latch, And Enable Data Output Bit (High to Low SDA while SCL is High)
USICTL0 &= ~USIGE; // Clear Output Latch (Return to Clock Control)
}
void i2c_stop(void)
{
// Prepare i2c STOP condition
USICTL0 |= USIOE; // Enable Data Output Bit (Turn SDA into Output)
USISRL = 0x00; // Load USISRL Lower Byte Shift Register MSB with 0 for i2c STOP
USICNT = 1; // Load USICNT Counter with number of Bits to Send. USIIFG Auto-Cleared
// Data TXed by USI I2C
while((USICTL1 & USIIFG) != 0x01); // Delay, Wait for USIIFG, Counter down to 0
// Send i2c STOP condition
USISRL = 0xFF; // Load USISRL Lower Byte Shift Register MSB with 1 for i2c STOP
USICTL0 |= USIGE; // Force Output Latch (Low to High SDA while SCL is High)
USICTL0 &= ~USIOE & ~USIGE ; // Clear Data Output Enable Bit and Output Latch (Release SCL)
//P1OUT &= ~LED; // Turn P1.0 Led off
}
unsigned char i2c_write8(unsigned char c)
{
// TX
USICTL0 |= USIOE; // Enable Data Output Bit (Turn SDA into Output)
USISRL = c; // Load USISRL Lower Byte Shift Register with 8 Bit data (Byte)
USICNT = 8; // Load USICNT Counter with number of Bits to Send. USIIFG Auto-Cleared
// Data TXed by USI I2C
while((USICTL1 & USIIFG) != 0x01); // Delay, Wait for USIIFG, Counter down to 0
// RX
// Data TXed. Ready to Receive (n)ACK from i2c Slave
USICTL0 &= ~USIOE; // Clear Data Output Enable Bit (Turn SDA into Input)
USICNT = 1; // Load USICNT Counter with number of Bits to Receive. USIIFG Auto-Cleared
// Data RXed by USI I2C
while((USICTL1 & USIIFG) != 0x01); // Delay, Wait for USIIFG, Counter down to 0
// Return Data
c = USISRL; // LSB of USISRL Holds Ack Status of 0 = ACK (0x00) or 1 = NACK (0x01)
return c;
}
unsigned char i2c_read8(unsigned char acknack)
{
// RX
USICTL0 &= ~USIOE; // Clear Data Output Enable Bit (Turn SDA into Input)
USISRL = 0x00; // Clear USISRL Lower Byte Shift Register (Byte)
USICNT = 8; // Load USICNT Counter with number of Bits to Receive. USIIFG Auto-Cleared
// Data RXed by USI I2C
while((USICTL1 & USIIFG) != 0x01); // Delay, Wait for USIIFG, Counter down to 0
// Copy Data to c
unsigned char c;
c = USISRL; // USISRL Holds Received Data
// TX
// Data RXed. Ready to Send (n)ACK to i2c Slave
USICTL0 |= USIOE; // Enable Data Output Bit (Turn SDA into Output)
USISRL = acknack; // Load USISRL Lower Byte Shift Register MSB with acknack (0x00 = Ack, 0xFF = Nack)
USICNT = 1; // Load USICNT Counter with number of Bits to Send. USIIFG Auto-Cleared
// Data TXed by USI I2C
while((USICTL1 & USIIFG) != 0x01); // Delay, Wait for USIIFG, Counter down to 0
// Return Data
return c;
}