CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Incorrect code generation for output pins on PIC 16F15354 ?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
JimHearne



Joined: 06 Apr 2021
Posts: 8
Location: UK

View user's profile Send private message

Incorrect code generation for output pins on PIC 16F15354 ?
PostPosted: Fri Mar 01, 2024 4:11 am     Reply with quote

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: 19238

View user's profile Send private message

PostPosted: Fri Mar 01, 2024 4:58 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Mar 01, 2024 5:20 am     Reply with quote

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: 1319

View user's profile Send private message

PostPosted: Mon Mar 04, 2024 8:47 am     Reply with quote

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: 19238

View user's profile Send private message

PostPosted: Mon Mar 04, 2024 11:04 am     Reply with quote

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. Very Happy
Thanks for that.
JimHearne



Joined: 06 Apr 2021
Posts: 8
Location: UK

View user's profile Send private message

PostPosted: Tue Mar 05, 2024 4:32 am     Reply with quote

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: 19238

View user's profile Send private message

PostPosted: Tue Mar 05, 2024 7:34 am     Reply with quote

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. Very Happy
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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