Subversion Repositories Code-Repo

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
260 Kevin 1
// <editor-fold defaultstate="collapsed" desc="Configuration Bits">
2
// PIC16F1825 Configuration Bit Settings
3
 
4
// CONFIG1
5
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
273 Kevin 6
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT software controlled)
260 Kevin 7
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
8
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
9
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
10
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
11
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
12
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
13
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
14
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
15
 
16
// CONFIG2
17
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
18
#pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
19
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
20
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
21
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
22
// </editor-fold>
23
 
24
#include "defines.h"
25
#include "INTERRUPTS.h"
273 Kevin 26
#include "IO.h"
260 Kevin 27
#include "I2C1.h"
28
#include "I2C2.h"
277 Kevin 29
#include "CPS.h"
260 Kevin 30
#include "TLC59116.h"
31
#include "MCP23009.h"
32
 
273 Kevin 33
persistent uint8_t op_state;
260 Kevin 34
 
273 Kevin 35
void Reset_Board(uint8_t next_state) {
36
    op_state = next_state;
37
    RESET();
38
}
260 Kevin 39
 
273 Kevin 40
uint8_t Get_Last_Reset(void) {
41
    uint8_t ret;
42
    if (PCONbits.nPOR == 0) {
43
        ret = RESET_POR;
44
    } else if (PCONbits.nBOR == 0) {
45
        ret = RESET_BOR;
46
    } else if (STATUSbits.nTO == 0) {
47
        ret = RESET_WDT;
48
    } else if (PCONbits.nRMCLR == 0) {
49
        ret = RESET_MCLR;
50
    } else if (PCONbits.STKOVF || PCONbits.STKUNF) {
51
        ret = RESET_STK;
52
    } else if (PCONbits.nRI == 0) {
53
        ret = RESET_RST;
54
    } else {
55
        ret = RESET_POR;
56
    }
260 Kevin 57
 
273 Kevin 58
    PCON = 0x0F;
59
    STATUSbits.nPD = 1;
60
    STATUSbits.nTO = 1;
61
    return ret;
260 Kevin 62
}
63
 
64
uint8_t Read_Address(void) {
273 Kevin 65
    uint8_t ret = I2C1_SLAVE_PREFIX;
66
    if (!I2C_ADDR_3_PORT)
67
        ret |= 0x08;
68
    if (!I2C_ADDR_2_PORT)
69
        ret |= 0x04;
70
    if (!I2C_ADDR_1_PORT)
71
        ret |= 0x02;
72
    if (!I2C_ADDR_0_PORT)
73
        ret |= 0x01;
74
 
260 Kevin 75
    return ret;
76
}
77
 
273 Kevin 78
BTN_STATUS btns;
275 Kevin 79
LED_VALUES leds = {0x00};
273 Kevin 80
 
