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

Read/Write w25q32
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
vtrx



Joined: 11 Oct 2017
Posts: 142

View user's profile Send private message

Read/Write w25q32
PostPosted: Wed May 27, 2020 1:36 pm     Reply with quote

Would anyone have any example using memory w25q32 with PIC 18Fxx?
temtronic



Joined: 01 Jul 2010
Posts: 9228
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed May 27, 2020 1:54 pm     Reply with quote

I assume you're running the PIC on 3 volts ??
vtrx



Joined: 11 Oct 2017
Posts: 142

View user's profile Send private message

PostPosted: Wed May 27, 2020 2:52 pm     Reply with quote

Yes.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed May 27, 2020 3:47 pm     Reply with quote

This guy says his driver works. He had a voltage problem but he fixed it.
http://www.ccsinfo.com/forum/viewtopic.php?t=43047
vtrx



Joined: 11 Oct 2017
Posts: 142

View user's profile Send private message

PostPosted: Wed May 27, 2020 6:33 pm     Reply with quote

PCM programmer wrote:
This guy says his driver works. He had a voltage problem but he fixed it.
http://www.ccsinfo.com/forum/viewtopic.php?t=43047


I will study the code.
I just have an example of sequential reading to generate wav sounds, but I want to understand how to record the bytes.
vtrx



Joined: 11 Oct 2017
Posts: 142

View user's profile Send private message

PostPosted: Thu May 28, 2020 5:15 am     Reply with quote

I think there is an error in this piece of code;

Code:
#ifndef EEPROM_SELECT

#define EEPROM_SELECT PIN_A0
#define EEPROM_CLK    PIN_A1
#define EEPROM_DI     PIN_A2
#define EEPROM_DO     PIN_A2

#endif


The A2 definition is repeated.
temtronic



Joined: 01 Jul 2010
Posts: 9228
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu May 28, 2020 8:47 am     Reply with quote

It depends upon the mode the EEPROM is being used....

from the datasheet...
Dual and Quad SPI instructions use the bidirectional IO pins to serially write instructions, addresses or data to the device
...

'regular' or 'normal' or 'old' SPI uses unidirectional IO pins....

I 'assume' the driver can be configured for the different modes ?

Jay
vtrx



Joined: 11 Oct 2017
Posts: 142

View user's profile Send private message

PostPosted: Thu May 28, 2020 12:13 pm     Reply with quote

Code:
#bit    som          = 0x06.3  //pino 9 saida de som
#bit    tris_som     = 0x86.3  //sentido
#bit    mosi         = 0x05.1  //pino 18
#bit    miso         = 0x05.4  //pino 3
#bit    cs           = 0x05.3  //pino 2
#bit    slk          = 0x05.0  //pino 17

...
void clock(void){ slk=1; delay_us(1);slk=0; delay_us(1);}



Can I use it this way?

Code:

#define mosi PIN_B0
#define miso PIN_B1
#define cs   PIN_B2
#define slk  PIN_B3

...
void clock(void){ output_high(slk); delay_us(1);output_low(slk); delay_us(1);}
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Fri May 29, 2020 7:30 am     Reply with quote

OK. I've rewritten the posted code to use standard SPI.
I've also added a sector erase function (that erases 4K rather than the
whole chip). Remember you need to be writing to erased memory.

The functions are designed to be called the same way as the originals,
so with an unsigned int32 byte address for read/write (I'm being 'sneaky',
and accessing this through a union, but the compiler knows how to do
this). I've not checked my typing, so 'no guarantees'. This is setup to
work with the pins you list.

Code:

