|
|
View previous topic :: View next topic |
Author |
Message |
russk2txb
Joined: 30 Mar 2008 Posts: 109 Location: New Jersey
|
problems accessing 25LC160D external EEPROM via SPI |
Posted: Sat Aug 15, 2009 9:09 am |
|
|
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
|
|
Posted: Sat Aug 15, 2009 9:36 am |
|
|
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
|
|
Posted: Sat Aug 15, 2009 12:28 pm |
|
|
Thanks, Ttlemah, for the help. I see that I had forgotten to put in the write command. That sure makes a difference
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
|
|
Posted: Sat Aug 15, 2009 2:13 pm |
|
|
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
|
|
Posted: Sat Aug 15, 2009 2:30 pm |
|
|
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
|
|
Posted: Sat Aug 15, 2009 3:01 pm |
|
|
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 |
|
|
|
|
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
|