Maker Pro
Maker Pro

PIC Programming Question - Microchip C18

Hey there,

I have a question about PIC programming in Microchip C18:

Why is it that this block of code does nothing:

Code:
#pragma config FOSC = IRC
#pragma config PLLEN = ON
#pragma config WDTEN = OFF
#pragma config MCLRE = OFF

void main(void)
{
    char on = 0;
    OSCTUNE = 0b11000000;
    OSCCON = 0b01100000;

    TRISA = 0b00001010;
    TRISB = 0;
    TRISC = 0;
    
    while(1)
    {
        LATCbits.LATC0 = on;
        on = ( on == 1 ? 0 : 1 );
        Delay10KTCYx(100);
    }
    return;
}

While this block of code makes the output pulse on and off:

Code:
#pragma config FOSC = IRC
#pragma config PLLEN = ON
#pragma config WDTEN = OFF
#pragma config MCLRE = OFF

void main(void)
{
    OSCTUNE = 0b11000000;
    OSCCON = 0b01100000;

    TRISA = 0b00001010;
    TRISB = 0;
    TRISC = 0;
    
    while(1)
    {
        LATCbits.LATC0 = 0x00;
        Delay10KTCYx(100);
        LATCbits.LATC0 = 0x01;
        Delay10KTCYx(100);
    }
    return;
}

I have set up the PIC to run at 8 MHz CPU Frequency (8 MHz clock / 4 with 4x PLL), with all PORTC pins as outputs. Watchdog timer is off.

As far as I can see, both these loops are equivalent, as the first one will toggle on between 0 and 1, causing the output to flash, and the second one hard-codes the flashing.

If I simulate in MPLAB X, both code samples seem to work! The PIC is a PIC18F14K22, programmer is USBPICProg, which is able to write the program to the PIC and read it back to me correctly. I have a 0.1uF cap between Vdd and Vss, and I have MCLR set at 3.3V (despite me using it as a standard input pin).

Any ideas? :S
 
Ok, I noticed that the type of the "on" variable didn't match the type of the "LATCbits.LATC0" variable, so I changed the program to this:

Code:
void main(void)
{
    unsigned on = 1;
    OSCTUNE = 0b11000000;
    OSCCON = 0b01100000;

    TRISA = 0b00001010;
    TRISB = 0;
    TRISC = 0;


    while(1)
    {
        LATCbits.LATC0 = on = ( on == 1 ? 0 : 1 );
        Delay10KTCYx(100);
    }
    return;
}

The output is now permanently high. This is even more odd than before, as the first iteration of that loop should surely make the output low:

on = 1; // on = 1
LATC0 = on = ( on == 1 ? 0 : 1 ) // condition is true, so on = 0, so LATC0 = 0

And because the delay is always 100x10k instruction cycles, I should be seeing equal amounts of on and off time.

Really stuck on this one, but I'll keep trying stuff out.

EDIT: I've now tested on both Linux and Windows, and the hex code generated by the compiler was the same on each. Also, I tried reducing the clock speed, and the problem persists. I also made the on variable volatile, to try to make sure the compiler was doing everything I said to do, but that made no difference. I'm all out of ideas now...
 
Last edited:

Harald Kapp

Moderator
Moderator
This seems to be a quirk of the Compiler.
I tried this in Visual C++:
Code:
#include "stdafx.h"

using namespace System;

int main(array<System::String ^> ^args)
{
	int on;
	on = 1;
	while (1)
	{
    on = (on ==1 ? 0 : 1);
	Console::WriteLine(Convert::ToString( on ));
	}
    return 0;
}
and it works like a charm.

Have you tried making LATCbits.LATC0 void? Are any optimization active which may remove code that the compiler thinks is unnecessary? Have a look at the assembler code (not Hex code) to find out what the compiler generates from the C code.

Harald
 
Last edited:
I'll take a look at the assembler, althought I only have limited knowledge of assembler, so whether I'll be able to make anything of it is another matter... :p
 

Harald Kapp

Moderator
Moderator
I don't know MPLAB, but many compilers comment the intermediate assembler code with the respective lines of C code. You may have to set certein compiler options to achieve that.

Harald
 
Ok, I found a way of getting the assembler with the C code, but I don't know enough to work out whether it's doing what it's meant to.

However, I did notice that my old code produced quite a lot of assembler for the assignment to LATCbits.LATC0, so I changed that to use a single XOR instead of the ternary operator ?: . I also changed the output from C0 to B7, thinking the problem may be to do with the analogue input that can be used on C0. However, the output does not go high at all now.

Here's the new C code:

Code:
void main(void)
{
    unsigned on = 1;
    OSCTUNE = 0b11000000;
    OSCCON = 0b00110000;

    TRISA = 0b00001010;
    TRISB = 0;
    TRISC = 0;


    while(1)
    {
        LATBbits.LATB7 = on ^= 0x01;
        Delay10KTCYx(1);
    }
    return;
}

