SPI between 16F18346 and 16F1829

Thread Starter

Nik@

Joined Apr 1, 2021
29
Hi all
I am trying to use spi protocoll between 2 pics. 16F18346 is master mode and 16F1829 is slave mode. Master sends 1 waits 5sec and sends a 0. The slave operates an led acording the on off commands. Also the SS pin on slave side is active.Simple looks but?? I enclose the codes if anyone can see something wrong because project is not working at all. Thanks.

Master SPI:
/******************************************************************************/
/* Files to Include                                                           */
/******************************************************************************/

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */

#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/******************************************************************************/
/* User Global Variable Declaration                                           */
/******************************************************************************/
#define _XTAL_FREQ   4000000

/* i.e. uint8_t <variable_name>; */

/******************************************************************************/
/* Main Program                                                               */
/******************************************************************************/
void SPI_Master_Init();
void SPI_Write(unsigned char x);
unsigned char SPI_Read();
unsigned char DataRdySPI( void );

void main(void)
{
    /* Configure the oscillator for the device */
    ConfigureOscillator();
    // NOSC HFINTOSC; NDIV 4;
    OSCCON1 = 0x62;
    // CSWHOLD may proceed; SOSCPWR Low power; SOSCBE crystal oscillator;
    OSCCON3 = 0x00;
    // LFOEN disabled; ADOEN disabled; SOSCEN disabled; EXTOEN disabled; HFOEN disabled;
    OSCEN = 0x00;
    // HFFRQ 4_MHz;
    OSCFRQ = 0x03;
    // HFTUN 0;
    OSCTUNE = 0x00;

    /* Initialise I/O and Peripherals for application */
    InitApp();
    SPI_Master_Init();
    LATCbits.LATC0 = 1; // Select slave high
    
    while(1)
    {
        LATCbits.LATC0 = 0;
        __delay_ms(2);
        SPI_Write(0x01);
        __delay_ms(2);
        LATCbits.LATC0 = 1;
        __delay_ms(5000);
        
        LATCbits.LATC0 = 0;
        __delay_ms(2);
        SPI_Write(0x00);
        __delay_ms(2);
        LATCbits.LATC0 = 1;
        __delay_ms(5000);
    }

}

void SPI_Master_Init()
{
    // Set SPI Mode To Master + Set SCK Rate To FOSC/4
    SSP1CON1bits.SSPM = 0x00;
    // Enable The Synchronous Serial Port
    SSP1CON1bits.SSPEN = 1;
    // Configure The Clock Polarity & Phase
    SSP1STATbits.CKE = 1;
    SSP1CON1bits.CKP = 0;
    // Configure The Sampling Time (Let's make it at middle)
    SSP1STATbits.SMP = 0;
    // Set BaudRate
    SSP1ADD = 0x01;
    // Configure The IO Pins For SPI Master Mode
    TRISBbits.TRISB4 = 1; // SDI -> Input
    TRISBbits.TRISB6 = 0; // SCK -> Output
    TRISCbits.TRISC0 = 0; // SS  -> Output
    TRISCbits.TRISC6 = 0; // SDO -> Output
    ANSELB = 0x00;
    ANSELC = 0x00;
    
    SSP1CLKPPS = 0x0E;  // RB6->MSSP1:SCK1;   
    RB6PPS = 0x18;      // RB6->MSSP1:SCK1;   
    RC6PPS = 0x19;      // RC6->MSSP1:SDO1;   
    SSP1DATPPS = 0x0C;  // RB4->MSSP1:SDI1;
    
    PIE1bits.SSP1IE = 1;
    INTCONbits.PEIE = 1;
    INTCONbits.GIE = 1;
}

void SPI_Write(unsigned char x)
{
    unsigned char data_flush;
    SSP1BUF=x;            /* Copy data in SSBUF to transmit */
    while(!PIR1bits.SSP1IF);    /* Wait for complete 1 byte transmission */
    PIR1bits.SSP1IF=0;        /* Clear SSPIF flag */
    data_flush=SSP1BUF;        /* Flush the data */
}

unsigned char SPI_Read()
{   
    SSP1BUF=0xff;        /* Copy flush byte in SSBUF */
    while(!PIR1bits.SSP1IF);    /* Wait for complete 1 byte transmission */
    PIR1bits.SSP1IF=0;
    return(SSP1BUF);        /* Return received byte */
}
Slave SPI:
/******************************************************************************/
/* Files to Include                                                           */
/******************************************************************************/

#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */

#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */

/******************************************************************************/
/* User Global Variable Declaration                                           */
/******************************************************************************/
#define _XTAL_FREQ   4000000

/* i.e. uint8_t <variable_name>; */
char incoming = 0;

