View previous topic :: View next topic |
Author |
Message |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed Feb 03, 2010 4:40 pm |
|
|
I told you, that a combination of spi_write() and spi_read() doesn't work with PCD. I only forgot, that it can cause
spi_read() to never return.
I also told you, that my SPI mode coding from the begin of the said thread was wrong and has been corrected
at the end.
As your waveform reveal, you actually selected mode 0 instead of intended mode 3. Fortunately, the SPI EEPROM supports both modes. For clarity, I inserted the correct mode moding below.
To avoid the spi_write()/spi_read() problem, simply replace all occurences of sp_write() with spi_read(). (It writes as well, but waits for the previous SPI transaction to finish before.)
Code: | #include <24F16KA101.h>
#define SPI_CLK_DIV_2 0x001B
#define SPI_CKE 0x0100
#define SPI_CKP 0x0040
#define SPI_MODE_0 (SPI_CKE)
#define SPI_MODE_1 (0)
#define SPI_MODE_2 (SPI_CKP | SPI_CKE)
#define SPI_MODE_3 (SPI_CKP)
#define EEPROM_SELECT PIN_B15
int1 ext_eeprom_ready(void)
{
char spi_data;
output_low(EEPROM_SELECT);
spi_read(0x05);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(!bit_test(spi_data, 0));
}
//-------------------------------------------------------------------
void write_ext_eeprom(int16 address, char spi_data)
{
//while(!ext_eeprom_ready());
output_low(EEPROM_SELECT);
spi_read(0x06);
output_high(EEPROM_SELECT);
output_low(EEPROM_SELECT);
spi_read(0x02);
spi_read(address >> 8);
spi_read(address);
spi_read(spi_data);
output_high(EEPROM_SELECT);
}
//-------------------------------------------------------------------
int16 read_ext_eeprom(int16 address)
{
char spi_data;
//while(!ext_eeprom_ready());
output_low(EEPROM_SELECT);
spi_read(0x03);
spi_read(address >> 8);
spi_read(address);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(spi_data);
}
void main()
{
int16 addr;
int16 SPI_Temp;
setup_spi(SPI_MASTER | SPI_MODE_3 |SPI_CLK_DIV_1);
output_high(EEPROM_SELECT);
for(;;)
{
for(addr = 5; addr < 6 ; addr++)
{
write_ext_eeprom(addr,'G');
}
//fprintf(coma,"Read From SPI and print out....\r\n");
for(addr=5 ; addr <6 ; addr++)
{
SPI_Temp = read_ext_eeprom(addr);
// fprintf(comb,"%d",SPI_Temp);
}
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
sindyme
Joined: 05 Aug 2009 Posts: 37
|
|
Posted: Wed Feb 03, 2010 9:44 pm |
|
|
Hello Fvm, I'm very thanks for you.
My SPI can work now.
I use this code control 25LC series EEPROM & "16M" SPI Flash.
This is "16M SPI Flash" URL:
http://www.spansion.com/Products/Pages/ProductDetails.aspx?ProdID=S25FL128P
The size is very very very big for me.
There is my working code. Anyone can use it to test SPI EEPROM.
Code: |
#include <stdio.h>
#include <string.h>
//-------------------------------------------------------------------
#define SPI_CLK_DIV_2 0x001B
#define SPI_CKE 0x0100
#define SPI_CKP 0x0040
#define SPI_MODE_0 (SPI_CKE)
#define SPI_MODE_1 (0)
#define SPI_MODE_2 (SPI_CKP | SPI_CKE)
#define SPI_MODE_3 (SPI_CKP)
#define EEPROM_SELECT PIN_B15
int16 addr;
char SPI_Temp;
int1 ext_eeprom_ready(void)
{
char spi_data;
output_low(EEPROM_SELECT);
spi_read(0x05);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(!bit_test(spi_data, 0));
}
//-------------------------------------------------------------------
void write_ext_eeprom(int16 address, char spi_data)
{
while(!ext_eeprom_ready());
output_low(EEPROM_SELECT);
spi_read(0x06);
output_high(EEPROM_SELECT);
output_low(EEPROM_SELECT);
spi_read(0x02);
spi_read(address >> 8);
//spi_read(address >> 8);
spi_read(address);
spi_read(spi_data);
output_high(EEPROM_SELECT);
}
//-------------------------------------------------------------------
int16 read_ext_eeprom(int16 address)
{
char spi_data;
while(!ext_eeprom_ready());
output_low(EEPROM_SELECT);
spi_read(0x03);
spi_read(address >> 8);
//spi_read(address >> 8);
spi_read(address);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(spi_data);
}
void main()
{
setup_spi(SPI_MASTER | SPI_MODE_3 |SPI_CLK_DIV_1);
setup_wdt(WDT_OFF);
setup_timer1(TMR_DISABLED|TMR_DIV_BY_1);
enable_interrupts(INT_RDA);
enable_interrupts(INT_RDA2);
fprintf(coma,"coma working OK ... \r\n");
fprintf(comb,"comb working OK ... \r\n");
delay_ms(500);
output_high(EEPROM_SELECT);
output_high(pin_a0);
for(;;)
{
tesflag = input_state(pin_a1);
if(tesflag==1)
{
for(addr = 10; addr < 15 ; addr++)
{
write_ext_eeprom(addr,TESTTB[addr]);
}
for(addr=10 ; addr <15 ; addr++)
{
SPI_Temp = read_ext_eeprom(addr);
fprintf(comb,"%c",SPI_Temp);
}
tesflag = 0;
}
}
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
sindyme
Joined: 05 Aug 2009 Posts: 37
|
|
Posted: Fri Feb 05, 2010 2:21 am |
|
|
Hello Fvm and everybody
I still had the question, my "PIC24F16KA101" already work on SPI.
Now I change "PIC24F16KA101" to "PIC24FJ256GB106" but same code can't work on "PIC24FJ256GB106".
I have note "RPI Select" that I use #pin_select to set my "SDO, SDI and SCK". But "256GB106" still can't work.
And I have use logic analyzer to check SDO, SDI signal.
I find the signal clock have wrong.
My code send 0x05 -> 0x06 -> 0x02 -> 16bit address and data. but the clock have wrong.
There is logic analyzer image for SPI URL :
http://sindyme.myweb.hinet.net/logic_spi2.bmp
and this is my code for "PIC24FJ256GB106"
Code: |
#include <stdio.h>
#include <string.h>
//-------------------------------------------------------------------
#define SPI_CLK_DIV_2 0x001B
#define SPI_CKE 0x0100
#define SPI_CKP 0x0040
#define SPI_MODE_0 (SPI_CKE)
#define SPI_MODE_1 (0)
#define SPI_MODE_2 (SPI_CKP | SPI_CKE)
#define SPI_MODE_3 (SPI_CKP)
#pin_select SDI1=PIN_B4
#pin_select SDO1=PIN_B5
#pin_select SCK1OUT=PIN_B8
#define EEPROM_SELECT PIN_B9
int1 tesflag;
int32 addr;
char SPI_Temp;
char TESTTB[]="1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//-------------------------------------------------------------------
int1 ext_eeprom_ready(void)
{
char spi_data;
output_low(EEPROM_SELECT);
spi_write(0x05);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(!bit_test(spi_data, 0));
}
//-------------------------------------------------------------------
void write_ext_eeprom(int32 address, char spi_data)
{
while(!ext_eeprom_ready());
output_low(EEPROM_SELECT);
spi_write(0x06);
output_high(EEPROM_SELECT);
output_low(EEPROM_SELECT);
spi_write(0x02);
spi_write(address >> 8);
spi_write(address >> 8);
spi_write(address);
spi_write(spi_data);
output_high(EEPROM_SELECT);
}
//-------------------------------------------------------------------
int32 read_ext_eeprom(int32 address)
{
char spi_data;
while(!ext_eeprom_ready());
output_low(EEPROM_SELECT);
spi_write(0x03);
spi_write(address >> 8);
spi_write(address >> 8);
spi_write(address);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(spi_data);
}
//-------------------------------------------------------------------
void main()
{
setup_spi(SPI_MASTER | SPI_MODE_3 |SPI_CLK_DIV_1);
setup_spi2(SPI_SS_DISABLED);
setup_wdt(WDT_ON);
setup_timer1(TMR_DISABLED|TMR_DIV_BY_1);
enable_interrupts(INT_RDA);
enable_interrupts(INT_RDA2);
output_high(EEPROM_SELECT);
output_high(pin_e4);
for(;;)
{
tesflag = input_state(pin_e4);
if(tesflag==1)
{
for(addr = 15; addr < 20 ; addr++)
{
write_ext_eeprom(addr,'G');
}
for(addr=15 ; addr <20 ; addr++)
{
SPI_Temp = read_ext_eeprom(addr);
fprintf(comb,"%d",SPI_Temp);
}
delay_ms(1300);
tesflag = 0;
}
}
} |
Could I ask where is the mistake? |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Feb 05, 2010 5:47 am |
|
|
You are using spi_write() again. It doesn't work. |
|
![](templates/subSilver/images/spacer.gif) |
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Fri Feb 05, 2010 7:39 am |
|
|
And you can't use SPI_Write or XFER and immediately raise nCS.
Think about it:
You write the register:
SPIBUF = some value
Then raise the nCS line:
bset reg.bit
How long do you think it takes at 8 SPI clocks vs 1 instruction? Who gets there first.
Probably your PIC's PC counter wins and you raise nCS before SPIBUF is fully sent.
You need some sort of delay before raising nCS to idle.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Feb 05, 2010 8:56 am |
|
|
Quote: | You need some sort of delay before raising nCS to idle. |
You don't need it when using spi_read() exclusively, because it waits for termination of transfer. |
|
![](templates/subSilver/images/spacer.gif) |
sindyme
Joined: 05 Aug 2009 Posts: 37
|
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Feb 05, 2010 1:51 pm |
|
|
Quote: | My SPI Flash have "16M", that datasheet say address must send 24bit.
So I must spi_write() again. |
Simply: No.
Seems like you did understand neither the problem with spi_write() nor the solution.
Here is a brief explanation. It's only valid for PIC24 and dsPIC.
spi_read() can simply replace spi_write(). Both functions are writing data to the SPI buffer. spi_read() is also reading data from the buffer, but you can ignore the read data, as I did in my example.
The important difference between both functions is the way, how they check the SPI status.
spi_write()
- waits for empty transmit buffer
- writes to the buffer
- return while SPI send is still in progress
spi_read()
- writes to the buffer (always necessary to start a transmission)
- waits for full receive buffer
- reads from the buffer
there are additional actions as clearing overflow, but they are not important to understand the basic sequence
If you perform a sequence spi_write() + spi_read(), the second write takes place before the transmission is finished. Possibly the receive buffer never gets full and the spi_read() waits forever.
By using spi_read() only, the SPI transactions are scheduled one-by-one, as required.
My SPI example from the previous thread has been dedicated by the way to 1..16 MBit SPI Flash:
Code: | SPI_nCS = 0;
spi_read(0x06); // WREN
SPI_nCS = 1;
SPI_nCS = 0;
spi_read(0xd8); // Sector erase
spi_read(eeaddr.b[2]);
spi_read(0);
spi_read(0);
SPI_nCS = 1; |
|
|
![](templates/subSilver/images/spacer.gif) |
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Fri Feb 05, 2010 10:38 pm |
|
|
It *is* pretty funny that a "read" function writes data.
Hahaha..
-Ben
EDIT: ok. Maybe not so funny. _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
![](templates/subSilver/images/spacer.gif) |
sindyme
Joined: 05 Aug 2009 Posts: 37
|
|
Posted: Fri Feb 05, 2010 11:52 pm |
|
|
OK ~ I will test the code on next week.
Today and tomorrow is sunday. |
|
![](templates/subSilver/images/spacer.gif) |
sindyme
Joined: 05 Aug 2009 Posts: 37
|
|
Posted: Fri Feb 05, 2010 11:54 pm |
|
|
Code: | SPI_nCS = 0;
spi_read(0x06); // WREN
SPI_nCS = 1;
SPI_nCS = 0;
spi_read(0xd8); // Sector erase
spi_read(eeaddr.b[2]);
spi_read(0);
spi_read(0);
SPI_nCS = 1; |
OK ~ I will test the code next week.
Today and tomorrow is sunday. |
|
![](templates/subSilver/images/spacer.gif) |
sindyme
Joined: 05 Aug 2009 Posts: 37
|
|
Posted: Sun Feb 07, 2010 8:49 pm |
|
|
Update Msg :
would you teach me that how can i set these ?
//spi_read(eeaddr.b[2]);
//erase_tp = spi_read(0);
//erase_tp = spi_read(0);
I do not understand
Code: | SPI_nCS = 0;
spi_read(0x06); // WREN
SPI_nCS = 1;
SPI_nCS = 0;
spi_read(0xd8); // Sector erase
spi_read(eeaddr.b[2]);
spi_read(0);
spi_read(0);
SPI_nCS = 1;
|
Good morning FVM & everybody.
Excuse me, how can I include your code ?
I don't understand how I should write this code.
Would you teach me how can I write it.
I have tried these.... but I am indefinite.
Code: |
#define SPI_CLK_DIV_2 0x001B
#define SPI_CKE 0x0100
#define SPI_CKP 0x0040
#define SPI_MODE_0 (SPI_CKE)
#define SPI_MODE_1 (0)
#define SPI_MODE_2 (SPI_CKP | SPI_CKE)
#define SPI_MODE_3 (SPI_CKP)
#pin_select SDI1=PIN_B4
#pin_select SDO1=PIN_B5
#pin_select SCK1OUT=PIN_B8
#define EEPROM_SELECT PIN_B9
int1 eeprom_Sector_erase(void)
{
char erase_tp;
output_low(EEPROM_SELECT); //SPI_nCS = 0;
spi_read(0x06); // WREN
output_high(EEPROM_SELECT); //SPI_nCS = 1;
output_low(EEPROM_SELECT); //SPI_nCS = 0;
spi_read(0xd8); // Sector erase
//spi_read(eeaddr.b[2]);
//erase_tp = spi_read(0);
//erase_tp = spi_read(0);
output_high(EEPROM_SELECT); //SPI_nCS = 1;
return(!bit_test(erase_tp, 0));
}
//-------------------------------------------------------------------
int1 ext_eeprom_ready(void)
{
char spi_data;
output_low(EEPROM_SELECT);
spi_write(0x05);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(!bit_test(spi_data, 0));
}
//-------------------------------------------------------------------
void write_ext_eeprom(int32 address, char spi_data)
{
while(!ext_eeprom_ready());
output_low(EEPROM_SELECT);
spi_write(0x06);
output_high(EEPROM_SELECT);
output_low(EEPROM_SELECT);
spi_write(0x02);
spi_write(address >> 8);
spi_write(address >> 8);
spi_write(address);
spi_write(spi_data);
output_high(EEPROM_SELECT);
}
//-------------------------------------------------------------------
int32 read_ext_eeprom(int32 address)
{
char spi_data;
while(!eeprom_Sector_erase());
output_low(EEPROM_SELECT);
spi_write(0x03);
spi_write(address >> 8);
spi_write(address >> 8);
spi_write(address);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(spi_data);
}
//-------------------------------------------------------------------
|
|
|
![](templates/subSilver/images/spacer.gif) |
sindyme
Joined: 05 Aug 2009 Posts: 37
|
|
Posted: Sun Feb 07, 2010 10:20 pm |
|
|
Hello Fvm
I edit my code that all spi_write change to spi_read().
It already might work.
But have a wrong.
EX : I send all ASCII to test, I find the "ASCII of "H"、"I" & "J" clock is wrong !! "H"、"I" & "J" become --> "@" "A" "B" .............
what's happend
Code: |
#define SPI_CLK_DIV_2 0x001B
#define SPI_CKE 0x0100
#define SPI_CKP 0x0040
#define SPI_MODE_0 (SPI_CKE)
#define SPI_MODE_1 (0)
#define SPI_MODE_2 (SPI_CKP | SPI_CKE)
#define SPI_MODE_3 (SPI_CKP)
#pin_select SDI1=PIN_B4
#pin_select SDO1=PIN_B5
#pin_select SCK1OUT=PIN_B8
#define EEPROM_SELECT PIN_B9
char TESTTB[50]="1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//HIJ will become @AB .... :shock: :shock:
//-------------------------------------------------------------------
int1 ext_eeprom_ready(void)
{
char spi_data;
output_low(EEPROM_SELECT);
spi_read(0x05);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(!bit_test(spi_data, 0));
}
//-------------------------------------------------------------------
void write_ext_eeprom(int32 address, char spi_data)
{
while(!ext_eeprom_ready());
output_low(EEPROM_SELECT);
spi_read(0x06);
output_high(EEPROM_SELECT);
output_low(EEPROM_SELECT);
spi_read(0x02);
spi_read(address >> 8);
spi_read(address >> 8);
spi_read(address);
spi_read(spi_data);
output_high(EEPROM_SELECT);
}
//-------------------------------------------------------------------
int32 read_ext_eeprom(int32 address)
{
char spi_data;
while(!ext_eeprom_ready());
output_low(EEPROM_SELECT);
spi_read(0x03);
spi_read(address >> 8);
spi_read(address >> 8);
spi_read(address);
spi_data = spi_read(0);
output_high(EEPROM_SELECT);
return(spi_data);
}
//-------------------------------------------------------------------
void main()
{
setup_spi(SPI_MASTER | SPI_MODE_3 |SPI_CLK_DIV_64);
setup_spi2(SPI_SS_DISABLED);
setup_wdt(WDT_OFF);
setup_timer1(TMR_DISABLED|TMR_DIV_BY_1);
enable_interrupts(INT_RDA);
enable_interrupts(INT_RDA2);
output_high(EEPROM_SELECT);
output_high(pin_e4);
fprintf(coma,"coma working OK ... \r\n");
fprintf(comb,"comb working OK ... \r\n");
for(;;)
{
tesflag = input_state(pin_e4);
if(tesflag==1)
{
for(addr = 0; addr < 36 ; addr++)
{
write_ext_eeprom(addr,TESTTB[addr]);
}
for(addr=0; addr <36 ; addr++)
{
SPI_Temp = read_ext_eeprom(addr);
fprintf(comb,"%c",SPI_Temp);
}
delay_ms(1000);
tesflag = 0;
}
}
}
| ![Shocked](images/smiles/icon_eek.gif) |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Feb 08, 2010 12:53 am |
|
|
One error in your code is, that you don't wait for each write to finish. You must either check the EEPPROM status or
insert a delay. It's all in the EEPROM datasheet. |
|
![](templates/subSilver/images/spacer.gif) |
sindyme
Joined: 05 Aug 2009 Posts: 37
|
|
Posted: Mon Feb 08, 2010 2:39 am |
|
|
This discussion might end.
I solved all problems.
Thanks "Fvm & everybody help ~ |
|
![](templates/subSilver/images/spacer.gif) |
|