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

Who can help me SPI EEPROM on PIC24 series
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
sindyme



Joined: 05 Aug 2009
Posts: 37

View user's profile Send private message MSN Messenger

Who can help me SPI EEPROM on PIC24 series
PostPosted: Sun Jan 31, 2010 7:56 pm     Reply with quote

Hello everybody, I have question about SPI EEPROM on PIC2416KA101.
My PIC2416KA101 can't work on SPI EEPROM.
This is my C code. Who can help me solve this question ? I'm very thankful for any help.
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)
#define EEPROM_SELECT PIN_B15

//setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4);
//setup_spi(SPI_MASTER | SPI_L_TO_H| SPI_XMIT_L_TO_H | SPI_CLK_DIV_4);
//setup_spi(SPI_MASTER | SPI_H_TO_L| SPI_XMIT_L_TO_H | SPI_CLK_DIV_4);
//setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4);
//setup_spi(SPI_MASTER|SPI_MODE_0_0|SPI_CLK_DIV_4);
setup_spi(SPI_MASTER | SPI_MODE_1 |SPI_CLK_DIV_4);
//setup_spi2( FALSE );

//( I have try  each setting of setup_spi )

void main()
{

for(;;)
   {
      fprintf(coma,"Write to SPI....\r\n");
      for(addr = 0; addr < 10 ; addr++)
      {
          write_ext_eeprom(addr,TESTTB[addr]); 
      }
     
      fprintf(coma,"Read From SPI....\r\n");
      for(addr=0 ; addr <10  ; addr++)
      {
         SPI_Temp = read_ext_eeprom(addr);
         fprintf(comb,"==>%d\r\n",SPI_Temp);
      }
      delay_ms(15000);
     
   }

}

I have reference to the following webpage:
http://www.ccsinfo.com/forum/viewtopic.php?t=41045&highlight=pic24+spi
http://www.ccsinfo.com/forum/viewtopic.php?t=28199&start=1
By the way ~ my PIC18 series can work, but same code can't work on PIC24 series.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Mon Feb 01, 2010 12:34 am     Reply with quote

CCS built-in functions have several issues with PCD/PIC24. They are generally working, but often not as
expected. The topic has been addressed in the forum before. I suggest to read also this older thread: (It's a
rather long story, and I used a wrong SPI mode coding in part of the contributions, be aware).
http://www.ccsinfo.com/forum/viewtopic.php?t=38491
There'a a short snippet in the post for reading the SPI-Flash ID-Byte. If it works, you're nearly done.

I have several problems with your post. You don't tell about the SPI flash device, and you don't tell an explicite
reference for the used flash routines. If you are using PCM programmer's "hardware SPI" driver from the second thread,
it doesn't work with PCD, I think. As discussed in the above thread, the combination of spi_write() and spi_read()
doesn't work correctly, you should use spi_read() exclusively (that's my simple solution for the time being, there
are possibly others).

With industry standard SPI-Flash (I used e.g. ST/Numonyx M25P04), mode 0 or mode 3 are correct, mode 1
or 2 can't work.

P.S.: I realized, that you refered to SPI EEPROM rather than SPI flash. They are similar in most aspects, e.g.
SPI modes. But the said read ID command doesn't exist.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

My SPI still can't work on PIC24 series?
PostPosted: Wed Feb 03, 2010 12:41 am     Reply with quote

You may want to read the above post, particularly regarding mixing of spi_write() and spi_read().

I didn't yet use, spi_xfer(), so I can't tell about it. Also I didn't use V4.104, because the compiler temporarily
lost it's knowledge of some basic C syntax elements in this version. But I'm not aware of changes to the SPI
handling in V4.104.
sindyme



Joined: 05 Aug 2009
Posts: 37

View user's profile Send private message MSN Messenger

PostPosted: Wed Feb 03, 2010 2:55 am     Reply with quote

Hello Fvm

I use Logic Analyzer to check my SPI signal.
I find the "PIC24F16KA101" only send "SOD signal out" , it no have run spi_read function.
How can i do ...

There is my SPI logic image URL :
http://sindyme.sg1010.myweb.hinet.net/logic_spi.bmp
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Feb 03, 2010 3:07 am     Reply with quote

With a LA, you should be able to clarify the issue in a short. Can you please also tell, which code lines are
generating the shown 4 Byte transfers and what's the assignment of LA channels. SCK obvious, nCS too, the
others aren't clear to me.
sindyme



Joined: 05 Aug 2009
Posts: 37

View user's profile Send private message MSN Messenger

PostPosted: Wed Feb 03, 2010 3:35 am     Reply with quote

I update my image URL :
http://sindyme.sg1010.myweb.hinet.net/logic_spi.bmp

PS : With Logic Analyzer that I find CCS no run spi_read function.
When I only put "write_ext_eeprom" function at main(), my L.A.
will run logic signal.
If I only put "read_ext_eeprom" function at main(), my L.A
will to wait. ( PIC no run spi_read function .... )


I use these code to test SPI EEPROM
Code:

#define SPI_CLK_DIV_2    0x001B
#define SPI_CPHA_0       0x0100

#define SPI_MODE_0 (SPI_L_TO_H | SPI_CPHA_0)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L | SPI_CPHA_0)
#define SPI_MODE_3 (SPI_H_TO_L)

#define EEPROM_SELECT PIN_B15


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(int16 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);
   spi_write(spi_data);
   output_high(EEPROM_SELECT);
}
//-------------------------------------------------------------------
int16 read_ext_eeprom(int16 address)
{
   char spi_data;

   //while(!ext_eeprom_ready());

   output_low(EEPROM_SELECT);
   spi_write(0x03);
   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);
   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);
      }
         
   }
   
}

My CCS Ver is "PCDIDE 4.104"
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Feb 03, 2010 4:40 pm     Reply with quote

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);
      }
   }
}
sindyme



Joined: 05 Aug 2009
Posts: 37

View user's profile Send private message MSN Messenger

PostPosted: Wed Feb 03, 2010 9:44 pm     Reply with quote

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;
      }   
   }
}
sindyme



Joined: 05 Aug 2009
Posts: 37

View user's profile Send private message MSN Messenger

PostPosted: Fri Feb 05, 2010 2:21 am     Reply with quote

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?
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Feb 05, 2010 5:47 am     Reply with quote

You are using spi_write() again. It doesn't work.
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Fri Feb 05, 2010 7:39 am     Reply with quote

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
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Feb 05, 2010 8:56 am     Reply with quote

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.
sindyme



Joined: 05 Aug 2009
Posts: 37

View user's profile Send private message MSN Messenger

PostPosted: Fri Feb 05, 2010 12:29 pm     Reply with quote

FvM wrote:
You are using spi_write() again. It doesn't work.



My SPI Flash have "16M", that datasheet say address must send 24bit.

So I must spi_write() again.

This is "16M SPI Flash" URL:
http://www.spansion.com/Products/Pages/ProductDetails.aspx?ProdID=S25FL128P
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Feb 05, 2010 1:51 pm     Reply with quote

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;
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Fri Feb 05, 2010 10:38 pm     Reply with quote

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
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