| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| vtrx 
 
 
 Joined: 11 Oct 2017
 Posts: 144
 
 
 
			    
 
 | 
			
				| Read/Write w25q32 |  
				|  Posted: Wed May 27, 2020 1:36 pm |   |  
				| 
 |  
				| Would anyone have any example using memory w25q32 with PIC 18Fxx? |  |  
		|  |  
		| temtronic 
 
 
 Joined: 01 Jul 2010
 Posts: 9589
 Location: Greensville,Ontario
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed May 27, 2020 1:54 pm |   |  
				| 
 |  
				| I assume you're running the PIC on 3 volts ?? |  |  
		|  |  
		| vtrx 
 
 
 Joined: 11 Oct 2017
 Posts: 144
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed May 27, 2020 2:52 pm |   |  
				| 
 |  
				| Yes. |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 |  |  
		|  |  
		| vtrx 
 
 
 Joined: 11 Oct 2017
 Posts: 144
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed May 27, 2020 6:33 pm |   |  
				| 
 |  
				| 
 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: 144
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu May 28, 2020 5:15 am |   |  
				| 
 |  
				| 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: 9589
 Location: Greensville,Ontario
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu May 28, 2020 8:47 am |   |  
				| 
 |  
				| 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: 144
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu May 28, 2020 12:13 pm |   |  
				| 
 |  
				|  	  | 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: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri May 29, 2020 7:30 am |   |  
				| 
 |  
				| 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.
  |  |  
		|  |  
		| vtrx 
 
 
 Joined: 11 Oct 2017
 Posts: 144
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri May 29, 2020 8:19 am |   |  
				| 
 |  
				| 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: 9589
 Location: Greensville,Ontario
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Fri May 29, 2020 10:35 am |   |  
				| 
 |  
				| yes, please post your program in the 'code library' forum.. Jay
 |  |  
		|  |  
		| vtrx 
 
 
 Joined: 11 Oct 2017
 Posts: 144
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sat May 30, 2020 4:30 pm |   |  
				| 
 |  
				| 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: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun May 31, 2020 2:26 am |   |  
				| 
 |  
				| 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: 144
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun May 31, 2020 1:38 pm |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |