|
|
View previous topic :: View next topic |
Author |
Message |
vtrx
Joined: 11 Oct 2017 Posts: 142
|
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: 9228 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: 142
|
|
Posted: Wed May 27, 2020 2:52 pm |
|
|
Yes. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
vtrx
Joined: 11 Oct 2017 Posts: 142
|
|
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: 142
|
|
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: 9228 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: 142
|
|
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: 19515
|
|
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: 142
|
|
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: 9228 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: 142
|
|
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: 19515
|
|
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: 142
|
|
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
|