]>
Commit | Line | Data |
---|---|---|
1 | #include <util/twi.h> | |
2 | #include <avr/interrupt.h> | |
3 | #include <stdio.h> | |
4 | #include "i2c.h" | |
5 | #include "bmc.h" | |
6 | #include "ipmb.h" | |
7 | ||
8 | #define TWCR_ACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC); | |
9 | #define TWCR_NACK TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC); | |
10 | #define TWCR_RESET TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(1<<TWSTO)|(0<<TWWC); | |
11 | ||
12 | volatile unsigned char i2c_databuf[24]; | |
13 | volatile uint8_t i2c_len = 0x00; | |
14 | static volatile uint8_t i2c_pos = 0x00; | |
15 | volatile uint8_t i2c_done = 0x00; | |
16 | ||
17 | #define I2C_FREQ 20000UL | |
18 | ||
19 | void i2c_init() | |
20 | { | |
21 | /* SCLf = F_CPU / (16 + 2 * TWBR * 4^TWPS) | |
22 | * TWPS is 0 => | |
23 | * TWBR = (F_CPU/(2 * SCL)) - 8 | |
24 | */ | |
25 | TWBR = (F_CPU/(2*I2C_FREQ))-8; | |
26 | TWAR = BMC_ADDR & 0xfe; | |
27 | TWDR = 0x00; | |
28 | TWCR &= ~((1<<TWSTA) | (1<<TWSTO)); | |
29 | TWCR |= ((1<<TWEA) | (1<<TWEN) | (1<<TWIE)); | |
30 | #ifdef __AVR_ATmega16__ | |
31 | PORTC = 0x03; | |
32 | #else | |
33 | #error "Don't know how to set pullups for this chip, please add support" | |
34 | #endif | |
35 | } | |
36 | ||
37 | void i2c_send(unsigned char *buf, int len) | |
38 | { | |
39 | uint8_t old_TWCR = TWCR; | |
40 | uint8_t old_SREG = SREG; | |
41 | int i; | |
42 | ||
43 | cli(); | |
44 | ||
45 | TWCR = ((1<<TWINT) | (1<<TWSTA) | (1<<TWEN)); /* Send start */ | |
46 | ||
47 | while(!(TWCR & (1<<TWINT))) {} | |
48 | if (TW_STATUS != TW_START) { | |
49 | #ifdef DEBUG | |
50 | printf("I2C: error sending START\n"); | |
51 | #endif | |
52 | goto out; | |
53 | } | |
54 | ||
55 | TWDR = buf[0]; /* SLA_W */ | |
56 | TWCR = ((1<<TWINT) | (1<<TWEN)); | |
57 | ||
58 | while(!(TWCR & (1<<TWINT))) {} | |
59 | if (TW_STATUS != TW_MT_SLA_ACK) { | |
60 | #ifdef DEBUG | |
61 | printf("I2C: error sending SLA_W\n"); | |
62 | #endif | |
63 | goto out2; | |
64 | } | |
65 | ||
66 | for(i = 1; i < len; i++) { | |
67 | TWDR = buf[i]; /* Send Data */ | |
68 | TWCR = ((1<<TWINT) | (1<<TWEN)); | |
69 | ||
70 | while(!(TWCR & (1<<TWINT))) {} | |
71 | if (TW_STATUS != TW_MT_DATA_ACK) { | |
72 | #ifdef DEBUG | |
73 | printf("I2C: error sending DATA byte %d\n", i); | |
74 | #endif | |
75 | goto out2; | |
76 | } | |
77 | } | |
78 | ||
79 | #ifdef DEBUG | |
80 | printf("I2C Data sent\n"); | |
81 | #endif | |
82 | ||
83 | out2: | |
84 | TWCR = ((1<<TWINT) | (1<<TWEN) | (1<<TWSTO)); | |
85 | while(TWCR & (1<<TWSTO)) {} | |
86 | ||
87 | out: | |
88 | SREG = old_SREG; | |
89 | TWCR = old_TWCR | (1<<TWINT); | |
90 | } | |
91 | ||
92 | ISR (TWI_vect, ISR_BLOCK) | |
93 | { | |
94 | if (i2c_done) | |
95 | TWCR_RESET; | |
96 | ||
97 | switch (TW_STATUS) { | |
98 | case TW_SR_SLA_ACK: | |
99 | #ifdef DEBUG | |
100 | printf("I2C: Slave 0x%02x adressed\n", TWDR); | |
101 | #endif | |
102 | i2c_pos = 0x00; | |
103 | i2c_databuf[i2c_pos] = TWDR; | |
104 | i2c_pos++; | |
105 | TWCR_ACK; | |
106 | break; | |
107 | ||
108 | case TW_SR_DATA_ACK: | |
109 | #ifdef DEBUG | |
110 | printf("I2C: Data received: 0x%02x\n", TWDR); | |
111 | #endif | |
112 | if (i2c_pos >= sizeof(i2c_databuf)) { | |
113 | TWCR_RESET; | |
114 | i2c_pos = 0x00; | |
115 | break; | |
116 | } | |
117 | i2c_databuf[i2c_pos] = TWDR; | |
118 | i2c_pos++; | |
119 | TWCR_ACK; | |
120 | break; | |
121 | ||
122 | case TW_SR_STOP: | |
123 | #ifdef DEBUG | |
124 | printf("I2C: STOP received\n"); | |
125 | #endif | |
126 | i2c_len = i2c_pos; | |
127 | i2c_pos = 0x00; | |
128 | i2c_done = 0x01; | |
129 | TWCR_RESET; | |
130 | break; | |
131 | ||
132 | case TW_NO_INFO: | |
133 | #ifdef DEBUG | |
134 | printf("I2C: TW_NO_INFO received status 0x%2x\n", TW_STATUS); | |
135 | #endif | |
136 | TWCR |= (1<<TWINT); | |
137 | break; | |
138 | ||
139 | default: | |
140 | #ifdef DEBUG | |
141 | printf("I2C: Unimplemented status 0x%02x\n", TW_STATUS); | |
142 | #endif | |
143 | TWCR_RESET; | |
144 | break; | |
145 | } | |
146 | } |