Flash Memory M25P80, W25Q64FV or SST26VF064B Read and Write

Discussion on projects that are created by users and posted on mikroElektronika website.
Post Reply
Author
Message
Bill Legge
Posts: 235
Joined: 28 Oct 2007 03:16
Location: West Australia

Flash Memory M25P80, W25Q64FV or SST26VF064B Read and Write

#1 Post by Bill Legge » 13 Jan 2019 09:22

Working code follows for three different serial flash memory.
M25P80 on the EasyPICFusionv7 board accessed by SW13. 8 Mbit.
SST26VF064B on the FLASH2 Click. 64Mbit.
W25Q64FV from TronixLabs in Australia. 64Mbit.
All use SPI3 but have different chip select pins - see the Serial_Flash.h file to comment/uncomment.
Commands are the same except for some of the ERASE commands.
I have used SerialFlash_E64() that erases 64Mbytes on all the chips.
I have also used SerialFlash_ChipErase() that is common.
If you use other erase commands my code may not work?

First the file Test_Serial_Flash.c

Code: Select all

////////////////////////////////////////////////////////////////////////////////
// Project:         SERIAL_FLASH                                              //
// File:            Test_Serial_Flash.c                                       //
// Function:        Read and write to serial flash memory                     //
//                  M25P80(on board EasyPICFusionv7 or W25Q64FV               //
//                  or SST26VF064B on FLASH2 Click                            //
// Set Up:          See attached Notes.c                                      //
// MCU:             32MX795F512L                                              //
// Board:           EasyPIC_Fusionv7                                          //
// Power:           3.3V for MCU and TFT                                      //
// Xtal:            Running at 80MHz                                          //
// Compiler:        mikroC PRO for PIC32 version 4.0.0                        //
// Programmer:      ICD3 or on-board                                          //
// Author:          WVL                                                       //
// Date:            11 Jan 2019                                               //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Brief set up                                                               //
// Select flash type by commemt/uncomment #defines in Serial_Flash.h          //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
#include "Serial_Flash.h"       // constants, pin allocations, prototypes     //
#include "Serial_Flash.c"       // functions                                  //
#include "Notes.c"              // memory details and set up                  //
#define  HEARTBEAT LatG0_bit    // flashed for looping                        //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function prototype - direct PrintOut to UART2 on USBA                      //
void U2(char c);                                                              //
////////////////////////////////////////////////////////////////////////////////
// Function prototype - direct PrintOut to UART5 on MikroBus 2 - right        //
void U5(char c);                                                              //
////////////////////////////////////////////////////////////////////////////////

