Please help me understand this C code

Discussion in 'Programmer's Corner' started by wannaBinventor, Aug 27, 2010.

  1. wannaBinventor

    Thread Starter Active Member

    Apr 8, 2010
    I'm trying to work with a PIC16F818 to program and operate microchip's MRF49XA transceiver. I've read most of the datasheet and wanted to see some code examples to fill games in my understanding, but it appears microchip only offers a C code example. I only know assembly, so this presents a problem.

    Can someone help me understand these lines of code?

    Code ( (Unknown Language)):
    2. void RegisterSet(WORD setting)
    3. {
    4.     nCS = 0;
    5.     SPIWrite(setting >> 8);
    6.     SPIWrite(setting);
    7.     nCS = 1;
    8. }
    The nCS =0/1 I get, but is it calling a function called SPI write? What does (setting>>8) mean?

    Code ( (Unknown Language)):
    2. void SPIWrite(BYTE data)
    3. {
    4.     BYTE i;
    6.     #if defined(HARDWARE_SPI)
    7.         PIR1bits.SSP1IF = 0;
    8.         i = SSP1BUF;
    9.         SSP1BUF = data;
    10.         while(PIR1bits.SSP1IF == 0){}
    11.     #else
    13.         SPI_SDO = 0;
    14.         SPI_SCK = 0;
    16.         for(i = 0; i < 8; i++)
    17.         {
    18.             SPI_SDO = ((data & (0x80 >> i)) > 0) ? 1:0;
    19.             SPI_SCK = 1;
    20.             SPI_SCK = 0;  
    21.         }  
    22.         SPI_SDO = 0;  
    23.     #endif
    The if statement above: I'm pretty much lost. What is going on in that IF statement? I'm understanding that the else statement tells it to set those variables (SPI_SDO) to 0 if the above condition isn't met, but what the heck is happening in that "for" loop?

    Code ( (Unknown Language)):
    2. void MRF49XAInit(void)
    3. {
    4.     // configuring the MRF49XA radio
    5.     RFIE = 0;
    6.     RegisterSet(FIFORSTREG);
    7.     RegisterSet(FIFORSTREG | 0x0002);       // enable synchron latch
    8.     RegisterSet(GENCREG);
    9.     RegisterSet(AFCCREG);
    10.     RegisterSet(CFSREG);
    11.     RegisterSet(DRVSREG);
    12.     RegisterSet(PMCREG);
    13.     RegisterSet(RXCREG);
    14.     RegisterSet(TXCREG);
    15.     // antenna tuning on startup
    16.     RegisterSet(PMCREG | 0x0020);           // turn on the transmitter
    17.     delay_ms(5);                            // wait for oscillator to stablize
    18.     // end of antenna tuning
    19.     RegisterSet(PMCREG | 0x0080);           // turn off transmitter, turn on receiver
    20.     RegisterSet(GENCREG | 0x0040);          // enable the FIFO
    21.     RegisterSet(FIFORSTREG);
    22.     RegisterSet(FIFORSTREG | 0x0002);       // enable synchron latch
    23.     RegisterSet(0x0000);                    // read status byte (read ITs)
    25.     RFIE = 1;
    26. }
    What does the (GENCREG | 0x0040) mean? Why do some names have hex behind them while others dont? Does that mean they are 0x00? What is "RegisterSet" actually doing?

    Thanks very much for the help!
  2. hgmjr

    Retired Moderator

    Jan 28, 2005
    The (setting>>8) passes the high byte of the 16-bit value to the function SPIWrite.

    This statement is followed immediately by the next line that passes the low byte of the variable "setting" to the same function.

  3. Papabravo


    Feb 24, 2006
    #if defined(...)

    is a conditional compilation sequence. It is an instruction to the C compilers pre-processor to select either the #if part or the #else part to pass to the compiler. The selection is based on weather a particular symbol is defined or not. In the #if case the processor has a hardware peripheral to implement the SPI and in the #else case the SPI interface is done in software by direct control of the port lines.

    You really should get a copy of K&R are at least read the documentation that came with the compiler.
  4. Papabravo


    Feb 24, 2006
    The vertical bar | character is a bitwise OR operator.

    The function RegisterSet writes two bytes of data to the SPI interface. It is setting the value of the registers in the SPI peripheral device on the other end of the SPI bus.
  5. wannaBinventor

    Thread Starter Active Member

    Apr 8, 2010
    Thanks for that.

    Can you guys confirm based on this snips of code provided that the MRF49XA (SPI slave) is NOT sending its individual register addresses to the microcontroller and saying "Hey, what configuration bits do you have to give me for this address?" The datasheet uses the following wording when talking about all of it's register addresses:
    "The command code bits (10111000b) are serially sent to the microcontroller to identify the bits to be
    written in the TXBREG."

    This code seems to indicate that it is in fact the MICROCONTROLLER addressing each SPI slave register, but that data sheet seems to say otherwise. Is the datasheet right, or did it just word it badly?

    I found the header file separately in the sample project, with this piece of code in it:
    Code ( (Unknown Language)):
    2.     #define AFCCREG                 0xC4F7
    3.     #define TXCREG                  0x9850          // Deviation: 75kHz
    4.     #define TXBREG                  0xB800
    5.     #define RXCREG                  0x9481          // BW 200KHz, LNA gain 0dB, RSSI -97dBm
    6.     #define FIFORSTREG              0xCA81
    7.     #define DRVSREG                 0xC623          // Data Rate:9579Baud
    8.     #define PMCREG                  0x8201
    Comparing this with the datasheet and the comments, things are starting to make sense. In the above code, is it the same as just saying in ASM:
    PMCREG EQU 0x8201
    In other words, just defining variable.

    If this is the case is that whole "register set" code section just looking back at the value for each defined name and then clocking in the 8 MSB followed by the 8 LSB in the 16bit values defined above?

    When it says:

    Code ( (Unknown Language)):
    1. void   RegisterSet (WORD setting)
    Is "WORD" used in the sense of "two bytes?"

    Should I think of this as flowing in the same way that PIC assembly flows with the "SPIWRITE" portion being like making a call?

    Something like this:
    BCF nCS
    BSF nCS

    Thanks again.
    Last edited: Aug 27, 2010
  6. Papabravo


    Feb 24, 2006
    SPI is inherently a bi-directional transfer. At the same time that the master is sending bits out on the MOSI (Master Out Slave In) line, the slave device is sending bits to the master on the MISO (Master In Slave Out) line. Is sounds like the device is echoing the bits it receives with a 1/2 clock delay.

    It is probable that the 16-bit words defined consist of and address in the high byte and a data value in the low byte. That is why the strange looking code is required to modify some of the arguments passed to the function call RegisterSet. IMHO it is an obscure way to do things and I certainly would not have written such a piece of code in that fashion.
  7. retched

    AAC Fanatic!

    Dec 5, 2009
    I would have to agree with Papabravo.

    If you are trying to learn C using this code, you are learning the bad way to do it.

    This will trip you up in the future.
  8. Markd77

    Senior Member

    Sep 7, 2009
    I'm not much up on C but I think this is not defining them but setting the contents of the variables (or more likely constants).
    Have a look in the files named in the INCLUDE section. You should find some of the functions in them. They are probably mostly in the Microchip folder on your computer.
  9. wannaBinventor

    Thread Starter Active Member

    Apr 8, 2010
    Actually, I'm not trying to learn C with this code. I'm just trying to learn to program the MRF49XA rf transceiver, and this is the only sample code that I can find (its from microchips website).

    Since I don't wish to take the time to learn the ins and outs of C, I'm going to write the code in assembly, but I needed to try and work out some gaps of understanding that the data sheet left.

    I'm just going to write a software SPI in assembly, but I wanted to have my ducks in a row before I spent some hours writing a code that was all wrong.

    I think I'll just put all the addresses and configuration bits in different user files and then use BTFSC or BTFSS commands for each bit to set or clear the MOSI line pin. Then I think I'll use a BTFSC or BTFSS commands to set each bit along with a RLF command to put everything where it is suppose to be in the byte for data on the MISO line.

    Thanks for the help!
  10. t06afre

    AAC Fanatic!

    May 11, 2009
    It was a discussion on the Microchip forum about this The most important thing is what the compiler recognise. I guess the most compilers recognise the "SPIWrite(setting >> 8);" statement as "use the high byte"
    But I prefer using the union method my self. Also to the OP. You should get a copy of a good book about C.
    Here is two books that I have used
    "C Programming Language (2nd Edition) by Brian W. Kernighan and Dennis M. Ritchie" (sometimes referred to as K&R)
    "Beginning C: From Novice to Professional, Fourth Edition Copyright © 2006 by Ivor Horton"