1 | #include <pic18fregs.h> |
---|
2 | #include <stdio.h> |
---|
3 | #include <math.h> |
---|
4 | #include <my_serial.h> |
---|
5 | |
---|
6 | extern char stack; |
---|
7 | extern char stack_end; |
---|
8 | |
---|
9 | #pragma stack 0x100 256 |
---|
10 | |
---|
11 | void _reset (void) __naked __interrupt 0; |
---|
12 | void _startup (void) __naked; |
---|
13 | |
---|
14 | static char counter_1hz; |
---|
15 | static volatile short counter_10hz; |
---|
16 | static volatile unsigned int softintrs; |
---|
17 | #define INT_10HZ 0x0001 |
---|
18 | #define INT_AD 0x0002 |
---|
19 | #define INT_DOAD 0x0004 |
---|
20 | |
---|
21 | #define TIMER0_5MS 192 /* 48 without PLL */ |
---|
22 | |
---|
23 | #define TIMER2_10HZ 1000 |
---|
24 | |
---|
25 | #define CLRWDT __asm__("clrwdt") |
---|
26 | #define SLEEP __asm__("sleep") |
---|
27 | |
---|
28 | static char ad_channel; |
---|
29 | static long ad_i_result; |
---|
30 | static long ad_v_result; |
---|
31 | |
---|
32 | #define PRINTHEX(v) \ |
---|
33 | { \ |
---|
34 | unsigned char c = (v); \ |
---|
35 | if (c < 10) { \ |
---|
36 | putchar('0' + c); \ |
---|
37 | } else { \ |
---|
38 | putchar(('a' - 10) + c ); \ |
---|
39 | } \ |
---|
40 | } |
---|
41 | |
---|
42 | void |
---|
43 | main(void) __naked |
---|
44 | { |
---|
45 | unsigned char c; |
---|
46 | softintrs = 0; |
---|
47 | counter_1hz = 10; |
---|
48 | |
---|
49 | ANCON0 = 0xf0; /* an0-an3 analog, an4-an7 digital */ |
---|
50 | ANCON1 = 0x3f; /* an8-12 digital */ |
---|
51 | |
---|
52 | TRISCbits.TRISC1 = 0; |
---|
53 | TRISCbits.TRISC2 = 0; |
---|
54 | PORTCbits.RC1 = 0; |
---|
55 | PORTCbits.RC2 = 0; |
---|
56 | |
---|
57 | |
---|
58 | /* switch PLL on */ |
---|
59 | OSCTUNEbits.PLLEN = 1; |
---|
60 | |
---|
61 | /* configure sleep mode: PRI_IDLE */ |
---|
62 | OSCCONbits.SCS = 0; |
---|
63 | OSCCONbits.IDLEN = 1; |
---|
64 | /* everything is low priority by default */ |
---|
65 | IPR1 = 0; |
---|
66 | IPR2 = 0; |
---|
67 | IPR3 = 0; |
---|
68 | IPR4 = 0; |
---|
69 | IPR5 = 0; |
---|
70 | INTCON = 0; |
---|
71 | INTCON2 = 0; |
---|
72 | INTCON3 = 0; |
---|
73 | INTCON2bits.RBPU = 1; |
---|
74 | |
---|
75 | RCONbits.IPEN=1; /* enable interrupt priority */ |
---|
76 | |
---|
77 | /* configure timer0 as free-running counter at 46.875Khz */ |
---|
78 | T0CON = 0x07; /* b00000111: internal clock, 1/256 prescaler */ |
---|
79 | INTCONbits.TMR0IF = 0; |
---|
80 | INTCONbits.TMR0IE = 0; /* no interrupt */ |
---|
81 | T0CONbits.TMR0ON = 1; |
---|
82 | |
---|
83 | #if 0 |
---|
84 | /* configure UART for 57600Bps at 48Mhz */ |
---|
85 | SPBRG1 = 12; |
---|
86 | #endif |
---|
87 | /* configure UART for 921600Bps at 48Mhz */ |
---|
88 | TXSTA1bits.BRGH = 1; |
---|
89 | BAUDCON1bits.BRG16 = 1; |
---|
90 | SPBRGH1 = 0; |
---|
91 | SPBRG1 = 12; |
---|
92 | |
---|
93 | USART_INIT(0); |
---|
94 | stdout = STREAM_USER; /* Use the macro PUTCHAR with printf */ |
---|
95 | |
---|
96 | #if TIMER2_10HZ == 100 |
---|
97 | /* configure timer2 for 1Khz interrupt */ |
---|
98 | T2CON = 0x22; /* b00100010: postscaller 1/5, prescaler 1/16 */ |
---|
99 | PR2 = 150; /* 1khz output */ |
---|
100 | #elif TIMER2_10HZ == 1000 |
---|
101 | /* configure timer2 for 10Khz interrupt */ |
---|
102 | T2CON = 0x22; /* b00100010: postscaller 1/5, prescaler 1/16 */ |
---|
103 | PR2 = 15; /* 10khz output */ |
---|
104 | #elif TIMER2_10HZ == 2000 |
---|
105 | /* configure timer2 for 20Khz interrupt */ |
---|
106 | T2CON = 0x21; /* b00100001: postscaller 1/5, prescaler 1/4 */ |
---|
107 | PR2 = 29; /* 20khz output */ |
---|
108 | #else |
---|
109 | #error "unknown TIMER2_10HZ" |
---|
110 | #endif |
---|
111 | counter_10hz = TIMER2_10HZ; |
---|
112 | T2CONbits.TMR2ON = 1; |
---|
113 | PIR1bits.TMR2IF = 0; |
---|
114 | IPR1bits.TMR2IP = 1; /* high priority interrupt */ |
---|
115 | PIE1bits.TMR2IE = 1; |
---|
116 | |
---|
117 | |
---|
118 | INTCONbits.GIE_GIEH=1; /* enable high-priority interrupts */ |
---|
119 | INTCONbits.PEIE_GIEL=1; /* enable low-priority interrrupts */ |
---|
120 | |
---|
121 | /* |
---|
122 | * configure ADC: |
---|
123 | * AN3: vref+ |
---|
124 | * AN2: I |
---|
125 | * AN1: vout |
---|
126 | */ |
---|
127 | |
---|
128 | ADCON0 = 0xc1; /* b11000001 */ |
---|
129 | /* clk = fosc/64, tacq = 4tad (5.33us) */ |
---|
130 | ADCON1 = 0x96; /* b10010110 */ |
---|
131 | /* ANCON already set up */ |
---|
132 | |
---|
133 | /* start calibration */ |
---|
134 | ADCON1bits.ADCAL = 1; |
---|
135 | ADCON0bits.GO_NOT_DONE =1; |
---|
136 | while (ADCON0bits.GO_NOT_DONE) |
---|
137 | ; /* wait */ |
---|
138 | ADCON1bits.ADCAL = 0; |
---|
139 | PIR1bits.ADIF = 0; |
---|
140 | PIE1bits.ADIE = 1; |
---|
141 | |
---|
142 | printf("hello world\n"); |
---|
143 | /* enable watch dog timer */ |
---|
144 | WDTCON = 0x01; |
---|
145 | |
---|
146 | printf("\nready\n"); |
---|
147 | /* start I calibration process */ |
---|
148 | ad_channel = 0; |
---|
149 | ADCON0bits.CHS = 0; |
---|
150 | softintrs &= ~INT_DOAD; |
---|
151 | PORTCbits.RC1 = 1; |
---|
152 | PORTCbits.RC2 = 0; |
---|
153 | |
---|
154 | again: |
---|
155 | while (1) { |
---|
156 | CLRWDT; |
---|
157 | if (softintrs & INT_AD) { |
---|
158 | softintrs &= ~INT_AD; |
---|
159 | if (ad_channel == 0) { |
---|
160 | PRINTHEX(PORTB & 0xf); |
---|
161 | PRINTHEX(ADRESH & 0xf); |
---|
162 | PRINTHEX(ADRESL >> 4); |
---|
163 | PRINTHEX(ADRESL & 0xf); |
---|
164 | |
---|
165 | //printf("%1x%3x", (PORTB & 0xf), ADRESL | (ADRESH << 8)); |
---|
166 | /* |
---|
167 | * needs 2Tac, or 32 instrutions |
---|
168 | * before next sample. assume we |
---|
169 | * already have them since the |
---|
170 | * interrupt |
---|
171 | */ |
---|
172 | ad_channel = 1; |
---|
173 | ADCON0bits.CHS = 1; |
---|
174 | } else { |
---|
175 | ad_channel = 0; |
---|
176 | ADCON0bits.CHS = 0; |
---|
177 | PRINTHEX(ADRESH & 0xf); |
---|
178 | PRINTHEX(ADRESL >> 4); |
---|
179 | PRINTHEX(ADRESL & 0xf); |
---|
180 | putchar('X'); |
---|
181 | //printf("%3xX", ADRESL | (ADRESH << 8)); |
---|
182 | } |
---|
183 | } |
---|
184 | |
---|
185 | if ((softintrs & INT_AD) == 0 && |
---|
186 | (softintrs & INT_DOAD) && |
---|
187 | ADCON0bits.GO_NOT_DONE == 0) { |
---|
188 | ADCON0bits.GO_NOT_DONE = 1; |
---|
189 | softintrs &= ~INT_DOAD; |
---|
190 | } |
---|
191 | |
---|
192 | if (RCREG1 == 'r') |
---|
193 | break; |
---|
194 | SLEEP; |
---|
195 | |
---|
196 | } |
---|
197 | |
---|
198 | end: |
---|
199 | |
---|
200 | while ((c = getchar()) != 'r') { |
---|
201 | printf("got %c\n", c); |
---|
202 | goto again; |
---|
203 | } |
---|
204 | printf("returning\n"); |
---|
205 | while (PIE1bits.TX1IE) |
---|
206 | ; /* wait for transmit to complete */ |
---|
207 | INTCONbits.PEIE=0; /* disable peripheral interrupts */ |
---|
208 | INTCONbits.GIE=0; /* disable interrrupts */ |
---|
209 | } |
---|
210 | |
---|
211 | unsigned int |
---|
212 | timer0_read() __naked |
---|
213 | { |
---|
214 | /* return TMR0L | (TMR0H << 8), reading TMR0L first */ |
---|
215 | __asm |
---|
216 | movf _TMR0L, w |
---|
217 | movff _TMR0H, _PRODL |
---|
218 | return |
---|
219 | __endasm; |
---|
220 | } |
---|
221 | |
---|
222 | /* Vectors */ |
---|
223 | void _reset (void) __naked __interrupt 0 |
---|
224 | { |
---|
225 | __asm__("goto __startup"); |
---|
226 | } |
---|
227 | |
---|
228 | |
---|
229 | void _startup (void) __naked |
---|
230 | { |
---|
231 | |
---|
232 | __asm |
---|
233 | // Initialize the stack pointer |
---|
234 | lfsr 1, _stack_end |
---|
235 | lfsr 2, _stack_end |
---|
236 | clrf _TBLPTRU, 0 // 1st silicon doesn't do this on POR |
---|
237 | |
---|
238 | // initialize the flash memory access configuration. this is harmless |
---|
239 | // for non-flash devices, so we do it on all parts. |
---|
240 | bsf _EECON1, 7, 0 |
---|
241 | bcf _EECON1, 6, 0 |
---|
242 | __endasm ; |
---|
243 | |
---|
244 | /* Call the user's main routine */ |
---|
245 | main(); |
---|
246 | __asm__("reset"); |
---|
247 | } |
---|
248 | |
---|
249 | /* |
---|
250 | * high priority interrupt. Split in 2 parts; one for the entry point |
---|
251 | * where we'll deal with timer0, then jump to another address |
---|
252 | * as we don't have enough space before the low priority vector |
---|
253 | */ |
---|
254 | void _irqh (void) __naked __shadowregs __interrupt 1 |
---|
255 | { |
---|
256 | __asm |
---|
257 | bcf _PIR1, 1 |
---|
258 | goto _irqh_timer2 |
---|
259 | __endasm ; |
---|
260 | |
---|
261 | } |
---|
262 | |
---|
263 | void irqh_timer2(void) __naked |
---|
264 | { |
---|
265 | /* |
---|
266 | * no sdcc registers are automatically saved, |
---|
267 | * so we have to be carefull with C code ! |
---|
268 | */ |
---|
269 | #if 0 |
---|
270 | counter_10hz--; |
---|
271 | if (counter_10hz == 0) { |
---|
272 | counter_10hz = TIMER2_10HZ; |
---|
273 | softintrs |= INT_10HZ; |
---|
274 | } |
---|
275 | #endif |
---|
276 | if (softintrs & INT_DOAD) { |
---|
277 | PORTCbits.RC2=1; |
---|
278 | } |
---|
279 | softintrs |= INT_DOAD; |
---|
280 | __asm |
---|
281 | retfie 1 |
---|
282 | nop |
---|
283 | __endasm; |
---|
284 | } |
---|
285 | |
---|
286 | void _irq (void) __interrupt 2 /* low priority */ |
---|
287 | { |
---|
288 | USART_INTR; |
---|
289 | if (PIE1bits.ADIE && PIR1bits.ADIF) { |
---|
290 | PIR1bits.ADIF = 0; |
---|
291 | softintrs |= INT_AD; |
---|
292 | } |
---|
293 | } |
---|