PBP 3.0 really needed?


Closed Thread
Results 1 to 31 of 31

Hybrid View

  1. #1
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: PBP 3.0 really needed?

    ....I discovered you do an ASM Interrupt, part way through the ISR jump out of ASM, add some PBP, then jump back into ASM to RETFIE
    In the end your compiled PBP statements are ASM too so yes, in theory, you can do that but remember that the PBP statements you use in that ISR might use the same system variables as your main routine and can therefor corrupt those values for whatever it was your main program was doing when it got interrupted.

    DT-Ints, as I'm sure you know, handles this by reserving space for, saving on ISR entry and restoring on ISR exit all these system variables. It's somewhat clever in that it "only" saves/restores system variables that the program uses but it does so no matter if the code in the ISR would affect those variables or not.

    What I've done on occasions is to write my ISR in PBP but treat it as an assembly type interrupt and then, by looking at the generated .lst file, figure out which system variables my PBP ISR code is actually affecting and then add save/restore code for those ONLY. It works but you need to be very methodical and follow every library call and it's obviously extremely easy to mess up since adding a single line of code to ISR (or even chaning one) could effectively ruin your day.

    I'd like to see it built into the compiler with enough intelligense to analyze the code in the ISR and determine exaclty which variables are actually needed to be saved/restored. I mean, sure the main program might use variable T1,T2,T3 but if the code in the ISR only uses T2 then why waste time and space on saving/restoring all three? Some sort of report would be a nice touch so one can figure out the expected latency - which would then obviously vary depending on code complexity of the ISR.

    It would be interesting to know how the compiler(s) from MikroE is handling this, anyone in the know?

    /Henrik.

  2. #2
    Join Date
    May 2013
    Location
    australia
    Posts
    2,644


    Did you find this post helpful? Yes | No

    Default Re: PBP 3.0 really needed?

    USERCOMMAND, seldom mentioned on this forum, can accommodate most new chip features.
    although its not much use for NCO module since the compiler can only pass word values to the assembler for pic16's
    its possible to use the 64bit math capability of the assembler in asm blocks
    eg
    create a template like this and adjust nco osc and output freq to suit, the other nco regs could be included also if you like


    Code:
    ASM  
    NCO_OUT_FREQ = 10000000
    NCO_OSC = OSC
    NCO_INT  = NCO_OUT_FREQ*2096/(NCO_OSC*1000)
      MOVE?CB   NCO1INCL ,LOW (NCO_INT)
      MOVE?CB   NCO1INCH ,HIGH (NCO_INT)
      MOVE?CB   NCO1INCU ,UPPER (NCO_INT)
    ENDASM
    which if fine if you don't need to change nco settings on the fly too much

    * this is untested the formula might not be correct ,I don't have a chip with a nco to test with
    Warning I'm not a teacher

  3. #3
    Join Date
    May 2013
    Location
    australia
    Posts
    2,644


    Did you find this post helpful? Yes | No

    Default Re: PBP 3.0 really needed?

    Henrik

    mikroc is not much different , it has various R vars as working registers , I believe it saves/restores only as many of these as the isr requires

    microc lst and c snippets
    lst
    Code:
    ;  LST file generated by mikroListExporter - v.2.0 
    ; Date/Time: 5/16/2015 12:02:53 PM
    ;----------------------------------------------
    
    ;Address Opcode 	ASM
    0x0000	0x158A      	BSF        PCLATH, 3
    0x0001	0x2800      	GOTO       2048
    _interrupt:
    0x0004	0x00FF      	MOVWF      R15
    0x0005	0x0E03      	SWAPF      STATUS, 0
    0x0006	0x0183      	CLRF       STATUS
    0x0007	0x00CD      	MOVWF      ___saveSTATUS
    0x0008	0x080A      	MOVF       PCLATH, 0
    0x0009	0x00CE      	MOVWF      ___savePCLATH
    0x000A	0x018A      	CLRF       PCLATH
    0x000B	0x0870      	MOVF       R0, 0
    0x000C	0x00A3      	MOVWF      35
    0x000D	0x0871      	MOVF       R1, 0
    0x000E	0x00A2      	MOVWF      34
    0x000F	0x0872      	MOVF       R2, 0
    0x0010	0x00A1      	MOVWF      33
    0x0011	0x0873      	MOVF       R3, 0
    0x0012	0x00A0      	MOVWF      32
    0x0013	0x0804      	MOVF       FSR, 0
    0x0014	0x00A4      	MOVWF      36
    ;uv_16f648a_lcd.c,232 :: 		void interrupt(void)
    ;uv_16f648a_lcd.c,236 :: 		if (INTCON.RBIF)  {   // RbC_INT
    0x0015	0x1C0B      	BTFSS      INTCON, 0
    0x0016	0x2852      	GOTO       L_interrupt47
    ;uv_16f648a_lcd.c,237 :: 		ev = ev << 2;
    0x0017	0x082F      	MOVF       interrupt_ev_L0, 0
    0x0018	0x00F3      	MOVWF      R3
    0x0019	0x0DF3      	RLF        R3, 1
    0x001A	0x1073      	BCF        R3, 0
    0x001B	0x0DF3      	RLF        R3, 1
    0x001C	0x1073      	BCF        R3, 0
    0x001D	0x0873      	MOVF       R3, 0
    0x001E	0x00AF      	MOVWF      interrupt_ev_L0
    ;uv_16f648a_lcd.c,238 :: 		ev = ev | ((PORTB & 0b00110000) >> 4);
    0x001F	0x3030      	MOVLW      48
    0x0020	0x0506      	ANDWF      PORTB, 0
    0x0021	0x00F2      	MOVWF      R2
    0x0022	0x0872      	MOVF       R2, 0
    0x0023	0x00F0      	MOVWF      R0
    0x0024	0x0CF0      	RRF        R0, 1
    0x0025	0x13F0      	BCF        R0, 7
    0x0026	0x0CF0      	RRF        R0, 1
    0x0027	0x13F0      	BCF        R0, 7
    0x0028	0x0CF0      	RRF        R0, 1
    0x0029	0x13F0      	BCF        R0, 7
    0x002A	0x0CF0      	RRF        R0, 1
    0x002B	0x13F0      	BCF        R0, 7
    0x002C	0x0873      	MOVF       R3, 0
    0x002D	0x04F0      	IORWF      R0, 1
    0x002E	0x0870      	MOVF       R0, 0
    0x002F	0x00AF      	MOVWF      interrupt_ev_L0
    ;uv_16f648a_lcd.c,239 :: 		count +=  lut[ev & 0xf];
    0x0030	0x300F      	MOVLW      15
    0x0031	0x05F0      	ANDWF      R0, 1
    0x0032	0x0870      	MOVF       R0, 0
    0x0033	0x3E30      	ADDLW      interrupt_lut_L0
    0x0034	0x0084      	MOVWF      FSR
    0x0035	0x0800      	MOVF       INDF, 0
    0x0036	0x00F0      	MOVWF      R0
    0x0037	0x0870      	MOVF       R0, 0
    0x0038	0x07AC      	ADDWF      _count, 1
    0x0039	0x1803      	BTFSC      STATUS, 0
    0x003A	0x0AAD      	INCF       _count+1, 1
    0x003B	0x3000      	MOVLW      0
    0x003C	0x1BF0      	BTFSC      R0, 7
    0x003D	0x30FF      	MOVLW      255
    0x003E	0x07AD      	ADDWF      _count+1, 1
    ;uv_16f648a_lcd.c,240 :: 		ccc = count >> 2;         // divide 4 for 1 count per detent
    0x003F	0x082C      	MOVF       _count, 0
    0x0040	0x00F0      	MOVWF      R0
    0x0041	0x082D      	MOVF       _count+1, 0
    0x0042	0x00F1      	MOVWF      R0+1
    0x0043	0x0CF1      	RRF        R0+1, 1
    0x0044	0x0CF0      	RRF        R0, 1
    0x0045	0x13F1      	BCF        R0+1, 7
    0x0046	0x1B71      	BTFSC      R0+1, 6
    0x0047	0x17F1      	BSF        R0+1, 7
    0x0048	0x0CF1      	RRF        R0+1, 1
    0x0049	0x0CF0      	RRF        R0, 1
    0x004A	0x13F1      	BCF        R0+1, 7
    0x004B	0x1B71      	BTFSC      R0+1, 6
    0x004C	0x17F1      	BSF        R0+1, 7
    0x004D	0x0870      	MOVF       R0, 0
    0x004E	0x00A5      	MOVWF      _ccc
    0x004F	0x0871      	MOVF       R0+1, 0
    0x0050	0x00A6      	MOVWF      _ccc+1
    ;uv_16f648a_lcd.c,241 :: 		INTCON.RBIF = 0;
    0x0051	0x100B      	BCF        INTCON, 0
    ;uv_16f648a_lcd.c,242 :: 		}
    L_interrupt47:
    ;uv_16f648a_lcd.c,243 :: 		if (PIR1.TMR1IF){     // tmr2
    0x0052	0x1C0C      	BTFSS      PIR1, 0
    0x0053	0x2874      	GOTO       L_interrupt48
    ;uv_16f648a_lcd.c,244 :: 		TMR1H = 63515/256;
    0x0054	0x30F8      	MOVLW      248
    0x0055	0x008F      	MOVWF      TMR1H
    ;uv_16f648a_lcd.c,245 :: 		TMR1L= 63515%256;
    0x0056	0x301B      	MOVLW      27
    0x0057	0x008E      	MOVWF      TMR1L
    ;uv_16f648a_lcd.c,246 :: 		milli += 2;
    0x0058	0x3002      	MOVLW      2
    0x0059	0x00F0      	MOVWF      R0
    0x005A	0x01F1      	CLRF       R0+1
    0x005B	0x01F2      	CLRF       R0+2
    0x005C	0x01F3      	CLRF       R0+3
    0x005D	0x0827      	MOVF       _milli, 0
    0x005E	0x07F0      	ADDWF      R0, 1
    0x005F	0x0828      	MOVF       _milli+1, 0
    0x0060	0x1803      	BTFSC      STATUS, 0
    0x0061	0x0F28      	INCFSZ     _milli+1, 0
    0x0062	0x07F1      	ADDWF      R0+1, 1
    0x0063	0x0829      	MOVF       _milli+2, 0
    0x0064	0x1803      	BTFSC      STATUS, 0
    0x0065	0x0F29      	INCFSZ     _milli+2, 0
    0x0066	0x07F2      	ADDWF      R0+2, 1
    0x0067	0x082A      	MOVF       _milli+3, 0
    0x0068	0x1803      	BTFSC      STATUS, 0
    0x0069	0x0F2A      	INCFSZ     _milli+3, 0
    0x006A	0x07F3      	ADDWF      R0+3, 1
    0x006B	0x0870      	MOVF       R0, 0
    0x006C	0x00A7      	MOVWF      _milli
    0x006D	0x0871      	MOVF       R0+1, 0
    0x006E	0x00A8      	MOVWF      _milli+1
    0x006F	0x0872      	MOVF       R0+2, 0
    0x0070	0x00A9      	MOVWF      _milli+2
    0x0071	0x0873      	MOVF       R0+3, 0
    0x0072	0x00AA      	MOVWF      _milli+3
    ;uv_16f648a_lcd.c,247 :: 		PIR1.TMR1IF = 0;
    0x0073	0x100C      	BCF        PIR1, 0
    ;uv_16f648a_lcd.c,248 :: 		}
    L_interrupt48:
    ;uv_16f648a_lcd.c,249 :: 		}
    L_end_interrupt:
    L__interrupt120:
    0x0074	0x0823      	MOVF       35, 0
    0x0075	0x00F0      	MOVWF      R0
    0x0076	0x0822      	MOVF       34, 0
    0x0077	0x00F1      	MOVWF      R1
    0x0078	0x0821      	MOVF       33, 0
    0x0079	0x00F2      	MOVWF      R2
    0x007A	0x0820      	MOVF       32, 0
    0x007B	0x00F3      	MOVWF      R3
    0x007C	0x0824      	MOVF       36, 0
    0x007D	0x0084      	MOVWF      FSR
    0x007E	0x084E      	MOVF       ___savePCLATH, 0
    0x007F	0x008A      	MOVWF      PCLATH
    0x0080	0x0E4D      	SWAPF      ___saveSTATUS, 0
    0x0081	0x0083      	MOVWF      STATUS
    0x0082	0x0EFF      	SWAPF      R15, 1
    0x0083	0x0E7F      	SWAPF      R15, 0
    0x0084	0x0009      	RETFIE
    ; end of _interrupt
    c isr


    Code:
    void interrupt(void)
     {
     static  signed char lut[] = {0,-1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
     static signed char ev = 0;
       if (INTCON.RBIF)  {   // RbC_INT
           ev = ev << 2;
           ev = ev | ((PORTB & 0b00110000) >> 4);
           count +=  lut[ev & 0xf];
            ccc = count >> 2;         // divide 4 for 1 count per detent
           INTCON.RBIF = 0;
       }
      if (PIR1.TMR1IF){     // tmr2
            TMR1H = 63515/256;
            TMR1L= 63515%256;
            milli += 2;
            PIR1.TMR1IF = 0;
       }
    }

    and a different one

    lst
    Code:
    ;  LST file generated by mikroListExporter - v.2.0 
    ; Date/Time: 1/4/2015 11:01:07 AM
    ;----------------------------------------------
    
    ;Address Opcode 	ASM
    0x0000	0x2D50      	GOTO       1360
    _interrupt:
    0x0004	0x00FF      	MOVWF      R15
    0x0005	0x0E03      	SWAPF      STATUS, 0
    0x0006	0x0183      	CLRF       STATUS
    0x0007	0x00C5      	MOVWF      ___saveSTATUS
    0x0008	0x080A      	MOVF       PCLATH, 0
    0x0009	0x00C4      	MOVWF      ___savePCLATH
    0x000A	0x018A      	CLRF       PCLATH
    0x000B	0x0870      	MOVF       R0, 0
    0x000C	0x00A1      	MOVWF      33
    ;dr3200-pic16f88.c,111 :: 		void interrupt(){
    ;dr3200-pic16f88.c,113 :: 		if (PIR1.TMR1IF){
    0x000D	0x1C0C      	BTFSS      PIR1, 0
    0x000E	0x2822      	GOTO       L_interrupt25
    ;dr3200-pic16f88.c,115 :: 		T1CON.TMR1ON = 0;        // stop TIMER1
    0x000F	0x1010      	BCF        T1CON, 0
    ;dr3200-pic16f88.c,116 :: 		data_in  = data_in << 1;// shift data to the left
    0x0010	0x0DBF      	RLF        _data_in, 1
    0x0011	0x0DC0      	RLF        _data_in+1, 1
    0x0012	0x103F      	BCF        _data_in, 0
    ;dr3200-pic16f88.c,117 :: 		porta.ra2=portc.rc5 ;
    0x0013	0x1A87      	BTFSC      PORTC, 5
    0x0014	0x2817      	GOTO       L__interrupt35
    0x0015	0x1105      	BCF        PORTA, 2
    0x0016	0x2818      	GOTO       L__interrupt36
    L__interrupt35:
    0x0017	0x1505      	BSF        PORTA, 2
    L__interrupt36:
    ;dr3200-pic16f88.c,118 :: 		if (PORTC.RC5 == 1)     // sample the incoming signal   // inverted
    0x0018	0x1E87      	BTFSS      PORTC, 5
    0x0019	0x281B      	GOTO       L_interrupt26
    ;dr3200-pic16f88.c,119 :: 		data_in = data_in | 1;       // no need to ask for zero, since data_in is initially
    0x001A	0x143F      	BSF        _data_in, 0
    L_interrupt26:
    ;dr3200-pic16f88.c,120 :: 		++data_bit;          // increment counter of bits
    0x001B	0x0AA6      	INCF       _data_bit, 1
    ;dr3200-pic16f88.c,121 :: 		tmr1h = t3h;          // preload TIMER1 with T3 == 0xFFFF-T2
    0x001C	0x0828      	MOVF       _t3h, 0
    0x001D	0x008F      	MOVWF      TMR1H
    ;dr3200-pic16f88.c,122 :: 		tmr1l = t3l;       // preload TIMER1 with T3 == 0xFFFF-T2
    0x001E	0x0827      	MOVF       _t3l, 0
    0x001F	0x008E      	MOVWF      TMR1L
    ;dr3200-pic16f88.c,123 :: 		T1CON.TMR1ON =  1;          // start TIMER1
    0x0020	0x1410      	BSF        T1CON, 0
    ;dr3200-pic16f88.c,125 :: 		PIR1.TMR1IF=  0;               // clear TMR1IF
    0x0021	0x100C      	BCF        PIR1, 0
    ;dr3200-pic16f88.c,126 :: 		}
    L_interrupt25:
    ;dr3200-pic16f88.c,127 :: 		}
    L_end_interrupt:
    L__interrupt34:
    0x0022	0x0821      	MOVF       33, 0
    0x0023	0x00F0      	MOVWF      R0
    0x0024	0x0844      	MOVF       ___savePCLATH, 0
    0x0025	0x008A      	MOVWF      PCLATH
    0x0026	0x0E45      	SWAPF      ___saveSTATUS, 0
    0x0027	0x0083      	MOVWF      STATUS
    0x0028	0x0EFF      	SWAPF      R15, 1
    0x0029	0x0E7F      	SWAPF      R15, 0
    0x002A	0x0009      	RETFIE
    ; end of _interrupt
    c code
    Code:
     void interrupt(){
    
      if (PIR1.TMR1IF){
    
             T1CON.TMR1ON = 0;        // stop TIMER1
             data_in  = data_in << 1;// shift data to the left
              porta.ra2=portc.rc5 ;
             if (PORTC.RC5 == 1)     // sample the incoming signal   // inverted
             data_in = data_in | 1;       // no need to ask for zero, since data_in is initially
             ++data_bit;          // increment counter of bits
             tmr1h = t3h;          // preload TIMER1 with T3 == 0xFFFF-T2
             tmr1l = t3l;       // preload TIMER1 with T3 == 0xFFFF-T2
             T1CON.TMR1ON =  1;          // start TIMER1
    
             PIR1.TMR1IF=  0;               // clear TMR1IF
       }
    }
    Last edited by richard; - 17th December 2017 at 00:21.
    Warning I'm not a teacher

  4. #4
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: PBP 3.0 really needed?

    Quote Originally Posted by HenrikOlsson View Post
    In the end your compiled PBP statements are ASM too so yes, in theory, you can do that but remember that the PBP statements you use in that ISR might use the same system variables as your main routine and can therefor corrupt those values for whatever it was your main program was doing when it got interrupted. /Henrik.
    I jumped out of ASM so "cheat" with a PAUSE 300 line, so no variables were modified. Creating a 300 ms pause in ASM is nowhere near as clean as PBP. Everything else I'm using ASM in my ISR.

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,612


    Did you find this post helpful? Yes | No

    Default Re: PBP 3.0 really needed?

    I'm sorry but I'm afraid you're mistaken, variables most certainly WAS modified. I'm not talking about "your" variables, I'm talking about PBPs internal variables.
    You say that it's a lot "cleaner" to do a PAUSE with PBP (and I agree) but how do you think PBP does that PAUSE for you "behind the scenes"?

    A PAUSE 300 compiles to this (for a 16F628A):
    Code:
    movlw   low ((0012Ch) >> 8)
    movwf   R1 + 1
    movlw   low (low (0012Ch))
    call    PAUSEL
    Already here we can see that system variable R1 is being used. The code also calls library routine PAUSEL and if you look that one up you'll see that it, on top of R1 also might use R0.

    Now, let's take this super simple example of your main program being in the middle of a PAUSE 1000 when the interrupt happens. The PAUSE in the main routine obviously compiles to the same code as the PAUSE in the ISR so it's obviously using the same system variables (R1 and possibly R0). What do you think happens with the timing of the PAUSE statement in the main program when the PAUSE statement in the ISR overwrites system variables R1 and possibly R0?

    /Henrik.

  6. #6
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: PBP 3.0 really needed?

    Henrik, stuff like this gets me thinking inside a much larger box over time. You have a knowledge base different (and in my opinion larger) than mine when it comes to programming. I so appreciate these little jewels. I know it worked in the application I used it for, but it could easily have done unexpected things, based on your post. Thanks again for teaching me.

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts