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

problems accessing 25LC160D external EEPROM via SPI

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

problems accessing 25LC160D external EEPROM via SPI
PostPosted: Sat Aug 15, 2009 9:09 am     Reply with quote

I'm trying to use software SPI to write and read the Microchip 25LC160D eeprom. Compiler is 4.083 and chip is 18F6723. I think I am writing it correctly, but am unable to read. Here is my write code:
Code:
#use spi (DI=PIN_C1, DO=PIN_C5, CLK=PIN_C0, BITS=16, MODE=0, stream=SPI_PORT)

void WriteExLong (long addr, long val)
{
   output_low (EX_ROM);             // select Rom
   spi_xfer (SPI_PORT, EX_WREN, 8); // Send write enable command
   output_high (EX_ROM);            // set write enable latch
   delay_us (5);
   output_low (EX_ROM);             // reselect Rom
   spi_xfer (SPI_PORT, addr, 16);
   spi_xfer (SPI_PORT, val, 16);
   output_high (EX_ROM);            // Latch
}


And my read code:
Code:
long ReadExLong (long addr)
{
   long   val = 0;

   output_low (EX_ROM);               // select Rom
   spi_xfer (SPI_PORT, EX_READ, 8);   // send read command
   spi_xfer (SPI_PORT, addr, 16);     // send address
   val = spi_xfer (SPI_PORT, 0, 16);  // read data
   output_high (EX_ROM);              // Latch
 
   return val;
}
For the read code I have also tried:
Code:
long ReadExLong (long addr)
{
   long   val = 0;

   output_low (EX_ROM);                 // select Rom
   spi_xfer (SPI_PORT, EX_READ, 8);     // send read command
   val = spi_xfer (SPI_PORT, addr, 16); // send addr & read data
   output_high (EX_ROM);                // Latch

   return val;
}
The first method of reading always returns all FFFF, and the second method always returns all zero.

I have tried using the #USE SPI enable pin method of selecting the ROM, but it does not work right. CS has to be initially high, go low during access, and then go back high. But using the enable pin leaves CS low after access is complete. Changing ENABLE_ACTIVE from 0 to 1 makes no difference that I can see.

I can confirm, by scope, that the correct read and write commands, and address values are being sent to the ROM for both read and write. Can also confirm that correct data values are being sent during write. But do not see any data on the DO line from the ROM during read.

By the way, the same #USE SPI setup works fine to control two MCP4822 DAC chips on the same board.

Any suggestions?

Thanks, Russ
Ttelmah
Guest







PostPosted: Sat Aug 15, 2009 9:36 am     Reply with quote

After you reselect the ROM in your write code, you need to send a 'write' command.
Remember you need to check the WIP bit has gone off, before you can read.
Hopefully you have the /HOLD pin high?.
Make sure you have set EX_ROM high at the start of your code, before calling these routines.

Best Wishes
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

PostPosted: Sat Aug 15, 2009 12:28 pm     Reply with quote

Thanks, Ttlemah, for the help. I see that I had forgotten to put in the write command. That sure makes a difference Embarassed

Once I added that things started to work, a little. I am writing a table of 36 long values, but some of the values did not write. I ended up having to use three delays in the write routine to get it to write every value to my table:

Code:
void WriteExLong (long addr, long val)
{
   delay_ms (5);
   output_low (EX_ROM);      // select Rom

   spi_xfer (SPI_PORT, EX_WREN, 8);
   output_high (EX_ROM);      // set write enable latch
   delay_us (5);
   output_low (EX_ROM);      // reselect Rom
   delay_us (10);
   spi_xfer (SPI_PORT, EX_WRITE, 8);
   spi_xfer (SPI_PORT, addr, 16);
   spi_xfer (SPI_PORT, val, 16);
   output_high (EX_ROM);      // Latch
}
The initial delay of 5 ms is absolutely required, although it can be either before or after the CS line is set low. The second delay is also required, and I note, specified in the data sheet for the 25LC160D. The third delay is also required or writes will be missed.

In place of delays 1 and 3, I tried using code like:
Code:
   do {
      spi_xfer (SPI_PORT, EX_RSTAT, 8);   // read status command
      stat = spi_xfer (SPI_PORT, 0, 8);   // get status
   } while (bit_test (stat, 0));
I tested bit zero for WIP and bit 1 for WREN (in the second case), but that did not work. It is as if it does not wait (the bits are already set), but the delays are still necessary. It also does not make any difference if I set baud rate as slow as possible (9600), or let it run wide open (no baud specified) it works exactly the same.

So all seems to be working ok, but I'm just a little concerned that I had to use those delays. I can see nothing in the data sheet that indicates it might be necessary...

My read routine did not need any delays, or tests for WIP.

Thanks for any further insight you may provide.

Russ
Ttelmah
Guest







PostPosted: Sat Aug 15, 2009 2:13 pm     Reply with quote

You are not showing where you waited for WIP, relative to your CS. It should be something like:

Code:

void WriteExLong (long addr, long val)
{
   int8 stat;
   output_low (EX_ROM);      // select Rom

   spi_xfer (SPI_PORT, EX_WREN, 8);
   output_high (EX_ROM);      // set write enable latch
   delay_us (5);
   output_low (EX_ROM);      // reselect Rom
   delay_us (10);
   spi_xfer (SPI_PORT, EX_WRITE, 8);
   spi_xfer (SPI_PORT, addr, 16);
   spi_xfer (SPI_PORT, val, 16);
   output_high (EX_ROM);      // Latch
   delay_us(5);
   output_low(EX_ROM);
   do {
      delay_us(5);
      spi_xfer (SPI_PORT, EX_RSTAT, 8);   // read status command
      stat = spi_xfer (SPI_PORT, 0, 8);   // get status
   } while (bit_test (stat, 0));
   output_high(EX_ROM);
}


If you are writing multiple bytes sequentially, you really should consider generating a multi-byte write. It takes the same time to write an entire page to the ROM, as a single byte.....

Best Wishes
russk2txb



Joined: 30 Mar 2008
Posts: 109
Location: New Jersey

View user's profile Send private message

PostPosted: Sat Aug 15, 2009 2:30 pm     Reply with quote

Thanks, I will try that. I see what it going on now. I had tried it there but did not set CS high and then low again, before testing the bit. Of course it hung, and I understood why, but did not think of toggling the CS up and down and then testing. The data sheets do not give a clue that this is necessary. In fact they do not even tell you that you have to test for WIP before starting another write. They only tell you about the status register and that you CAN check these values.

Oh well, I guess it is clear to anyone who has used one of these chips before, or who has more experience with SPI. I'm getting there...

I do intend to do block reads and writes, but when it did not work, I thought to simplify and get things working before trying it again.

Thanks again, Russ
Ttelmah
Guest







PostPosted: Sat Aug 15, 2009 3:01 pm     Reply with quote

The data sheet, tells you that the write does not actually start, till the CS line goes high after the command. No point in testing a 'write in progress' bit, till you have triggered the write.
I added the short delay in the loop, since it seems pointless to just keep reading the register. However it may actually be necessary to include the CS operation inside the loop as well. If you look at the timing diagram for the 'read status' operation, it shows the CS being dropped at the start, then raised at the end. So something like:

Code:

   do {
      delay_us(5);
      output_low(EX_ROM);
      spi_xfer (SPI_PORT, EX_RSTAT, 8);   // read status command
      stat = spi_xfer (SPI_PORT, 0, 8);   // get status
      output_high(EX_ROM);
   } while (bit_test (stat, 0));


There doesn't seem to be any suggestion in the data sheet, that delays are needed between operating the select, and accessing the registers. The 'setup' times, are in nSec, with a 'worst case of 250nSc, so even a 1uSec delay should be all that is needed after dropping the line, or between dropping it and raising it.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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