Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Help with SPI EEPROM

Status
Not open for further replies.

MrNobody

New Member
Hi,
Below is the code to write "8" into SPI eeprom and then read "8" back and store it in "data1". However, "data1" is always 0 no matter what i write to the eeprom. Attached is my circuit in Proteus. Please advice..

Code:
#include <p18F4620.h>
#include <delays.h>
#include <spi.h>
#include <usart.h>
#include <stdio.h>

#pragma config WDT = OFF
#pragma config MCLRE = ON
#pragma config LVP = OFF
#pragma config OSC = HSPLL
#define CLOCK_FREQ		(40000000ul)      // Hz 

#define CSEE PORTCbits.RC0 // select line for Serial EEPROM

#define SEE_WRSR 	1 // write status register
#define SEE_WRITE 	2 // write command
#define SEE_READ 	3 // read command
#define SEE_WDI 	4 // write disable
#define SEE_STAT 	5 // read status register
#define SEE_WEN 	6 // write enable


void SPIEEPROMInit();
void UARTInit();

int writeSPI( int data)
{
	SSPBUF = data; // write to buffer for TX
	while( !SSPSTATbits.BF ) // wait for transfer to complete
	return SSPBUF; // read the received value
}//writeSPI

void main()
{
        int data1, data2, i;	
	SPIEEPROMInit();
	UARTInit();


	// send a Write command
	CSEE = 0; // select the Serial EEPROM
	writeSPI( SEE_WRITE); // send command, ignore immediate data
	writeSPI( 0); // send MSB of memory address
	writeSPI( 1); // send LSB of memory address
	writeSPI( 8 ); // send the actual data to be written
	CSEE = 1; // start actual EEPROM write cycle

	// send a Write command
	CSEE = 0; // select the Serial EEPROM
	writeSPI( SEE_READ); // send command, ignore immediate data
	writeSPI( 0); // send MSB of memory address
	writeSPI( 1); // send LSB of memory address
	Delay10KTCYx(1);
	data1 = writeSPI( 0); // send dummy, read data
	
	CSEE = 1; // terminate the read sequence, return to low power
  	
while (1);
}

void SPIEEPROMInit()
{
	SSPSTAT = 0xC0; //SPI Bus mode 0,0
	SSPCON1 = 0x21; //Enable SSP,Fosc/16

	DDRCbits.RC7 = 0; //Define CS as Output
	DDRCbits.RC3 = 0; //Define SCK as Output
	DDRCbits.RC4 = 1; //Define SDI as Input
	DDRCbits.RC5 = 0; //Define SDO as Output
	CSEE = 1; // start actual EEPROM write cycle
}


void UARTInit()
{
	SPBRG = 64;
	TXSTA = 0b00100010;
	RCSTA = 0b10010000;
	BAUDCON = 0b00000000;
	TRISCbits.TRISC7 = 1;
	TRISCbits.TRISC0 = 0;
}
 
attached is the schematic.
 

Attachments

  • SPI_EEPROM.png
    SPI_EEPROM.png
    325 KB · Views: 2,090
Are you sure that the data comes back at the same time you are writing the low order address in the read routine?

