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

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

Firmware for V2 boards

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