///////////////////////////////////////////////////////////////////////////
////   Library for a Winbond W25Xxx (128 KB --> 16 MB)                 ////
////                                                                   ////
////   init_ext_eeprom();    Call before the other functions are used  ////
////                                                                   ////
////   write_ext_eeprom(a, d);  Write the byte d to the address a      ////
////                                                                   ////
////   d = read_ext_eeprom(a);   Read the byte d from the address a    ////
////                                                                   ////
////   b = ext_eeprom_ready();  Returns TRUE if the eeprom is ready    ////
////                            to receive opcodes                     ////
////   b = ext_eeprom_busy(); Returns TRUE if EEPROM busy              ////
////                                                                   ////
////   erase_ext_eeprom(); Erases the whole EEPROM                     ////
////                                                                   ////
////   erase_page(a); erases the 4K page containing address a          ////
////                                                                   ////
////                                                                   ////
////   The main program may define EEPROM_SELECT, EEPROM_DI, EEPROM_DO ////
////   and EEPROM_CLK to override the defaults below.                  ////
////                                                                   ////
////                                                                   ////
////                      Pin Layout                                   ////
////   -----------------------------------------------                 ////
////   |    __                                       |                 ////
////   | 1: CS   EEPROM_SELECT | 8: VCC   +5V        |                 ////
////   |                       |    ____             |                 ////
////   | 2: DO   EEPROM_DO     | 7: HOLD  +5V        |                 ////
////   |    __                 |                     |                 ////
////   | 3: WP   +5V           | 6: CLK   EEPROM_CLK |                 ////
////   |                       |                     |                 ////
////   | 4: GND  Ground        | 5: DIO   EEPROM_DI  |                 ////
////   -----------------------------------------------                 ////
////                                                                   ////
///////////////////////////////////////////////////////////////////////////
//Re-written to use standard SPI


#ifndef EEPROM_SELECT

#define EEPROM_SELECT PIN_A0
#define EEPROM_CLK    PIN_A1
#define EEPROM_DI     PIN_A2
#define EEPROM_DO     PIN_B3

#endif

//define the SPI interface. For best speed use hardware SPI.
#use spi(MASTER, MODE=0, DI=EEPROM_DO, DO=EEPROM_DI, CLK=EEPROM_CLK, STREAM=W25X)
//Remember PIC DI, is EEPROM DO and vice versa.

#define EEPROM_ADDRESS  unsigned int32

#define RDSR 0x05 // rdsr opcode
#define WREN 0x06 // wren opcode
#define CHIP_ERASE 0xc7 // chip erase
#define PG_PGM 0x2 //program a page
#define RD_DATA 0x3 //read a byte
#define SECT_ERASE 0x20 //erase 4K sector

//note this uses 'data'
#define SEND_BYTE(x)    output_low(EEPROM_SELECT); data=spi_xfer(W25X, x, 8); output_high(EEPROM_SELECT)

void init_ext_eeprom(void)
{
   output_high(EEPROM_SELECT);
}

BOOLEAN ext_eeprom_busy(void)
{
   //Read the status register and return the busy bit
   BYTE data;
     
   output_low(EEPROM_SELECT);
   
   data=spi_xfer(W25X, RDSR, 8); //RDSR instruction
   data=spi_xfer(W25X, 0, 8); //get reply
 
   output_high(EEPROM_SELECT);
   
   return bit_test(data, 0);
}

#define ext_eeprom_ready() !ext_eeprom_busy()

void erase_ext_eeprom(void)
{
   BYTE data; //dummy data byte to ensure SPI completes read
   //Full chip erase

   // ensure EEPROM is idle
   while(ext_eeprom_busy())
      ;
   
   SEND_BYTE(WREN); //WREN instruction
   SEND_BYTE(CHIP_ERASE); //ERASE instruction
   
   while(ext_eeprom_busy())
      ; //wait for completion
}

union access {
   unsigned int32 whole;
   BYTE bytes[4];
}

void erase_page(union access address)
{
   //erase a 4K page contining the address 'address'
   output_low(EEPROM_SELECT);
   data=spi_xfer(W25X, SECT_ERASE, 8); //sector erase instruction
   data=spi_xfer(W25X, address.bytes[2], 8); //top byte of address
   data=spi_xfer(W25X, address.bytes[1], 8); //middle byte
   data=spi_xfer(W25X, address.bytes[0], 8); //LSB
   output_high(EEPROM_SELECT);
   while(!ext_eeprom_ready())
      ; //wait to complete
}

void write_ext_eeprom(union access address, BYTE val)
{
   //single byte write
   BYTE data;
   
   // ensure EEPROM is idle
   while(!ext_eeprom_ready())
      ;
   
   output_low(EEPROM_SELECT);
   data=spi_xfer(W25X, PG_PGM, 8); //Program page instruction
   data=spi_xfer(W25X, address.bytes[2], 8); //top byte of address
   data=spi_xfer(W25X, address.bytes[1], 8); //middle byte
   data=spi_xfer(W25X, address.bytes[0], 8); //LSB
   data=spi_xfer(W25X, val, 8); //data byte
   output_high(EEPROM_SELECT);
   while(!ext_eeprom_ready())
      ; //wait to complete
}

