#include #include #include #include extern char stack; extern char stack_end; #pragma stack 0x100 256 void _reset (void) __naked __interrupt 0; void _startup (void) __naked; static char counter_1hz; static volatile short counter_10hz; static volatile unsigned int softintrs; #define INT_10HZ 0x0001 #define INT_AD 0x0002 #define INT_DOAD 0x0004 #define TIMER0_5MS 192 /* 48 without PLL */ #define TIMER2_10HZ 1000 #define CLRWDT __asm__("clrwdt") #define SLEEP __asm__("sleep") static char ad_channel; static long ad_i_result; static long ad_v_result; #define PRINTHEX(v) \ { \ unsigned char c = (v); \ if (c < 10) { \ putchar('0' + c); \ } else { \ putchar(('a' - 10) + c ); \ } \ } void main(void) __naked { unsigned char c; softintrs = 0; counter_1hz = 10; ANCON0 = 0xf0; /* an0-an3 analog, an4-an7 digital */ ANCON1 = 0x3f; /* an8-12 digital */ TRISCbits.TRISC1 = 0; TRISCbits.TRISC2 = 0; PORTCbits.RC1 = 0; PORTCbits.RC2 = 0; /* switch PLL on */ OSCTUNEbits.PLLEN = 1; /* configure sleep mode: PRI_IDLE */ OSCCONbits.SCS = 0; OSCCONbits.IDLEN = 1; /* everything is low priority by default */ IPR1 = 0; IPR2 = 0; IPR3 = 0; IPR4 = 0; IPR5 = 0; INTCON = 0; INTCON2 = 0; INTCON3 = 0; INTCON2bits.RBPU = 1; RCONbits.IPEN=1; /* enable interrupt priority */ /* configure timer0 as free-running counter at 46.875Khz */ T0CON = 0x07; /* b00000111: internal clock, 1/256 prescaler */ INTCONbits.TMR0IF = 0; INTCONbits.TMR0IE = 0; /* no interrupt */ T0CONbits.TMR0ON = 1; #if 0 /* configure UART for 57600Bps at 48Mhz */ SPBRG1 = 12; #endif /* configure UART for 921600Bps at 48Mhz */ TXSTA1bits.BRGH = 1; BAUDCON1bits.BRG16 = 1; SPBRGH1 = 0; SPBRG1 = 12; USART_INIT(0); stdout = STREAM_USER; /* Use the macro PUTCHAR with printf */ #if TIMER2_10HZ == 100 /* configure timer2 for 1Khz interrupt */ T2CON = 0x22; /* b00100010: postscaller 1/5, prescaler 1/16 */ PR2 = 150; /* 1khz output */ #elif TIMER2_10HZ == 1000 /* configure timer2 for 10Khz interrupt */ T2CON = 0x22; /* b00100010: postscaller 1/5, prescaler 1/16 */ PR2 = 15; /* 10khz output */ #elif TIMER2_10HZ == 2000 /* configure timer2 for 20Khz interrupt */ T2CON = 0x21; /* b00100001: postscaller 1/5, prescaler 1/4 */ PR2 = 29; /* 20khz output */ #else #error "unknown TIMER2_10HZ" #endif counter_10hz = TIMER2_10HZ; T2CONbits.TMR2ON = 1; PIR1bits.TMR2IF = 0; IPR1bits.TMR2IP = 1; /* high priority interrupt */ PIE1bits.TMR2IE = 1; INTCONbits.GIE_GIEH=1; /* enable high-priority interrupts */ INTCONbits.PEIE_GIEL=1; /* enable low-priority interrrupts */ /* * configure ADC: * AN3: vref+ * AN2: I * AN1: vout */ ADCON0 = 0xc1; /* b11000001 */ /* clk = fosc/64, tacq = 4tad (5.33us) */ ADCON1 = 0x96; /* b10010110 */ /* ANCON already set up */ /* start calibration */ ADCON1bits.ADCAL = 1; ADCON0bits.GO_NOT_DONE =1; while (ADCON0bits.GO_NOT_DONE) ; /* wait */ ADCON1bits.ADCAL = 0; PIR1bits.ADIF = 0; PIE1bits.ADIE = 1; printf("hello world\n"); /* enable watch dog timer */ WDTCON = 0x01; printf("\nready\n"); /* start I calibration process */ ad_channel = 0; ADCON0bits.CHS = 0; softintrs &= ~INT_DOAD; PORTCbits.RC1 = 1; PORTCbits.RC2 = 0; again: while (1) { CLRWDT; if (softintrs & INT_AD) { softintrs &= ~INT_AD; if (ad_channel == 0) { PRINTHEX(PORTB & 0xf); PRINTHEX(ADRESH & 0xf); PRINTHEX(ADRESL >> 4); PRINTHEX(ADRESL & 0xf); //printf("%1x%3x", (PORTB & 0xf), ADRESL | (ADRESH << 8)); /* * needs 2Tac, or 32 instrutions * before next sample. assume we * already have them since the * interrupt */ ad_channel = 1; ADCON0bits.CHS = 1; } else { ad_channel = 0; ADCON0bits.CHS = 0; PRINTHEX(ADRESH & 0xf); PRINTHEX(ADRESL >> 4); PRINTHEX(ADRESL & 0xf); putchar('X'); //printf("%3xX", ADRESL | (ADRESH << 8)); } } if ((softintrs & INT_AD) == 0 && (softintrs & INT_DOAD) && ADCON0bits.GO_NOT_DONE == 0) { ADCON0bits.GO_NOT_DONE = 1; softintrs &= ~INT_DOAD; } if (RCREG1 == 'r') break; SLEEP; } end: while ((c = getchar()) != 'r') { printf("got %c\n", c); goto again; } printf("returning\n"); while (PIE1bits.TX1IE) ; /* wait for transmit to complete */ INTCONbits.PEIE=0; /* disable peripheral interrupts */ INTCONbits.GIE=0; /* disable interrrupts */ } unsigned int timer0_read() __naked { /* return TMR0L | (TMR0H << 8), reading TMR0L first */ __asm movf _TMR0L, w movff _TMR0H, _PRODL return __endasm; } /* Vectors */ void _reset (void) __naked __interrupt 0 { __asm__("goto __startup"); } void _startup (void) __naked { __asm // Initialize the stack pointer lfsr 1, _stack_end lfsr 2, _stack_end clrf _TBLPTRU, 0 // 1st silicon doesn't do this on POR // initialize the flash memory access configuration. this is harmless // for non-flash devices, so we do it on all parts. bsf _EECON1, 7, 0 bcf _EECON1, 6, 0 __endasm ; /* Call the user's main routine */ main(); __asm__("reset"); } /* * high priority interrupt. Split in 2 parts; one for the entry point * where we'll deal with timer0, then jump to another address * as we don't have enough space before the low priority vector */ void _irqh (void) __naked __shadowregs __interrupt 1 { __asm bcf _PIR1, 1 goto _irqh_timer2 __endasm ; } void irqh_timer2(void) __naked { /* * no sdcc registers are automatically saved, * so we have to be carefull with C code ! */ #if 0 counter_10hz--; if (counter_10hz == 0) { counter_10hz = TIMER2_10HZ; softintrs |= INT_10HZ; } #endif if (softintrs & INT_DOAD) { PORTCbits.RC2=1; } softintrs |= INT_DOAD; __asm retfie 1 nop __endasm; } void _irq (void) __interrupt 2 /* low priority */ { USART_INTR; if (PIE1bits.ADIE && PIR1bits.ADIF) { PIR1bits.ADIF = 0; softintrs |= INT_AD; } }