|
|
View previous topic :: View next topic |
Author |
Message |
Ranfo
Joined: 08 Sep 2008 Posts: 38
|
SPI Flash memory and DSPIC33 |
Posted: Tue Mar 03, 2020 10:44 am |
|
|
DSPIC33EP512MC806 and IS25LQ080B
Anybody know how to make this work?
Everything just returns 0x00. If I add set_pullup(SPI1_CS) everything returns 0xFF.
Code: |
// SPI_FLASH.C
//
//
//
// Drivers for IS25LQ080B SERIAL FLASH MEMORY 1MB
// 256 Sectors, 4Kx8 bits each
// Sector Address: 0x000000 to 0x0FF000
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
#ifndef SPI1_CS
#define SPI1_CS PIN_E7 // 3
#define SPI1_DI PIN_G8 // 6
#define SPI1_DO PIN_G7 // 5
#define SPI1_CLK PIN_G6 // 4
#define SPI1_WP PIN_E6 // 2
#define READ 0x03 // Read Data From Memory
#define WRITE 0x02 // Write Data Into Memory
#define RDSR 0x05 // Read Status Register
#define WREN 0x06 // Set Write Enable
#define ERASE 0xD7 // Sector Erase 4KB (D7h/20h)
#define RDMDID 0x90 // Read Manufacturer and Device ID
#define RSTEN 0x66 // Reset-Enable
#define RESET 0x99 // Chip Reset
int8 gSpi_Buffer[256];
#use SPI ( STREAM=SPI1, CLK=SPI1_CLK, DO=SPI1_DO, DI=SPI1_DI, BAUD=100000, BITS=8, MODE=0, MASTER )
#endif
// ----------------------------------------------------------------------------
int8 spi_Ready() {
int8 data;
output_low(SPI1_CS);
spi_xfer(SPI1, RDSR);
data = spi_xfer(SPI1, 0);
output_high(SPI1_CS);
return data&0x01;
}
void spi_Init()
{
input(SPI1_DO);
output_high(SPI1_CS);
output_high(SPI1_WP);
output_low(SPI1_DI);
output_low(SPI1_CLK);
while (spi_Ready());
}
void spi_SendAddress(int32 address, int8 command)
{
spi_xfer(SPI1, command);
spi_xfer(SPI1, make8(address,2));
spi_xfer(SPI1, make8(address,1));
spi_xfer(SPI1, make8(address,0));
}
int8 spi_ReadByte(int32 address)
{
int8 data;
while(spi_Ready());
output_low(SPI1_CS);
spi_SendAddress(SPI1, READ);
data=spi_xfer(SPI1, 0);
output_high(SPI1_CS);
return data;
}
|
|
|
|
Ranfo
Joined: 08 Sep 2008 Posts: 38
|
|
Posted: Tue Mar 03, 2020 12:14 pm |
|
|
Made some changes. Still does not work.
Trial and Error not getting me anywhere.
Code: |
#ifndef SPI2_CS
#define SPI2_CS PIN_E7 // 3
#define SPI2_DI PIN_G8 // 6
#define SPI2_DO PIN_G7 // 5
#define SPI2_CLK PIN_G6 // 4
#define SPI2_WP PIN_E6 // 2
#define READ 0x03 // Read Data From Memory
#define WRITE 0x02 // Write Data Into Memory
#define RDSR 0x05 // Read Status Register
#define WREN 0x06 // Set Write Enable
#define ERASE 0xD7 // Sector Erase 4KB (D7h/20h)
#define RDMDID 0x90 // Read Manufacturer and Device ID
#define RSTEN 0x66 // Reset-Enable
#define RESET 0x99 // Chip Reset
int8 gSpi_Buffer[256];
#use SPI ( STREAM=SPI2, SPI2, BAUD=100000, BITS=8, MODE=0, MASTER )
#endif
// ----------------------------------------------------------------------------
int8 spi_Ready() {
int8 data;
output_low(SPI2_CS);
spi_xfer(SPI2, RDSR);
data = spi_xfer(SPI2, 0);
output_high(SPI2_CS);
return data&0x01;
}
void spi_Init()
{
input(SPI2_DO);
output_high(SPI2_CS);
output_high(SPI2_WP);
output_low(SPI2_DI);
output_low(SPI2_CLK);
while (spi_Ready());
}
void spi_SendAddress(int32 address, int8 command)
{
spi_xfer(SPI2, command);
spi_xfer(SPI2, make8(address,2));
spi_xfer(SPI2, make8(address,1));
spi_xfer(SPI2, make8(address,0));
}
int8 spi_ReadByte(int32 address)
{
int8 data;
while(spi_Ready());
output_low(SPI2_CS);
spi_SendAddress(address, READ);
data=spi_xfer(SPI2, 0);
output_high(SPI2_CS);
return data;
}
void spi_Erase(int8 sector)
{
while(spi_Ready());
int32 address = (int32) sector * 0x1000;
output_low(SPI2_CS);
spi_SendAddress(address, ERASE);
output_high(SPI2_CS);
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19588
|
|
Posted: Tue Mar 03, 2020 1:07 pm |
|
|
Er. Your pin naming is wrong.
You say that SPI2_DO is G7, but this is the DI pin not the DO pin.
Same applies to the next define as well.
You do understand that the PIC's DO line goes to the chip's DI.
Then you are not write enabling he chip.
The hardware WR bit controls allowing access to the status register.
To physically write to the chip, this has to be turned off, but then the WEL
bit has to be set in software as well.
From the data sheet:
Quote: |
Before the execution of any program, erase or Write Status/Function Register instruction, the Write Enable
Latch (WEL) bit must be enabled by executing a Write Enable (WREN) instruction. If the WEL bit is not enabled,
the program, erase or write register instruction will be ignored
|
This is common for all chips like this.
Hold pin also needs to be high. |
|
|
Ranfo
Joined: 08 Sep 2008 Posts: 38
|
|
Posted: Tue Mar 03, 2020 1:51 pm |
|
|
Ttelmah,
Thank you. I did not design the circuit and will have someone double check the ins and outs. If they are backwards then there is not much I can do to make this work.
I see that I forgot to send the WREN command before ERASE, but as above, if DI and DO are reversed it won't work anyway. |
|
|
Ranfo
Joined: 08 Sep 2008 Posts: 38
|
|
Posted: Tue Mar 03, 2020 4:00 pm |
|
|
The circuit is wired correctly. I changed the names to avoid confusion.
Added spi_xfer(SPI2, WREN); to the erase function.
Still, nothing works.
Is there a WORKING example out there some place? |
|
|
Ranfo
Joined: 08 Sep 2008 Posts: 38
|
|
Posted: Tue Mar 03, 2020 4:02 pm |
|
|
Code: |
#ifndef SPI2_CS
#define SPI2_CS PIN_E7 // 3
#define SPI2_DO PIN_G8 // 6
#define SPI2_DI PIN_G7 // 5
#define SPI2_CLK PIN_G6 // 4
#define SPI2_WP PIN_E6 // 2
#define READ 0x03 // Read Data From Memory
#define WRITE 0x02 // Write Data Into Memory
#define RDSR 0x05 // Read Status Register
#define WREN 0x06 // Set Write Enable
#define ERASE 0xD7 // Sector Erase 4KB (D7h/20h)
#define RDMDID 0x90 // Read Manufacturer and Device ID
#define RSTEN 0x66 // Reset-Enable
#define RESET 0x99 // Chip Reset
int8 gSpi_Buffer[256];
#use SPI ( STREAM=SPI2, SPI2, BAUD=100000, BITS=8, MODE=0, MASTER )
#endif
// ----------------------------------------------------------------------------
int8 spi_Ready() {
int8 data;
output_low(SPI2_CS);
spi_xfer(SPI2, RDSR);
data = spi_xfer(SPI2, 0);
output_high(SPI2_CS);
return data&0x01;
}
void spi_Init()
{
input(SPI2_DI);
output_high(SPI2_CS);
output_high(SPI2_WP);
output_low(SPI2_DO);
output_low(SPI2_CLK);
while (spi_Ready());
}
void spi_SendAddress(int32 address, int8 command)
{
// Is this right?
spi_xfer(SPI2, command);
spi_xfer(SPI2, make8(address,2));
spi_xfer(SPI2, make8(address,1));
spi_xfer(SPI2, make8(address,0));
// Or this?
// spi_xfer(SPI2, command);
// spi_xfer(SPI2, address);
}
int8 spi_ReadByte(int32 address)
{
int8 data;
while(spi_Ready());
output_low(SPI2_CS);
spi_SendAddress(address, READ);
data=spi_xfer(SPI2, 0);
output_high(SPI2_CS);
return data;
}
void spi_Erase(int8 sector)
{
while(spi_Ready());
int32 address = (int32) sector * 0x1000;
output_low(SPI2_CS);
spi_xfer(SPI2, WREN);
spi_SendAddress(address, ERASE);
output_high(SPI2_CS);
}
|
|
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Tue Mar 03, 2020 6:17 pm |
|
|
In another memory chip that I am using now, you must bring CS high and then back down between two instructions. In your erase function, you are doing write enable and another instruction on one single chip select event.
Check section 8 (p19) on your data sheet. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19588
|
|
Posted: Wed Mar 04, 2020 1:03 am |
|
|
You do realise that 'erased' gives 0xFF on flash memories.
Nowhere do you actually attempt to write to the chip.
I've got a library I use for a similar FLASH EEPROM. I'll dig it out and
post it later to show how you have to work. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19588
|
|
Posted: Wed Mar 04, 2020 2:43 am |
|
|
OK. I've modified it so the commands match what this chip uses and
added a basic test routine. No guarantees since it involved quite a bit of
'tweaking'....
Code: |
#include <33EP512MC806.h>
#build (stack=512)
#use delay(internal=58.96MHz)
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
//Now program the SPI port
#define SPI2_CS PIN_E7 // 3
#define SPI2_DO PIN_G8 // 6
#define SPI2_DI PIN_G7 // 5
#define SPI2_CLK PIN_G6 // 4
#define SPI2_WP PIN_E6 // 2
#define MAX_ADDRESS 0xFFFFFUL //change this according to chip
#USE SPI ( STREAM=SPI2_EEPROM, SPI2, BAUD=4000000, BITS=8, MODE=0, MASTER )
//Don't use the same name for the stream as the hardware port.
//define some pins for UART
#PIN_SELECT U1TX=PIN_E5
#PIN_SELECT U1RX=PIN_E4
#USE RS232 (UART1, baud=9600, ERRORS) //default port for output
#define EE_READ 0x03 // Read Data From Memory
#define EE_PP 0x2 //Page program
#define EE_CER 0xc7 //chip erase
#define EE_WREN 0x6 //write enable
#define EE_WRDI 0x4 //write disable
#define EE_RDSR 0x5 //read status
#define EE_WRSR 0x1 //write status
#define EE_RDID 0xAB //read ID
#define EE_RSTEN 0x66 //software reset enable
#define EE_RST 0x99 //software reset
#define EE_IRP 0x62 //program information row
#define EE_IRRD 0x68 //read information row
#define EE_SECLOCK 0x24 //sector lock
#define EE_SEC_UNLOCK 0x26 //sector unlock
#define EE_SECERASE 0xD7 //erase sector
byte read_status(void)
{
//read the status register
byte rval;
output_low(SPI2_CS);
spi_xfer(SPI2_EEPROM,EE_RDSR); //read status register command
rval=spi_xfer(SPI2_EEPROM,0); //read reply
output_high(SPI2_CS); //deselect chip
return rval; //return value
}
void read_block(unsigned int32 address, byte * data, int count)
{
if (count==0)
return; //do nothing if count==0
if (address>MAX_ADDRESS)
return; //do nothing if address above maximum supported.
//Now need to read status register to know if chip is busy
do {
delay_cycles(10);
} while (bit_test(read_status(),0)==1) ; //wait if chip busy - add timeout if needed here
output_low(SPI2_CS);
//read 'count' bytes from memory at 'address'
spi_xfer(SPI2_EEPROM,EE_READ); //send READ command
spi_xfer(SPI2_EEPROM,make8(address,2)); //msb of address
spi_xfer(SPI2_EEPROM,make8(address,1)); //NMSB
spi_xfer(SPI2_EEPROM,make8(address,0)); //LSB
//Now need to read bytes
do {
*(data++)=spi_xfer(SPI2_EEPROM,0); //clock out null bytes to read data
} while(--count); //for count bytes
output_high(SPI2_CS);
}
void enable_write(void)
{
//set the WEL required before any write operation
output_high(SPI2_WP); //disable hardware WP
output_low(SPI2_CS);
//set write enable
spi_xfer(SPI2_EEPROM,EE_WREN); //set write enable bit
output_high(SPI2_CS); //terminate command
}
void write_block(unsigned int32 address, byte * data, int count)
{
if (count==0)
return; //do nothing if count==0
if (address>MAX_ADDRESS)
return; //do nothing if address above maximum supported.
if (count>256)
return; //do nothing if attempt to write > 256 bytes
//Now need to read status register to know if chip is busy
do {
delay_cycles(10);
} while (bit_test(read_status(),0)==1) ; //wait if chip busy - add timeout if needed here
//Now before I can write need to enable write operation
enable_write();
//Now single CS and send the command with address
output_low(SPI2_CS);
spi_xfer(SPI2_EEPROM,EE_PP); //send page write command
spi_xfer(SPI2_EEPROM,make8(address,2)); //msb of address
spi_xfer(SPI2_EEPROM,make8(address,1)); //NMSB
spi_xfer(SPI2_EEPROM,make8(address,0)); //LSB
do {
spi_xfer(SPI2_EEPROM,*(data++)); //clock out bytes to write
} while(--count); //for count bytes
output_high(SPI2_CS); //deselect
}
void erase_sector(unsigned int32 address)
{
//erase 4K sector
if (address>MAX_ADDRESS)
return; //do nothing if address above maximum supported.
do {
delay_cycles(10);
} while (bit_test(read_status(),0)==1) ; //wait if chip busy - add timeout if needed here
enable_write();
output_low(SPI2_CS); //select
spi_xfer(SPI2_EEPROM,EE_SECERASE); //send erase sector command
address &=0x7FFF000UL; //page to erase
spi_xfer(SPI2_EEPROM,make8(address,2)); //msb of address
spi_xfer(SPI2_EEPROM,make8(address,1)); //NMSB
spi_xfer(SPI2_EEPROM,make8(address,0)); //LSB
output_high(SPI2_CS); //deselect
}
BYTE read_id(void)
{
//read the product ID
BYTE value;
do {
delay_cycles(10);
} while (bit_test(read_status(),0)==1) ; //wait if chip busy - add timeout if needed here
output_low(SPI2_CS); //select
spi_xfer(SPI2_EEPROM,EE_RDID); //send read ID command
spi_xfer(SPI2_EEPROM,0);
spi_xfer(SPI2_EEPROM,0);
spi_xfer(SPI2_EEPROM,0); //three dummy bytes required
value=spi_xfer(SPI2_EEPROM,0); //read reply
output_high(SPI2_CS); //deselect
return value; //return reply
}
void main(void)
{
BYTE ID;
delay_us(500);
BYTE buffer[16];
BYTE new[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int count;
//Now test reading ID and see if chip value is reasonable
ID=read_ID(); //note this also wakes chip from power down.
//This should be 0x13 for IS25LQ080B
if (ID==0x13)
{
//OK we are talking to the chip
//Read start of memory. If erased, write some new test data
read_block(0UL, buffer, 16);
for (count=0;count<16;count++)
{
if (buffer[count]!=0xFF)
{
printf("Data found\n");
break; //there is some data in the block
}
}
if (count==16)
{
//here block was empty so write something
write_block(0UL,new,16);
}
read_block(0UL, buffer, 16); //read again
//Now compare with 'new' as test.
for (count=0;count<16;count++)
{
if (buffer[count]!=new[count])
{
printf("Data ERROR\n");
break; //
}
}
if (count==16)
{
printf("Data matches\n");
}
}
while(TRUE)
{
//something
}
}
|
|
|
|
Ranfo
Joined: 08 Sep 2008 Posts: 38
|
|
Posted: Wed Mar 04, 2020 2:46 pm |
|
|
Wonderful Ttelmah! Using your example I have it all working and apparently much faster than a bitbang solution I was using before. It should all be down hill from here. Thank you much.
Code: |
#ifndef SPI_FLASH2
#define SPI_FLASH2
#define MAX_ADDRESS 0x0FFFFF
#define SPI2_CS PIN_E7 // 3
#define SPI2_DO PIN_G8 // 6
#define SPI2_DI PIN_G7 // 5
#define SPI2_CLK PIN_G6 // 4
#define SPI2_WP PIN_E6 // 2
#define EE_READ 0x03 // Read Data From Memory
#define EE_WRITE 0x02 // Write Data Into Memory
#define EE_RDSR 0x05 // Read Status Register
#define EE_WREN 0x06 // Set Write Enable
#define EE_ERASE 0xD7 // Sector Erase 4KB (D7h/20h)
#define EE_RDMDID 0x90 // Read Manufacturer and Device ID
#define EE_RSTEN 0x66 // Reset-Enable
#define EE_RESET 0x99 // Chip Reset
#define EE_IRP 0x62 // program information row
#define EE_IRRD 0x68 // read information row
#define EE_SECLOCK 0x24 // sector lock
#define EE_SEC_UNLOCK 0x26 // sector unlock
#define EE_SECERASE 0xD7 // erase sector
#define EE_RDID 0xAB // Read ID
#endif
#USE SPI ( STREAM=SPI2EE, SPI2, BAUD=4000000, BITS=8, MODE=0, MASTER )
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Read the status register
// ----------------------------------------------------------------------------
byte spi2_read_status()
{
byte rval;
output_low(SPI2_CS);
spi_xfer(SPI2EE, EE_RDSR); // Read status register command
rval=spi_xfer(SPI2EE, 0); // Read reply
output_high(SPI2_CS); // Deselect chip
return rval; // Return value
}
// Read EEPROM product ID (IS25LQ080B=0x13)
// ----------------------------------------------------------------------------
byte spi2_read_id()
{
byte value;
do { // Wait if chip busy
delay_cycles(10);
} while (bit_test(spi2_read_status(), 0)==1);
output_low(SPI2_CS); // Select
spi_xfer(SPI2EE, EE_RDID); // Send read ID command
spi_xfer(SPI2EE, 0);
spi_xfer(SPI2EE, 0);
spi_xfer(SPI2EE, 0); // Three dummy bytes required
value=spi_xfer(SPI2EE, 0); // Read reply
output_high(SPI2_CS); // Deselect
return value; // Return reply
}
// Read Block
// ----------------------------------------------------------------------------
void spi2_read_block(unsigned int32 address, byte * data, int16 count)
{
if (count==0) return;
if (address>MAX_ADDRESS) return;
do { // Wait while chip busy
delay_cycles(10);
} while (bit_test(spi2_read_status(),0)==1);
output_low(SPI2_CS);
spi_xfer(SPI2EE, EE_READ); // Send READ command
spi_xfer(SPI2EE, make8(address,2)); // MSB of address
spi_xfer(SPI2EE, make8(address,1)); // NMSB
spi_xfer(SPI2EE, make8(address,0)); // LSB
do {
*(data++)=spi_xfer(SPI2EE, 0); // clock out null bytes to read data
} while(--count); // for count bytes
output_high(SPI2_CS);
}
// Write Enable
// ----------------------------------------------------------------------------
void spi2_enable_write()
{
output_high(SPI2_WP); // Disable hardware WP
output_low(SPI2_CS);
spi_xfer(SPI2EE, EE_WREN); // Set write enable bit
output_high(SPI2_CS); // Deselect
}
// Erase Sector (0-255)
// ----------------------------------------------------------------------------
void spi2_erase_sector(int8 sector)
{
int32 address = (int32) sector * 0x1000;
if (address>MAX_ADDRESS) return;
do { // Wait while chip busy
delay_cycles(10);
} while (bit_test(spi2_read_status(),0)==1);
spi2_enable_write(); // Enable Write
output_low(SPI2_CS); // Select
spi_xfer(SPI2EE, EE_SECERASE); // Send erase sector command
spi_xfer(SPI2EE, make8(address,2)); // MSB
spi_xfer(SPI2EE, make8(address,1)); // NMSB
spi_xfer(SPI2EE, make8(address,0)); // LSB
output_high(SPI2_CS); // Deselect
}
// Write Block
// ----------------------------------------------------------------------------
void spi2_write_block(unsigned int32 address, byte * data, int count)
{
if (count==0) return;
if (address>MAX_ADDRESS) return;
if (count>256) return;
do { // Wait while chip busy
delay_cycles(10);
} while (bit_test(spi2_read_status(),0)==1) ;
spi2_enable_write(); // Enable Write
output_low(SPI2_CS); // Select
spi_xfer(SPI2EE, EE_WRITE); // Send page write command
spi_xfer(SPI2EE, make8(address,2)); // MSB
spi_xfer(SPI2EE, make8(address,1)); // NMSB
spi_xfer(SPI2EE, make8(address,0)); // LSB
do {
spi_xfer(SPI2EE, *(data++)); // Clock out bytes
} while(--count);
output_high(SPI2_CS); // Deselect
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19588
|
|
Posted: Thu Mar 05, 2020 1:11 am |
|
|
Good. Glad I got close. |
|
|
|
|
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
|