|
|
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: 19539
|
|
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: 1354
|
|
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: 19539
|
|
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: 19539
|
|
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
|