Why are you using `int' variables when in all probability SSPBUF is byte wide register?
 
Last edited:
mrmonteith:
below is the updated code with WRITE ENABLE and WRITE DISABLE command.. However, eventhough I add the command, i still do not receive any data from EEPROM..

Code:
#include <p18F4620.h>
#include <delays.h>
#include <spi.h>
#include <usart.h>
#include <stdio.h>

#pragma config WDT = OFF
#pragma config MCLRE = ON
#pragma config LVP = OFF
#pragma config OSC = HSPLL
#define CLOCK_FREQ		(40000000ul)      // Hz 

#define CSEE PORTCbits.RC0 // select line for Serial EEPROM

#define SEE_WRSR 	1 // write status register
#define SEE_WRITE 	2 // write command
#define SEE_READ 	3 // read command
#define SEE_WDI 	4 // write disable
#define SEE_STAT 	5 // read status register
#define SEE_WEN 	6 // write enable


void SPIEEPROMInit();
void UARTInit();

int writeSPI( int data)
{
	SSPBUF = data; // write to buffer for TX
	while( !SSPSTATbits.BF ) // wait for transfer to complete
	return SSPBUF; // read the received value
}//writeSPI2

void main()
{
int data1, data2, i;	
	SPIEEPROMInit();
	UARTInit();


	// send a Write command
	CSEE = 0; // select the Serial EEPROM
	writeSPI( SEE_WEN); // send command, ignore immediate data
	writeSPI( SEE_WRITE); // send command, ignore immediate data
	writeSPI( 0); // send MSB of memory address
	writeSPI( 10 ); // send the actual data to be written
	CSEE = 1; // start actual EEPROM write cycle
	
        // send a Write command
	CSEE = 0; // select the Serial EEPROM
	writeSPI( SEE_READ); // send command, ignore immediate data
	writeSPI( 0); // send MSB of memory address
	writeSPI( 1); // send LSB of memory address
	data1 = writeSPI( 0); // send dummy, read data
	writeSPI( SEE_WDI); // send command, ignore immediate data
	CSEE = 1; // terminate the read sequence, return to low power
  	
while (1);
}

void SPIEEPROMInit()
{
	SSPSTAT = 0xC0; //SPI Bus mode 0,0
	SSPCON1 = 0x21; //Enable SSP,Fosc/16

	DDRCbits.RC7 = 0; //Define CS as Output
	DDRCbits.RC3 = 0; //Define SCK as Output
	DDRCbits.RC4 = 1; //Define SDI as Input
	DDRCbits.RC5 = 0; //Define SDO as Output
	CSEE = 1; // start actual EEPROM write cycle
}


void UARTInit()
{
	SPBRG = 64;
	TXSTA = 0b00100010;
	RCSTA = 0b10010000;
	BAUDCON = 0b00000000;
	TRISCbits.TRISC7 = 1;
	TRISCbits.TRISC0 = 0;
}


Papabravo:
Are you sure that the data comes back at the same time you are writing the low order address in the read routine?
I am not sure.. how do i know..?
As for 'int' instead of 'byte', well.. eventhough it is 'int', if the EEPROM send data, PIC should at least receive something eventhough it is 'int' right..?
 
You have to deselect the EEPROM after sending the WEN command or it is ignored.

Mike.
 
MrNobody said:
Papabravo:

I am not sure.. how do i know..?
As for 'int' instead of 'byte', well.. eventhough it is 'int', if the EEPROM send data, PIC should at least receive something eventhough it is 'int' right..?
The way you wrote the code you assume that the data byte that you return from the read is available to you on the same 8-bit transaction where you are writing the low order address byte. I think it is unlikely that your assumption is correct. It is more likely that the data will be returned to you on the NEXT transaction after sending the address when you send a dummy byte to the part and get back the data.

Weather the `int' / `byte' situation makes a difference depends on your compiler. Have you looked at the assembly language code generated by the compiler to confirm that you know what the compiler is doing?

You know what the part is doing and how to talk to it by VERY CAREFULLY reading and understanding the datasheet. It seems possible that you were in too big a hurry to have taken the time to do a thourough job of digesting the available information. So slow down, take some time, and go back and do the due diligence.
 
Hi..
I have spent hours and hours looking at the datasheet and trying to understand the waveform..
Finally i manage to get the correct reply from the eeprom.. I sent "0b10101010" to the eeprom (in Proteus) and when I monitor the signal using oscilloscope, i can see "0b10101010" from the eeprom..

However, when I check the SSPBUF register, it remains 0. Can anybody please help me with this final step of how I can receive the data and store in a variable..? By the way, I am using Microchip C18..

Below is the complete code and attached is the signal showing the whole read sequence.

Oh.. by the way, in the picture, the MSB of the SO signal looks weird.. It is suppose to be 0b10101010 (8 bits) but it looks like 0b110101010 (9 bits).. Anybody knows why it is that way..?
Thanks..

Code:
#include <p18F4620.h>
#include <delays.h>
#include <spi.h>
#include <usart.h>
#include <stdio.h>

#pragma config WDT = OFF
#pragma config MCLRE = ON
#pragma config LVP = OFF
#pragma config OSC = HSPLL
#define CLOCK_FREQ		(40000000ul)      // Hz 

#define CSEE PORTCbits.RC0 // select line for Serial EEPROM

#define SEE_WRSR 	1 // write status register
#define SEE_WRITE 	2 // write command
#define SEE_READ 	3 // read command
#define SEE_WRDI 	4 // write disable
#define SEE_STAT 	5 // read status register
#define SEE_WREN 	6 // write enable


void SPIEEPROMInit();
void UARTInit();

