Cannot load data to SSPBUF?

Status
Not open for further replies.

helloleong

New Member
Im using the PIC16F727 to communicate with the EEPROM X25650 by SPI
But when i use debugger to debug the code, it cannot get out of the SPI_OUTPUT function while loop,
since the BF (buffer full bits) does not set (the data cannot completely transfer to the buffer?)

here's the code im doin:
Code:
#include	<stdio.h>
#include	<pic.h>
#include	<htc.h>

//Detail in MPLAB Configue > Configuration Bits window
__CONFIG(INTIO & WDTDIS & PWRTDIS & MCLREN & BORDIS & UNPROTECT & PLLEN);
__CONFIG(VCAPRA0);

//GLOBAL VARIABLE
unsigned char CStest;	
unsigned char SDOtest; 	
unsigned char SDItest; 	
unsigned char SCKtest;
unsigned char BFtest;
#define	Buzzer	RA7

/******* EEPROM ReadWrite.c ***********/
unsigned char 	Result, dummy; //Data;
unsigned char	H_addr=0, L_addr=0, data;
unsigned char 	miss;

unsigned char	Pin_No=0;
unsigned char 	spi_received=0;
unsigned char	Increase=0;

unsigned char 	ERROR=0;
unsigned char	PageSize=32;
unsigned char	NHigh=0;
unsigned char 	NLow=0;

unsigned char 	Temp;
unsigned char	ClearM_Counter=0;
unsigned char	W;

//GLOBAL FUNCTIONS			
void Init(void);

//EEPROM Funstion
void WREN();
char SPI_OUTPUT (char spi_byte);
void write_data(char L_addr, char H_addr, char data);
char read_data(char L_addr, char H_addr);
void Start_read(char L_addr, char H_addr);
char RDSR();
void WRSR();

//EEPROM defination
#define CS   RC7	//active low (Chip Selection)
#define SDI  RC5 	//serial data input  //wrong swap: original #define SDI RC4
#define SDO RC4 	//serial data output //wrong swap: original #define SDO RC5 
#define SCK RC3	//synchronous clock //**change: original #define SCK RC3

/*******Control2_Main.c*******/
#define BLUE	RA1 //TRI-LED BLUE
#define GREEN	RA2 //TRI-LED GREEN
#define RED	RA3 //TRI-LED RED



/******************************************************************************/
/*           Main Routine			                     
/******************************************************************************/

void main(void)
{
	Init();
	
	//Test byte to watch on
	CStest=RC7;
	SDOtest=RC5;
	SDItest=RC4;
	SCKtest=RC3;
	BFtest=BF;
	
//	W = 0x00;
//	bank0 SSPBUF = W;
	
//	while(!BF);   //Even i put out the code. Still stuck at here. Cannot get out of the loop
//	dummy = SSPBUF;

	WREN ();	
	write_data(0x00, 0x00, 0xAB);	
	Temp = read_data(0x00, 0x00);
	
	if(Temp==0xAB)	{		
		BLUE=1;
		GREEN = 0;
		RED = 1;
	}		
	else{
		BLUE=1;
		GREEN = 1;
		RED = 0;
	}
}	



//----------------------------------Initialization-------------------------------//				

void Init(void)
{
	OSCCON = 0b00100000;   // Internal 8Mhz @PLL 

	//*Port Description*//
//------------------------------------------------------------------------
//      7	6	5	4	3	2	1	0  	 |
//      --	--	--	--	--	--	--	--       |
//PortA	Buzzer	DS	CPS7(1)	CPS6(4)	LRED	LGREEN	LBLUE	Cap4(1uF)|
//PortB	PGD	PGC	CPS5(7)	CPS4(*)	CPS3(2)	CPS2(5)	CPS(8)	CPS(0)	 |
//PortC	CE	-	MOSI	MISO	SCLCK	ALRM	LOCK	-	 |
//PortD	LS0H	L789	L456	L321	CPS11(3)CPS10(6)CPS9(0)	CPS8(#)  |
//PortE                                 MCLR	D0	D1	 -       |
//------------------------------------------------------------------------
	
	TRISA	= 0b01110000;	//Setting for input=1 or output=0
	ANSELA	= 0b01110000;	//Setting for analogue=1 or digital=0

	TRISB	= 0b00111111;
	ANSELB	= 0b00001111;

	TRISC	= 0b00010001;
	
	TRISD	= 0b00111111;
	ANSELD	= 0b00111111;

	TRISE	= 0b1000;
	ANSELE	= 0b0000;
	
	POR = 1; //No Power-on Reset occured
	
	//Read - SSP control register (Default) bit 0 to 3 need to be set at 0000 for highest SPI speed
	SSPCON = 0b00110000;
	// bit3-0  |||||____ SSPM<3:0>: Synchronous Serial Port Mode Select bits. 0000 = SPI Master mode, clock = FOSC/4
	// bit4  * ||||_____ CKP: Clock Polarity Select bit, 1 = Idle state for clock is a high level. 0 = Idle state for clock is a low level
	// bit5    |||______ SSPEN: Synchronous Serial Port Enable bit. 1 = Enables serial port and configures SCK, SDO and SDI as serial port pins(1)
	// bit6    ||_______ SSPOV: Receive Overflow Indicator bit. 0 = No overflow
	// bit7    |________ WCOL: Write Collision Detect bit. 0 = No collision
	
	//SSPSTAT: SYNC SERIAL PORT STATUS REGISTER (SPI Mode)
	SSPSTAT= 0b01000000;	//SSP status register (Synchronous Serial Port)
	// bit7    ||||||||_ BF: Buffer Full Status bit. 0 = Receive not complete, SSPBUF is empty.
	// bit6    |||||||__ No use. Used in I2C mode only.
	// bit5    ||||||___ "
	// bit4    |||||____ "
	// bit3    ||||_____ "
	// bit2    |||______ "
	// bit1 *  ||_______ CKE: SPI Clock Edge Select bit. 1 = Data stable on falling edge of SCK
	// bit0 *  |________ SMP: SPI Data Input Sample Phase bit. SPI Master mode: 0 = Input data sampled at middle of data output time.
	
	//SSPEN = 1 //Turn on SSP module
	SSPIF	= 0;	// Synchronous Serial Port Interrupt Flag bit
	SSPIE	= 1;	// Synchronous Serial Interrupt Enable bit
	PEIE	= 1;	// Peripheral Interrupt Enable bit

	//Interupt Enable
	GIE = 1;

	BLUE=1;
	RED=1;
	GREEN=1;	

}

/************************************************************************************/
/*   WREN(void): Write Enable (Instruct EEPROM by giving input of 0x06)			
/************************************************************************************/
void WREN ()
{
	CS=0;	//Chip Select
	dummy = SPI_OUTPUT(0x06); //Set write enable latch
	CS=1;	//Chip Deselect
}

/************************************************************************************/
/*   RDSR(void):Read Status Register (Instruct EEPROM by giving input of 0x05)	
/************************************************************************************/
char RDSR ()
{
	CS=0;
	dummy = SPI_OUTPUT(0x05);
	CS=1;
	return dummy;
}


/***********************************************************************************/
/*   WRSR(void):Write Status Register (Instruct EEPROM by giving input of 0x01)
/***********************************************************************************/
void WRSR()
{
	CS=0;
	dummy = SPI_OUTPUT(0x01);
	dummy = SPI_OUTPUT(0x00); //**Maybe no use
	CS=1;
}


/***********************************************************************************/
/*   write_data(char *H_addr, char *L_addr, char *data)	
/*   Write instruction 0x02 to the EEPROM first.			
/*   Write data of 'data' to 'H_addr & L_addr)	
/***********************************************************************************/
void write_data(char H_addr, char L_addr, char data)
{

	CS=0;
	dummy =	SPI_OUTPUT(0x02);
	H_addr |= 0x8; 
	dummy = SPI_OUTPUT (H_addr);
	dummy = SPI_OUTPUT (L_addr);
	dummy = SPI_OUTPUT (data);
	
	CS=1;
}

/**********************************************************************************/
/*   SPI_OUTPUT(char spi_byte)		
/*   Output to SSPBUF and wait till all transfered into SSPSR 	   
/*   Check if BF Full. (BF full = complete_)	          
/**********************************************************************************/
char SPI_OUTPUT (char spi_byte)
{
	if(WCOL) WCOL = 0;
	if(SSPOV) SSPOV = 0;
	
	SSPBUF = spi_byte;
	
	//do{}
	while(!BF); //Get stuck here
	return SSPBUF;	
}

