Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

PIC18F25K22 SPI interfacing program

Status
Not open for further replies.

BryanF

Newbie level 6
Joined
Apr 29, 2016
Messages
11
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
105
I'm new to PIC18F25K22 programming. I want to know how to write C program for SPI interfacing of two PIC18F25K22.

I want to start by using master controller to blink the LED's of the slave.

Please guide me.
 

How much experience do you have with embedded software design and writing?
What IDE and compiler will you use? Some compilers have peripheral libraries that might help you but for something as simple as the SPI peripheral I would recommend that you interact with the SPI SFRs directly.
Do you understand what SPI exchanges are?
Have you devised a suitable protocol to sit over the SPI exchange to do what you want?
There are a lot of examples on the Internet for both master and slave SPI code.
However, if you are new to not just that MCU but the PIC programming in general, then I suggest you start with just getting a LED to blink on one device. There is a bit of a learning curve with PIC devices to make sure that you get the config bits set correctly, the oscillator sorted out and the programming/debugging working correctly. There are many tutorials (look up Gooligum for one example) available that will help you. Once you have the LED flashing then you can start to do what you want as the initial hump in the learning curve is past.
Susan
 
  • Like
Reactions: BryanF

    BryanF

    Points: 2
    Helpful Answer Positive Rating
I have been trying to make connections between master and slave as:

Capture.PNG

The master program is :



Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include<P18F25k22.h>
#include<stdio.h>
#include<string.h>
#include<math.h> 
#include<stdlib.h>  
#include<delays.h>
#include <eep.h> 
 
    
///////////////////////////////////////////////////////////////////////////////////////
 
 
void sec1_delay(void);
void spi(unsigned char);             //SPI Function To send the data
void delay_10sec(void);         //delay
 
 
void main(void)
{
    INTCONbits.GIE=1;  // Enable the global Interrupt
 
    TRISCbits.RC3 =0;  //sclk1 o/p
    PORTCbits.RC3 = 0;
 
    TRISCbits.RC5 =0; //sdo o/p
    PORTCbits.RC5 = 0;
 
    TRISCbits.RC4 =1; //sdi i/p
    PORTCbits.RC4 = 1;
 
    TRISAbits.RA5 =0; //SS
    PORTAbits.RA5 = 0;
 
    TRISBbits.RB5 = 0; // LED
    PORTBbits.RB5 = 0;
 
    TRISBbits.RB6 = 0; // LED
    PORTBbits.RB6 = 0;
 
    SSP1STAT =0x40;              
    SSP1CON1=0x22;              //Configure  SSPCON1 for ENABLE SERIAL PORT
                                                    // and disable general I/O pin ,, SPI master clock= Fosc/64
        
    
                                                    // we are only sending the data so we do't need to set SPI pin as input
        while(1)                      // loop for ever so that led keep repeating that pattern
        {
        PORTBbits.RB5 = 1;                 // 1 LED to check it is in while
        
        spi(1);                   // send 01 hex to the SPI port it will glow the first led
 
        Delay10KTCYx(400);         // wait for approximate 1sec   ,
                                                     //if we do't give the delay then led will flash too fast that
                                                    // we can't even know when it glow and when it off
 
        spi(0);                   //send 0 to turn of slave LED
 
        Delay10KTCYx(400);           // wait for 1 sec
        
 
        }
 
 
}
 
 
 
void spi(unsigned char myData)
{
PORTBbits.RB6 = ~PORTBbits.RB6;       // second LED to see function is executed.
SSP1BUF = myData;                    // put the data in the SSPBUF register which going to be send
 
while(!SSP1STATbits.BF);           // wait until the all bits sended
}
 
 
 
 
void sec1_delay(void)
{
 
        BY_PASS_RESET=0;
        BY_PASS_SET=1;
        Delay10KTCYx(60);
        BY_PASS_SET=0;
        delay_10sec();
        delay_10sec();
            
        BY_PASS_RESET=1;
        BY_PASS_SET=0;
        Delay10KTCYx(60);
        BY_PASS_RESET=0;
        delay_10sec();
        delay_10sec();
 
}
 
 
void delay_10sec(void)
{
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
Delay10KTCYx(200);
 
}