void writeSPI()
{
	CSEE = 0;
	SSPBUF = SEE_WREN; 			// write to buffer for TX
	while( !SSPSTATbits.BF ); 	// wait for transfer to complete
	CSEE = 1;					// brought high to set write enable latch
	Delay1TCY();				// 100ns delay. minimum delay is 50ns.

	CSEE = 0;
	SSPBUF = SEE_WRITE;
	while( !SSPSTATbits.BF );	// wait for transfer to complete
	SSPBUF = 0b00000000;		// First address byte
	while( !SSPSTATbits.BF ); 	// wait for transfer to complete
	SSPBUF = 0b00000010;		// Second address byte
	while( !SSPSTATbits.BF ); 	// wait for transfer to complete
	SSPBUF = 0b10101010;		// Write data
	while( !SSPSTATbits.BF ); 	// wait for transfer to complete
	CSEE = 1;					// To start writing
	Delay10KTCYx(5);			// Internal write cycle time of 5ms
	
	CSEE = 0;
	SSPBUF = SEE_WRDI;
	while( !SSPSTATbits.BF );	// wait for transfer to complete
	CSEE = 1;
}//writeSPI

int readSPI()
{
	CSEE = 0;
	SSPBUF = SEE_READ;
	while( !SSPSTATbits.BF );	// wait for transfer to complete
	SSPBUF = 0b00000000;		// First address byte
	while( !SSPSTATbits.BF ); 	// wait for transfer to complete
	SSPBUF = 0b00000010;		// Second address byte
	while( !SSPSTATbits.BF ); 	// wait for data received
	Delay1TCY();
	SSPBUF = 0b00000000;		// Send dummy byte
	while( !SSPSTATbits.BF ); 	// wait for data received
	CSEE = 1;					// Stop receiving
	return SSPBUF;
}//readSPI

void main()
{
int data1, data2, i;	
	SPIEEPROMInit();
	UARTInit();



  	
while (1)
{
	writeSPI();
	Delay10KTCYx(100);			//Delay 1ms
	data1 = readSPI();
	Delay10KTCYx(100);			//Delay 1ms
}
}

void SPIEEPROMInit()
{
	SSPSTAT = 0xC0; //SPI Bus mode 0,0
	SSPCON1 = 0x21; //Enable SSP,Fosc/16

	DDRCbits.RC7 = 0; //Define CS as Output
	DDRCbits.RC3 = 0; //Define SCK as Output
	DDRCbits.RC4 = 1; //Define SDI as Input
	DDRCbits.RC5 = 0; //Define SDO as Output
	CSEE = 1; / 
}


void UARTInit()
{
	SPBRG = 64;
	TXSTA = 0b00100010;
	RCSTA = 0b10010000;
	BAUDCON = 0b00000000;
	TRISCbits.TRISC7 = 1;
	TRISCbits.TRISC0 = 0;
	TRISCbits.TRISC1 = 0;
}
 

Attachments

  • SPI_EEPROM_Read.png
    SPI_EEPROM_Read.png
    49 KB · Views: 399
Oh.. by the way, below are the rest of the waveform for different commands, for those who are interested.
 

Attachments

  • SPI_EEPROM_WREN.png
    SPI_EEPROM_WREN.png
    35.9 KB · Views: 290
  • SPI_EEPROM_WRITE.png
    SPI_EEPROM_WRITE.png
    40.4 KB · Views: 267
  • SPI_EEPROM_WRDI.png
    SPI_EEPROM_WRDI.png
    31.3 KB · Views: 260
The C18 compiler provides some functions for hardware SPI that you might use in your code. Also, you might study app note 995. Very useful reading!

The getcSPI() function reads a byte from the SPI bus; the WriteSPI(unsigned char) function sends a command to the SPI bus.

For example, reading a byte from the slave device should be achieved with the following function:

Code:
unsigned char var;

//...

unsigned char spi_read(unsigned char HAddr, unsigned char LAddr)
{
  CSEE = 0;                           
  WriteSPI(0x03);    // WriteSPI is defined in "spi.h"
  WriteSPI(Hddr);
  WriteSPI(LAddr); 
  var = getcSPI();   // getcSPI is defined in "spi.h"
  CSEE = 1;          
  return var;                       
}
 
Last edited:
eng1 said:
The C18 compiler provides some functions for hardware SPI that you might use in your code. Also, you might study app note 995. Very useful reading!

The getcSPI() function reads a byte from the SPI bus; the WriteSPI(unsigned char) function sends a command to the SPI bus.

For example, reading a byte from the slave device should be achieved with the following function:

Code:
unsigned char var;

//...

unsigned char spi_read(unsigned char HAddr, unsigned char LAddr)
{
  CSEE = 0;                           
  WriteSPI(0x03);    // WriteSPI is defined in "spi.h"
  WriteSPI(Hddr);
  WriteSPI(LAddr); 
  var = getcSPI();   // getcSPI is defined in "spi.h"
  CSEE = 1;          
  return var;                       
}
Thanks.. i have that app note.. will look at it again..
 
Check the the AN995 Source Code, it does exactly what you want.
Also check section 2.8.2 in the C18 libraries guide.

Hope this helps.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top