• AVR Freaks

Hot!How to use SPI on 16F1454 ?

Author
nim65s
New Member
  • Total Posts : 5
  • Reward points : 0
  • Joined: 2019/07/14 01:58:47
  • Location: Toulouse
  • Status: offline
2019/07/17 06:03:13 (permalink)
0

How to use SPI on 16F1454 ?

Hi,

I am trying to use SPI on the 16F1454. To get started, I tried to use 2 PIC : one SPI master and one slave:

Linux ← USB ← Master PIC → SPI → Slave PIC → USB → Linux.

I adaptated a CDC serial example from MLA to get the parts "Linux ← USB ← Master PIC" and "Slave PIC → USB → Linux" work.

So now, I can monitor from linux the master trying to send SPI data to the slave, and the slave trying to receive those data. But the slave behavior shows that there is no reception.

Here is the code I used, stripped from USB related stuff:


// SPI helper functions for Master

void SPI_Master_Init()
{
  // Set SPI Mode To Master + Set SCK Rate To Fosc/64
  SSP1M0 = 0;
  SSP1M1 = 0;
  SSP1M2 = 0;
  SSP1M3 = 0;
  // Enable The Synchronous Serial Port
  SSPEN = 1;
  // Configure The Clock Polarity & Phase (SPI Mode Num. 1)
  CKP = 0;
  CKE = 0;
  // Configure The Sampling Time (Let's make it at middle)
  SMP = 0;
  // Configure The IO Pins For SPI Master Mode
  TRISC0 = 0; // SCK -> Output
  TRISC1 = 1; // SDI -> Input
  TRISC2 = 0; // SDO -> Output
  TRISC3 = 0; // SS -> Output
}

void SPI_Write(uint8_t Data)
{
  SSP1IF = 0;
  WCOL = 0;
  SSPBUF = Data;
  while(!BF);
}


// SPI helper functions for Slave

void SPI_Slave_Init()
{
  // Set Spi Mode To Slave + SS Enabled
  SSP1M0 = 0;
  SSP1M1 = 0;
  SSP1M2 = 1;
  SSP1M3 = 0;
  // Enable The Synchronous Serial Port
  SSPEN = 1;
  // Configure The Clock Polarity & Phase (SPI Mode Num. 1)
  CKP = 0;
  CKE = 0;
  // Clear The SMP Bit
  SMP = 0;
  // Configure The IO Pins For SPI Master Mode
  TRISC0 = 1; // SCK -> Intput
  TRISC1 = 1; // SDI -> Input
  TRISC2 = 0; // SDO -> Output
  TRISC3 = 1; // SS -> Input
}

uint8_t SPI_Read()
{
  uint8_t Data = 42;
  if(BF) // Check If Any New Data Is Received
  {
    Data = SSPBUF; // Read The Buffer
    BF = 0; // Clear The Buffer-Filled Indicator Bit
    SSP1IF = 0; // Clear The Interrupt Flag Bit
    SSPOV = 0; // Clear The Overflow Indicator Bit
  }
  return Data;
}


// master / slave test connection

uint8_t spi_data[] = {1, 2, 0};

void master()
{
  RC3 = 0; // !SS
  __delay_ms(1);

  spi_data[0]++;
  SPI_Write(spi_data[0]);
  if (USBUSARTIsTxTrfReady()) { putUSBUSART(spi_data, 3); }

  __delay_ms(1);
  RC3 = 1; // SS
  __delay_ms(1000);
}

void slave()
{
  spi_data[1] = SPI_Read() * 2 + 1;
  if (USBUSARTIsTxTrfReady()) { putUSBUSART(spi_data, 3); }
  __delay_ms(500);
}

 
So with this code, I expect to read from the master


1 2 0
2 2 0
3 2 0



And I do (or almost: it is counting 2 by 2…), and from the slave:


1 3 0
1 5 0
1 7 0



But I only read lines with "1 85 0", where 85 == 42 * 2 + 1, so this shows that "SPI_Read()" receive nothing.

I got this from a few tutorials online, and I also found some pieces of similar stuff in MLA, like


 void SPIPut(uint8_t v)
{
        uint8_t i;

        PIR1bits.SSP1IF = 0;
        //clear SSP1BUF
        i = SSP1BUF;

        do
        {
            SSP1CON1bits.WCOL = 0;
            SSP1BUF = v;
        } while( SSP1CON1bits.WCOL );

        while( PIR1bits.SSP1IF == 0 );

        PIR1bits.SSP1IF = 0;
}




But it wasn't giving me much results.

My final goal will be to have a DWM1001 module to stream geolocation data by USB. So far, it works great if I plug its SPI to a RPi, but I can't get a 2m SPI cable, and that's why I bought a few PIC16F1454. For this, the same PIC will be used for both emission and reception of SPI data.

Am I doing anything wrong ?

Also, I don't use any composant but the PICs, and I put SDO from master to SDI on slave and vice versa. SCK & SS are also connected.
 
 
PS: I initially sent this post to the wrong forum, sorry.
#1