I'm unable to send data. The grounds of both microcontrollers have been connected with the connections of SCLK, SDI, SDO and SS is grouded (one slave).

Please suggest changes in the program.
 
Last edited by a moderator:

Hi,

With your schematic "send" of data from master can not be prohibited. (As long as all global inputs are set up as inputs)

Only "receive" may be problematic when none or multiple slaves send data at the same time.

Please give more details.
A scope of all the signals could help to identify the problem.

Klaus
 
  • Like
Reactions: BryanF

    BryanF

    Points: 2
    Helpful Answer Positive Rating
Hi
I think the best you could do if you are beginner is to use MPLAB Code Configurator - free plugin for MPLABX. It could do all the job for even int driven communication, and in 90% it should work.

In your code there is a lot of bugs – for instance if you would like to set pin level you should set LAT not PORT bits. If you would like to read pin state you should disable analog input and etc.
Good idea is to first configure software and then enable GIE. And sometime it is good idea to clear IF before enable GIE. Question why do you enable GIE when you don’t use it?
There could be a lot of bugs in oscillator or chip config bits (#pragmas)
In my opinion Code Configurator is the best solution for you, and you could concentrate on code writing, even without reading of datasheet
 

Hi,

A scope of all the signals could help to identify the problem.

Klaus

sir, the images of sclk and sdo has been attached. Some data I'm getting at the sdo pin as '0xff' value has been given in the SBUF register.
sclk:
Sclk.jpg
sdo:
Sdo.jpg
the slave program is:
Code:
#include<P18F25k22.h>
#include<stdio.h>
#include<string.h>
#include<math.h> 
#include<stdlib.h>  
#include<delays.h>
#include <eep.h> 
#include <spi.h>


void spi(unsigned char);             //SPI Function To send the data


#pragma code // end of the code
/*-------------------------*/


void main(void)
{	//SSP1BUF = 0;
	
	
	TRISCbits.RC3 =1;  //sclk1 i/p
	LATCbits.LATC3 = 1;

	TRISCbits.RC5 =0; //sdo o/p
	LATCbits.LATC5 = 0;

	TRISCbits.RC4 =1; //sdi i/p
	LATCbits.LATC4 = 1;

	TRISAbits.RA5 = 1; // SS i/p

	TRISBbits.RB5 = 0; 
	LATBbits.LATB5 = 1;

	TRISBbits.RB6 = 0; 
	LATBbits.LATB6 = 1;

	INTCONbits.GIE=1; 

	SSP1STAT =0x00;              
	SSP1CON1=0x25;
		

                                                   
while(1)                    
		{
		if(SSP1STATbits.BF == 1)
             {
                PORTBbits.RB5 = ~PORTBbits.RB5;
				PORTBbits.RB6 = SSP1BUF;
             }


}


}
 

Hi,

Your scope picture show true sending "FF".

I estimate the SPI clock frequency to about 1.6MHz.

So where do you see a problem?

***
Please post ONE scope picture with ALL signals.

Klaus
 
  • Like
Reactions: BryanF

    BryanF

    Points: 2
    Helpful Answer Positive Rating
The sclk signal is at the top (yellow) and sdo at bottom(blue).

20160503_171018.jpg

sir i'm unable to turn the LED on which is connected in the slave at RB6. Please refer the post #6, i have posted the slave program.

Please suggest corrections so that reception problem is solved.
 

Hi,

sir i'm unable to turn the LED on
Slow down. Turning on the LED with a SPI command is the last piece of the chain.
Debug step by step.

Debug according data flow:
* First you need to ensure that CLK, SDO (master) and CS-n(Master) is correct. Correct in timing, and correct voltage.
--> send "0x95" instead "0xFF". We need a scope picture with zoomed in timing. One complete byte from beginning to end.
* then you need to ensure, that the correct slave is accessed
--> toggle the LED every time the "addressed" slave receives any byte.
* then ensure that the slave receives the correct byte.
--> toggle the LED on correct byte receive.

Klaus
 
  • Like
Reactions: BryanF

    BryanF

    Points: 2
    Helpful Answer Positive Rating
sir the image with '0x95' sent is:
20160503_184811.jpg
1-clk, 2-sdo, 3-ss bar, sdi remains 0

the master program is:
Code:
#include<P18F25k22.h>
#include<stdio.h>
#include<string.h>
#include<math.h> 
#include<stdlib.h>  
#include<delays.h>
#include <eep.h> 
#include <spi.h>


void spi(unsigned char);             //SPI Function To send the data


void main(void)
{
	
	TRISCbits.RC3 =0;  //sclk1 o/p

	TRISCbits.RC5 =0; //sdo o/p

	TRISCbits.RC4 =1; //sdi i/p

	TRISCbits.RC2 =0; //SS
	

	TRISBbits.RB5 = 0; // LED
	LATBbits.LATB5 = 0;

	TRISBbits.RB6 = 0; // LED
	LATBbits.LATB6 = 0;

	SSP1STAT =0x40;              // Transmit occurs on transition from active to Idle clock state
	SSP1CON1=0x22;              //Configure  SSPCON1 for ENABLE SERIAL PORT
                                    // and disable general I/O pin ,, SPI master clock= Fosc/64
		
	
INTCONbits.GIE=1;  // Enable the global Interrupt

while(1)                      // loop for ever so that led keep repeating that pattern
		{
		
		PORTBbits.RB5 = 1; // led
		PORTCbits.RC2 = 0;
		spi(0x9F);                   // send hex to the SPI port 
		PORTCbits.RC2 = 1;
			

		}


}



void spi(unsigned char myData)
{

PORTBbits.RB6 = ~PORTBbits.RB6;      //led
SSP1BUF = myData;                    // put the data in the SSPBUF register which going to be send
while(!SSP1STATbits.BF);           // wait until the all bits sended

PIR1bits.SSP1IF = 1;   // clear interrupt
}
 

to togle bit you should use

LATBbits.RB5 = ~PORTBbits.RB5;

instead of

PORTBbits.RB5 = ~PORTBbits.RB5;
 

Hi,

Not that bad.

But you sent "0x9F" instead of "0x95". This is no problem. We see the data is sent out.

You see your data_change is very close to the falling clock edge. Please verify the timing specification in this.

Also the CS_inactive time is very short. just for the testing i recommend to insert a delay (some microseconds). (Later you can do without delay).

***
Testing:
Please change only one item in your software, then verify it. Then do the next change.

Klaus
 
  • Like
Reactions: BryanF

    BryanF

    Points: 2
    Helpful Answer Positive Rating
to togle bit you should use

LATBbits.RB5 = ~PORTBbits.RB5;

instead of

PORTBbits.RB5 = ~PORTBbits.RB5;

maybe better idea it would be to use

LATBbits.RB5 = ~LATBbits.RB5;

Another question.
How do you program PIC. Maybe debug mode and breakpoint while read SSP1BUF it would be better idea then guess from oscilloscope?
 

Hi,

it would be better idea then guess from oscilloscope
Guessing?
In my eyes the picture of a scope says more about the real world conditions than a simulation.

Klaus
 

By the way, you can clean up your code a lot. Given the code for the master and slave, the only #include you need is the first one - all the others are not needed.
The SPI pins are on port pinss that have analog capability. Therefore you need to make sure these are set to 'digital' mode with the appropriate ANSELx register. If you don't then a pin in analog mode will always be read as a digital '0'.
I agree with the comments above about the use of the LAT registers. To avoid RMW bugs the rule is always "read from the PORT, write to the LAT".
Also, I'm not sure what you intend to happen when you write a byte (SSP1BUF) to a single bit (RB6 which should be LATBbits.LATB6). You will only get the LSB used so I'm not sure what the point is on sending 0x9f (except for testing to see the SDO line changing which is certainly useful).
Susan
 

Hi,

You will only get the LSB used so I'm not sure what the point is on sending 0x9f (except for testing to see the SDO line changing which is certainly useful).

Sending 0xFF is just a flat line. It is impossible to see the timing. Also impossible to find out if MSB or LSB first. Also impossible to find out wether all bits are transmitted or not.

Therefore i chose a code with some "informative bit code".

Klaus
 

Understand - but that particular point was: why assign a byte to a bit? I know it works but is not good style (IMO).
(Also the PIC SPI peripherals are all [the the best of my knowledge] MSB first. However this is all inside the MCU and after the SPI exchange.]
Susan
 

Hi,

Is your slave receive routine with interrups?
If so:
Place the "LED toggle" function at the beginning of the receive ISR.
Check if the LED is toggeling.

Klaus
 

sir I have not used interrupt routine in slave program.

The image having 1-clk, 2-sdo, 3-sdi, 4-ss bar.
the data sent is '0x95' and '0x65'. I have LEDs at RB6 and RB5 of slave and master.
20160504_124655.jpg
the master code:
Code:
void main(void)
{
	TRISBbits.RB4 = 0; // LED
	LATBbits.LATB4 = 0;	

	TRISCbits.RC3 =0;  //sclk1 o/p

	TRISCbits.RC5 =0; //sdo o/p

	TRISCbits.RC4 =1; //sdi i/p

	TRISCbits.RC2 =0; //SS
	

	TRISBbits.RB5 = 0; // LED

	TRISBbits.RB6 = 0; // LED

	SSP1STAT =0x40;              // Configure SSPSTAT  for transmission occur from idle to active clock and Buffer flag =0	
	SSP1CON1=0x22;              //Configure  SSPCON1 for ENABLE SERIAL PORT
                                                    // and disable general I/O pin ,, SPI master clock= Fosc/64
		
	
INTCONbits.GIE=1;  // Enable the global Interrupt

while(1)                      // loop for ever so that led keep repeating that pattern
		{
		
		LATBbits.LATB5 = 1;    //led
		LATCbits.LATC2 = 0;   // ss bar
		spi(0x95);                   // send 01 hex to the SPI port it will glow the first led
		spi(0x65);
		LATCbits.LATC2 = 1;
		 Delay10TCYx(9);    // 36us delay
	
		}


}



void spi(unsigned char myData)
{

LATBbits.LATB6 = ~LATBbits.LATB6;
SSP1BUF = myData; 
SSP1BUF = myData;                    // put the data in the SSPBUF register which going to be send
while(!SSP1STATbits.BF);           // wait until the all bits sended

PIR1bits.SSP1IF = 1;   // clear interrupt
}

slave code:
Code:
#include<P18F25k22.h>
#include<delays.h>
#include <spi.h>

#pragma code 

void main(void)
{		
	ANSELA = 0x00;  // digital input
	ANSELB = 0x00;

	TRISCbits.RC3 =1;  //sclk1 i/p

	TRISCbits.RC5 =0; //sdo o/p

	TRISCbits.RC4 =1; //sdi i/p

	TRISAbits.RA5 = 1; // SS i/p

	TRISB = 0;
	LATB = 0;


	SSP1STAT =0x40;              
	SSP1CON1=0x24;
		
	INTCONbits.GIE=1; 
                                                   
while(1)                    
		{
				LATBbits.LATB5 = 1;  //led

               		if(SSP1STATbits.BF)
             {
				PORTB = SSP1BUF;  
				SSP1BUF = 0;
             }


}


}

sir as i see data is being sent. but I think I'm getting my slave program wrong. please help in getting the reception of data in slave controller.
 

Hi,

Code:
while(1)                    
		{
				LATBbits.LATB5 = 1;  //led

               		if(SSP1STATbits.BF)
             {
				PORTB = SSP1BUF;  
				SSP1BUF = 0;
             }


}
I´m not familiar with PIC nor with the assembler. It´s hard for me to help. But I try...

this is an endless loop. LATB sets the bit...
if the "IF command" is true, then this is overwritten by the SPI data, but immediately after that in the next loop the LED data will be set to 1 again. So there is no visible toggle. Even with a scope it will be hard to detect.
Don´t you need to clear the status flags?

***
With the code an experienced pic programmer could better assist you.

Klaus
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top