• AVR Freaks

Hot!PIC I/O pins, bitfields and 8-bit-variables (as example)

Author
ALPL
Super Member
  • Total Posts : 327
  • Reward points : 0
  • Joined: 2006/12/30 02:52:11
  • Location: Austria
  • Status: offline
2021/02/28 02:57:05 (permalink)
0

PIC I/O pins, bitfields and 8-bit-variables (as example)

Hello,
I want to show the behaviour of the XC8 compiler regarding I/O-operations on pins which might be interesting for beginners and people who migrate from Arduino to PIC.
 
To set in XC8 a PIC output pin high (TRIS-bit of this pin is 0) we usually write (just as example): LATAbits.LA0=1; (for pin RA0). To set the same output pin low we usually write: LATAbits.LA0=0;  This can be easily checked with a LED attached to this pin.
 
Now it might happen that for example we want to clock out data over the communication line depending on the bit-status in an 8-bit variable (eg software-SPI). We check each bit in the byte-variable and send a HIGH(1) if the bit in the current location is set and a LOW(0) if the bit is not set (MSB first):
 
#define dataPin LATAbits.LA0
#define clockPin LATAbits.LA1
 
void SPI_transmit(unsigned char val)
{
    unsigned char i;

    for (i = 0; i < 8; i++)  
    {
        dataPin= (val & (1 << (7 - i)));      // test bit (7-i) in val
            
        clockPin=1;
        clockPin=0;        
    }
}

 
In the Arduino-world this will work ( using digitalWrite(pin, value) to output the bit ), because the digitalWrite() will treat any value higher than 0 as 1 and therefore return a 1 for above condition. So there is no problem - the routine is working as desired.
 
With PIC/XC8 the lights remain dark, a 0 is sent even if the bit in the tested location was 1 - unless bit 0 in the tested byte was set! The XC8-compiler treats any truncation of a 8/16/32-bit-variable to a bitfield-value as 0 if bit 0 in the variable was not set and as 1 if the bit 0 was set, regardless of the bit-test result.
 
The same happens if you write directly (which is a very obvious example) eg
LATAbits.LA0 = 6;     >> LA0=0
but
LATAbits.LA0 = 13;    >> LA0=1
 
All this may look silly but such mistakes may happen and can cost a lot of time to find them, especially if they are hidden in more complex expressions.
 
The solution for above problem is either to write the code differently or use a double negation:
void SPI_transmit(unsigned char val)
{
    unsigned char i;

    for (i = 0; i < 8; i++)  
    {
        dataPin= !!(val & (1 << (7 - i)));
            
        clockPin=1;
        clockPin=0;        
    }
}

 
This method (the double negation) converts clearly zero to zero and any non-zero value to 1.
 
Above code example you will find in the net when you search for a serial shiftOut() function. My intention was to show the different behaviour of the Arduino digitalWrite-function and the PIC-compiler.
post edited by ALPL - 2021/02/28 03:11:40
#1

7 Replies Related Threads

    ric
    Super Member
    • Total Posts : 30223
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: PIC I/O pins, bitfields and 8-bit-variables (as example) 2021/02/28 03:08:18 (permalink)
    +1 (1)
    Do note, shifting by a variable amount is a terribly inefficient thing to do in a PIC.
    This will generate much tighter assembly code
    void SPI_transmit(unsigned char val)
    {
        unsigned char i=8;

        do
        {
            datapin = 0;
            if (val & 0x80)
                datapin = 1;
            val <<= 1;
            clockPin=1;
            clockPin=0;        
        } while (-- i);
    }


    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #2
    ALPL
    Super Member
    • Total Posts : 327
    • Reward points : 0
    • Joined: 2006/12/30 02:52:11
    • Location: Austria
    • Status: offline
    Re: PIC I/O pins, bitfields and 8-bit-variables (as example) 2021/02/28 03:14:56 (permalink)
    0
    Hi ric, thank you for showing a better option. The intention was just to point out what might go wrong and to explain the !! operator-combination.
    post edited by ALPL - 2021/02/28 03:19:37
    #3
    ric
    Super Member
    • Total Posts : 30223
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: PIC I/O pins, bitfields and 8-bit-variables (as example) 2021/02/28 03:22:59 (permalink)
    +1 (1)
    Agree, copying a calculation result to a 1 bit variable is different to calling a function that takes a boolean value.
    You have a valid point that people may fall into the habit of assuming that non-zero will produce a high, but it won't in this situaiton.
    There is much to be learned by checking the assembly language output, to see what gyrations the  compiler has to go through to implementt your code.
    That's where you find that it's more efficient to stick to "bit set" and "bit clear", as these are single assembly instructions if the bit# is a constant.
     
    post edited by ric - 2021/02/28 03:24:16

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #4
    1and0
    Access is Denied
    • Total Posts : 12265
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: PIC I/O pins, bitfields and 8-bit-variables (as example) 2021/02/28 03:23:57 (permalink)
    +2 (2)
    Sound like the Arduino function digitalWrite(pin, value) does this:
    void digitalWrite(pin, value) 
    {
        pin = value ? 1 : 0;
    }

    or this
    void digitalWrite(pin, value) 
    {
        pin = !!value;
    }

    when the pin as set as output.
    #5
    ALPL
    Super Member
    • Total Posts : 327
    • Reward points : 0
    • Joined: 2006/12/30 02:52:11
    • Location: Austria
    • Status: offline
    Re: PIC I/O pins, bitfields and 8-bit-variables (as example) 2021/02/28 03:28:59 (permalink)
    0
    @1and0: digitalWrite(pin, value) is unfortunately not that simple - this function has quite a lot of overhead. An idea what this looks like you will find under:
    https://github.com/arduin...duino/wiring_digital.c
    #6
    1and0
    Access is Denied
    • Total Posts : 12265
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: PIC I/O pins, bitfields and 8-bit-variables (as example) 2021/02/28 03:34:54 (permalink)
    0
    ALPL
    @1and0: digitalWrite(pin, value) is unfortunately not that simple - this function has quite a lot of overhead. An idea what this looks like you will find under:
    https://github.com/arduin...duino/wiring_digital.c

    I know it is not that simple from reading this: https://www.arduino.cc/reference/en/language/functions/digital-io/digitalwrite/
    before posting my previous reply. It accepts two integers for the pin and value.  Too much overhead for me. ;)
    #7
    1and0
    Access is Denied
    • Total Posts : 12265
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: PIC I/O pins, bitfields and 8-bit-variables (as example) 2021/02/28 03:43:26 (permalink)
    +1 (1)
    Anyway, XC8 is a C compiler that conforms to C Standard. Think of a pin as a single-bit bit-field of integer type of 1 bit wide. Assigning another integer to this will trigger a conversion and the result is only the least significant bit.  Similarly, when a 16-bit variable is assigned to an 8-bit variable, only the lower byte is used.
     
    As you have shown, to convert a value to a boolean value of 0 or 1, one way is to use double logical negation because the result of a logical operator is either 0 (false) or 1 (true).
    post edited by 1and0 - 2021/02/28 03:51:47
    #8
    Jump to:
    © 2021 APG vNext Commercial Version 4.5