And the assembler:

Code:
          void main(void)
0014  CFD9     MOVFF FSR2L, POSTINC1
0016  FFE6     NOP
0018  CFE1     MOVFF FSR1L, FSR2L
001A  FFD9     NOP
001C  0E02     MOVLW 0x2
001E  26E1     ADDWF FSR1L, F, ACCESS
50:            {
51:                unsigned on = 1;
0020  0E01     MOVLW 0x1
0022  6EDE     MOVWF POSTINC2, ACCESS
0024  6ADD     CLRF POSTDEC2, ACCESS
52:                OSCTUNE = 0b11000000;
0026  0EC0     MOVLW 0xC0
0028  6E9B     MOVWF OSCTUNE, ACCESS
53:                OSCCON = 0b00110000;
002A  0E30     MOVLW 0x30
002C  6ED3     MOVWF OSCCON, ACCESS
54:            
55:                TRISA = 0b00001010;
002E  0E0A     MOVLW 0xA
0030  6E92     MOVWF TRISA, ACCESS
56:                TRISB = 0;
0032  6A93     CLRF TRISB, ACCESS
57:                TRISC = 0;
0034  6A94     CLRF TRISC, ACCESS
58:            
59:            
60:                while(1)
004E  D7F3     BRA 0x36
61:                {
62:                    LATBbits.LATB7 = on ^= 0x01;
0036  0E01     MOVLW 0x1
0038  1ADF     XORWF INDF2, F, ACCESS
003A  50DF     MOVF INDF2, W, ACCESS
003C  B0E8     BTFSC WREG, 0, ACCESS
003E  8E8A     BSF LATB, 7, ACCESS
0040  A0E8     BTFSS WREG, 0, ACCESS
0042  9E8A     BCF LATB, 7, ACCESS
63:                    Delay10KTCYx(1);
0044  0E01     MOVLW 0x1
0046  6EE6     MOVWF POSTINC1, ACCESS
0048  EC1E     CALL 0x23C, 0
004A  F001     NOP
004C  52E5     MOVF POSTDEC1, F, ACCESS
64:                }
65:                return;
66:            }

Any further help would be greatly appreciated! :)
 
Ok, I've reduced the code further still, and found that the program appears to be freezing, not just failing to run. However, I can't be certain about this.

Perhaps more importantly, I found that this doesn't work:

Code:
void main(void)
{
    unsigned on = 1;
    OSCTUNE = 0b11000000;
    OSCCON = 0b01100000;

    TRISA = 0b00001010;
    TRISB = 0;
    TRISC = 0;


    while(1)
    {
        LATC = 0x01;
        Delay10KTCYx(100);
        LATC = 0x00;
        Delay10KTCYx(100);
    }
    return;
}

Assembler:

Code:
    void main(void)
0014  CFD9     MOVFF FSR2L, POSTINC1
0016  FFE6     NOP
0018  CFE1     MOVFF FSR1L, FSR2L
001A  FFD9     NOP
001C  0E02     MOVLW 0x2
001E  26E1     ADDWF FSR1L, F, ACCESS
50:            {
51:                unsigned on = 1;
0020  0E01     MOVLW 0x1
0022  6EDE     MOVWF POSTINC2, ACCESS
0024  6ADD     CLRF POSTDEC2, ACCESS
52:                OSCTUNE = 0b11000000;
0026  0EC0     MOVLW 0xC0
0028  6E9B     MOVWF OSCTUNE, ACCESS
53:                OSCCON = 0b01100000;
002A  0E60     MOVLW 0x60
002C  6ED3     MOVWF OSCCON, ACCESS
54:            
55:                TRISA = 0b00001010;
002E  0E0A     MOVLW 0xA
0030  6E92     MOVWF TRISA, ACCESS
56:                TRISB = 0;
0032  6A93     CLRF TRISB, ACCESS
57:                TRISC = 0;
0034  6A94     CLRF TRISC, ACCESS
58:            
59:            
60:                while(1)
0050  D7F2     BRA 0x36
61:                {
62:                    LATC = 0x01;
0036  0E01     MOVLW 0x1
0038  6E8B     MOVWF LATC, ACCESS
63:                    Delay10KTCYx(100);
003A  0E64     MOVLW 0x64
003C  6EE6     MOVWF POSTINC1, ACCESS
003E  EC1F     CALL 0x23E, 0
0040  F001     NOP
0042  52E5     MOVF POSTDEC1, F, ACCESS
64:                    LATC = 0x00;
0044  6A8B     CLRF LATC, ACCESS
65:                    Delay10KTCYx(100);
0046  0E64     MOVLW 0x64
0048  6EE6     MOVWF POSTINC1, ACCESS
004A  EC1F     CALL 0x23E, 0
004C  F001     NOP
004E  52E5     MOVF POSTDEC1, F, ACCESS
66:                }
67:                return;
68:            }