8 Replies Related Threads

    ric
    Super Member
    • Total Posts : 24566
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: How to use SPI on 16F1454 ? 2019/07/18 13:34:27 (permalink)
    +3 (3)
    You will go mad trying to code separate read and write routines for SPI.
    It is an exchange protocol. Every transaction is a simultaneous read and write, and you should have a single function that does both.
    Just pass it zero when you only want to read, and discard the return value when you only want to write.
    SS is only handled by the hardware in the slave. You have to control it manually in the Master.
    Make sure all pins with analog functionality have been switched to digital mode.
     

    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
    nim65s
    New Member
    • Total Posts : 5
    • Reward points : 0
    • Joined: 2019/07/14 01:58:47
    • Location: Toulouse
    • Status: offline
    Re: How to use SPI on 16F1454 ? 2019/07/18 22:00:34 (permalink)
    0
    Thanks for your answer !
     
    Actually, this was the first thing I tried:
     

    char spiReadWrite(char v)
    {
      PIR1bits.SSP1IF = 0;
      do
      {
        SSPCON1bits.WCOL = 0;
        SSPBUF = v;
      } while (SSPCON1bits.WCOL);
      while (PIR1bits.SSP1IF == 0);
      return SSPBUF;
    }

     
    But it wasn't working better.
     
    About the SS part, yes I think I am doing that only in the "master()" function
     
    And, quoting the datasheet: Analog features are not available on PIC16(L)F1454 devices.
    #3
    ric
    Super Member
    • Total Posts : 24566
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: How to use SPI on 16F1454 ? 2019/07/19 00:05:35 (permalink)
    0
    Get rid of that WCOL loop for now.

    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
    nim65s
    New Member
    • Total Posts : 5
    • Reward points : 0
    • Joined: 2019/07/14 01:58:47
    • Location: Toulouse
    • Status: offline
    Re: How to use SPI on 16F1454 ? 2019/07/19 03:23:27 (permalink)
    0
    I tried again with the following:
     

    uint8_t spiReadWrite(uint8_t v)
    {
      PIR1bits.SSP1IF = 0;
      SSPBUF = v;
      //while (PIR1bits.SSP1IF == 0);
      return SSPBUF;
    }

     
    If I uncomment the "while (PIR1bits.SSP1IF == 0);", I don't read anything on the serial port, and if I comment it, I read only the dummy thing I write in v.
     
    I get the exact same behavior if I use "while ( !SSPSTATbits.BF );" instead.
     
    So I guess the slave just never gets any data, and the buffer is not filled.
    #5
    NorthGuy
    Super Member
    • Total Posts : 5803
    • Reward points : 0
    • Joined: 2014/02/23 14:23:23
    • Location: Northern Canada
    • Status: online
    Re: How to use SPI on 16F1454 ? 2019/07/19 06:09:23 (permalink)
    0
    nim65s
    If I uncomment the "while (PIR1bits.SSP1IF == 0);", I don't read anything on the serial port ...



    Is that on the slave? This simply means that the slave hasn't seen any transmission from the master.
     
    I'd suggest you work on the master side first and make sure you can produce a good signal.
    #6
    nim65s
    New Member
    • Total Posts : 5
    • Reward points : 0
    • Joined: 2019/07/14 01:58:47
    • Location: Toulouse
    • Status: offline
    Re: How to use SPI on 16F1454 ? 2019/07/19 10:20:22 (permalink)
    0
    I don't have access to an oscilloscope, but with a multimeter, I think that I can see that the signals from the master are correct: eg. if I send data non-stop, SDO is  ~2.5V, and if I send one byte every 2s, SDO alternates between 0V & 5V at ~0.5Hz.
    #7
    NorthGuy
    Super Member
    • Total Posts : 5803
    • Reward points : 0
    • Joined: 2014/02/23 14:23:23
    • Location: Northern Canada
    • Status: online
    Re: How to use SPI on 16F1454 ? 2019/07/19 10:31:22 (permalink)
    0
    nim65s
    I don't have access to an oscilloscope, but with a multimeter, I think that I can see that the signals from the master are correct: eg. if I send data non-stop, SDO is  ~2.5V, and if I send one byte every 2s, SDO alternates between 0V & 5V at ~0.5Hz.




    How about SCK? Does it go to 2.5V too?
     
    How about the SS pin? Is it driven low?
    #8
    PStechPaul
    Super Member
    • Total Posts : 2437
    • Reward points : 0
    • Joined: 2006/06/27 16:11:32
    • Location: Cockeysville, MD, USA
    • Status: online
    Re: How to use SPI on 16F1454 ? 2019/07/19 13:30:46 (permalink)
    0
    An oscilloscope is pretty much a necessity for debugging anything but the most trivial PIC projects. A decent scope, or scope/DMM, can be had for well under $100. Also, a logic probe will suffice for detecting signals such as SPI.
     
    You may also be able to use extra input pins on the PIC to detect logic signals, and use LEDs to indicate their presence, perhaps with extended ON times to see very short pulses.

     
    #9
    Jump to:
    © 2019 APG vNext Commercial Version 4.5