| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| JimHearne 
 
 
 Joined: 06 Apr 2021
 Posts: 8
 Location: UK
 
 
			    
 
 | 
			
				| Incorrect code generation for output pins on PIC 16F15354 ? |  
				|  Posted: Fri Mar 01, 2024 4:11 am |   |  
				| 
 |  
				| Hi all, 
 Compiler version 5.105, PIC 16F15354
 
 This is a very hacked down program so show what i believe the problem is.
 I initalise a variable op_on to  1 and then in the main loop i output that variable to a couple of port pins.
 So the pins should just remain high.
 But the compiler generates code that always sets the pin low, then conditionally skips the next instruction (BSF) if the variable is 0
 So i end up with pulses on the output pins.
 
 Am i doing something really silly or is this a bug, could somebody try compiling the code on a later version of the compiler. If that works then we will renew the compiler license.
 
 Many thanks,
 Jim
 
 
 
  	  | Code: |  	  | //Compiler version 5.105 
 #include <16F15354.h>
 #fuses RSTOSC_HFINTRC_32MHZ, WDT512, PUT, nolvp, PROTECT, NOMCLR, WRT, BROWNOUT, NODEBUG, BORV27, NOFCMEN
 
 #use delay(clock=32000000,RESTART_WDT)
 
 #byte port_a = 0x00c
 #byte port_b = 0x00d
 
 #byte tris_a = 0x012
 #byte tris_b = 0x013
 
 #byte latch_a = 0x18
 #byte latch_b = 0x19
 
 #bit op_pin      = latch_a.5
 #bit spare_1        = latch_b.4
 
 int1 op_on=1;
 
 void main()
 {
 port_a = 0;
 tris_a = 0;       // all outputs
 
 port_b=0;
 tris_b = 0b00001111; // half inputs
 
 while(1)
 {
 spare_1=op_on;
 op_pin=op_on;
 }
 }
 | 
 
 
 LST file
 
 
  	  | Code: |  	  | CCS PCM C Compiler, Version 5.103, 54209               01-Mar-24 09:33 
 Filename:   C:\Nextcloud\Solumetrix Backup\work\All Products\chlorking\Hypogen\code\test\Hypogen Iss2.4 PIC 16F15354 test.lst
 
 ROM used:   31 words (1%)
 Largest free fragment is 2048
 RAM used:   6 (1%) at main() level
 17 (3%) worst case
 Stack used: 0 locations
 Stack size: 16
 
 *
 0000:  MOVLP  00
 0001:  GOTO   main
 0002:  NOP
 .................... //Compiler version 5.105
 ....................
 .................... #include <16F15354.h>
 .................... //////////// Standard Header file for the PIC16F15354 device ////////////////
 .................... ///////////////////////////////////////////////////////////////////////////
 .................... ////        (C) Copyright 1996, 2020 Custom Computer Services          ////
 .................... //// This source code may only be used by licensed users of the CCS C  ////
 .................... //// compiler.  This source code may only be distributed to other      ////
 .................... //// licensed users of the CCS C compiler.  No other use, reproduction ////
 .................... //// or distribution is permitted without written permission.          ////
 .................... //// Derivative programs created using this software in object code    ////
 .................... //// form are not restricted in any way.                               ////
 .................... ///////////////////////////////////////////////////////////////////////////
 .................... #device PIC16F15354
 ....................
 .................... #list
 ....................
 .................... #fuses RSTOSC_HFINTRC_32MHZ, WDT512, PUT, nolvp, PROTECT, NOMCLR, WRT, BROWNOUT, NODEBUG, BORV27, NOFCMEN
 ....................
 .................... #use delay(clock=32000000,RESTART_WDT)
 ....................
 .................... #byte port_a = 0x00c
 .................... #byte port_b = 0x00d
 ....................
 .................... #byte tris_a = 0x012
 .................... #byte tris_b = 0x013
 ....................
 .................... #byte latch_a = 0x18
 .................... #byte latch_b = 0x19
 ....................
 .................... #bit op_pin      = latch_a.5
 .................... #bit spare_1        = latch_b.4
 ....................
 .................... int1 op_on=1;
 ....................
 .................... void main()
 0003:  BSF    op_on
 0004:  MOVLB  3E
 0005:  CLRF   38
 0006:  CLRF   43
 0007:  CLRF   4E
 0008:  MOVLB  13
 0009:  CLRF   CM1CON1
 000A:  CLRF   CM1NCH
 000B:  CLRF   CM1PCH
 000C:  CLRF   CM1CON0
 000D:  CLRF   CM2CON1
 000E:  CLRF   CM2NCH
 000F:  CLRF   CM2PCH
 0010:  CLRF   CM2CON0
 .................... {
 ....................    port_a = 0;
 0011:  MOVLB  00
 0012:  CLRF   PORTA
 ....................    tris_a = 0;       // all outputs
 0013:  CLRF   TRISA
 ....................
 ....................    port_b=0;
 0014:  CLRF   PORTB
 ....................    tris_b = 0b00001111; // half inputs
 0015:  MOVLW  0F
 0016:  MOVWF  TRISB
 ....................
 ....................    while(1)
 ....................    {
 ....................       spare_1=op_on;
 0017:  BCF    LATB.LATB4
 0018:  BTFSC  op_on
 0019:  BSF    LATB.LATB4
 ....................       op_pin=op_on;
 001A:  BCF    LATA.LATA5
 001B:  BTFSC  op_on
 001C:  BSF    LATA.LATA5
 001D:  GOTO   017
 ....................    }
 .................... }
 001E:  SLEEP
 
 Configuration Fuses:
 Word  1: 1F8F   ECH RSTOSC_HFINTRC_32MHZ NOCLKOUT CKS NOFCMEN
 Word  2: 3DFC   NOMCLR PUT NOLPBOR BROWNOUT BORV27 ZCDDIS PPS1WAY STVREN NODEBUG
 Word  3: 3F84   WDT512 NOWDT WDTWIN_SW WDTCLK_SW
 Word  4: 1F7F   BBSIZ512 NOBOOTBLOCK NOSAF WRT NOWRTB NOWRTC NOWRTSAF NOLVP
 Word  5: 3FFE   PROTECT
 | 
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Mar 01, 2024 4:58 am |   |  
				| 
 |  
				| Neither. It is not incorrect. You are disabling the protection the compiler has
 against this by not using it's own functions....
 
 The compiler is trying to save space & time to do a bit conditional bit set,
 and the most efficient way to do this is as the compiler codes. The alternative would be to test, and then code. So:
 
  	  | Code: |  	  | if (op_on)
 spare_1=1;
 else
 spare_1=0;
 
 //which gives:
 ....................       if (op_on)
 0017:  BTFSS  20.0
 0018:  GOTO   01B
 ....................          spare_1=1;
 0019:  BSF    19.4
 001A:  GOTO   01C
 ....................       else
 ....................          spare_1=0;
 001B:  BCF    19.4
 
 | 
 
 This however results in this taking nearly twice the time of the compiler's
 default approach. On the basis of the fastest solution, the compiler chooses
 to use the clear then set approach. _When working on a memory cell_.
 Now understand that because you are coding the port registers as
 #bit and #byte, the compiler thinks you are just talking to memory.
 The 'glitch' then would not matter. If instead you used the compilers
 own bit output code, the compiler then knows you are talking to an
 output bit and knows to avoid this. So if you code as:
 
  	  | Code: |  	  | ....................       output_bit(PIN_A5, op_on);
 001C:  BTFSC  20.0
 001D:  GOTO   020
 001E:  BCF    18.5
 001F:  GOTO   021
 0020:  BSF    18.5
 0021:  GOTO   017
 
 | 
 
 The compiler carefully avoids the glitch (as shown with fast_io selected).
 You are effectively disabling the protection the compiler has against
 this when doing port I/O by not using the compilers own functions.
 
 If you want to keep treating the I/O as a normal memory cell, then
 code the test approach I show above as a macro. So something like:
 
  	  | Code: |  	  | #define OP_BIT(SOURCE, DEST) if(SOURCE) DEST=1; else DEST=0
 
 void main()
 {
 port_a = 0;
 tris_a = 0;       // all outputs
 
 port_b=0;
 tris_b = 0b00001111; // half inputs
 
 while(TRUE)
 {
 OP_BIT(op_on, spare_1);
 OP_BIT(op_on, op_pin);
 }
 }
 //Which then generates the same assembler as the compiler uses for pin
 //I/O.
 
 ....................       OP_BIT(op_on, spare_1);
 0017:  BTFSS  20.0
 0018:  GOTO   01B
 0019:  BSF    19.4
 001A:  GOTO   01C
 001B:  BCF    19.4
 ....................       OP_BIT(op_on, op_pin);
 001C:  BTFSS  20.0
 001D:  GOTO   020
 001E:  BSF    18.5
 001F:  GOTO   021
 0020:  BCF    18.5
 
 | 
 |  |  
		|  |  
		| JimHearne 
 
 
 Joined: 06 Apr 2021
 Posts: 8
 Location: UK
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri Mar 01, 2024 5:20 am |   |  
				| 
 |  
				| Hi Ttelmah, Thank you very much for the detailed explanation, it makes sense.
 I've been writing code on the PICs with the CCS compiler for around 20 years and i've always used #bit and #byte for the port registers (with fast_io)
 It was the way my boss showed me but at that time there was a deep distrust of any CCS built in functions so i guess thats why.
 I wonder if the older versions of the compiler compiled the code differently, or i've just been very lucky before.
 Thinking about it, this could explain  some other issues i've had in the past.
 
 Thanks again for the quick reply and help.
 
 Jim
 |  |  
		|  |  
		| jeremiah 
 
 
 Joined: 20 Jul 2010
 Posts: 1401
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Mar 04, 2024 8:47 am |   |  
				| 
 |  
				| Side note, you can can set your bit variables as volatile and that tells the compiler to not do any weird optimizations.  Example: 
 
 
  	  | Code: |  	  | //Compiler version 5.105
 
 #include <16F15354.h>
 #fuses RSTOSC_HFINTRC_32MHZ, WDT512, PUT, nolvp, PROTECT, NOMCLR, WRT, BROWNOUT, NODEBUG, BORV27, NOFCMEN
 
 #use delay(clock=32000000,RESTART_WDT)
 
 #byte port_a = 0x00c
 #byte port_b = 0x00d
 
 #byte tris_a = 0x012
 #byte tris_b = 0x013
 
 #byte latch_a = 0x18
 #byte latch_b = 0x19
 
 volatile int1 op_pin;
 #bit op_pin      = latch_a.5
 #bit spare_1        = latch_b.4
 
 int1 op_on=1;
 
 void main()
 {
 port_a = 0;
 tris_a = 0;       // all outputs
 
 port_b=0;
 tris_b = 0b00001111; // half inputs
 
 while(TRUE)
 {
 spare_1=op_on;
 op_pin=op_on;
 }
 }
 
 | 
 
 generates:
 
 
  	  | Code: |  	  | ....................
 ....................    while(TRUE)
 ....................    {
 ....................       spare_1=op_on;
 0017:  BCF    19.4
 0018:  BTFSC  20.0
 0019:  BSF    19.4
 ....................       op_pin=op_on;
 001A:  BTFSS  20.0
 001B:  BCF    18.5
 001C:  BTFSC  20.0
 001D:  BSF    18.5
 001E:  GOTO   017
 
 | 
 
 and you can see the difference between the "volatile" op_pin and the standard spare_1
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Mar 04, 2024 11:04 am |   |  
				| 
 |  
				| That is both sensible and useful. Makes total sense if you think about it, and interesting that the compiler
 is applying this keyword like this.
   Thanks for that.
 |  |  
		|  |  
		| JimHearne 
 
 
 Joined: 06 Apr 2021
 Posts: 8
 Location: UK
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Mar 05, 2024 4:32 am |   |  
				| 
 |  
				| Hi Jeremiah, Thank you for that additional information, that will make it much easier to update existing code rather than having to rewrite it to use the CCS functions.
 
 Many thanks,
 
 Jim
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Mar 05, 2024 7:34 am |   |  
				| 
 |  
				| I must admit when I was looking at this one of the things I tried was turning the optimisation down. The clear, test, set sequence is an 'optimisation' on
 how to perform this operation, taking less time and code space than the
 test, set or reset sequence, but brings the downside that the value changes
 during the sequence. The volatile keyword function, is to turn off compiler
 optimisations on the access to the variable, ensuring that it is reloaded
 each time. I had not considered that the compiler might be smart enough
 to accept this for the bit variable.
 A potentially very useful discovery.
  |  |  
		|  |  
		|  |  
  
	| 
 
 | You cannot post new topics in this forum You cannot reply to topics in this forum
 You cannot edit your posts in this forum
 You cannot delete your posts in this forum
 You cannot vote in polls in this forum
 
 |  
 Powered by phpBB © 2001, 2005 phpBB Group
 
 |