BYTE read_ext_eeprom(union access address)
{
   BYTE data;
   
   // ensure EEPROM is idle
   while(!ext_eeprom_ready())
      ;

   output_low(EEPROM_SELECT);
   data=spi_xfer(W25X, RD_DATA, 8); //Read data instruction
   data=spi_xfer(W25X, address.bytes[2], 8); //top byte of address
   data=spi_xfer(W25X, address.bytes[1], 8); //middle byte
   data=spi_xfer(W25X, address.bytes[0], 8); //LSB
   data=spi_xfer(W25X, 0, 8); //dummy byte
   output_high(EEPROM_SELECT);
   
   return(data);
}


Hopefully will give a good starting point. Very Happy
vtrx



Joined: 11 Oct 2017
Posts: 142

View user's profile Send private message

PostPosted: Fri May 29, 2020 8:19 am     Reply with quote

Thank you very much!
I will check your routines.
I was able to faithfully reproduce a 11025khz wav audio using an 18FXX and 25Qxx memory.
If anyone is interested, i will post the complete project.

Main:

Code:
/*******************************************************************************
Play wav 25QxxFV

******************************************************************************/
#include <18F2550.h>
#fuses XTPLL,NOWDT,PROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,MCLR,CPB,CPD  //4MHZ,USB-48MHZ,CPU-48MHZ
//#fuses XTPLL,NOWDT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,MCLR,CPB,BROWNOUT,BORV20 //SEM PROTEÇÃO
//#fuses XTPLL,NOWDT,PROTECT,NOLVP,NODEBUG,USBDIV,PLL1,CPUDIV1,VREGEN,NOMCLR,CPB,CPD  //4MHZ,USB-48MHZ,CPU-48MHZ (NOMCLR=RE3 como entrada)

#use delay(clock=48000000)

#define EEPROM_SELECT PIN_B2
#define EEPROM_CLK    PIN_B3
#define EEPROM_DI     PIN_B0
#define EEPROM_DO     PIN_B1

#include <W25Xxx.c>

#use fast_io(c)
#use fast_io(b)
 

// Define taxa de amostragem(algoritimo não exato)
#define Tam_wav   524272         //Tamanho do bytes de áudio
#define PR2       1500
#define wav11025  4
#define wav22050  2

int            wait;
//-------------------------------------------------------------------------
void Play_wav(int32 address)
{
   BYTE cmd[4], i, data;
   int32 Loop;
   
   cmd[0] = (BYTE) address;
   cmd[1] = (BYTE) (address >> 8);
   cmd[2] = (BYTE) (address >> 16);
   cmd[3] = 0x03;                   //(Read Data 03H)
   
   // Wait until the eeprom is done with a previous write
   while(!ext_eeprom_ready());
   output_low(EEPROM_SELECT);
//....................................................   
   for(i=0; i<32; ++i)
   {
      output_bit(EEPROM_DI, shift_left(cmd, 4, 0));
      output_high(EEPROM_CLK);   // data latches
      output_low(EEPROM_CLK);    // back to idle
   }
for(Loop=0; Loop < Tam_wav; Loop++)             
  { 
   for(i=0; i<8; ++i)
   {
      output_high(EEPROM_CLK);
      shift_left(&data, 1, input(EEPROM_DO));
      output_low(EEPROM_CLK);    // data latches & back to idle
   }
       wait=wav11025;
       while(wait);   
      set_pwm1_duty(data);         //saida analogica RC2   
  }   
 
   output_high(EEPROM_SELECT);   
}
//============================================================================
#INT_TIMER2
void int_tmr2()
{
   if(wait) wait--;
}
//============================================================================
void main()
{
//   set_tris_a(0b11111111);
   set_tris_b(0b11110000);
   set_tris_c(0b11110001);
  // output_b ( 0x00 );
   
   setup_timer_2(T2_DIV_BY_1, PR2, 1);
   setup_ccp1(CCP_PWM);
   setup_vref(FALSE);
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER2);
   
   init_ext_eeprom();
   
 while(1)
 {
  Play_wav(0x0000);
  delay_ms(1000);
 }
 
}
//....


W25Xxx.c:


