-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
executable file
·470 lines (394 loc) · 18.3 KB
/
main.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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
#include "maindefs.h"
#include <stdio.h>
#ifndef __XC8
#include <usart.h>
#include <i2c.h>
#include <timers.h>
#else
#include <plib/usart.h>
#include <plib/i2c.h>
#include <plib/timers.h>
#endif
#include "interrupts.h"
#include "messages.h"
#include "my_uart.h"
#include "my_i2c.h"
#include "uart_thread.h"
#include "timer1_thread.h"
#include "timer0_thread.h"
#include "atod.h"
#include "debug.h"
//Setup configuration registers
#ifdef __USE18F45J10
// CONFIG1L
#pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on SWDTEN bit))
#pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable bit (Reset on stack overflow/underflow disabled)
#ifndef __XC8
// Have to turn this off because I don't see how to enable this in the checkboxes for XC8 in this IDE
#pragma config XINST = ON // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode enabled)
#else
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode enabled)
#endif
// CONFIG1H
#pragma config CP0 = OFF // Code Protection bit (Program memory is not code-protected)
// CONFIG2L
#pragma config FOSC = HSPLL // Oscillator Selection bits (HS oscillator, PLL enabled and under software control)
#pragma config FOSC2 = ON // Default/Reset System Clock Select bit (Clock selected by FOSC as system clock is enabled when OSCCON<1:0> = 00)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = ON // Two-Speed Start-up (Internal/External Oscillator Switchover) Control bit (Two-Speed Start-up enabled)
// CONFIG2H
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = DEFAULT // CCP2 MUX bit (CCP2 is multiplexed with RC1)
#else
#ifdef __USE18F2680
#pragma config OSC = IRCIO67 // Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
// CONFIG2L
#pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 3 // Brown-out Reset Voltage bits (VBOR set to 2.1V)
// CONFIG2H
#pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config PBADEN = OFF // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
// CONFIG4L
#pragma config STVREN = OFF // Stack Full/Underflow Reset Enable bit (Stack full/underflow will not cause Reset)
#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config BBSIZ = 1024 // Boot Block Size Select bits (1K words (2K bytes) Boot Block)
#ifndef __XC8
// Have to turn this off because I don't see how to enable this in the checkboxes for XC8 in this IDE
#pragma config XINST = ON // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode enabled)
#endif
#else
#ifdef __USE18F26J50
// PIC18F26J50 Configuration Bit Settings
// CONFIG1L
#pragma config WDTEN = OFF // Watchdog Timer (Disabled - Controlled by SWDTEN bit)
#pragma config PLLDIV = 3 // PLL Prescaler Selection bits (Divide by 3 (12 MHz oscillator input))
#pragma config STVREN = OFF // Stack Overflow/Underflow Reset (Disabled)
#pragma config XINST = ON // Extended Instruction Set (Enabled)
// CONFIG1H
#pragma config CPUDIV = OSC1 // CPU System Clock Postscaler (No CPU system clock divide)
#pragma config CP0 = OFF // Code Protect (Program memory is not code-protected)
// CONFIG2L
#pragma config OSC = HSPLL // Oscillator (HS+PLL, USB-HS+PLL)
#pragma config T1DIG = OFF // T1OSCEN Enforcement (Secondary Oscillator clock source may not be selected)
#pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator (High-power operation)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = ON // Internal External Oscillator Switch Over Mode (Enabled)
// CONFIG2H
#pragma config WDTPS = 32768 // Watchdog Postscaler (1:32768)
// CONFIG3L
#pragma config DSWDTOSC = T1OSCREF// DSWDT Clock Select (DSWDT uses T1OSC/T1CKI)
#pragma config RTCOSC = T1OSCREF// RTCC Clock Select (RTCC uses T1OSC/T1CKI)
#pragma config DSBOREN = OFF // Deep Sleep BOR (Disabled)
#pragma config DSWDTEN = OFF // Deep Sleep Watchdog Timer (Disabled)
#pragma config DSWDTPS = G2 // Deep Sleep Watchdog Postscaler (1:2,147,483,648 (25.7 days))
// CONFIG3H
#pragma config IOL1WAY = ON // IOLOCK One-Way Set Enable bit (The IOLOCK bit (PPSCON<0>) can be set once)
#pragma config MSSP7B_EN = MSK7 // MSSP address masking (7 Bit address masking mode)
// CONFIG4L
#pragma config WPFP = PAGE_63 // Write/Erase Protect Page Start/End Location (Write Protect Program Flash Page 63)
#pragma config WPEND = PAGE_WPFP// Write/Erase Protect Region Select (valid when WPDIS = 0) (Page WPFP<5:0> through Configuration Words erase/write protected)
#pragma config WPCFG = OFF // Write/Erase Protect Configuration Region (Configuration Words page not erase/write-protected)
// CONFIG4H
#pragma config WPDIS = OFF // Write Protect Disable bit (WPFP<5:0>/WPEND region ignored)
#else
#ifdef __USE18F46J50
// PIC18F46J50 Configuration Bit Settings
// CONFIG1L
#pragma config WDTEN = OFF // Watchdog Timer (Disabled - Controlled by SWDTEN bit)
#pragma config PLLDIV = 3 // PLL Prescaler Selection bits (Divide by 3 (12 MHz oscillator input))
#pragma config STVREN = OFF // Stack Overflow/Underflow Reset (Disabled)
#ifndef __XC8
// Have to turn this off because I don't see how to enable this in the checkboxes for XC8 in this IDE
#pragma config XINST = ON // Extended Instruction Set (Enabled)
#else
#pragma config XINST = OFF // Extended Instruction Set (Disabled)
#endif
// CONFIG1H
#pragma config CPUDIV = OSC1 // CPU System Clock Postscaler (No CPU system clock divide)
#pragma config CP0 = OFF // Code Protect (Program memory is not code-protected)
// CONFIG2L
#pragma config OSC = HSPLL // Oscillator (HS+PLL, USB-HS+PLL)
#pragma config T1DIG = OFF // T1OSCEN Enforcement (Secondary Oscillator clock source may not be selected)
#pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator (High-power operation)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = ON // Internal External Oscillator Switch Over Mode (Enabled)
// CONFIG2H
#pragma config WDTPS = 32768 // Watchdog Postscaler (1:32768)
// CONFIG3L
#pragma config DSWDTOSC = T1OSCREF// DSWDT Clock Select (DSWDT uses T1OSC/T1CKI)
#pragma config RTCOSC = T1OSCREF// RTCC Clock Select (RTCC uses T1OSC/T1CKI)
#pragma config DSBOREN = OFF // Deep Sleep BOR (Disabled)
#pragma config DSWDTEN = OFF // Deep Sleep Watchdog Timer (Disabled)
#pragma config DSWDTPS = G2 // Deep Sleep Watchdog Postscaler (1:2,147,483,648 (25.7 days))
// CONFIG3H
#pragma config IOL1WAY = ON // IOLOCK One-Way Set Enable bit (The IOLOCK bit (PPSCON<0>) can be set once)
#pragma config MSSP7B_EN = MSK7 // MSSP address masking (7 Bit address masking mode)
// CONFIG4L
#pragma config WPFP = PAGE_63 // Write/Erase Protect Page Start/End Location (Write Protect Program Flash Page 63)
#pragma config WPEND = PAGE_WPFP// Write/Erase Protect Region Select (valid when WPDIS = 0) (Page WPFP<5:0> through Configuration Words erase/write protected)
#pragma config WPCFG = OFF // Write/Erase Protect Configuration Region (Configuration Words page not erase/write-protected)
// CONFIG4H
#pragma config WPDIS = OFF // Write Protect Disable bit (WPFP<5:0>/WPEND region ignored)
#else
Something is messed up.
The PIC selected is not supported or the preprocessor directives are wrong.
#endif
#endif
#endif
#endif
void main(void) {
signed char length;
unsigned char msgtype;
unsigned char last_reg_recvd;
uart_comm uc;
i2c_comm ic;
unsigned char msgbuffer[MSGLEN + 1];
unsigned char i;
uart_thread_struct uthread_data; // info for uart_lthread
timer1_thread_struct t1thread_data; // info for timer1_lthread
timer0_thread_struct t0thread_data; // info for timer0_lthread
#ifdef __USE18F2680
OSCCON = 0xFC; // see datasheet
// We have enough room below the Max Freq to enable the PLL for this chip
OSCTUNEbits.PLLEN = 1; // 4x the clock speed in the previous line
#else
#ifdef __USE18F45J10
OSCCON = 0x82; // see datasheeet
OSCTUNEbits.PLLEN = 0; // Makes the clock exceed the PIC's rated speed if the PLL is on
#else
#ifdef __USE18F26J50
OSCCON = 0xE0; // see datasheeet
OSCTUNEbits.PLLEN = 1;
#else
#ifdef __USE18F46J50
OSCCON = 0xE0; //see datasheet
OSCTUNEbits.PLLEN = 1;
#else
Something is messed up.
The PIC selected is not supported or the preprocessor directives are wrong.
#endif
#endif
#endif
#endif
// initialize my uart recv handling code
init_uart_recv(&uc);
// initialize the i2c code
init_i2c(&ic);
// init the timer1 lthread
init_timer1_lthread(&t1thread_data);
// initialize message queues before enabling any interrupts
init_queues();
// Initialize the A/D converter and its inturrupts
init_ad();
#ifndef __USE18F26J50
// set direction for PORTB to output
TRISB = 0x0;
LATB = 0x0;
#endif
// how to set up PORTA for input (for the V4 board with the PIC2680)
/*
PORTA = 0x0; // clear the port
LATA = 0x0; // clear the output latch
ADCON1 = 0x0F; // turn off the A2D function on these pins
// Only for 40-pin version of this chip CMCON = 0x07; // turn the comparator off
TRISA = 0x0F; // set RA3-RA0 to inputs
*/
// initialize Timers
OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_16);
#ifdef __USE18F26J50
// MTJ added second argument for OpenTimer1()
OpenTimer1(TIMER_INT_ON & T1_SOURCE_FOSC_4 & T1_PS_1_8 & T1_16BIT_RW & T1_OSC1EN_OFF & T1_SYNC_EXT_OFF,0x0);
#else
#ifdef __USE18F46J50
OpenTimer1(TIMER_INT_ON & T1_SOURCE_FOSC_4 & T1_PS_1_8 & T1_16BIT_RW & T1_OSC1EN_OFF & T1_SYNC_EXT_OFF,0x0);
#else
OpenTimer1(TIMER_INT_ON & T1_PS_1_8 & T1_16BIT_RW & T1_SOURCE_INT & T1_OSC1EN_OFF & T1_SYNC_EXT_OFF);
#endif
#endif
// Decide on the priority of the enabled peripheral interrupts
// 0 is low, 1 is high
// Timer1 interrupt
IPR1bits.TMR1IP = 0;
// USART RX interrupt
IPR1bits.RCIP = 0;
// I2C interrupt
IPR1bits.SSPIP = 1;
// configure the hardware i2c device as a slave (0x9E -> 0x4F) or (0x9A -> 0x4D)
#if 1
// Note that the temperature sensor Address bits (A0, A1, A2) are also the
// least significant bits of LATB -- take care when changing them
// They *are* changed in the timer interrupt handlers if those timers are
// enabled. They are just there to make the lights blink and can be
// disabled.
i2c_configure_slave(0x9E);
#else
// If I want to test the temperature sensor from the ARM, I just make
// sure this PIC does not have the same address and configure the
// temperature sensor address bits and then just stay in an infinite loop
i2c_configure_slave(0x9A);
#ifdef __USE18F2680
LATBbits.LATB1 = 1;
LATBbits.LATB0 = 1;
LATBbits.LATB2 = 1;
#endif
for (;;);
#endif
// must specifically enable the I2C interrupts
PIE1bits.SSPIE = 1;
// configure the hardware USART device
#ifdef __USE18F26J50
Open1USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT &
USART_CONT_RX & USART_BRGH_LOW, 0x19);
#else
#ifdef __USE18F46J50
Open1USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT &
USART_CONT_RX & USART_BRGH_LOW, 0x19);
#else
OpenUSART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT &
USART_CONT_RX & USART_BRGH_LOW, 0x19);
#endif
#endif
// Peripheral interrupts can have their priority set to high or low
// enable high-priority interrupts and low-priority interrupts
enable_interrupts();
/* Junk to force an I2C interrupt in the simulator (if you wanted to)
PIR1bits.SSPIF = 1;
_asm
goto 0x08
_endasm;
*/
// printf() is available, but is not advisable. It goes to the UART pin
// on the PIC and then you must hook something up to that to view it.
// It is also slow and is blocking, so it will perturb your code's operation
// Here is how it looks: printf("Hello\r\n");
//CURTIS CHANGES
// Set the tri state logic to output
TRISBbits.TRISB0 = 0;
TRISBbits.TRISB1 = 0;
TRISBbits.TRISB2 = 0;
TRISBbits.TRISB3 = 0;
// Configure bits for UART
setup_uart_send();
// END CURTIS CHANGES
// loop forever
// This loop is responsible for "handing off" messages to the subroutines
// that should get them. Although the subroutines are not threads, but
// they can be equated with the tasks in your task diagram if you
// structure them properly.
while (1) {
// Call a routine that blocks until either on the incoming
// messages queues has a message (this may put the processor into
// an idle mode)
block_on_To_msgqueues();
// At this point, one or both of the queues has a message. It
// makes sense to check the high-priority messages first -- in fact,
// you may only want to check the low-priority messages when there
// is not a high priority message. That is a design decision and
// I haven't done it here.
length = ToMainHigh_recvmsg(MSGLEN, &msgtype, (void *) msgbuffer);
if (length < 0) {
// no message, check the error code to see if it is concern
if (length != MSGQUEUE_EMPTY) {
// This case be handled by your code.
}
} else {
switch (msgtype) {
case MSGT_TIMER0:
{
timer0_lthread(&t0thread_data, msgtype, length, msgbuffer);
break;
};
case MSGT_I2C_DATA:
case MSGT_I2C_DBG:
{
// Here is where you could handle debugging, if you wanted
// keep track of the first byte received for later use (if desired)
last_reg_recvd = msgbuffer[0];
break;
};
case MSGT_I2C_RQST:
{
// Generally, this is *NOT* how I recommend you handle an I2C slave request
// I recommend that you handle it completely inside the i2c interrupt handler
// by reading the data from a queue (i.e., you would not send a message, as is done
// now, from the i2c interrupt handler to main to ask for data).
//
// The last byte received is the "register" that is trying to be read
// The response is dependent on the register.
switch (last_reg_recvd) {
case 0xaa:
{
length = 2;
msgbuffer[0] = 0x51;
msgbuffer[1] = 0xAA;
break;
}
case 0xa8:
{
length = 1;
msgbuffer[0] = 0x3A;
break;
}
case 0xa9:
{
length = 1;
msgbuffer[0] = 0xA3;
break;
}
};
start_i2c_slave_reply(length, msgbuffer);
break;
};
case MSGT_SENSOR_IR1:
{
DEBUG_ON(GET_SENSOR_MAIN);
unsigned short int adValue = msgbuffer[1];
adValue = adValue << 8 | msgbuffer[0];
FromMainLow_sendmsg( sizeof(adValue), MSGT_UART_SEND_DATA, &adValue);
DEBUG_OFF(GET_SENSOR_MAIN);
break;
};
default:
{
// Your code should handle this error
break;
};
};
}
// Check the low priority queue
length = ToMainLow_recvmsg(MSGLEN, &msgtype, (void *) msgbuffer);
if (length < 0) {
// no message, check the error code to see if it is concern
if (length != MSGQUEUE_EMPTY) {
// Your code should handle this situation
}
} else {
switch (msgtype) {
case MSGT_TIMER1:
{
timer1_lthread(&t1thread_data, msgtype, length, msgbuffer);
break;
};
case MSGT_OVERRUN:
case MSGT_UART_DATA:
{
uart_lthread(&uthread_data, msgtype, length, msgbuffer);
break;
};
default:
{
// Your code should handle this error
break;
};
};
}
}
}