260 Kevin 81
int main(void) {
82
    uint8_t buffer[32];
83
    uint8_t result, length;
84
    uint8_t i2c_slave_addr;
273 Kevin 85
//    uint8_t op_state;
86
    uint8_t i;
260 Kevin 87
 
88
    // Set internal oscillator speed to 32MHz
89
    OSCCONbits.SPLLEN = 1;  // 4x PLL enable (overwritten by config bits)
90
    OSCCONbits.IRCF = 0xE;  // Base frequency @ 8MHz
91
    OSCCONbits.SCS = 0b00;  // System clock determined by config bits
92
 
93
    // Initialize I/O
273 Kevin 94
    IO_Init();
260 Kevin 95
 
273 Kevin 96
    uint8_t last_reset = Get_Last_Reset();
97
    if (last_reset == RESET_POR || last_reset == RESET_BOR ||
98
            last_reset == RESET_MCLR || last_reset == RESET_WDT ||
99
            last_reset == RESET_STK) {
100
        op_state = OP_STATE_IDLE;
101
    }
102
//    if (last_reset == RESET_RST) {
103
//        op_state = OP_STATE_ACTIVE;
104
//    }
105
 
260 Kevin 106
    i2c_slave_addr = Read_Address();
107
 
273 Kevin 108
    // Delay a bit to allow I2C lines to stabilize
275 Kevin 109
    __delay_ms(10);
273 Kevin 110
 
260 Kevin 111
    // Initialize I2C1 in slave mode
112
    I2C1_DATA i2c1_data;
113
    I2C1_Init(&i2c1_data);
114
    I2C1_Configure_Slave(i2c_slave_addr);
115
 
116
    // Initialize I2C2 in master mode
117
    I2C2_DATA i2c2_data;
118
    I2C2_Init(&i2c2_data);
275 Kevin 119
    I2C2_Configure_Master(I2C_1MHZ);
260 Kevin 120
 
277 Kevin 121
    CPS_DATA cps_data;
122
    CPS_Init(&cps_data);
123
 
260 Kevin 124
    // Initialize interrupts
125
    Interrupt_Init();
126
    Interrupt_Enable();
127
 
273 Kevin 128
    MCP23009_Init(&btns);
129
    MCP23009_Query();
130
 
260 Kevin 131
    TLC59116_Init();
273 Kevin 132
//    TLC59116_Write_All(&leds);
260 Kevin 133
 
273 Kevin 134
    if (op_state == OP_STATE_IDLE) {
275 Kevin 135
//        IO_IOC_Enable();
273 Kevin 136
        Idle_Animation();
137
    } else if (op_state == OP_STATE_ACTIVE) {
277 Kevin 138
        uint8_t button_R = 0, button_L = 0;
139
        uint8_t dir_state = DIR_S;
140
        leds.single.LED_S = DIR_BRIGHTNESS;
141
        TLC59116_Write_All(&leds);
273 Kevin 142
        while (1) {
143
            // Check if an I2C message was received
277 Kevin 144
            do {
145
                result = I2C1_Get_Status();
146
            } while (!result);
147
            length = I2C1_Read_Buffer(buffer);
148
            if (length == 1 && buffer[0] == CMD_RESET) {
149
                Reset_Board(OP_STATE_IDLE);
150
            } else if (length == 1 && buffer[0] == CMD_ACTIVE) {
151
                Reset_Board(OP_STATE_ACTIVE);
152
            } else if (length == 17 && buffer[0] == CMD_SET_LEDS) {
153
                for (i = 0; i < 16; i++) {
154
                    leds.w[i] = buffer[i + 1];
273 Kevin 155
                }
277 Kevin 156
                // Reset the direction LEDs
157
                if (dir_state == DIR_S)
158
                    leds.single.LED_S = DIR_BRIGHTNESS;
159
                else if (dir_state == DIR_W)
160
                    leds.single.LED_W = DIR_BRIGHTNESS;
161
                else if (dir_state == DIR_N)
162
                    leds.single.LED_N = DIR_BRIGHTNESS;
163
                else if (dir_state == DIR_E)
164
                    leds.single.LED_E = DIR_BRIGHTNESS;
165
                TLC59116_Write_All(&leds);
260 Kevin 166
            }
277 Kevin 167
 
275 Kevin 168
 
277 Kevin 169
            // Check if either capacitive buttons were pressed
170
            if (cps_data.btn_pressed[0] && button_R == 0) {
171
                // Right button went from unpressed -> pressed
172
                dir_state = Direction_Rotate_CClockwise(dir_state);
173
                TLC59116_Write_All(&leds);
174
            }
175
            if (cps_data.btn_pressed[1] && button_L == 0) {
176
                // Left button went from unpressed -> pressed
177
                dir_state = Direction_Rotate_Clockwise(dir_state);
178
                TLC59116_Write_All(&leds);
179
            }
180
            // Save the previous button state
181
            button_R = cps_data.btn_pressed[0];
182
            button_L = cps_data.btn_pressed[1];
183
 
184
            // Poll the hardware buttons
275 Kevin 185
            I2C2_Master_Restart(MCP23009_ADDR, MCP23009_GPIOA, 1);
186
            do {
187
                result = I2C2_Get_Status();
188
            } while (!result);
189
            length = I2C2_Read_Buffer(buffer);
190
            btns.w = buffer[0];
277 Kevin 191
            // Change the direction according to the user's perspective
192
            if (dir_state == DIR_W) {
193
                uint8_t tmp = btns.BTN_R_S;
194
                btns.BTN_R_S = btns.BTN_R_W;
195
                btns.BTN_R_W = btns.BTN_R_N;
196
                btns.BTN_R_N = btns.BTN_R_E;
197
                btns.BTN_R_E = tmp;
198
            } else if (dir_state == DIR_E) {
199
                uint8_t tmp = btns.BTN_R_S;
200
                btns.BTN_R_S = btns.BTN_R_E;
201
                btns.BTN_R_E = btns.BTN_R_N;
202
                btns.BTN_R_N = btns.BTN_R_W;
203
                btns.BTN_R_W = tmp;
204
            } else if (dir_state == DIR_N) {
205
                uint8_t tmp = btns.BTN_R_S;
206
                btns.BTN_R_S = btns.BTN_R_N;
207
                btns.BTN_R_N = tmp;
208
                tmp = btns.BTN_R_E;
209
                btns.BTN_R_E = btns.BTN_R_W;
210
                btns.BTN_R_W = tmp;
211
            }
260 Kevin 212
        }
270 Kevin 213
    }
214
}
260 Kevin 215
 
