// test.c // // multithreaded TDM /* Copyright (C) 2017 H.Poetzl ** ** This program is free software: you can redistribute it and/or ** modify it under the terms of the GNU General Public License ** as published by the Free Software Foundation, either version ** 2 of the License, or (at your option) any later version. */ // ------------------------------------------------ // configuration #define NO_BIT_DEFINES #include #include #define CONFIG(k, n) __code static char __at _ ## k __ ## k = n CONFIG(CONFIG1, _FEXTOSC_OFF & _RSTOSC_HFINT1 & _CSWEN_ON & _CLKOUTEN_OFF); CONFIG(CONFIG2, _MCLRE_ON & _WDTE_OFF & _PPS1WAY_OFF); #define CPU_NDIV 0 #define TMR2_PRE 2 #define TMR0_PRE (TMR2_PRE + CPU_NDIV + 5) static const uint8_t tmr0_val[] = { 0xA0, 0xA0, 0xA0, 0xA0 }; #include "tear_leds.h" /* ISR/asm related registers */ static volatile uint8_t __at (0x2100) seq[256]; __sfr __at (0x1A0) idx = 0; /* seq index */ __sfr __at (0x1A1) wrk = 0; /* seq index worker */ __sfr __at (0x1A2) bri = 0; /* brightness */ __sfr __at (0x1A3) adc = 0; /* adc channel */ __sfr __at (0x1A4) c1l = 0; /* adc channel */ __sfr __at (0x1A5) c1h = 0; /* adc channel */ __sfr __at (0x1A6) c2l = 0; /* adc channel */ __sfr __at (0x1A7) c2h = 0; /* adc channel */ __sfr __at (0x1A8) br1 = 0; /* brightness */ __sfr __at (0x1A9) br2 = 0; /* brightness */ __sfr __at (0x1AF) tmp = 0; /* test */ __sfr __at (0x1AE) tmp1 = 0; /* test */ __sfr __at (0x1AD) tmp2 = 0; /* test */ __sfr __at (0x1AC) tmp3 = 0; /* test */ #define IX(i) ((i) << 3) #define IA(i) (0x2100 + ((i) << 1)) #define WD(l,h) (((uint16_t)(h) << 8) | ((uint8_t)(l))) static const uint16_t seq_i[128] = { WD(IX(1), LED0A), 0x0000, codeE, IA(64), WD(IX(2), LED1A), 0x0000, codeL, IA(66), WD(IX(3), LED2A), 0x0000, codeR, IA(68), WD(IX(4), LED3A), 0x0000, codeL, IA(70), WD(IX(5), LED4A), 0x0000, codeR, IA(72), WD(IX(6), LED5A), 0x0000, codeL, IA(74), WD(IX(7), LED6A), 0x0000, codeR, IA(76), WD(IX(8), LED7A), 0x0000, codeL, IA(78), WD(IX(9), LED8A), 0x0000, codeR, IA(80), WD(IX(10), LED9A), 0x0000, codeL, IA(82), WD(IX(11), LEDAA), 0x0000, codeR, IA(84), WD(IX(12), LEDBA), 0x0000, codeL, IA(86), WD(IX(0), LEDCA), 0x0000, codeR, IA(88), [64] = 0, 0x0168, [66] = 0, 0x016C, [68] = 0, 0x0170, [70] = 0, 0x0174, [72] = 0, 0x0178, [74] = 0, 0x017C, [76] = 0, 0x0385, [78] = 0, 0x027C, [80] = 0, 0x0278, [82] = 0, 0x0274, [84] = 0, 0x0270, [86] = 0, 0x026C, [88] = 0, 0x0268, }; #include "pwm_val.h" void irq(void) __interrupt 0 { __asm BANKSEL PIR4 BTFSC PIR4,CCP1IF BRA _ccp1 BANKSEL PIR0 BTFSC PIR0,TMR0IF BRA _tmr0 _out: RETFIE _tmr0: BCF PIR0,TMR0IF ; BANKSEL LEDBL ; BSF LEDBL,LEDB ; BCF LEDBL,LEDB ; BANKSEL T2CON ; BTFSC T2CON,TMR2ON ; BRA _ccp1 BANKSEL _idx MOVFW _idx ; use index MOVWF FSR0L BANKSEL TOSL MOVWF FSR0L_SHAD ; update FSR0L MOVIW 4[FSR0] ; code addr lsb MOVWF TOSL MOVIW 5[FSR0] ; code addr msb MOVWF TOSH MOVIW 6[FSR0] MOVWF FSR1L_SHAD ; update FSR1L MOVIW 7[FSR0] MOVWF FSR1H_SHAD ; update FSR1H ; BRA _out RETFIE _ccp1: BCF PIR4,CCP1IF BANKSEL T2CON BCF T2CON,TMR2ON BANKSEL _idx MOVFW _idx ; use index MOVWF _wrk ; save for worker MOVWF FSR0L MOVLW 0x0E ; pps bank 29 MOVWF FSR1H MOVIW 1[FSR0] ; this pps addr MOVWF FSR1L BCF INDF1,2 ; reset pps to GPIO MOVIW 0[FSR0] ; new index MOVWF _idx MOVWF FSR0L MOVIW 1[FSR0] ; next pps addr MOVWF FSR1L BSF INDF1,2 ; set pps to CLC1 BANKSEL CCPR1L MOVIW 2[FSR0] ; pwm lsbs MOVWF CCPR1L MOVIW 3[FSR0] ; pwm msbs MOVWF CCPR1H ; BANKSEL LEDCL ; BSF LEDCL,LEDC ; BCF LEDCL,LEDC ; BRA _out RETFIE __endasm; } // -------------------------------------------------- // and our main entry point void main() { // all digital ANSELA = 0; ANSELB = 0; ANSELC = 0; // all input TRISA = 0xFF; TRISB = 0xFF; TRISC = 0xFF; // all OC ODCONA = 0xFF; ODCONB = 0xFF; ODCONC = 0xFF; // all outputs '1' LATA = 0xFF; LATB = 0xFF; LATC = 0xFF; // reset PPS LED0P = 0; LED1P = 0; LED2P = 0; LED3P = 0; LED4P = 0; LED5P = 0; LED6P = 0; LED7P = 0; LED8P = 0; LED9P = 0; LEDAP = 0; LEDBP = 0; LEDCP = 0; LEDDP = 0; LEDEP = 0; LEDFP = 0; __asm BANKSEL TRISA BCF LED0T,LED0 BCF LED1T,LED1 BCF LED2T,LED2 BCF LED3T,LED3 BCF LED4T,LED4 BCF LED5T,LED5 BCF LED6T,LED6 BCF LED7T,LED7 BCF LED8T,LED8 BCF LED9T,LED9 BCF LEDAT,LEDA BCF LEDBT,LEDB BCF LEDCT,LEDC BCF LEDDT,LEDD BCF LEDET,LEDE BCF LEDFT,LEDF __endasm; /* configure oscillator */ OSCCON3bits.CSWHOLD = 0; OSCCON1bits.NDIV = CPU_NDIV; /* configure Timer 0 */ T0CON0 = 0; T0CON0bits.T016BIT = 0; T0CON0bits.T0OUTPS = 0b0000; /* Postscaler = 1 */ T0CON1 = 0; T0CON1bits.T0CS = 0b100; /* Source = LFINTOSC */ T0CON1bits.T0CS = 0b011; /* Source = HFINTOSC */ T0CON1bits.T0ASYNC = 1; T0CON1bits.T0CKPS = TMR0_PRE; TMR0H = tmr0_val[TMR2_PRE]; TMR0L = 0x00; /* configure Timer 2 */ T2CON = 0; T2CONbits.TMR2ON = 0; /* Timer is off */ T2CONbits.T2CKPS = TMR2_PRE; /* Prescaler */ T2CONbits.T2OUTPS = 0b0000; /* Postscaler = 1 */ PR2 = 0xFF; TMR2 = 0; /* configure CCP1 */ CCPTMRSbits.C1TSEL = 0b01; /* Based on Timer2 */ CCP1CON = 0; CCP1CONbits.CCP1MODE = 0b1111; /* PWM mode */ CCP1CONbits.CCP1FMT = 1; /* Left aligned */ CCP1CONbits.CCP1EN = 1; /* Enable CCP1 */ CCPR1H = 0x80; CCPR1L = 0x40; /* configure CCP2 */ CCPTMRSbits.C2TSEL = 0b01; /* Based on Timer2 */ CCP2CON = 0; CCP2CONbits.CCP2MODE = 0b1111; /* PWM mode */ CCP2CONbits.CCP2FMT = 1; /* Left aligned */ CCP2CONbits.CCP2EN = 0; /* Enable CCP1 */ CCPR2H = 0xF0; CCPR2L = 0x00; /* configure CLKR */ CLKRCON = 0; CLKRCONbits.CLKRDC = 0b10; /* 50% duty cycle */ CLKRCONbits.CLKRDIV = 0b010; /* FOSC/4 */ CLKRCONbits.CLKREN = 1; /* configure CLC */ CLC1SEL0bits.LC1D1S = 0b01100; /* CCP1 output */ CLC1GLS0 = 0b00000010; /* one true in */ CLC1GLS1 = 0; CLC1GLS2 = 0; CLC1GLS3 = 0; CLC1POL = 0b00000011; CLC1CONbits.LC1MODE = 0b000; /* AND - OR */ CLC1CONbits.LC1EN = 1; /* Enable LC1 */ /* configure EUSART */ TX1STA = 0; TX1STAbits.TXEN = 1; TX1STAbits.BRGH = 1; RC1STA = 0; RC1STAbits.SPEN = 1; RC1STAbits.CREN = 0; BAUD1CON = 0; BAUD1CONbits.BRG16 = 1; BAUD1CONbits.WUE = 0; SP1BRG = 0; SP1BRGH = 0; /* configure ADC */ ADCON0 = 0; ADCON0bits.ADON = 1; ADCON1 = 0; ADCON1bits.ADFM = 0; /* left justified */ ADCON1bits.ADCS = 0b111; /* ADCRC osc */ ADCON1bits.ADNREF = 0; /* AVSS reference */ // ADCON1bits.ADPREF = 0b00; /* AVDD reference */ ADCON1bits.ADPREF = 0b11; /* FVR reference */ ADACT = 0; /* no auto conversion */ /* configure FVR */ FVRCON = 0; FVRCONbits.FVREN = 1; FVRCONbits.TSEN = 1; // FVRCONbits.ADFVR = 0b01; /* Gain 1x (1.024V) */ FVRCONbits.ADFVR = 0b10; /* Gain 2x (2.048V) */ /* disable unused modules */ PMD0 = 0b00000101; /* All but Clock Net,CLKR,FVR */ PMD1 = 0b11111010; /* All but Timer 0,2 */ PMD2 = 0b01000110; /* All but ADC */ PMD3 = 0b11111110; /* All but CCP1 */ PMD4 = 0b00000010; /* All but UART1*/ PMD5 = 0b00011101; /* All but CLC1 */ /* PPS */ PPSLOCKbits.PPSLOCKED = 0; // LED9P = 0b01100; // LED0P = 0b11110; /* clock on LED0 */ // LED1P = 0b10100; /* TX1 on LED1 */ RA0PPS = 0b10100; /* TX1 on ICSPDAT */ // RA1PPS = 0b10100; /* TX1 on ICSPCLK */ // TXPPS = LED1I; // LED2P = 0b01100; /* CCP1 on LED2 */ // LED3P = 0b00100; /* CLC1 on LED3 */ // LED6P = 0b00100; /* CLC1 on LED3 */ ANSELAbits.ANSA1 = 1; /* RA1 is analog */ WPUAbits.WPUA1 = 0; /* RA1 no pullup */ LATAbits.LATA1 = 0; /* GND for ADC */ ANSELAbits.ANSA4 = 1; /* RA4 is analog */ WPUAbits.WPUA4 = 0; /* RA4 no pullup */ LATAbits.LATA4 = 0; /* GND for ADC */ __asm BANKSEL _idx MOVLW 0xFF MOVWF _idx MOVLW high(_seq) MOVWF FSR0H MOVLW low(_seq) MOVWF FSR0L MOVLW high(_seq_i) MOVWF FSR1H MOVLW low(_seq_i) MOVWF FSR1L _copy: MOVIW FSR1++ MOVWI FSR0++ DECFSZ _idx,F BRA _copy MOVLW high(_seq) MOVWF FSR0H MOVLW low(_seq) MOVWF FSR0L BANKSEL CCPR1L MOVIW 2[FSR0] ; pwm lsbs MOVWF CCPR1L MOVIW 3[FSR0] ; pwm msbs MOVWF CCPR1H __endasm; PIR0bits.TMR0IF = 0; /* clear TMR0 irq */ PIE0bits.TMR0IE = 1; /* enable TMR0 irq */ PIR1bits.TMR2IF = 0; /* clear TMR2 irq */ PIE1bits.TMR2IE = 0; /* enable TMR2 irq */ PIR4bits.CCP1IF = 0; /* clear CCP1 irq */ PIE4bits.CCP1IE = 1; /* enable CCP1 irq */ INTCONbits.PEIE = 1; /* enable peripheral irq */ INTCONbits.GIE = 1; /* enable global irq */ T0CON0bits.T0EN = 1; /* enable timer */ while (1); /* wait for first irq */ } static inline void prep(void) { __asm BANKSEL TMR2 MOVLW 0xFF MOVWF TMR2 BANKSEL T2CON BSF T2CON,TMR2ON BANKSEL CCPR1L MOVFW CCPR1L ; check for zero PWM IORWF CCPR1H,W BANKSEL PIR4 BTFSC STATUS,2 ; skip if not zero PWM BSF PIR4,CCP1IF __endasm; } static inline void wait_pwm(void) { __asm BANKSEL T2CON BTFSC T2CON,TMR2ON BRA $-1 __endasm; } static inline void done(void) { __asm SLEEP BRA $-1 __endasm; } #if 0 static inline void done_adc(void) { __asm BANKSEL ADCON0 BSF ADCON0,ADGO SLEEP BRA $-1 __endasm; } #endif static inline void adc_ana1(void) { __asm BANKSEL ADCON0 MOVLW 0xFC IORWF ADCON0,F ; select FVR BANKSEL TRISA BCF TRISA,1 ; ground RA1 NOP BSF TRISA,1 ; back to input BANKSEL ADCON0 MOVLW 0x07 ANDWF ADCON0,F ; select ANA1 BSF ADCON0,ADGO __endasm; } static inline void adc_ana4(void) { __asm BANKSEL ADCON0 MOVLW 0xFC IORWF ADCON0,F ; select FVR BANKSEL TRISA BCF TRISA,4 ; ground RA4 NOP BSF TRISA,4 ; back to input ; BANKSEL ADCON0 ; MOVLW 0x13 ; ANDWF ADCON0,F ; select ANA4 ; BSF ADCON0,ADGO MOVLW 0x13 BANKSEL ADCON0 MOVWF ADCON0 __endasm; } static inline void pwm16(void) { __asm BANKSEL _bri MOVFW _bri CALL pwm_v16l MOVWI 2[FSR0] MOVFW _bri CALL pwm_v16h MOVWI 3[FSR0] __endasm; } static inline void pwm64(void) { __asm BANKSEL _bri MOVFW _bri CALL pwm_v64l MOVWI 2[FSR0] MOVFW _bri CALL pwm_v64h MOVWI 3[FSR0] __endasm; } static inline void common(void) { __asm MOVFW INDF1 BZ $norm$ ; init CLRF INDF1 $norm$: BANKSEL _bri CLRF _bri ; default MOVIW 3[FSR1] ; flags BZ $done$ ; no cap MOVWF _tmp CLRF _br1 BTFSS _tmp,0 BRA $no_c1$ MOVIW 2[FSR1] ; limit SUBWF _c1l,W BC $no_c1$ LSRF WREG,W BTFSC WREG,4 MOVWF _br1 $no_c1$: CLRF _br2 BTFSS _tmp,1 BRA $no_c2$ MOVIW 2[FSR1] ; limit SUBWF _c2l,W BC $no_c2$ LSRF WREG,W BTFSC WREG,4 MOVWF _br2 $no_c2$: MOVFW _tmp XORLW 0x3 BNZ $no_mix$ MOVFW _br1 SUBWF _br2,W SKPNC BCF _tmp,1 $no_mix$: MOVFW _br1 BTFSC _tmp,0 MOVWF _bri MOVFW _br2 BTFSC _tmp,1 MOVWF _bri $done$: BANKSEL ADRESH MOVFW ADRESH MOVWI 1[FSR1] ; save ADC result ; BANKSEL TX1REG ; MOVWF TX1REG ; output ADC ; NOP ; BANKSEL _bri ; SUBLW 0xA4 ; BTFSC STATUS,C ; COMF _bri,F __endasm; } static void codeR(void) { prep(); common(); pwm16(); wait_pwm(); adc_ana1(); done(); } static void codeL(void) { prep(); common(); pwm16(); wait_pwm(); adc_ana4(); done(); } static void codeE(void) { prep(); common(); __asm MOVLW 0x00 BANKSEL TX1REG MOVWF TX1REG ; output val BANKSEL _tmp MOVLW 6 MOVWF _tmp CLRF _c1l CLRF _c1h _loop1: MOVIW 5[FSR1] ADDWF _c1l,F CLRW ADDWFC _c1h,F ADDFSR FSR1,8 DECFSZ _tmp,F BRA _loop1 LSRF _c1h,F RRF _c1l,F LSRF _c1h,F RRF _c1l,F LSRF _c1h,F RRF _c1l,F MOVFW _c1l BANKSEL TX1REG MOVWF TX1REG ; output val MOVIW 6[FSR0] MOVWF FSR1L MOVIW 7[FSR0] MOVWF FSR1H BANKSEL _tmp MOVLW 6 MOVWF _tmp CLRF _c2l CLRF _c2h _loop2: MOVIW 9[FSR1] ADDWF _c2l,F CLRW ADDWFC _c2h,F ADDFSR FSR1,8 DECFSZ _tmp,F BRA _loop2 LSRF _c2h,F RRF _c2l,F LSRF _c2h,F RRF _c2l,F LSRF _c2h,F RRF _c2l,F MOVLW 0x07 ADDWF _c2l,F MOVFW _c2l BANKSEL TX1REG MOVWF TX1REG ; output val __endasm; pwm16(); wait_pwm(); done(); }