Code:
///////////////////////////////////////////////////////////////////////////
////   Library for a Winbond W25Xxx (128 KB --> 16 MB)                 ////
////                                                                   ////
////   init_ext_eeprom();    Call before the other functions are used  ////
////                                                                   ////
////   write_ext_eeprom(a, d);  Write the byte d to the address a      ////
////                                                                   ////
////   d = read_ext_eeprom(a);   Read the byte d from the address a    ////
////                                                                   ////
////   b = ext_eeprom_ready();  Returns TRUE if the eeprom is ready    ////
////                            to receive opcodes                     ////
////                                                                   ////
////   The main program may define EEPROM_SELECT, EEPROM_DI, EEPROM_DO ////
////   and EEPROM_CLK to override the defaults below.                  ////
////                                                                   ////
////                                                                   ////
////                      Pin Layout                                   ////
////   -----------------------------------------------                 ////
////   |    __                                       |                 ////
////   | 1: CS   EEPROM_SELECT | 8: VCC   +5V        |                 ////
////   |                       |    ____             |                 ////
////   | 2: DO   EEPROM_DO     | 7: HOLD  +5V        |                 ////
////   |    __                 |                     |                 ////
////   | 3: WP   +5V           | 6: CLK   EEPROM_CLK |                 ////
////   |                       |                     |                 ////
////   | 4: GND  Ground        | 5: DIO   EEPROM_DI  |                 ////
////   -----------------------------------------------                 ////
////                                                                   ////
///////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996, 2003 Custom Computer Services          ////
//// This source code may only be used by licensed users of the CCS C  ////
//// compiler.  This source code may only be distributed to other      ////
//// licensed users of the CCS C compiler.  No other use, reproduction ////
//// or distribution is permitted without written permission.          ////
//// Derivative programs created using this software in object code    ////
//// form are not restricted in any way.                               ////
///////////////////////////////////////////////////////////////////////////


#ifndef EEPROM_SELECT
 #define EEPROM_SELECT PIN_A0
#endif
#ifndef EEPROM_CLK
 #define EEPROM_CLK    PIN_A1
#endif
#ifndef EEPROM_DI
 #define EEPROM_DI     PIN_A2
#endif
#ifndef EEPROM_DO
 #define EEPROM_DO     PIN_A3
#endif

#define EEPROM_ADDRESS  int32

void init_ext_eeprom()
{
   output_high(EEPROM_SELECT);
   output_low(EEPROM_DI);
   output_low(EEPROM_CLK);
}

BOOLEAN ext_eeprom_ready()
{
   BYTE rdsr, i, data;   
   rdsr = 0x05;                  // rdsr opcode  (Read Status Register 1)
   output_low(EEPROM_SELECT);   
   for(i=0; i<8; ++i)
   {
      output_bit(EEPROM_DI, shift_left(&rdsr, 1, 0));
      output_high(EEPROM_CLK);   // data latches
      output_low(EEPROM_CLK);    // back to idle
   } 
   for(i=0; i<8; ++i)
   {
      output_high(EEPROM_CLK);
      shift_left(&data, 1, input(EEPROM_DO));
      output_low(EEPROM_CLK);    // data latches & back to idle
   }   
   output_high(EEPROM_SELECT);   
   return !bit_test(data, 0);
}

void erase_ext_eeprom()
{
   BYTE i, wren, erase;
   
   wren  = 0x06;                  // wren opcode (Write Enable 06H)
   erase = 0xc7;                 // chip erase
   
   // Wait until the eeprom is done with a previous write
   while(!ext_eeprom_ready());
   
   output_low(EEPROM_SELECT);   
   for(i=0; i<8; ++i)
   {
      output_bit(EEPROM_DI, shift_left(&wren, 1, 0));
      output_high(EEPROM_CLK);   // data latches
      output_low(EEPROM_CLK);    // back to idle
   } 
   output_high(EEPROM_SELECT); 
   output_low(EEPROM_SELECT); 
   for(i=0; i<8; ++i)
   {
      output_bit(EEPROM_DI, shift_left(&erase, 1, 0));
      output_high(EEPROM_CLK);   // data latches
      output_low(EEPROM_CLK);    // back to idle
   } 
   output_high(EEPROM_SELECT); 
   delay_ms(40000);              // tCE
}

