CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

SPI on PIC16F876 and EEPROM
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
beaker404



Joined: 24 Jul 2012
Posts: 163

View user's profile Send private message

SPI on PIC16F876 and EEPROM
PostPosted: Thu Oct 06, 2016 2:04 pm     Reply with quote

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: 9246
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Oct 06, 2016 4:33 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 06, 2016 5:15 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Oct 07, 2016 9:43 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Oct 07, 2016 9:53 am     Reply with quote

my compiler specifics are:

CCS PCM C Compiler, Version 5.026
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 07, 2016 2:30 pm     Reply with quote

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:
Code:
ext_eeprom_ready()
beaker404



Joined: 24 Jul 2012
Posts: 163

View user's profile Send private message

PostPosted: Fri Oct 07, 2016 2:52 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Oct 07, 2016 2:53 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Oct 07, 2016 2:57 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Oct 07, 2016 3:03 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Oct 07, 2016 4:56 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 10, 2016 6:25 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 10, 2016 12:49 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 10, 2016 12:55 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 10, 2016 1:42 pm     Reply with quote

Digikey , chip reads:

95160WP
K612R
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group