void main(){
    char                      x = 0;
    char                     y = 99;       // seed for random number
    char                   read = 0;
    char                 write =  0;
    unsigned int              a = 0;
    unsigned int              b = 0;
    unsigned int              c = 0;
    unsigned short    my_string[25];       // conversion unsigned long to string
    unsigned long  test_address = 0;       // test byte read and write
    unsigned long   array_start = 0;       // test page read and write
    char             test_page[300];       // to test 256 byte page write
    char             read_page[300];       // for page read
    // Init MCU
    AD1PCFG = 0xFFFF;           // 1=digital 0=analog
    JTAGEN_bit = 0;             // disable JTAG
    // Ports and pins
    TRISA = 0;
    TRISB = 0;
    TRISC = 0;
    TRISD = 0;
    TRISE = 0;
    TRISF = 0;
    TRISG = 0;
    LATD0_bit = 0;             // WP Write Protect pin for FLASH2 Click
    LATC1_bit = 1;             // Hold pin for FLASH2 Click
    // Init peripherals
    UART5_Init(9600);          // used MikroBus2 U5Tx/RF13 U5Rx/Rf12 not used U2Tx/RF5 U2Rx/RF4
    delay_ms(100);
    Printout(U5,"Test_Serial_Flash_Memory now running\r\n");
    for(x=0;x<10;x++){
        HEARTBEAT = ~HEARTBEAT;
        delay_ms(100);
    }
    // Init serial flash using SPI3
    // Uses SPI3 on SDO3/RF8 SDI3/RF2 SCK3/RD5 and on MikroBus sockets 
    // SPI clock is 80/8 = 10MHz, slow but OK
    SerialFlash_Start();
    SerialFlash_WriteSR(0);
    SerialFlash_UnlockSST();
    Printout(U5,"Starting SerialFlash_ChipErase()\r\n");
    Printout(U5,"Some flash memory takes a long tims to bulk erase\r\n");
    SerialFlash_ChipErase();    //  all bytes set to 0xFF
    Printout(U5,"SerialFlash_ChipErase() completed\r\n");
    delay_ms(20);
    
    test_address = 2000;        // assign value after declaration

    while(1){
         // Test read and write to W25Q64FV or M25P80 or SST26VF064B
        SerialFlash_WriteByte(write,test_address);
        read =  SerialFlash_ReadByte(test_address);
        // Display results
        Printout(U5,"Test byte read and write\r\n");
        a = write;
        b = read;
        LongWordToStrWithZeros(test_address, my_string);
        Printout(U5,"Write:%u Read:%u Address:%s\r\n",a,b,my_string);
        
        // Generate 256 random bytes for write/read test
        srand(y);       // new sequence of random ints
        for(c=0;c<=255;c++)test_page[c] = rand();

        // Test page read and write to W25Q64FV or M25P80 or SST26VF064B
        // Using page 1000. Start address = 1000*256 = 256,000
       array_start = 256000UL;
        // All flash memory uses 0xD8 to erase 64kByte
        // So erase from 256,000/65,536 = 3.9 ie sector 3
        // Start address is = 3*65,536 = 196,608        
        // Size of sector varies between flash memories
        // But the command byte 0xD8 erases 64kbytes in all chips
        // The function SerialFlash_E64KB uses this commonality
        SerialFlash_E64KB(196608UL);    // erase the area we are writing to
        SerialFlash_WriteArray(array_start,&test_page,256);
        // Display results
        Printout(U5,"Test array read and write\r\n");
        for(c=0;c<256;c++){
            read =  SerialFlash_ReadByte(array_start);
            a = test_page[c];
            b = read;
            LongWordToStrWithZeros(array_start, my_string);
            Printout(U5,"test_page:[%u]%u   \tread_page:[%u]%u at Addresss:%s\r\n",c,a,c,b,my_string);
            array_start++;
        }
        
        // Housekeeping
        test_address++;     // increment address for byte write/read
        write++;            // increment data for byte write
        y++;                // increment seed for random array
        HEARTBEAT = ~HEARTBEAT;
        delay_ms(1000);
    }

}
////////////////////////////////////////////////////////////////////////////////
// Function - direct PrintOut stream to the PC via UART2                      //
void U2(char c){UART2_Write(c);}                                              //                                                                              
////////////////////////////////////////////////////////////////////////////////
// Function - direct PrintOut stream to the PC via UART5                      //
void U5(char c){UART5_Write(c);}                                              //                                                                              
////////////////////////////////////////////////////////////////////////////////
Then the Serial_Flash.c file that drives the flash memory:

Code: Select all

////////////////////////////////////////////////////////////////////////////////
// Project:         SERIAL_FLASH                                              //
// File:            Serial_Flash.c                                            //
// Function:        Read and write to serial flash memory                     //
//                  M25P80(on board EasyPICFusionv7 or W25Q64FV               //
//                  or SST26VF064B on FLASH2 Click                            //
// Set Up:          See attached Notes.c                                      //
// MCU:             32MX795F512L                                              //
// Board:           EasyPIC_Fusionv7                                          //
// Power:           3.3V for MCU and TFT                                      //
// Xtal:            Running at 80MHz                                          //
// Compiler:        mikroC PRO for PIC32 version 4.0.0                        //
// Programmer:      ICD3 or on-board                                          //
// Author:          WVL                                                       //
// Date:            11 Jan 2019                                               //
////////////////////////////////////////////////////////////////////////////////

#include <built_in.h>   // decomposition of 20 bit address into 8 bits