277 Kevin 216
uint8_t Direction_Rotate_Clockwise(uint8_t dir_state) {
217
    uint8_t ret;
218
    switch (dir_state) {
219
        case DIR_S:
220
            leds.single.LED_S = 0x00;
221
            leds.single.LED_W = DIR_BRIGHTNESS;
222
            ret = DIR_W;
223
            break;
224
        case DIR_W:
225
            leds.single.LED_W = 0x00;
226
            leds.single.LED_N = DIR_BRIGHTNESS;
227
            ret = DIR_N;
228
            break;
229
        case DIR_N:
230
            leds.single.LED_N = 0x00;
231
            leds.single.LED_E = DIR_BRIGHTNESS;
232
            ret = DIR_E;
233
            break;
234
        case DIR_E:
235
            leds.single.LED_E = 0x00;
236
            leds.single.LED_S = DIR_BRIGHTNESS;
237
            ret = DIR_S;
238
            break;
239
    }
240
    return ret;
241
}
242
 
243
uint8_t Direction_Rotate_CClockwise(uint8_t dir_state) {
244
    uint8_t ret;
245
    switch (dir_state) {
246
        case DIR_S:
247
            leds.single.LED_S = 0x00;
248
            leds.single.LED_E = DIR_BRIGHTNESS;
249
            ret = DIR_E;
250
            break;
251
        case DIR_E:
252
            leds.single.LED_E = 0x00;
253
            leds.single.LED_N = DIR_BRIGHTNESS;
254
            ret = DIR_N;
255
            break;
256
        case DIR_N:
257
            leds.single.LED_N = 0x00;
258
            leds.single.LED_W = DIR_BRIGHTNESS;
259
            ret = DIR_W;
260
            break;
261
        case DIR_W:
262
            leds.single.LED_W = 0x00;
263
            leds.single.LED_S = DIR_BRIGHTNESS;
264
            ret = DIR_S;
265
            break;
266
    }
267
    return ret;
268
}
269
 
270
void Check_I2C_Idle(void) {
275 Kevin 271
    uint8_t buffer[32];
272
    uint8_t result, length, i;
273
 
274
    // Check if an I2C message was received
275
    result = I2C1_Get_Status();
276
    if (result) {
277
        length = I2C1_Read_Buffer(buffer);
278
        if (length == 1 && buffer[0] == CMD_RESET) {
279
            Reset_Board(OP_STATE_IDLE);
280
        } else if (length == 1 && buffer[0] == CMD_ACTIVE) {
281
            Reset_Board(OP_STATE_ACTIVE);
282
        }
283
    }
284
}
285
 