However, as soon as I remove the variable "on" from the program, the program works as expected and the output pulses, even though the variable did nothing in the first example.


Code:
   void main(void)
50:            {
51:                OSCTUNE = 0b11000000;
0014  0EC0     MOVLW 0xC0
0016  6E9B     MOVWF OSCTUNE, ACCESS
52:                OSCCON = 0b01100000;
0018  0E60     MOVLW 0x60
001A  6ED3     MOVWF OSCCON, ACCESS
53:            
54:                TRISA = 0b00001010;
001C  0E0A     MOVLW 0xA
001E  6E92     MOVWF TRISA, ACCESS
55:                TRISB = 0;
0020  6A93     CLRF TRISB, ACCESS
56:                TRISC = 0;
0022  6A94     CLRF TRISC, ACCESS
57:            
58:            
59:                while(1)
003E  D7F2     BRA 0x24
60:                {
61:                    LATC = 0x01;
0024  0E01     MOVLW 0x1
0026  6E8B     MOVWF LATC, ACCESS
62:                    Delay10KTCYx(100);
0028  0E64     MOVLW 0x64
002A  6EE6     MOVWF POSTINC1, ACCESS
002C  EC16     CALL 0x22C, 0
002E  F001     NOP
0030  52E5     MOVF POSTDEC1, F, ACCESS
63:                    LATC = 0x00;
0032  6A8B     CLRF LATC, ACCESS
64:                    Delay10KTCYx(100);
0034  0E64     MOVLW 0x64
0036  6EE6     MOVWF POSTINC1, ACCESS
0038  EC16     CALL 0x22C, 0
003A  F001     NOP
003C  52E5     MOVF POSTDEC1, F, ACCESS
65:                }
66:                return;
67:            }

I really have no clue why this variable initialization should cause the program to stop functioning. :confused:

Many Thanks!
 
It also seems to work if I declare the variable outside of the main function, or inside of the while loop. Just not at the top of main...

For example, this works:

Code:
unsigned on;
void main(void)
{
    OSCTUNE = 0b11000000;
    OSCCON = 0b01100000;

    TRISA = 0b00001010;
    TRISB = 0;
    TRISC = 0;
    on = 0;

    while(1)
    {
        LATCbits.LATC0 = on ^= 0x01;
        Delay10KTCYx(100);
    }
    return;
}

But this doesn't:

Code:
void main(void)
{
    unsigned on;

    OSCTUNE = 0b11000000;
    OSCCON = 0b01100000;

    TRISA = 0b00001010;
    TRISB = 0;
    TRISC = 0;
    on = 0;

    while(1)
    {
        LATCbits.LATC0 = on ^= 0x01;
        Delay10KTCYx(100);
    }
    return;
}
 
Last edited:

Harald Kapp

Moderator
Moderator
To be honest: I have no clue either. I'd think it should work. Even if on is used in one of the includes, since the scope of on being declared within main should be local.
You could give it a try and rename on to something that's unprobable to be used elsewhere, e.g. on_not_anywhere_else
See what the compiler does.


Funny that this code doesn't work
Code:
60:                while(1)
0050  D7F2     BRA 0x36
61:                {
62:                    LATC = 0x01;
0036  0E01     MOVLW 0x1
0038  6E8B     MOVWF LATC, ACCESS                      <- set LATC to 0x01
63:                    Delay10KTCYx(100);
003A  0E64     MOVLW 0x64
003C  6EE6     MOVWF POSTINC1, ACCESS
003E  EC1F     CALL 0x23E, 0                                    <- this is obviously the delay loop
0040  F001     NOP
0042  52E5     MOVF POSTDEC1, F, ACCESS
64:                    LATC = 0x00;
0044  6A8B     CLRF LATC, ACCESS                           <- set LATC to 0x00
65:                    Delay10KTCYx(100);
0046  0E64     MOVLW 0x64
0048  6EE6     MOVWF POSTINC1, ACCESS
004A  EC1F     CALL 0x23E, 0
004C  F001     NOP
004E  52E5     MOVF POSTDEC1, F, ACCESS
66:                }
67:                return;
Since the output stays at 1, the problem is possibly not within the main program but within the delay loop. Is this a proven routine or something you wrote? Can you inspect the code for the delay loop? Maybe it uses "on" and gets confused by you using "on" too?

Harald
 
If it's a decent compiler (which I assume it is, being made by Microchip), having on in main and in another function shouldn't matter at all. Delay10KTCYx(...) is a function from the C18 library - I've used it in another project with no problems :/

I think it's probably just a strange glitch. I'll see if I can contact Mircochip about it.
 
Hey, I asked this, and a question like this, on their forums the other day.

The answer I got was to use the C18 compiler's extended mode. Apparently, the standard mode is very poor at handling local variables and pointers, and has loads of bugs.

Switching to Extended mode produces better results for compiled code, but it can't be used with any assembler code. I think I'll probably use extended mode exclusively from now on though.
 
Top