/*********************************************************************************/
/*   read_data(char *H_addr, char *L_addr)	
/*   Write instruction 0x03 to the EEPROM first.
/*   Read from to H_addr & L_addr. Additional 0x00 is to push 'data' out
/*********************************************************************************/
char read_data(char H_addr, char L_addr)	//use low and high add
{	
	CS=0; 
	dummy = SPI_OUTPUT(0x03);
	dummy = SPI_OUTPUT(H_addr);
	dummy = SPI_OUTPUT(L_addr);
	CKP=0;
	spi_received = SPI_OUTPUT(0x00);
	CS=1;
	return spi_received;
}

Thank you.
 
I had a quick look and the a couple of things stood out,

This line is wrong,
Code:
	OSCCON = 0b00100000;   // Internal 8Mhz @PLL
The above will select 500kHz clock.

You are enabling interrupts without an ISR.
Code:
	SSPIF	= 0;	// Synchronous Serial Port Interrupt Flag bit
	SSPIE	= 1;	// Synchronous Serial Interrupt Enable bit
	PEIE	= 1;	// Peripheral Interrupt Enable bit

	//Interupt Enable
	GIE = 1;

Are you debugging this on actual hardware or with the simulator?

Mike.
 
Hi, thanks for ur reply. But i had enable PLLEN = 1 (16 MHz INTOSC) in the configuration word. And i refer to the PIC16F727 datasheet
When PLLEN = 1 (16 MHz INTOSC)
11 = 16MHz
10 = 8 MHz (POR value)
01 = 4MHz
00 = 2MHz.

Can i use SPI without using interrupt? Actually im doin the capacitance sense button. when a sequence of no. key in it will store to the eeprom.
The cap. sense already use interrupt method to detect. Do MPLAB IDE having simulator to debug without using hardware? (This is my first time deal with PIC)

And im using hardware to debug. Thanks.
 
WOW, Microchip have two documents with the following names, Pic16F7x7 datasheet and Pic16F72x datasheet. I was looking at the first one as the name suggests it covers the 16F727. How stupid is that. You are, of course, correct about the oscillator.

You can use SPI without interrupts but you can't use interrupts without an Interrupt Service Routine (ISR). When an interrupt is enabled and it gets triggered (by BF) then the code will immediately jump to location 4 and crash.

Mike.
 
Why do you have to use interrupts? You can just poll when needed.

Try turning interrupts off,
Code:
    //SSPEN = 1 //Turn on SSP module
    SSPIF	= 0;	// Synchronous Serial Port Interrupt Flag bit
    //SSPIE	= 1;	// Synchronous Serial Interrupt Enable bit
    PEIE	= 1;	// Peripheral Interrupt Enable bit

    //Interupt Enable
    //GIE = 1;
And poll the interrupt flag instead of BF,
Code:
char SPI_OUTPUT (char spi_byte)
{
    if(WCOL) WCOL = 0;
    if(SSPOV) SSPOV = 0;
    SSPIF=0;	
    SSPBUF = spi_byte;
    while(!SSPIF);
    return SSPBUF;	
}

Your code (using BF) will probably work anyway so it may be worth trying.

Mike.
 
Last edited:
Still cannot get out of the loop. Anyway thanks for your help.
I have to use interrupt, because other function was using it. (I cut it out, because its to lengthy)
 
I have a 16F886 setup on a dev borad and so tried this and it works fine,
Code:
void main(void){
char dummy;
    while(!osccon.HTS);
    osccon=0x71;            //8 meg
    ansel=0;
    anselh=0;
    option_reg=0b00000000;  //wpu on
    trisc.5=0;
    trisc.3=0;
    trisc.4=1;
    sspcon=0x30;
    sspstat=0x40;
    sspbuf=0x55;
    while(!sspstat.BF);
    dummy=sspbuf;
    while(1);
}
However, it only worked after I powered down the target circuit. It's as though the SSSP module can crash.

The above is BoostC but you should be able to follow it.

Mike.
 
Hi Mike, thanks for ur reply. The concept of your code is same as the code i wrote. I had consult mine local PIC representative. He said he couldn't see any problem of the code and he told me to check the connection from the PIC to the EEPROM. So i check it and all the connection are correct. He also call me to check the PIC pin waveform. All was OK.

Is it the other setting disable and crash with the SPI setting make it unable to function.
Will check on other setting.

And im using MPLAB IDE v8.50 and HI-TECH ANSI C Compiler and MPLAB @ ICD 2 LE In-circuit Debugger.

Any way thanks Mike.
 
Last edited:
I found what cause the problem. Once the SSPBUF receive and ready for 8bit data the SSPIF will be set and at the same time the data will shift out bit by bit. I did not clear the SSPIF cause the processor keep on checking on the interrupt function and get stuck.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…