void write_ext_eeprom(EEPROM_ADDRESS address, BYTE data)
{
   BYTE cmd[5], i, wren;
   
   wren   = 0x06;                  // wren opcode (Write Enable 06H)
   cmd[0] = data;
   cmd[1] = (BYTE) address;
   cmd[2] = (BYTE) (address >> 8);
   cmd[3] = (BYTE) (address >> 16);
   cmd[4] = 0x02;
   
   // Wait until the eeprom is done with a previous write
   while(!ext_eeprom_ready());
   
   output_low(EEPROM_SELECT); 
   for(i=0; i<8; ++i)
   {
      output_bit(EEPROM_DI, shift_left(&wren, 1, 0));
      output_high(EEPROM_CLK);   // data latches
      output_low(EEPROM_CLK);    // back to idle
   }   
   output_high(EEPROM_SELECT);   
   output_low(EEPROM_SELECT);   
   for(i=0; i<40; ++i)
   {
      output_bit(EEPROM_DI, shift_left(cmd, 5, 0));
      output_high(EEPROM_CLK);   // data latches
      output_low(EEPROM_CLK);    // back to idle
   }   
   output_high(EEPROM_SELECT);   
   delay_ms(3);                  // tPP
}

BYTE read_ext_eeprom(EEPROM_ADDRESS address)
{
   BYTE cmd[4], i, data;
   
   cmd[0] = (BYTE) address;
   cmd[1] = (BYTE) (address >> 8);
   cmd[2] = (BYTE) (address >> 16);
   cmd[3] = 0x03;                   //(Read Data 03H)
   
   // Wait until the eeprom is done with a previous write
   while(!ext_eeprom_ready());
   
   output_low(EEPROM_SELECT);   
   for(i=0; i<32; ++i)
   {
      output_bit(EEPROM_DI, shift_left(cmd, 4, 0));
      output_high(EEPROM_CLK);   // data latches
      output_low(EEPROM_CLK);    // back to idle
   }
   
   for(i=0; i<8; ++i)
   {
      output_high(EEPROM_CLK);
      shift_left(&data, 1, input(EEPROM_DO));
      output_low(EEPROM_CLK);    // data latches & back to idle
   }   
   output_high(EEPROM_SELECT);   
   return(data);
}
//-----------------------------------------------------------------------

temtronic



Joined: 01 Jul 2010
Posts: 9228
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri May 29, 2020 10:35 am     Reply with quote

yes, please post your program in the 'code library' forum..
Jay
vtrx



Joined: 11 Oct 2017
Posts: 142

View user's profile Send private message

PostPosted: Sat May 30, 2020 4:30 pm     Reply with quote

I'm back.
I read the datasheet of 25Q64 and I think it is not possible to write a single byte, i would have to delete a sector of at least 4k and then re-record.
That's true?
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Sun May 31, 2020 2:26 am     Reply with quote

You can write a single byte 'to' a page, if the location is already erased.

So once you have erased a page, you can write byte 0 in this page, then
go away, do something else and come back and then write to byte 1, or
any other byte in the page.

You can change any single bit from '1' to '0', but not change any bit
from '0' to '1'. The only way to get a bit back to '1' is to erase.

So if byte 0x10 in a page contained 0x55, you could write this to contain
0x1 for example without problems.

0x55 = 0b01010101
0x01 = 0b00000001

So the change only involves changing bits from 1 to 0.
However You could not write 0x2

0x55 = 0b01010101
0x02 = 0b00000010

This needs the second bit to be changed to 1, so requires an erase.

Now if you look at the virtual_eeprom.c driver, this is designed for
the internal program memory of the PIC, that behaves the same way.
This 'simulates' the memory behaving like a traditional EEPROM, by
writing a 'record', containing a byte number, and the value to be stored.
If the stored 'byte number', is 0xFFFF, then the location is empty and can
be used to hold a record. If it is 0x0000 then the record has been erased.
All values in between signify the record holds a stored byte.
If you ask to write the same location number, then it sets the existing
record to 0x0000, and goes looking for an empty location to store
the data. If it can't find an empty location in the 'page', it copies all
records that are in use into a new page, and erases the page.
Downside is that it makes accessing a particular byte a lot more
laborious, but it does mean you can apparently write single bytes as
needed....

MicroChip also has an application note on a similar approach.
vtrx



Joined: 11 Oct 2017
Posts: 142

View user's profile Send private message

PostPosted: Sun May 31, 2020 1:38 pm     Reply with quote

I have a int32 and data[0],data[1] and data[2].
how to load an int32 with these bytes?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun May 31, 2020 2:25 pm     Reply with quote

Use the make32() function. See the CCS manual, page 344:
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
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