-
Notifications
You must be signed in to change notification settings - Fork 0
/
i2c.c
224 lines (190 loc) · 6.88 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#include <xc.h>
#include <stdint.h>
#include "i2c.h"
#define I2C_SLAVE 0x2A
#define GLOBAL_LENGTH 8 //38-31
#define LED_LENGTH 9 // sizeof(LED)
#define MACHINE_SIZE 44 // sizeof(Machine)
#define LED_COUNT 4
void sendByte(uint8_t);
void I2CWait();
void I2CStart();
void I2CStop();
void computeUpdate(uint8_t * value, uint8_t * adrss, uint8_t * lastVal, uint8_t adress, const uint8_t * prev, const uint8_t * new);
void sendGlobals(const Machine * source);
void sendLED(const LED * source, uint8_t offset);
uint8_t getLED(const LED * source, uint8_t byteNo);
uint8_t getConfigByte(const Machine * source);
Machine last;
void configI2C(){
TRISB5 = 1;
TRISB7 = 1;
SSP2CON1 = 0b00101000;
SSP2ADD = 39; // 16000 kHz /(4 × (39 + 1)) = 100kHz
SSP2STAT = 0b10000000; //disable Slewratecontrol
}
//sends every byte in the machine to the slave and saves it in *last*
void sendStateMachine(const Machine * m){
//save machine
last = *m;
sendGlobals(m);
sendLED(&(last.LEDs[0]), MM_LED0_BASE_ADDR);
sendLED(&(last.LEDs[1]), MM_LED1_BASE_ADDR);
sendLED(&(last.LEDs[2]), MM_LED2_BASE_ADDR);
sendLED(&(last.LEDs[3]), MM_LED3_BASE_ADDR);
}
//checks for delta to *last* and updates accordingly after updating *last*
void updateStateMachine(const Machine * m){
uint8_t value[MACHINE_SIZE];
uint8_t adrss[MACHINE_SIZE];
uint8_t lastVal = 0;
//assemble update list
computeUpdate(value, adrss, &lastVal, MM_LED_COUNTER_ADDR, &(last.Counter), &(m->Counter));
computeUpdate(value, adrss, &lastVal, MM_LED_ENABLE_ADDR, &(last.Enable), &(m->Enable));
computeUpdate(value, adrss, &lastVal, MM_LED_STEPSIZE_ADDR, &(last.StepSize), &(m->StepSize));
computeUpdate(value, adrss, &lastVal, MM_LED_ATMIN_NUMFRAMES_ADDR, &(last.AtMin_NumFrames), &(m->AtMin_NumFrames));
computeUpdate(value, adrss, &lastVal, MM_LED_RAMP_NUMFRAMES_ADDR, &(last.Ramp_NumFrames), &(m->Ramp_NumFrames));
computeUpdate(value, adrss, &lastVal, MM_LED_ATMAX_NUMFRAMES_ADDR, &(last.AtMax_NumFrames), &(m->AtMax_NumFrames));
//construct config bytes
uint8_t oldConf = getConfigByte(&last);
uint8_t newConf = getConfigByte(m);
computeUpdate(value, adrss, &lastVal, MM_LED_CONFIG_ADDR, &(oldConf), &(newConf));
computeUpdate(value, adrss, &lastVal, MM_LED_UPDATE_DELAY_ADDR, &(last.UpdateDelay), &(m->UpdateDelay));
//add led updates to the list
for(int i = 0; i < LED_COUNT; i++){
uint8_t baseAddr = 64 + (i*16);
uint8_t prvByte;
uint8_t newByte;
for(int j = 0; j < LED_LENGTH; j++){
prvByte = getLED(&(last.LEDs[i]), j);
newByte = getLED(&((*m).LEDs[i]), j);
computeUpdate(value, adrss, &lastVal, baseAddr + j, &(prvByte), &(newByte));
}
}
//work through update list
uint8_t done = 0;
while(done < lastVal){
uint8_t interval = 0;
while((done + interval + 1) < lastVal && adrss[done+interval] == (adrss[done+interval+1]-1)) interval++;
//account for first elem
interval++;
//send array
I2CStart();
uint8_t payload = (0x00 | I2C_SLAVE);
sendByte(payload); //Adress the LED Board
sendByte(adrss[done]);
for(int i = 0; i < interval; i++){
sendByte(value[done+i]);
}
I2CStop();
done+=interval;
}
//save machine
last = *m;
}
// //one transmission session according to doc
// void sendArray(const uint8_t arr[], uint8_t l, uint8_t offset){
// I2CStart();
// uint8_t payload = (0x00 | I2C_SLAVE);
// sendByte(payload); //Adress the LED Board
// sendByte(offset);
// for(int i = 0; i < l; i++){
// sendByte(arr[i]);
// }
// I2CStop();
// }
//send single byte
void sendByte(uint8_t byte){
SSP2BUF = byte; // Move data to SSPBUF
I2CWait();
if(SSP2CON2bits.ACKSTAT){ //Error; No Ack
LATC = 0b0001111;
while(1){
uint16_t s = 0xFFFF;
while(s != 0) s--;
LATC = 0b0000000;
s = 0xFFFF;
while(s != 0) s--;
LATC = 0b0001111;
};
}
}
//wait for i2c interrupt flag to turn off
void I2CWait(){
while(!SSP2IF) continue;
SSP2IF = 0;
}
//start i2c session
void I2CStart(){
SSP2IF = 0;
SSP2CON2bits.SEN = 1; // Generate Start Condition
I2CWait();
}
//end i2c session
void I2CStop(){
SSP2CON2bits.PEN = 1;// Generate Stop Condition
I2CWait();
}
//extract to LED information and returns it
uint8_t getLED(const LED * source, uint8_t byteNo){
switch(byteNo){
case 0: return (uint8_t) (0x00FF & ((*source).Brightness.Red >> 8));
case 1: return (uint8_t) (0x00FF & ((*source).Brightness.Red >> 0));
case 2: return (uint8_t) (0x00FF & ((*source).Brightness.Green >> 8));
case 3: return (uint8_t) (0x00FF & ((*source).Brightness.Green >> 0));
case 4: return (uint8_t) (0x00FF & ((*source).Brightness.Blue >> 8));
case 5: return (uint8_t) (0x00FF & ((*source).Brightness.Blue >> 0));
case 6: return (*source).State;
case 7: return (*source).LogDim;
case 8: return (*source).Count;
default: return 0;
}
}
//extracts the infromation for one LED and sends it over i2c
void sendLED(const LED * source, uint8_t offset){
I2CStart();
uint8_t payload = (0x00 | I2C_SLAVE);
sendByte(payload); //Adress the LED Board
sendByte(offset);
for(int i = 0; i < LED_LENGTH; i++){
sendByte(getLED(source, i));
}
I2CStop();
}
//extracts the infromation for the globals and sends it over i2c
void sendGlobals(const Machine * source){
I2CStart();
uint8_t payload = (0x00 | I2C_SLAVE);
sendByte(payload); //Adress the LED Board
sendByte(MM_LED_COUNTER_ADDR);
for(int i = 0; i < GLOBAL_LENGTH; i++){
switch(i){
case 0: payload = (*source).Counter; break;
case 1: payload = (*source).Enable; break;
case 2: payload = (*source).StepSize; break;
case 3: payload = (*source).AtMin_NumFrames; break;
case 4: payload = (*source).Ramp_NumFrames; break;
case 5: payload = (*source).AtMax_NumFrames; break;
case 6: payload = getConfigByte(source); break;
case 7: payload = (*source).UpdateDelay; break;
}
sendByte(payload);
}
I2CStop();
}
//generate config byte
uint8_t getConfigByte(const Machine * source){
uint8_t val = 0;
if((*source).Lock) val |= 0x80;
if((*source).Up) val |= 0x40;
if((*source).Log) val |= 0x20;
return val;
}
//compares the data and adds it to the update buffer if necessary
void computeUpdate(uint8_t * value, uint8_t * adrss, uint8_t * lastVal, uint8_t adress, const uint8_t * prev, const uint8_t * new){
if((*prev) != (*new)){
value[*lastVal] = (*new);
adrss[*lastVal] = adress;
(*lastVal)++;
}
}