PIC XC8 compiler problem in interrupt - Page 1
Forum section: electronics / general

author: cv007
author_rank: Frequent Contributor
timestamp: October 25, 2017, 12:21:24 am
content: Has anyone else seen this with XC8?Maybe I'm missing something obvious, but it seems the compiler is using common ram 0x7E and 0x7F without properly saving/restoring in the interrupt. I had the stack option set to Reentrant (unknowingly) , and discovered the compiler was using common ram 0x7E/7F in a function but the isr was not properly restoring 0x7F, which it also used (causing an intermittent problem). Changing to Compiled stack option cures the problem but then ends up with a cleared bit0 for 0x7E (maybe compiler never uses that in Compiled stack, don't know). It would seem to me it should not make a difference which stack option is used, the isr should generate good code regardless. Any thoughts?Code:XC8 v1.41, v1.43, v1.44//-----------------------------// isr - Reentrant stack option//-----------------------------0004 3180 MOVLP 0x00005 087F MOVF 0x7F, W0006 00F0 MOVWF __pcstackCOMMON0007 3042 MOVLW 0x420008 0086 MOVWF FSR10009 3021 MOVLW 0x21000A 0087 MOVWF FSR1H000B 0020 MOVLB 0x0000C 0875 MOVF 0x75, W000D 00F1 MOVWF 0x71...isr code00DD 0871 MOVF 0xF1, W <-shows 0xF1, is actually 0x7100DE 00FF MOVWF 0xFF <-shows 0xFF, is actually 0x7F00DF 0009 RETFIE//-----------------------------// summary of above//-----------------------------common ram 0x7F copied to 0x70FSR1 = 0x2142BSR = 0common ram 0x75 copied to 0x71...isr codecommon ram 0x71 copied to 0x7F//-----------------------------0x7F is not being restored correctly//-----------------------------//-----------------------------// isr - Compiled stack option//-----------------------------0004 147E BSF 0x7E, 0x00005 3180 MOVLP 0x00006 0020 MOVLB 0x00007 087F MOVF 0x7F, W0008 00F1 MOVWF 0x71...isr code00D3 0871 MOVF 0xF1, W <-shows 0xF1, is 0x7100D4 0020 MOVLB 0x000D5 00FF MOVWF 0x7F00D6 107E BCF 0x7E, 0x000D7 0009 RETFIE//-----------------------------// summary of above//-----------------------------common ram 0x7E bit0 setPAGESEL = 0BSR = 0common ram 0x7F copied to 0x71...isr codeBSR = 0common ram 0x71 copied to 0x7Fcommon ram 0x7E bit0 cleared//-----------------------------0x7F is now properly restored, but...0x7E bit0 is being clobbered//-----------------------------

author: NorthGuy
author_rank: Super Contributor
timestamp: October 25, 2017, 01:57:04 am
content: Not necessarily a bug.In the compiled stack case, the "clobbering" of 0x7E.0 looks like a flag which lets the compiler know if it is inside ISR or not. This is definitely Ok.In the normal stack case, some of the common memory locations may be used by the compiler, perhaps to maintain stack. Unless the compiler allocated one of your variables at 0x7F there shouldn't be a problem neither. Only Microchip can tell if this is how they intended or a bug.

