View previous topic :: View next topic |
Author |
Message |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
SPI on PIC16F876 and EEPROM |
Posted: Thu Oct 06, 2016 2:04 pm |
|
|
Having some problems with my EEPROM project Using the SPI on the PIC16F876 and a M95160-WMN6TP EEPROM. The link to the datasheet is
http://www.st.com/content/ccc/resource/technical/document/datasheet/d4/5d/8e/0a/e0/c6/4a/c2/DM00043980.pdf/files/DM00043980.pdf/jcr:content/translations/en.DM00043980.pdf
I seem to only read back zeros even when I have hard coded a value to write out as in this code snippet.
Code: |
#FUSES XT,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NOLVP,NODEBUG
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=PIN_C6, rcv=PIN_C7,stream=USB_SERIAL,ERRORS)
/*
*********************************************************************************************
* DEFINES
*********************************************************************************************
*/
#DEFINE INTS_PER_SEC 15
#DEFINE EEPROM_W PIN_B0 // WRITE CONTROL
#DEFINE EEPROM_HOLD PIN_C0 // HOLD
#DEFINE EEPROM_S PIN_A5 // CHIP ENABLE
#DEFINE EEPROM_DELAY 250 // used to give a 250uS delay between key steps in read and write proceedures.
#DEFINE SPI_MODE_0_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#DEFINE SPI_MODE_0_1 (SPI_L_TO_H)
#DEFINE SPI_MODE_1_0 (SPI_H_TO_L)
#DEFINE SPI_MODE_1_1 (SPI_H_TO_L | SPI_XMIT_L_TO_H) |
my read function is:
Code: |
BYTE read_ext_eeprom(long address)
{
int8 data;
while(!ext_eeprom_ready());
output_low(EEPROM_S);
spi_write(0x03);
spi_write(address >> 8);
spi_write(address);
data = spi_read();
output_high(EEPROM_S);
return(data);
} |
my write function is:
Code: |
void write_ext_eeprom(long address, BYTE data)
{
while(!ext_eeprom_ready());
output_low(EEPROM_S);
spi_write(0x06);
output_high(EEPROM_S);
output_low(EEPROM_S);
spi_write(0x02);
spi_write(address >> 8);
spi_write(address);
spi_write(data);
output_high(EEPROM_S);
} |
my initialization function is:
Code: |
void INIT_HARDWARE() {
// This function sets the interrupts up, and initializes the EEPROM inputs.
set_rtcc(0);
setup_counters( RTCC_INTERNAL, RTCC_DIV_256 ); //15 interrupts/sec
enable_interrupts(INT_RTCC); // set up the RTCC counter
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL); // turn on all interrupts.
setup_adc_ports(NO_ANALOGS);
output_high(EEPROM_S);
output_high(EEPROM_W);
output_high(EEPROM_HOLD);
setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_64 );
} //end INIT_HARDWARE()
|
My eeprom ready check function is
Code: |
int1 ext_eeprom_ready(void)
{
int8 data;
output_low(EEPROM_S);
spi_write(0x05);
data = spi_read();
output_high(EEPROM_S);
return(!bit_test(data, 0));
}
|
My read eeprom portion of the main is
Code: |
base_address = 0;
for(i=0;i<100;i++) {
value = read_ext_EEPROM((base_address+i));
fprintf(USB_SERIAL,"%d\t",value);
}
|
My write eeprom portion of the main is
Code: |
srand(get_rtcc());
random_start = (int)(rand());
random_start = 8;
base_address = 0;
for(i=0;i<100;i++) {
write_ext_EEPROM(base_address+1,random_start+i);
}
|
Note that in the write portion of the main, I hard coded writing a constant out for the start number instead of rand() as a check, but still only read back zeros. Open for ideas here, checking hardware now, I have installed a new chip with the same results.
My SPI lines are tied as follows.
RC5/SDO is tied to D on the EEPROM
RC4/SDI is tied to Q on the EEPROM
RC3/SCK is tied to C on the EEPROM
Slave Select A5 is connected to S on the EEprom
The write enable line and hold line are both tied high.
Thanks all. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Thu Oct 06, 2016 4:33 pm |
|
|
You should really post your entire program not 'snippets' here and there. It's too busted up to see the 'flow'. Just code for the EEPROM device to test it. Get rid of 'other' code like timers and 'stuff' ,concentrate on JUST the EEPROM driver.
Also delete the rand function ! While you say you've hard coded ,just remove that code(rand) to make the program simpler and easier to follow...
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 06, 2016 5:15 pm |
|
|
Your main problem is that to read a data byte from the eeprom, the
master PIC must send 8 clocks (to get 8 bits). To do this, you must
give the spi_read() function a parameter. This is in the CCS manual.
Just use 0 as the parameter. Example:
Code: | result = spi_read(0); |
There are several places in your program where this needs to be fixed. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Fri Oct 07, 2016 9:43 am |
|
|
Continuing on with this problem. changed the spi_read() to spi_read(0) as recommended.
still not getting expected data when reading back from the EEPROM.
Here is a stripped version of my code,
Code: |
/*
*********************************************************************************************
* INCLUDES and CONTROLLER SETTINGS
*********************************************************************************************
*/
#include <16f876.h>
#include <stdlib.h>
#FUSES XT,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NOLVP,NODEBUG
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=PIN_C6, rcv=PIN_C7,stream=SERIAL,ERRORS)
/*
*********************************************************************************************
* DEFINES
*********************************************************************************************
*/
#DEFINE INTS_PER_SEC 15
#DEFINE EEPROM_W PIN_B0 // WRITE CONTROL
#DEFINE EEPROM_HOLD PIN_C0 // HOLD
#DEFINE EEPROM_S PIN_A5 // CHIP ENABLE
#DEFINE EEPROM_DELAY 250 // used to give a 250uS delay between key steps in read and write proceedures.
#DEFINE SPI_MODE_0_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#DEFINE SPI_MODE_0_1 (SPI_L_TO_H)
#DEFINE SPI_MODE_1_0 (SPI_H_TO_L)
#DEFINE SPI_MODE_1_1 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
/*
*********************************************************************************************
* GLOBAL VARIABLES
*********************************************************************************************
*/
int i=0;
int host_found_flg = 0;
int terminate_flg = 0;
int read_flg = 0;
int random_start = 0;
int write_flg = 0;
long base_address = 0; // EEPROM start address for block read and write.
int value = 0;
byte seconds; // a running seconds counter.
byte data_ticker=0; // used to set the rate at which Flow data is sent to the host.
byte int_15ths_count=15;
/*
*********************************************************************************************
* FUNCTIONS
*********************************************************************************************
+*/
//***************************************************************************
// RTCC INTERRUPT ROUTINE
//
// This routine interrupts 15 times per second.
// Every 3rd interrupt is 200mS exactly It is not used that way, just the math comes out that way if needed.
#int_rtcc
void clock_isr() { //This function is called every time the rtcc rolls.
//The RTCC rolls 15 times per second.
//This function keeps track of quarter seconds (every 15 rolls of the rtcc.
int_15ths_count = int_15ths_count - 1;
//average_index = average_index + 1; // used for current averaging.
if(int_15ths_count==0) { // fractional second has happened.
seconds = seconds + 1;
data_ticker = data_ticker + 1; // used for sending Flow data to host.
int_15ths_count = INTS_PER_SEC;
} // end if
} // end clock_isr()
// END RTCC INTERRUPT ROUTINE.
#int_rda
void serial_isr() {
// Reads incoming data from the USART and puts it in a buffer
disable_interrupts(int_rda);
disable_interrupts(int_rtcc);
char cChar;
cChar = fgetc(SERIAL);
//fprintf(SERIAL,"%c",cChar);
serial_buffer[buffer_index] = cChar; // put the char in the buffer.
//fprintf(SERIAL,"*");
//fprintf(SERIAL,"%c",serial_buffer[buffer_index]);
//fprintf(SERIAL,"*");
//fprintf(SERIAL,"\n\r");
buffer_index = buffer_index + 1; // index to next buffer location.
if(cChar == '#') { // The message is complete.
msg_complete_flg = 1;
//serial_buffer[buffer_index] = '\0'; // end of string char
buffer_index = 0; // reset buffer index to zero for next message.
} // end if
else {
msg_complete_flg = 0;
}
//serial_buffer[1] = 'M';
enable_interrupts(int_rtcc);
enable_interrupts(int_rda);
} // end serial_isr()
void SEND_GREETING() {
// This function sends a greeting to the host when called.
fprintf(SERIAL,"**EEPROM TEST 2016**#\n\r");
} // end SEND_GREETING()
char convert_2_char(int the_int) {
// converts an int from 0 - 9 to ASCII char.
char the_char = ' ';
the_char = '0' + the_int;
return the_char;
} // end convert_2_char();
//***************************************************************************
// INITIALIZE CONTROLLER HARDWARE
//
//
//
//***************************************************************************
void INIT_HARDWARE() {
// This function sets the interrupts up, and initializes the EEPROM inputs.
set_rtcc(0);
setup_counters( RTCC_INTERNAL, RTCC_DIV_256 ); //15 interrupts/sec
enable_interrupts(INT_RTCC); // set up the RTCC counter
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL); // turn on all interrupts.
setup_adc_ports(NO_ANALOGS);
output_high(EEPROM_S);
output_high(EEPROM_W);
output_high(EEPROM_HOLD);
setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_64 );
} //end INIT_HARDWARE()
int1 ext_eeprom_ready(void)
{
int8 data;
output_low(EEPROM_S);
spi_write(0x05);
data = spi_read(0);
output_high(EEPROM_S);
return(!bit_test(data, 0));
}
void write_ext_eeprom(long address, BYTE data)
{
while(!ext_eeprom_ready());
output_low(EEPROM_S);
spi_write(0x06);
output_high(EEPROM_S);
output_low(EEPROM_S);
spi_write(0x02);
spi_write(address >> 8);
spi_write(address);
spi_write(data);
output_high(EEPROM_S);
}
//--------------------------------
BYTE read_ext_eeprom(long address)
{
int8 data;
while(!ext_eeprom_ready());
output_low(EEPROM_S);
spi_write(0x03);
spi_write(address >> 8);
spi_write(address);
data = spi_read(0);
output_high(EEPROM_S);
return(data);
}
void main() {
base_address = 0;
SEND_GREETING();
init_hardware();
buffer_index = 0;
while(1) { // Endless loop.
host_found_flg = 0;
terminate_flg = 0;
while(!host_found_flg) {
if(seconds >= 1) { // send greeting every second to host.
seconds = 0;
SEND_GREETING();
} // end if
if(serial_buffer[0] == '%') { // host has made contact.
host_found_flg = 1; // get out of this wait loop.
}
} // end host found loop
msg_complete_flg = 0;
buffer_index = 0;
while(!terminate_flg) {
// ********** write out to EEPROM ******************
if(write_flg ==1) { // do this if the 'W' command is sent.
random_start = 1;
base_address = 0;
for(i=0;i<100;i++) {
write_ext_EEPROM(base_address+1,random_start+i);
delay_ms(10);
}
write_flg = 0;
}
if(read_flg == 1) { // read and send the stored data.
// Data starts at 0000 and is 1 byte each number.
base_address = 0;
for(i=0;i<100;i++) {
value = read_ext_EEPROM((base_address+i));
fprintf(SERIAL,"%d\t",value);
}
read_flg = 0;
}
} // end !terminate_flg while loop.
} // end endless while loop
} // end main.
|
the write_flg and read_flg variables are set by code I removed as it is working and has to do with the serial stream and buffers. All is well there, getting into the correct read or write sections of code, just not working right with EEPROM. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Fri Oct 07, 2016 9:53 am |
|
|
my compiler specifics are:
CCS PCM C Compiler, Version 5.026 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 07, 2016 2:30 pm |
|
|
Quote: | still not getting expected data when reading back from the EEPROM. |
Post the written data and the data that you read back.
At least post it for the first few addresses.
Also,
Read the status register and print it as a hex value.
What is its value ?
This function reads the status register. You can put a printf inside it
temporarily to display the value read:
|
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Fri Oct 07, 2016 2:52 pm |
|
|
with the code I have, a '1' is written out and this is what is in the written addresses:
-1 100 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1
excuse the format. looks like 100 written to one location, then -1 everywhere else. if the number is increased to 2 then the number is 101 and all other locations are -1 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 07, 2016 2:53 pm |
|
|
Please change your printf format to %x so the results will be displayed
in hex.
And show me the status register contents. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Fri Oct 07, 2016 2:57 pm |
|
|
looks like the status register is reading back a zero.
so monday I will look at signals with a scope. I verified my PCB and wiring and put a new chip on yesterday, so open for ideas but for now monday I will look at signals. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Fri Oct 07, 2016 3:03 pm |
|
|
hex formatted output:
ff 64 ff ff ff ff ff ff ff ff f
f ff ff ff ff ff ff ff ff ff f
f ff ff ff ff ff ff ff ff ff f
f ff ff ff ff ff ff ff ff ff f
f ff ff ff ff ff ff ff ff ff f
f ff ff ff ff ff ff ff ff ff f
f ff ff ff ff ff ff ff ff ff f
f ff ff ff ff ff ff ff ff ff f
f ff ff ff ff ff ff ff ff ff f
f ff ff ff ff ff ff ff ff ff |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 07, 2016 4:56 pm |
|
|
As a test, why don't you try the following modification. Comment the
existing code and add the two lines shown in bold in the routine below:
Quote: | int1 ext_eeprom_ready(void)
{
/*
int8 data;
output_low(EEPROM_S);
spi_write(0x05);
data = spi_read(0);
output_high(EEPROM_S);
return(!bit_test(data, 0));
*/
delay_ms(10); // Spec'ed value is 5 ms. Set it to 10 ms for safety.
return(1);
}
|
See if that gives a different result. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Mon Oct 10, 2016 6:25 am |
|
|
no difference in commenting out the code and adding the suggested two lines.
today I will be looking around with the scope. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Mon Oct 10, 2016 12:49 pm |
|
|
well all signals look correct and clean with a scope. not sure what the problem is here, anyone got any more ideas? I am getting close to admitting defeat (something that I hate) and trying to use internal memory of the 16F876 to store my data. I am only needing about 12 bytes. (3 negative floats) |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 10, 2016 12:55 pm |
|
|
Where did you buy the eeproms ?
What is the actual part number printed on the IC package itself ?
Post everything that's printed on the IC. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Mon Oct 10, 2016 1:42 pm |
|
|
Digikey , chip reads:
95160WP
K612R |
|
|
|