Connect with us

PIC Programming Question - Microchip C18

Discussion in 'Microcontrollers, Programming and IoT' started by LordSputnik, Jun 18, 2012.

Scroll to continue with content
  1. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    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
     
  2. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    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: Jun 18, 2012
  3. Harald Kapp

    Harald Kapp Moderator Moderator

    10,778
    2,433
    Nov 17, 2011
    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: Jun 19, 2012
  4. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    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
     
  5. Harald Kapp

    Harald Kapp Moderator Moderator

    10,778
    2,433
    Nov 17, 2011
    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
     
  6. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    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! :)
     
  7. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    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!
     
  8. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    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: Jun 19, 2012
  9. Harald Kapp

    Harald Kapp Moderator Moderator

    10,778
    2,433
    Nov 17, 2011
    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
     
  10. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    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.
     
  11. Harald Kapp

    Harald Kapp Moderator Moderator

    10,778
    2,433
    Nov 17, 2011
    Good luck - and I'd be interested if you get a result

    Harald
     
  12. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    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.
     
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-