270 Kevin 286
void Idle_Animation(void) {
287
    LED_VALUES leds = {0};
288
    uint8_t led_direction_bar[8] = {1,0,0,0,0,0,0,0};
289
    uint8_t led_direction_dir[8] = {1,0,0,0};
290
    uint8_t led_direction_ind[8] = {1,0,0,0};
291
    uint8_t led_8_high_thres = 0x80;    // Max brightness of the middle section
292
    uint8_t led_8_next_thresh = 0x40;   // Threshold to start the next LED
293
    uint8_t led_4_high_thres = 0x80;    // Max brightness of the side sections
294
    uint8_t led_4_next_thresh = 0x74;   // Threshold to start the next LED
295
    uint8_t i, next_led;
260 Kevin 296
 
270 Kevin 297
    for (i = 0; i < 16; i++) leds.w[i] = 0x00;
298
 
299
    while (1) {
300
 
275 Kevin 301
        // Check to see if a new message was received
277 Kevin 302
        Check_I2C_Idle();
275 Kevin 303
 
270 Kevin 304
        // Update the LEDs in the middle section
305
        for (i = 0; i < 8; i++) {
306
            // Change the LED brightness depending on its direction
307
            if (led_direction_bar[i] == 1) {
308
                leds.w[i]++;
309
            } else if (led_direction_bar[i] == 2) {
310
                leds.w[i]--;
311
            }
312
 
313
            // Change direction if peak brightness is reached
314
            // When the brightness reaches a middle threshold, start
315
            //   increasing the brightness of the next LED
316
            if (led_direction_bar[i] == 1 && leds.w[i] == led_8_high_thres) {
317
                led_direction_bar[i] = 2;
318
            } else if (led_direction_bar[i] == 1 && leds.w[i] == led_8_next_thresh) {
319
                next_led = (i == 7) ? 0 : i + 1;
320
                led_direction_bar[next_led] = 1;
321
            } else if (led_direction_bar[i] == 2 && leds.w[i] == 0x00) {
322
                led_direction_bar[i] = 0;
323
            }
324
        }
325
 
326
        // Update the LEDs in the right section
327
        for (i = 0; i < 4; i++) {
328
            // Change the LED brightness depending on its direction
329
            if (led_direction_dir[i] == 1) {
330
                leds.w[i+8]++;
331
            } else if (led_direction_dir[i] == 2) {
332
                leds.w[i+8]--;
333
            }
334
 
335
            // Change direction if peak brightness is reached
336
            // When the brightness reaches a middle threshold, start
337
            //   increasing the brightness of the next LED
338
            if (led_direction_dir[i] == 1 && leds.w[i+8] == led_4_high_thres) {
339
                led_direction_dir[i] = 2;
340
            } else if (led_direction_dir[i] == 1 && leds.w[i+8] == led_4_next_thresh) {
341
                next_led = (i == 3) ? 0 : i + 1;
342
                led_direction_dir[next_led] = 1;
343
            } else if (led_direction_dir[i] == 2 && leds.w[i+8] == 0x00) {
344
                led_direction_dir[i] = 0;
345
            }
346
        }
347
 
348
        // Update the LEDs in the left section
349
        for (i = 0; i < 4; i++) {
350
            // Change the LED brightness depending on its direction
351
            if (led_direction_ind[i] == 1) {
352
                leds.w[i+12]++;
353
            } else if (led_direction_ind[i] == 2) {
354
                leds.w[i+12]--;
355
            }
356
 
357
            // Change direction if peak brightness is reached
358
            // When the brightness reaches a middle threshold, start
359
            //   increasing the brightness of the next LED
360
            if (led_direction_ind[i] == 1 && leds.w[i+12] == led_4_high_thres) {
361
                led_direction_ind[i] = 2;
362
            } else if (led_direction_ind[i] == 1 && leds.w[i+12] == led_4_next_thresh) {
363
                next_led = (i == 3) ? 0 : i + 1;
364
                led_direction_ind[next_led] = 1;
365
            } else if (led_direction_ind[i] == 2 && leds.w[i+12] == 0x00) {
366
                led_direction_ind[i] = 0;
367
            }
368
        }
369
 
370
        // Write the LED values to the controller
371
        TLC59116_Write_All(&leds);
372
 
373
        // Delay a bit to slow down the animation
374
        __delay_ms(1);
260 Kevin 375
    }
270 Kevin 376
}