author: cv007
author_rank: Frequent Contributor
timestamp: October 25, 2017, 04:11:54 am
content: Here is the function I was debugging. The stack option was Reentrant (software), and 0x7F is used a number of times for temp use by the compiler. With the isr restoring the wrong value to 0x7F (its backing up to 0x70, but restoring from 0x71 as seen in first post- which I guess is probably all that's needed to see something is wrong), any number of opportunities are there for 0x7F to get corrupted by the isr. I only noticed the problem when I was repeatedly calling the brightness function and my display would 'glitch' (bright for a fraction of a second). With the debugger I was able to catch the isr changing the 'tmp' value (checked right after 'tmp' was set from table lookup).If the compiler is using 0x7F as a temp value, backing it up in the isr, but restoring from the wrong register, that is a problem it would seem to me. I find it hard to believe I'm discovering something new, so maybe I'm mistaken somehow but don't see it. Its the same on the last 3 versions of XC8, also no special options/configs are being used.Code:601: /*------------------------------------------------------------------------------602: - set brightness603: - lookup brightness from table, val = 0-127604: - adjust for timer1 period count605: - dig = digit2<<1 | digit1 (1=digit1,2=digit2,3=digit1 and digit2)606: ------------------------------------------------------------------------------*/607: void digit_brightness( uint8_t dig, uint8_t val )061F 3143 ADDFSR 1, 30620 3FFD MOVWI [-3]FSR1608: {609: val &= 127;0621 3F7C MOVIW [-4]FSR10622 397F ANDLW 0x7F0623 3FFC MOVWI [-4]FSR1610: #if USE_14BIT_ROM_CONST611: uint16_t tmp = rom_read((uint16_t)led_brightness_tbl + val);612: #else613: uint16_t tmp = led_brightness_tbl; <---using this (normal const data)0624 3F7C MOVIW [-4]FSR10625 00FE MOVWF 0x7E0626 01FF CLRF 0x7F <---0627 35FE LSLF 0x7E, F0628 0DFF RLF 0x7F, F <---0629 30F9 MOVLW 0xF9062A 077E ADDWF 0x7E, W062B 0084 MOVWF FSR0062C 3080 MOVLW 0x80062D 3D7F ADDWFC 0x7F, W <---062E 0085 MOVWF FSR0H062F 3F00 MOVIW FSR00630 00FE MOVWF 0x7E0631 3F01 MOVIW FSR00632 00FF MOVWF 0x7F <---0633 087E MOVF 0x7E, W0634 3FFE MOVWI [-2]FSR10635 087F MOVF 0x7F, W <---0636 3FFF MOVWI [-1]FSR1614: #endif615: tmp += TIMER1_COUNT_OFFSET; //adjust for timer1 irq period0637 3078 MOVLW 0x780638 00FE MOVWF 0x7E0639 30EC MOVLW 0xEC063A 00FF MOVWF 0x7F <---063B 3F7E MOVIW [-2]FSR1063C 077E ADDWF 0x7E, W063D 3FFE MOVWI [-2]FSR1063E 3F7F MOVIW [-1]FSR1063F 3D7F ADDWFC 0x7F, W <---0640 3FFF MOVWI [-1]FSR1616: ATOMIC(0641 138B BCF INTCON, 0x70642 3F7D MOVIW [-3]FSR10643 1C09 BTFSS WREG, 0x00644 2E4A GOTO 0x64A0645 3F7E MOVIW [-2]FSR10646 0020 MOVLB 0x00647 00A8 MOVWF 0x280648 3F7F MOVIW [-1]FSR10649 00A9 MOVWF 0x29064A 3F7D MOVIW [-3]FSR1064B 1C89 BTFSS WREG, 0x1064C 2E52 GOTO 0x652064D 3F7E MOVIW [-2]FSR1064E 0020 MOVLB 0x0064F 00AA MOVWF 0x2A0650 3F7F MOVIW [-1]FSR10651 00AB MOVWF 0x2B0652 178B BSF INTCON, 0x7617: if( dig & 1 ) digit.bright1 = tmp; //save adjusted timer1 count618: if( dig & 2 ) digit.bright2 = tmp;619: );620: }0653 317C ADDFSR 1, -40654 0008 RETURNQuoteThe assembly listing comments says its a compiler flag. and when compiling with Compiled stack option, 0x7E and 0x7F are not being used so I believe that.With the Reentrant stack option, 0x7E and 0x7F are being used in many places. I have an led display and its been working 99.9% fine, but there are/were things happening rarely that made me think my power has a problem, or my code has a problem, or I'm not understanding correctly how some peripheral works. If 0x7F is corrupted in the isr, it would explain a lot.

author: NorthGuy
author_rank: Super Contributor
timestamp: October 25, 2017, 04:28:50 am
content: Quote from: cv007 on October 25, 2017, 04:11:54 amIf the variable is used this way, then obviously changing it in the interrupt is a bug. You probably should report it to Microchip so that they could fix it.Quote from: cv007 on October 25, 2017, 04:11:54 amIt is not very surprising. I guess 99.9% of people use compiled stack. For some reason, it is considered more efficient. So, the bugs with normal stack have much less chances of being discovered.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: October 25, 2017, 05:13:17 am
content: Which PIC? Can you post a complete minimal code example which shows the problem?Most 8 bit PICs don't have a user accessible stack, so it has to be emulated. 'Compiled stack' allocates fixed RAM locations for each function's local variables. Different functions can use the same RAM provided they don't call each other. If they do then a copy of the affected function is created which references different RAM locations. In effect, the stack is 'compiled into' the code. This obviously does not permit recursion, as each level would need to have its own code which would quickly fill up the ROM.I see that XC8 now has a reentrant stack option for advanced midrange PICs. I wouldn't be surprised if this caused trouble in some circumstances.

author: cv007
author_rank: Frequent Contributor
timestamp: October 25, 2017, 05:37:58 am
content: This is minimal code that reproduces the problem-Code:/* =========================================XC8 v1.44MPLABX v4.01new project, PIC16F18854, all defaultoptions, except-stack option - Reentrantminimal code to show 0x7F is being usedin functions ( f() ), and 0x7F is alsobeing restored from the wrong registerin the isr=========================================*/#include <xc.h>unsigned short f(unsigned char a){return a^0x1234UL;}void main(void) {volatile unsigned char x = f(1);for(;;);}void interrupt ISR(){unsigned char x = LATA;}and the result-Code:Disassembly Listing for abcGenerated From:/home/owner/MPLABXProjects/abc.X/dist/default/production/abc.X.production.elfOct 25, 2017 12:24:45 AM--- /home/owner/MPLABXProjects/abc.X/newmain.c --------------------------------------------------------1: #include <xc.h>2: unsigned short f(unsigned char a){001E 3141 ADDFSR 1, 1001F 3FFF MOVWI [-1]FSR13: return a^0x1234UL;0020 3F7F MOVIW [-1]FSR10021 00FF MOVWF 0x7F0022 3034 MOVLW 0x340023 067F XORWF 0x7F, W0024 00F4 MOVWF 0x740025 3012 MOVLW 0x120026 00F5 MOVWF 0x754: }0027 317F ADDFSR 1, -10028 0008 RETURN5: void main(void) {0029 3141 ADDFSR 1, 16: volatile unsigned char x = f(1);002A 3001 MOVLW 0x1002B 3180 MOVLP 0x0002C 201E CALL 0x1E002D 3180 MOVLP 0x0002E 0874 MOVF 0x74, W002F 3FFF MOVWI [-1]FSR17: for(;;);0030 2830 GOTO 0x308: }9: void interrupt ISR(){0004 3180 MOVLP 0x00005 087F MOVF 0x7F, W0006 00F0 MOVWF __pcstackCOMMON0007 30F8 MOVLW 0xF80008 0086 MOVWF FSR10009 3020 MOVLW 0x20000A 0087 MOVWF FSR1H000B 0020 MOVLB 0x0000C 0875 MOVF 0x75, W000D 00F1 MOVWF 0x7110: unsigned char x = LATA;000E 0816 MOVF LATA, W000F 00FF MOVWF 0x7F0010 087F MOVF 0x7F, W0011 00F2 MOVWF x11: }0012 0871 MOVF 0x71, W0013 00FF MOVWF 0x7F0014 0009 RETFIEThis shows that functions are using 0x7F, and that the isr is restoring 0x7F from the wrong register (should be 0x70, not 0x71).edit-I also posted on the XC8 forum to see what they say.edit-they say submit a ticket, so I did