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