////////////////////////////////////////////////////////////////////////////////
// Other files needed:                                                        //
// Serial_Flash.h that defines function prototypes and CS                     //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// SerialFlash Commands                                                       //
static const unsigned short CMD_RDID  = 0x9F;  // Read ID                     //
static const unsigned short CMD_RDSR  = 0x05;  // Read status register        //
static const unsigned short CMD_WRSR  = 0x01;  // Write status register       //
static const unsigned short CMD_READ  = 0x03;  // Read Byte  - any number     //
static const unsigned short CMD_WRITE = 0x02;  // Page Write - 1 to 256 bytes //
static const unsigned short CMD_WREN  = 0x06;  // Write enable                //
static const unsigned short CMD_E64KB = 0xD8;  // Erase 64kBytes              //
static const unsigned short CMD_ERASE = 0xC7;  // Bulk erase                  //
// SerialFlash Commands for Flash2 Click SST26VF064B                          //
static const unsigned short CMD_REEN  = 0x66;  // Reset enable                //
static const unsigned short CMD_RST   = 0x99;  // Reset command               //
static const unsigned short CMD_ULBFR = 0x98;  // Global unlock               //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Functions for Flash2 Click SST26VF064B                                     //
////////////////////////////////////////////////////////////////////////////////
// Function - Reset the memory                                                //
void SerialFlash_Reset(){                                                     //
    CS = 0;                                                                   //
    SPI3_Write(CMD_REEN);   // reset enable                                   //
    CS = 1;                                                                   //
    delay_ms(1);                                                              //
    CS = 0;                                                                   //
    SPI3_Write(CMD_RST);    // reset command                                  //
    CS = 1;                                                                   //
    return;                                                                   //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////
// Function - Write to the status register                                    //
void SerialFlash_WriteSR(char status){                                        //
    CS = 0;                                                                   //
    SPI3_Write(CMD_WRSR);   // write to status register                       //
    SPI3_Write(0);          // dummy byte                                     //
    SPI3_Write(status);     // write status                                   //
    CS = 1;                                                                   //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////
// Initialize SPI bus and serial flash on SPI3                                //
// Max speed is 50HMz, use 80/2 = 40MHz                                       //
// M25P80 memory only accepts two SPI formats:                                //
//      _SPI_CLK_IDLE_HIGH,_SPI_ACTIVE_2_IDLE)                                //
//      _SPI_CLK_IDLE_LOW, _SPI_IDLE_2_ACTIVE)                                //
// Uses  SPI3 with MOSI/RF8 MISO/RF2 SCK3/RD15                                //
void SerialFlash_Start() {                                                    //
    SPI3_Init_Advanced(_SPI_MASTER,_SPI_8_BIT,8,_SPI_SS_DISABLE,\
    _SPI_DATA_SAMPLE_MIDDLE,_SPI_CLK_IDLE_LOW,_SPI_IDLE_2_ACTIVE);            //
    Delay_ms(100);                                                            //
    CS = 1;                     // CS bit disabled                            //
    SerialFlash_WriteEnable();  // CS cycled and WREN sent to chip            //
    SerialFlash_Reset();                                                      //
    Delay_ms(10);                                                             //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function - SerialFlash_WriteEnable()                                       //
void SerialFlash_WriteEnable(){                                               //
    CS = 0;                                                                   //
    SPI3_Write(CMD_WREN);                                                     //
    CS = 1;                                                                   //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function - SerialFlash_IsWriteBusy()                                       //
//            Bit 0 of the status register 1=busy 0=done                      //
char SerialFlash_IsWriteBusy(){                                               //
    char temp;                                                                //
    CS = 0;                                                                   //
    SPI3_Write(CMD_RDSR);                                                     //
    temp = SPI3_Read(0);                                                      //
    CS = 1;                                                                   //
    return (temp&0x01);                                                       //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function - Unlock memory on SST26VF064B/FLASH2 Click                       //
void SerialFlash_UnlockSST(){                                                 //
    SerialFlash_WriteEnable();                                                //
    CS = 0;                                                                   //
    SPI3_Write(CMD_ULBFR);                                                    //
    CS = 1;                                                                   //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function - SerialFlash_WriteByte() Function that writes a single byte      //
// Input: Data to be written and the address to which to store the data       //
void SerialFlash_WriteByte(char _data, unsigned long address){                //
    SerialFlash_WriteEnable();                                                //
    CS = 0;                                                                   //
    SPI3_Write(CMD_WRITE);                                                    //
    SPI3_Write(Higher(address));                                              //
    SPI3_Write(Hi(address));                                                  //
    SPI3_Write(Lo(address));                                                  //
    SPI3_Write(_data);                                                        //
    CS = 1;                                                                   //
    // Wait for write end                                                     //
    while(SerialFlash_isWriteBusy());                                         //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function - SerialFlash_ReadByte() reads the byte from the address          //
// Input: address to be read. Output: byte data from the address              //
char SerialFlash_ReadByte(unsigned long address){                             //
  char temp;                                                                  //
  CS = 0;                                                                     //
  SPI3_Write(CMD_READ);                                                       //
  SPI3_Write(Higher(address));                                                //
  SPI3_Write(Hi(address));                                                    //
  SPI3_Write(Lo(address));                                                    //
  temp = SPI3_Read(0);                                                        //
  CS = 1;                                                                     //
  return temp;                                                                //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function -SerialFlash_WriteWord()writes 2 succesive bytes of word variable //
// Input: Word data to be written and the address to which to store the data  //
void SerialFlash_WriteWord(unsigned int _data, unsigned long address){        //
  SerialFlash_WriteByte(Hi(_data),address);                                   //
  SerialFlash_WriteByte(Lo(_data),address+1);                                 //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function - SerialFlash_ReadWord()reads the word from the address           //
// Input: read address. Output: word data stored in two successive addresses  //
unsigned int SerialFlash_ReadWord(unsigned long address){                     //
  unsigned int temp;                                                          //
  Hi(temp) = SerialFlash_ReadByte(address);                                   //
  Lo(temp) = SerialFlash_ReadByte(address+1);                                 //
  return temp;                                                                //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function - SerialFlash_WriteArray() writes data to successive addresses    //
// Input: address of the begining, pointer to buffer containing data          //
// and number of bytes to be written                                          //
// Output: 1 - if write succeeded, 0 - if write failed                        //
char SerialFlash_WriteArray(unsigned long address, char *pData, unsigned int nCount){
  unsigned long   addr;                                                       //
  char             *pD;                                                       //
  unsigned int counter;                                                       //
  addr = address;                                                             //
  pD   = pData;                                                               //
  // WRITE                                                                    //
  for(counter = 0; counter < nCount; counter++){                              //
      SerialFlash_WriteByte(*pD++, addr++);                                   //
  }                                                                           //
  // VERIFY                                                                   //
  for (counter=0; counter < nCount; counter++){                               //
    if (*pData != SerialFlash_ReadByte(address))                              //
        return 0;                                                             //
    pData++;                                                                  //
    address++;                                                                //
  }                                                                           //
  return 1;                                                                   //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function SerialFlash_ReadArray() reads data from successive addresses      //
// Input: address of the begining, pointer to buffer where to store read data,//
// and number of bytes to be read. Output: none                               //
void SerialFlash_ReadArray(unsigned long address, char *pData, unsigned int nCount){
  CS = 0;                                                                     //
  SPI3_Write(CMD_READ);                                                       //
  SPI3_Write(Higher(address));                                                //
  SPI3_Write(Hi(address));                                                    //
  SPI3_Write(Lo(address));                                                    //
  while(nCount--){                                                            //
    *pData++ = SPI3_Read(0);                                                  //
  }                                                                           //
  CS = 1;                                                                     //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function - Erase 64kBytes from input address                               //
void SerialFlash_E64KB(unsigned long address){                                //
  SerialFlash_WriteEnable();                                                  //
  CS = 0;                                                                     //
  SPI3_Write(CMD_E64KB);                                                      //
  SPI3_Write(Higher(address));                                                //
  SPI3_Write(Hi(address));                                                    //
  SPI3_Write(Lo(address));                                                    //
  CS = 1;                                                                     //
  // Wait for write end                                                       //
  while(SerialFlash_IsWriteBusy());                                           //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function - SerialFlash_ChipErase() sends Chip Erase command                //
void SerialFlash_ChipErase(void){                                             //
  SerialFlash_WriteEnable();                                                  //
  CS = 0;                                                                     //
  SPI3_Write(CMD_ERASE);                                                      //
  CS = 1;                                                                     //
  // Wait for write end                                                       //
  while(SerialFlash_IsWriteBusy());                                           //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function SerialFlash_ReadID() reads the CHIP ID                            //
// Input: none Output: ID byte value                                          //
char SerialFlash_ReadID(void){                                                //
  char temp;                                                                  //
  CS = 0;                                                                     //
  SPI3_Write(CMD_RDID);                                                       //
  temp = SPI3_Read(0);                                                        //
  CS = 1;                                                                     //
  return temp;                                                                //
}                                                                             //
////////////////////////////////////////////////////////////////////////////////
And last the Serial_Flash.h file:

Code: Select all

////////////////////////////////////////////////////////////////////////////////
// Project:         SERIAL_FLASH                                              //
// File:            Serial_Flash.h                                            //
// Function:        Read and write to serial flash memory                     //
//                  M25P80(on board EasyPICFusionv7 or W25Q64FV               //
//                  or SST26VF064B on FLASH2 Click                            //
// Set Up:          See attached Notes.c                                      //
// MCU:             32MX795F512L                                              //
// Board:           EasyPIC_Fusionv7                                          //
// Power:           3.3V for MCU and TFT                                      //
// Xtal:            Running at 80MHz                                          //
// Compiler:        mikroC PRO for PIC32 version 4.0.0                        //
// Programmer:      ICD3 or on-board                                          //
// Author:          WVL                                                       //
// Date:            11 Jan 2019                                               //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Conditional compilation. Comment un-comment to define your chip type       //
#define M25P80     // CS is RD14                                              //
//#define W25Q64FV // CS is RC2                                               //
//#define FLASH2   // CS is RC2                                               //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// EasyPICFusionv7 board has RD14 hardwired as CS by SW13                     //
#ifdef M25P80                                                                 //
sbit CS at LATD14_bit;          // set on SW13                                //
#endif                                                                        //
#ifdef W25Q64FV                                                               //
sbit CS at LATC2_bit;           // left hand MikroBus socket                  //
#endif                                                                        //
#ifdef FLASH2                                                                 //
sbit CS at LATC2_bit;           // left hand MikroBus socket                  //
#endif                                                                        //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Prototypes for serial flash functions                                      //
void SerialFlash_Start();                                                     //
void SerialFlash_WriteEnable();                                               //
char SerialFlash_IsWriteBusy_();                                              //
void SerialFlash_UnlockSST();                                                 //
void SerialFlash_WriteByte(unsigned char _data, unsigned long address);       //
char SerialFlash_ReadByte(unsigned long address);                             //
void SerialFlash_WriteWord(unsigned int _data, unsigned long address);        //
unsigned int SerialFlash_ReadWord(unsigned long address);                     //
char SerialFlash_WriteArray(unsigned long address,char*pData, unsigned int nCount);
void SerialFlash_ReadArray(unsigned long address, char*pData, unsigned int nCount);
void SerialFlash_E64KB(unsigned long address);                                //
void SerialFlash_ChipErase(void);                                             //
char SerialFlash_ReadID(void);                                                //
// Prototypes for Flash2 Click SST26VF064B                                    //
void SerialFlash_Reset();                                                     //
void SerialFlash_WriteSR(char status);                                        //
////////////////////////////////////////////////////////////////////////////////
All this is in the Mikro SDK and Libstock but I find them confusing.
Let me know if this is useful?
Regards Bill Legge

User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: Flash Memory M25P80, W25Q64FV or SST26VF064B Read and Wr

#2 Post by filip » 16 Jan 2019 15:29

Hi,

Nice job indeed, I'm sure our users will appreciate this as much as we do.

Regards,
Filip.

Post Reply

Return to “User Projects”