/******************************************************************************/
/* Main Program                                                               */
/******************************************************************************/
void SPI_Slave_Init();
void SPI_Write(unsigned char x);
unsigned char SPI_Read();

void main(void)
{
    /* Configure the oscillator for the device */
    ConfigureOscillator();
    // SCS INTOSC; SPLLEN disabled; IRCF 4MHz_HF;
    OSCCON = 0x6A;
    // TUN 0;
    OSCTUNE = 0x00;
    // SBOREN disabled;
    BORCON = 0x00;

    /* Initialise I/O and Peripherals for application */
    InitApp();
    SPI_Slave_Init();
    LATBbits.LATB7 = 0;  //LED = off
    
    
    while(1)
    {
        incoming = SPI_Read();
        switch(incoming){
            case 1: LATBbits.LATB7 = 1; //LED on
            break;
            case 0: LATBbits.LATB7 = 0; //LED off
            break;
        }
    }

}

void SPI_Slave_Init()
{
    // Set SPI Mode To Master + Set SCK Rate To Fosc/4
    SSP1CON1bits.SSPM = 0b0100;
    // Enable The Synchronous Serial Port
    SSP1CON1bits.SSPEN = 1;
    // Configure The Clock Polarity & Phase
    SSP1STATbits.CKE = 1;
    SSP1CON1bits.CKP = 0;
    // Configure The Sampling Time (Let's make it at middle)
    SSP1STATbits.SMP = 0;
    SSP1ADD = 0x00;
    // Configure The IO Pins For SPI Master Mode
    TRISCbits.TRISC6 = 1; // SS  -> Input
    TRISCbits.TRISC7 = 0; // SDO -> Output
    TRISBbits.TRISB4 = 1; // SDI -> Input
    TRISBbits.TRISB6 = 1; // SCK -> Output
    TRISBbits.TRISB7 = 0; // LED -> Output
    ANSELB = 0x00;
    ANSELC = 0x00;
    
    /**
    APFCONx registers
    */
    APFCON0 = 0x00;
    APFCON1 = 0x00;
    
    PIE1bits.SSP1IE = 1;
    PEIE  = 1;
    GIE   = 1;
}

void SPI_Write(unsigned char x)
{
    unsigned char data_flush;
    SSP2BUF = x;            /* Copy data in SSBUF to transmit */
    while(!PIR4bits.SSP2IF);    /* Wait for complete 1 byte transmission */
    PIR4bits.SSP2IF = 0;        /* Clear SSPIF flag */
    data_flush = SSP2BUF;        /* Flush the data */
}

unsigned char SPI_Read()
{   
    SSP2BUF=0xff;        /* Copy flush byte in SSBUF */
    while(!PIR4bits.SSP2IF);    /* Wait for complete 1 byte transmission */
    PIR4bits.SSP2IF = 0;
    return(SSP2BUF);        /* Return received byte */   
}
 

geekoftheweek

Joined Oct 6, 2013
1,429
A couple of issues I noticed.

void SPI_Master_Init()
{
...
...
...
PIE1bits.SSP1IE = 1;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
}


void SPI_Write(unsigned char x)
{
...
...
...
while(!PIR1bits.SSP1IF); /* Wait for complete 1 byte transmission */
PIR1bits.SSP1IF=0; /* Clear SSPIF flag */
....
}
[/code]
In the master you have enabled the interrupt, but have not declared an interrupt routine. The program will hold at the
Code:
    while(!PIR1bits.SSP1IF);    /* Wait for complete 1 byte transmission */
but as soon as the interrupt happens it will jump to the program address 04h and start executing the code there instead of continuing on to the
Code:
     PIR1bits.SSP1IF=0;
Depending on how the program compiles it may keep jumping to 04h and run through the program up to that point over and over until it overflows the stack and resets.

The easiest way to fix it will be to remove the

Code:
    PIE1bits.SSP1IE = 1;
    INTCONbits.PEIE = 1;
    INTCONbits.GIE = 1;
The not so easy way will be to declare an interrupt function and handle the interrupt there. I normally use assembly myself so I don't have a good example or better explanation to offer, but I guarantee this is what is happening in the master.

On the slave end it's pretty much the same story with some differences....

Instead of using interrupts...
Code:
while(1)
    {
        if (PIR1bits.SSP1IF) {
             incoming = SSP1BUF;
             PIR1bits.SSP1IF =0;
             switch(incoming){
                 case 1: LATBbits.LATB7 = 1; //LED on
                     break;
                 case 0: LATBbits.LATB7 = 0; //LED off
                    break;
             }
       }
}
On the slave it will actually read the byte already in SSPBUF before setting the interrupt. The byte you then place in SSPBUF after the interrupt will be read on the next read from the master.

Hopefully that is enough of a start to get you in the right direction. Let us know how things go...
 
Last edited:
Top