source: trunk/software/firmware/main.c @ 13

Last change on this file since 13 was 13, checked in by bouyer, 5 years ago

Test both leds on boot
blink differently when when idle and when connected to console

File size: 12.6 KB
Line 
1#include <pic18fregs.h>
2#include <stdio.h> 
3#include <math.h> 
4#include <my_serial.h> 
5#include <my_serial2.h> 
6
7extern char stack; 
8extern char stack_end;
9
10#pragma stack 0x100 256
11
12void _reset (void) __naked __interrupt 0;
13void _startup (void) __naked;
14
15static char counter_2hz;               
16static volatile short counter_10hz;           
17static volatile unsigned char softintrs;
18#define INT_10HZ         (unsigned char)0x01
19#define INT_AD           (unsigned char)0x02
20#define INT_RX1          (unsigned char)0x08
21#define INT_RX1OF        (unsigned char)0x10
22
23static volatile unsigned char status;
24#define STAT_WAIT       (unsigned char)0x00
25#define STAT_MEASURE    (unsigned char)0x01
26#define STAT_EXIT       (unsigned char)0x02
27#define STAT_CONSOLE    (unsigned char)0x04
28
29static volatile unsigned char adstatus;
30#define ADSTAT_MEASURE  (unsigned char)0x01
31static unsigned char ad_resh;
32static unsigned char ad_resl;
33static unsigned char ad_channel;
34
35
36#define TIMER0_5MS 192 /* 48 without PLL */
37
38#define TIMER2_10HZ 1000
39
40#define LEDR LATAbits.LATA7
41#define LEDG LATAbits.LATA6
42#define PWRON LATCbits.LATC2
43#define RL1 LATCbits.LATC4
44#define RL2 LATCbits.LATC5
45#define SENSE PORTAbits.RA5
46
47#define CLRWDT __asm__("clrwdt")     
48#define SLEEP __asm__("sleep")     
49
50static void do_measure(void);
51static void do_console(void);
52static void do_cal_data(void);
53static void parse_rx(void);
54
55static char buf[84];
56
57/* address of calibration data in RAM */
58#define cal_data 0x01F000
59
60
61#if 1
62#define PRINTHEX(v) \
63        { \
64                unsigned char c = (v); \
65                if (c < 10) { \
66                        uart_putchar_hard('0' + c); \
67                } else { \
68                        uart_putchar_hard(('a' - 10) + c ); \
69                } \
70        }
71#else
72#define PRINTHEX(v) {}
73#endif
74
75void
76main(void) __naked
77{
78        softintrs = 0;
79
80        ANCON0 = 0xf0; /* an0-an3 analog, an4-an7 digital */
81        ANCON1 = 0x3f; /* an8-12 digital */
82
83        RL1 = 0;
84        TRISCbits.TRISC4 = 0;
85        RL2 = 0;
86        TRISCbits.TRISC5 = 0;
87        PWRON = 0;
88        TRISCbits.TRISC2 = 0;
89        LEDR = 1;
90        TRISAbits.TRISA7 = 0;
91        LEDG = 0;
92        TRISAbits.TRISA6 = 0;
93
94        /* switch PLL on */
95        OSCTUNEbits.PLLEN = 1;
96
97        /* configure sleep mode: PRI_IDLE */
98        OSCCONbits.SCS = 0;
99        OSCCONbits.IDLEN = 1;
100        /* everything is low priority by default */
101        IPR1 = 0;
102        IPR2 = 0;
103        IPR3 = 0;
104        IPR4 = 0;
105        IPR5 = 0;
106        INTCON = 0;
107        INTCON2 = 0;
108        INTCON3 = 0;
109        INTCON2bits.RBPU = 1;
110
111        RCONbits.IPEN=1; /* enable interrupt priority */
112
113        /* configure timer0 as free-running counter at 46.875Khz */   
114        T0CON = 0x07; /* b00000111: internal clock, 1/256 prescaler */ 
115        INTCONbits.TMR0IF = 0;
116        INTCONbits.TMR0IE = 0; /* no interrupt */
117        T0CONbits.TMR0ON = 1;
118
119#if 0
120        /* configure UART for 57600Bps at 48Mhz */
121        SPBRG1 = 12;
122#endif
123        /* configure UART for 921600Bps at 48Mhz */
124        TXSTA1bits.BRGH = 1;
125        BAUDCON1bits.BRG16 = 1;
126        SPBRGH1 = 0;
127        SPBRG1 = 12;
128
129        /* pre-configure UART2 */
130        /* turn off PPS write protect */
131        __asm
132        banksel _PPSCON
133        movlw   0x55
134        movwf   _EECON2, a
135        movlw   0xAA
136        movwf   _EECON2, a
137        BCF     _PPSCON, _IOLOCK, b
138        __endasm;
139
140        TRISCbits.TRISC0 = 1;
141        LATCbits.LATC1 = 1;
142        TRISCbits.TRISC1 = 0;
143        RPINR16 = 11; /* RC0 = RX */
144        RPOR12 = 6; /* RC1 = TX */
145        TXSTA2 = 0x24; /* TXEN, BRGH set, others clear */
146        RCSTA2 = 0x90; /* UART enable, receiver disabled */
147        BAUDCON2 = 0x08; /* BRG16 */
148
149        USART_INIT(0);
150        USART2_INIT(0);
151
152        stdout = STREAM_USER; /* Use the macro PUTCHAR with printf */
153
154#if TIMER2_10HZ == 100
155        /* configure timer2 for 1Khz interrupt */
156        T2CON = 0x22; /* b00100010: postscaller 1/5, prescaler 1/16 */
157        PR2 = 150; /* 1khz output */
158#elif TIMER2_10HZ == 1000
159        /* configure timer2 for 10Khz interrupt */
160        T2CON = 0x22; /* b00100010: postscaller 1/5, prescaler 1/16 */ 
161        PR2 = 15; /* 10khz output */
162#elif TIMER2_10HZ == 2000
163        /* configure timer2 for 20Khz interrupt */
164        T2CON = 0x21; /* b00100001: postscaller 1/5, prescaler 1/4 */ 
165        PR2 = 29; /* 20khz output */
166#else
167#error "unknown TIMER2_10HZ"
168#endif
169        counter_10hz = TIMER2_10HZ;
170        T2CONbits.TMR2ON = 1;
171        PIR1bits.TMR2IF = 0;
172        IPR1bits.TMR2IP = 1; /* high priority interrupt */
173        PIE1bits.TMR2IE = 1;
174
175        status = STAT_WAIT;
176        adstatus = 0;
177
178        INTCONbits.GIE_GIEH=1;  /* enable high-priority interrupts */   
179        INTCONbits.PEIE_GIEL=1; /* enable low-priority interrrupts */   
180
181        /*
182         * configure ADC:
183         * AN3: vref+
184         * AN2: I
185         * AN1: vout
186         */
187
188        ADCON0 = 0xc1; /* b11000001 */
189        /* clk = fosc/64, tacq = 4tad (5.33us) */
190        ADCON1 = 0x96; /* b10010110 */
191        /* ANCON already set up */
192
193        /* start calibration */
194        ADCON1bits.ADCAL = 1;
195        ADCON0bits.GO_NOT_DONE =1;
196        while (ADCON0bits.GO_NOT_DONE)
197                ; /* wait */
198        ADCON1bits.ADCAL = 0;
199        PIR1bits.ADIF = 0;
200        PIE1bits.ADIE = 1;
201
202        printf("hello world\n");
203        /* enable watch dog timer */ 
204        WDTCON = 0x01;
205        LEDR = 1;
206        LEDG = 1;
207        counter_2hz = 5;
208        while (counter_2hz > 0) {
209                if (softintrs & INT_10HZ) {
210                        softintrs &= ~INT_10HZ;
211                        counter_2hz--;
212                }
213        }
214        counter_2hz = 5;
215        LEDR = 0;
216        LEDG = 0;
217
218        printf("\nready\n");
219        ad_channel = 0;
220        ADCON0bits.CHS = 0;
221        PWRON = 0;
222
223        while ((status & STAT_EXIT) == 0) {
224                CLRWDT;
225                if (softintrs & INT_10HZ) {
226                        softintrs &= ~INT_10HZ;
227                        counter_2hz--;
228                        if (counter_2hz == 0) {
229                                counter_2hz = 5;
230                                LEDG ^= 1;
231                        }
232                }
233                if (softintrs & INT_RX1) {
234                        parse_rx();
235                } else {
236                        SLEEP;
237                        continue;
238                }
239                if (status & STAT_MEASURE)
240                        do_measure();
241                else if (status & STAT_CONSOLE)
242                        do_console();
243        }
244        printf("returning\n");
245        while (PIE1bits.TX1IE)
246                ; /* wait for transmit to complete */
247        INTCONbits.PEIE=0; /* disable peripheral interrupts */
248        INTCONbits.GIE=0;  /* disable interrrupts */
249}
250
251static void
252parse_rx()
253{
254        char c;
255        char c2;
256        char ok = 1;
257        char err = 0;
258        long br;
259        short brgreg = 0;
260
261        softintrs &= ~INT_RX1;
262        c = uart_getchar();
263        switch(c) {
264        case 'B':
265                c = uart_getchar();
266                br = 0;
267                while(c != '\n') {
268                        if (c < '0' || c > '9') {
269                                err = 1;
270                                break;
271                        }
272                        br = br * 10 + c - '0';
273                        c = uart_getchar();
274                }
275                if (br > 0) {
276                        /*
277                         * brg = F / 16 / (n + 1)
278                         * brg * (n + 1) = F / 16
279                         * n + 1 = F / 16 / brg
280                         * n = F / 16 / brg - 1
281                         * with F = 48Mhz
282                         * n = 3000000 / brg - 1
283                         */
284                        brgreg = (12000000L + br / 2) / br - 1;
285                        printf("brgreg %d\n", brgreg);
286                }
287                if (err == 0) {
288                        if (br > 0) {
289                                SPBRGH2 = (brgreg >> 8);
290                                SPBRG2 = (brgreg & 0xff);
291                        }
292                        status = STAT_CONSOLE;
293                }
294                break;
295        case 'C':
296                do_cal_data();
297                c = '\n';
298                break;
299        case 'E':
300                status = STAT_EXIT;
301                break;
302        case 'M':
303                c = uart_getchar();
304                if (c == '0') {
305                        if (status == STAT_MEASURE)
306                                ok = 0;
307                        status = STAT_WAIT;
308                } else if (c == '1') {
309                        status = STAT_MEASURE;
310                } else {
311                        err = 1;
312                }
313                break;
314        case 'P':
315                c = uart_getchar();
316                if (c == '0')
317                        PWRON = 0;
318                else if (c == '1')
319                        PWRON = 1;
320                else
321                        err = 1;
322                break;
323        case 'R':
324                c = uart_getchar();
325                if (c != '\n') {
326                        c2 = uart_getchar();
327                        if (c == '1') {
328                                if (c2 == '0')
329                                        RL1 = 0;
330                                else if (c2 == '1')
331                                        RL1 = 1;
332                                else
333                                        err = 1;
334                        } else if (c == '2') {
335                                if (c2 == '0')
336                                        RL2 = 0;
337                                else if (c2 == '1')
338                                        RL2 = 1;
339                                else
340                                        err = 1;
341                        } else {
342                                err = 1;
343                        }
344                        c = c2;
345                }
346                break;
347        case 'S':
348                printf("power %s RL %s %s SENSE %s GPIO 0x%x\n",
349                    PWRON ? "on" : "off",
350                    RL1 ? "on" : "off",
351                    RL2 ? "on" : "off",
352                    SENSE ? "off" : "on",
353                    PORTB);
354                break;
355        default:
356                err = 1;
357                break;
358        }
359        while (c != '\n')
360                c = uart_getchar();
361        if (err)
362                printf("\nERROR\n");
363        else if (ok)
364                printf("\nOK\n");
365
366        if (softintrs & INT_RX1OF) {
367                PIE1bits.RC1IE = 0;
368                softintrs &= ~INT_RX1OF;
369                softintrs &= ~INT_RX1;
370                uart_rxbuf_prod = uart_rxbuf_cons = 0;
371                PIE1bits.RC1IE = 1;
372        }
373}
374
375static void
376printhex(unsigned char c) __wparam __naked
377{
378        (void)c;
379        __asm
380        andlw 0x0f;
381        sublw 9;
382        bc decimal;
383        sublw '@';
384        goto _uart_putchar_hard;
385decimal:
386        sublw '9';
387        goto _uart_putchar_hard;
388        __endasm;
389}
390
391static void
392do_measure()
393{
394        softintrs &= ~INT_AD;
395        adstatus = ADSTAT_MEASURE;
396        ADCON0bits.CHS = 0;
397
398        LEDR = 0;
399        LEDG = 1;
400        UART_FLUSH();
401        uart_putchar_hard('X');
402        while (status & STAT_MEASURE) {
403                CLRWDT;
404                if (softintrs & INT_AD) {
405                        if (ad_channel == 0) {
406                                printhex(PORTB >> 4);
407                                printhex(PORTB);
408                                printhex(ad_resh);
409                                printhex(ad_resl >> 4);
410                                printhex(ad_resl);
411                        } else {
412                                printhex(ad_resh);
413                                printhex(ad_resl >> 4);
414                                printhex(ad_resl);
415                                uart_putchar_hard('X');
416                        }
417                        softintrs &= ~INT_AD;
418                }
419                if (softintrs & INT_RX1) {
420                        parse_rx();
421                } else {
422                        SLEEP;
423                }
424        }
425        adstatus = 0;
426        printf("\nOK\n");
427}
428
429static void
430do_console()
431{
432        char previous_rx1 = 0;
433        char c;
434        char more_work = 0;
435
436        printf("connecting to console - exit with #.\n");
437        /* clear buffer */
438        PIE3bits.RC2IE = 0;
439        uart2_rxbuf_prod = uart2_rxbuf_cons = 0;
440        PIE3bits.RC2IE = 1;
441        RCSTA2bits.SPEN = 1;
442        while ((status & STAT_CONSOLE) || more_work) {
443                CLRWDT;
444                more_work = 0;
445                if (softintrs & INT_10HZ) {
446                        softintrs &= ~INT_10HZ;
447                        LEDG ^= 1;
448                }
449                if (uart_rxbuf_cons != uart_rxbuf_prod) {
450                        c = uart_getchar();
451                        /*
452                         * #. exits console mode
453                         * ## sends #
454                         * anything else send both char unmodified
455                         */
456                        if (previous_rx1 == '#') {
457                                if (c == '.') {
458                                        status = STAT_WAIT;
459                                } else if (c == '#') {
460                                        uart2_putchar_raw(c);
461                                } else {
462                                        uart2_putchar_raw(previous_rx1);
463                                        uart2_putchar_raw(c);
464                                }
465                        } else {
466                                uart2_putchar_raw(c);
467                        }
468                        previous_rx1 = c;
469                        more_work = 1;
470                }
471                if (uart2_rxbuf_cons != uart2_rxbuf_prod) {
472                        c = uart2_getchar();
473                        uart_putchar_raw(c);
474                        more_work = 1;
475                }
476                if (more_work == 0 && (status & STAT_CONSOLE))
477                        SLEEP;
478        }
479        RCSTA2bits.SPEN = 0;
480        printf("exit from console\n");
481}
482
483static void
484do_write(void)
485{
486        EECON2 = 0x55;
487        EECON2 = 0xaa;
488        EECON1bits.WR = 1;
489        while (EECON1bits.WR)
490                ; /* wait */
491}
492
493static void
494do_cal_data()
495{
496        char i = 0;
497        char err = 0;
498        char c;
499
500        c = uart_getchar();
501        while (c != '\n') {
502                if ((c < '0' || c > '9') && c != ' ' && c != '.') {
503                        printf("cal error at %c (%d)\n", c, i);
504                        err = 1;
505                }
506                if (i > 82) {
507                        printf("cal error at %c (%d)\n", c, i);
508                        err = 1;
509                } else {
510                        buf[i] = c;
511                        i++;
512                }
513                c = uart_getchar();
514        }
515        if (err == 0 && i != 0 && i != 83) {
516                printf("cal error: %d\n", i);
517        } else if (err == 0 && i != 0) {
518                /* erase 1k block */
519                INTCONbits.GIE_GIEH=0; /* disable interrupts */
520                INTCONbits.PEIE_GIEL=0;
521                TBLPTRU = ((long)cal_data >> 16) & 0xff;
522                TBLPTRH = ((long)cal_data >> 8) & 0xff;
523                TBLPTRL = (long)cal_data & 0xff;
524                EECON1 = 0x14; /* enable write+erase */
525                do_write();
526                EECON1 = 0x00; /* disable write */
527                for (i = 0; i < 83; i++) {
528                        TABLAT = buf[i];
529                        __asm__("tblwt*+");
530                        if (i == 63) {
531                                __asm__("tblrd*-");
532                                EECON1 = 0x04; /* enable write */
533                                do_write();
534                                EECON1 = 0x00; /* disable write */
535                                __asm__("tblrd*+");
536                        }
537                }
538                __asm__("tblrd*-");
539                EECON1 = 0x04; /* enable write */
540                do_write();
541                EECON1 = 0x00; /* disable write */
542                INTCONbits.PEIE_GIEL=1;
543                INTCONbits.GIE_GIEH=1; /* enable interrupts */
544        }
545        printf("cal_data ");
546        TBLPTRU = ((long)cal_data >> 16) & 0xff;
547        TBLPTRH = ((long)cal_data >> 8) & 0xff;
548        TBLPTRL = (long)cal_data & 0xff;
549        EECON1 = 0x00; /* disable writes */
550        for (i = 0; i < 83; i++) {
551                __asm__("tblrd*+");
552                putchar(TABLAT);
553        }
554        printf("\n");
555}
556
557unsigned short
558timer0_read() __naked   
559{
560        /* return TMR0L | (TMR0H << 8), reading TMR0L first */
561        __asm   
562        movf    _TMR0L, w
563        movff   _TMR0H, _PRODL
564        return
565        __endasm;       
566}
567
568/* Vectors */
569void _reset (void) __naked __interrupt 0
570{
571        __asm__("goto __startup");
572}
573
574
575void _startup (void) __naked
576{
577
578  __asm
579    // Initialize the stack pointer
580    lfsr 1, _stack_end
581    lfsr 2, _stack_end
582    clrf _TBLPTRU, 0    // 1st silicon doesn't do this on POR
583   
584    // initialize the flash memory access configuration. this is harmless
585    // for non-flash devices, so we do it on all parts.
586    bsf _EECON1, 7, 0
587    bcf _EECON1, 6, 0
588    __endasm ;
589
590  /* Call the user's main routine */
591  main();
592  __asm__("reset");
593}
594
595/*
596 * high priority interrupt. Split in 2 parts; one for the entry point
597 * where we'll deal with timer0, then jump to another address
598 * as we don't have enough space before the low priority vector
599 */
600void _irqh (void) __naked __shadowregs __interrupt 1
601{
602        __asm
603        bcf   _PIR1, 1
604        goto _irqh_timer2
605        __endasm ;
606
607}
608
609void irqh_timer2(void) __naked
610{
611        /*
612         * no sdcc registers are automatically saved,
613         * so we have to be carefull with C code !
614         */
615        counter_10hz--;
616        if (counter_10hz == 0) {
617                counter_10hz = TIMER2_10HZ;
618                softintrs |= INT_10HZ;
619        }                           
620        if (adstatus & ADSTAT_MEASURE) {
621                if (PIR1bits.ADIF) {
622                        LEDR = 1;
623                }
624                ADCON0bits.GO_NOT_DONE = 1;
625        }
626        __asm
627        retfie 1
628        nop
629        __endasm;
630}
631
632void _irq (void) __interrupt 2 /* low priority */
633{
634        USART_INTR;
635        USART2_INTR;
636        if (PIE1bits.ADIE && PIR1bits.ADIF) {
637                if (softintrs & INT_AD) {
638                        LEDR = 1;
639                }
640                ad_channel = ADCON0bits.CHS;
641                ad_resl = ADRESL;
642                ad_resh = ADRESH;
643                /*
644                 * needs 2Tac, or 32 instrutions
645                 * before next sample. assume we'll
646                 * have them at timer2 interrupt
647                 */
648                if (ad_channel == 0)
649                        ADCON0bits.CHS = 1;
650                else
651                        ADCON0bits.CHS = 0;
652                PIR1bits.ADIF = 0;
653                softintrs |= INT_AD;
654        }
655}
Note: See TracBrowser for help on using the repository browser.