1
votes

I am using PIC32MX350F128L Microcontroller to read from and write to EEPROM(SST26VF032B) using SPI communication. SPI communication in this program is working, I have checked it by sending JEDEC code which is provided in the SST26VF032B datasheet. So when i send 0x9F i am getting 3 bytes of data as mentioned in the datasheet. When i run now i am sending a string of data to a specific address of eeprom and getting 0xff in return. I am erasing the eeprom before writing into it. So i think i am getting 0xff after erasing the eeprom. The writing, reading operations are not working. If i send a string of value or a BYTE i am getting 0xff in return. So can u guys please suggest me where i am going wrong. I am using UART for debugging purpose to read values recieved through spi communication. The complete code is below, i am using MPLAB X.

Best Regards

Sandesh

#include <xc.h>
#include <stdio.h>
#include <plib.h>
#include <p32xxxx.h>


/* Configuration Bits */

#pragma config FSRSSEL = PRIORITY_7     // Shadow Register Set Priority Select (SRS Priority 7)
#pragma config PMDL1WAY = ON            // Peripheral Module Disable Configuration (Allow only one reconfiguration)
#pragma config IOL1WAY = ON             // Peripheral Pin Select Configuration (Allow only one reconfiguration)

// DEVCFG2
#pragma config FPLLIDIV = DIV_2         // PLL Input Divider (2x Divider)
#pragma config FPLLMUL = MUL_20         // PLL Multiplier (20x Multiplier)
#pragma config FPLLODIV = DIV_1        // System PLL Output Clock Divider (PLL Divide by 1)

// DEVCFG1
#pragma config FNOSC = PRIPLL             // Oscillator Selection Bits (Primary Osc (XT,HS,EC))
#pragma config FSOSCEN = ON             // Secondary Oscillator Enable (Enabled)
#pragma config IESO = ON                // Internal/External Switch Over (Enabled)
#pragma config POSCMOD = HS            // Primary Oscillator Configuration (XT osc mode)
#pragma config OSCIOFNC = ON            // CLKO Output Signal Active on the OSCO Pin (Enabled)
#pragma config FPBDIV = DIV_1          // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/8)
#pragma config FCKSM = CSECME           // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576        // Watchdog Timer Postscaler (1:1048576)
#pragma config WINDIS = OFF             // Watchdog Timer Window Enable (Watchdog Timer is in Non-Window Mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
#pragma config FWDTWINSZ = WINSZ_25     // Watchdog Timer Window Size (Window Size is 25%)

// DEVCFG0
#pragma config DEBUG = OFF              // Background Debugger Enable (Debugger is Disabled)
#pragma config JTAGEN = OFF             // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx2        // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)
#pragma config PWP = OFF                // Program Flash Write Protect (Disable)
#pragma config BWP = OFF                // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF                 // Code Protect (Protection Disabled)

/* MACRO DEFINITIONS */

/* Defining the Slave Select Pin */
#define SS      LATDbits.LATD9

/* Defining the System Clock Frequency */
#define SYSCLK  40000000

 /* Macro to get array size in bytes
 * note that array size can't be found after passing pointer to a function */
#define LEN(x)  (sizeof(x) / sizeof(x[0]))

/* SST26VF032B EEPROM instructions */

/* Write Enable */
#define WREN    0x06   

/* Write Disable */
#define WRDI    0x04   

/* Initialize Start of Write Sequence */
#define WRITE   0x02    

/* Initialize Start of Read Sequence */
#define READ    0x03  

/*  Erase all sectors of Memory */
#define CE      0xc7   

/*  Read STATUS Register */
#define RDSR    0x05   

/* Function Prototypes */

/* UART bit configuration */
void Bitconfig_uart(void);

/* SPI Initialization */
void SPI1_Init(void);

/* UART Initialization */
void Init_uart(void);

/* Send a Character Byte through UART */
void UART5PutChar(char Ch);

/* Function to Read and Write SPI1 buffer */
int SPI1_transfer( int b);

/* Function to check the Status of SPI */
void waitBusy();

/* Function to erase the contents in EEPROM */
void eraseEEPROM();

/* Function to Read data from EEPROM */
void readEEPROM( int address, char* loadArray, int loadArray_size);

/* Function to Write to EEPROM */
void writeEEPROM( int address, char* storeArray, int storeArray_size);

/* Global Variables Declaration */
/* Declare variables to check the functionality of EEPROM */
int i,j = 0;
char st = 0x9F;
char rec;
int x,y,z;

/*******************************************************************************
* Function Name: main()
********************************************************************************
* Summary:
*  Initializes SPI
*  Erase EEPROM
*  Writes to EEPROM
*  Read from EEPROM
*
* Parameters:
*  None.
*
* Return:
*  None.
*
*******************************************************************************/
int main()
{    

    int i;
    /* Clock Setting */
    SYSTEMConfigPerformance(SYSCLK);

    /* UART bit configuration */
    Bitconfig_uart();

    /* Set the Controller OScillator Register bits */
    //OSCCON = 0x00002200;

    /* Initialize a String to Write to EEPROM and an array to Read back contents */
    char writeData[] = "123456789ABCDEF";

    /* Array to read 35 bytes of data */
    char readData[15];

    /* SPI Initialization */
    SPI1_Init();

    /* UART Initialization */
    Init_uart();

    /* Erase contents of EEPROM */
    eraseEEPROM();

    /* Write contents of writeData array to address 180 */
    writeEEPROM( 0x1000, writeData, LEN(writeData));

    /*
     JEDEC Code (working) getting output as per datasheet (0x9F = 159)
    SS=0;
    SPI1_transfer(159);
    x=SPI1_transfer(0);
    UART5PutChar(x);
    y=SPI1_transfer(0);
    UART5PutChar(y);
    z=SPI1_transfer(0);
    UART5PutChar(z);
    */
    while(1)
    {   
        /* Read contents of EEPROM into readData array
         * start at address 180 and read up to 180+length(readData) */
        readEEPROM( 0x1000, readData, LEN(readData) );
    }
} /* END main() */

/*******************************************************************************
* Function Name: SPI1_Init()
********************************************************************************
* Summary:
*  SPI1 Initialization
*
* Parameters:
*  None.
*
* Return:
*  None.
*
*******************************************************************************/
void SPI1_Init(void)
{
    /* Configure Peripheral Pin Select (PPS) for the SPI1 module
    * Note: SS will be toggled manually in code
    * SCK is hardwired to pin 55 */

    /* Output Pin Selection */
    RPE5R = 8;
    SDI1R = 3;

    /* RB4 (Slave Select 1) : output */
    TRISDbits.TRISD9 = 0;      

    /* SPI configuration */

    /* SPI1CON Register Configuration
     * MSTEN: Master Mode Enable bit = 1 (Master)
     * CKP (clock polarity control) = 0
     * CKE (clock edge control) = 1
     * ON: SPI Peripheral On bit
     * 8-bit, Master Mode */
    SPI1CON = 0x8120;

    /* SPI1BRG Register Configuration */
    SPI1BRG = 0x4D;
    //REFOCONbits.ON = 1;
   // REFOCONbits.DIVSWEN = 1;
}

/*******************************************************************************
* Function Name: SPI1_transfer()
********************************************************************************
* Summary:
*  Write to and Read from SPI1 buffer
*
* Parameters:
*  char b - Writes a Character to Buffer
*
* Return:
*  Char - Returns the Character Read from EEPROM
*
*******************************************************************************/
int SPI1_transfer( int b)
{
    /* write to buffer for TX */
    SPI1BUF = b;    

    /* wait transfer complete */
    while(!SPI1STATbits.SPIRBF);       

    /* read the received value */
    return SPI1BUF;                    
} /* END SPI1_transfer() */


/*******************************************************************************
* Function Name: waitBusy()
********************************************************************************
* Summary:
*  Checks if EEPROM is ready to be modified and waits if not ready
*
* Parameters:
*  None.
*
* Return:
*  None.
*
*******************************************************************************/
void waitBusy()
{
    char status = 0;

    do{
        /* Select EEPROM */
        SS = 0;

        /* Read EEPROM status register */
        SPI1_transfer(RDSR);       

        /* send dummy byte to receive incoming data */
        status = SPI1_transfer(0);  

        /* Release EEPROM */
        SS = 1;                           
    }

    /* write-in-progress while status<0> set to '1' */
    while( status & 0x01);            

} /* END waitBusy() */




/*******************************************************************************
* Function Name: readEEPROM()
********************************************************************************
* Summary:
* Reads data from EEPROM
*
* Parameters:
* Inputs:  address - EEPROM address
*          loadArray - array to load EEPROM data to
*          loadArray_size - number of bytes of EEPROM data to load into array
*
* Return:
*  None.
*
*******************************************************************************/
void readEEPROM( int address, char* loadArray, int loadArray_size)
{
    int i;

    /* Wait until EEPROM is not busy */
    waitBusy();

    /* Select EEPROM */
    SS = 0;                 

    /* Initiate Read */
    SPI1_transfer( READ);        

    /* Address must be 16-bits but we're transferring it in two 8-bit sessions */
    SPI1_transfer( address >> 16);
    SPI1_transfer( address >> 8);  
    SPI1_transfer( address);       

    /* Request and store loadArray_size number of bytes into loadArray */
    for( i=0 ; i<loadArray_size ; i++)
    {
        /* send dummy byte to read 1 byte */
        loadArray[i] = SPI1_transfer( 0x00);   
    }
    /* Release EEPROM */
    SS = 1;                        

        /* UART Test */
        for(i=0;i<35;i++)
        {
            UART5PutChar(loadArray[i]);
            for(j=0;j<20000;j++)
            {}
        }

} /* END readEEPROM() */

/*******************************************************************************
* Function Name: writeEEPROM()
********************************************************************************
* Summary:
* Write data to EEPROM
*
* Parameters:
* Inputs:  address -  EEPROM address
*          storeArray - array of which contents are stored in EEPROM
*          storeArray_size - number of bytes in array to store into EEPROM
*
* Return:
*  None.
*
*******************************************************************************/

void writeEEPROM( int address, char* storeArray, int storeArray_size)
{
    int i;

    /* Wait until EEPROM is not busy */
    waitBusy();

    /* Select EEPROM */
    SS = 0;

    /* Send WRITE_ENABLE command */
    SPI1_transfer( WREN);

    /* Release EEPROM */
    SS = 1;                

    /* Select EEPROM again after WREN cmd */
    SS = 0;

    /* Initiate Write */
    SPI1_transfer( WRITE);

    SPI1_transfer( address >> 16 );
    SPI1_transfer( address >> 8 );
    SPI1_transfer( address );

    /* write 1 byte at a time from array */
    /* MSB at lowest address (0 - first letter in string) */
    for( i=0 ; i<storeArray_size; i++)
    {
            /* Initiate Write */
            SPI1_transfer( WRITE);
            SPI1_transfer( (address+i) >> 16 );
            SPI1_transfer( (address+i) >> 8 );
            SPI1_transfer( address+i );

        SPI1_transfer( storeArray[i]);
    }
    /* Release EEPROM */
    SS = 1;                       

} /* END writeEEPROM() */

/*******************************************************************************
* Function Name: eraseEEPROM()
********************************************************************************
* Summary:
* Erase entire contents of EEPROM
*
* Parameters:
*  None
*
* Return:
*  None.
*
*******************************************************************************/
void eraseEEPROM()
{
    /* Wait until EEPROM is not busy */
    waitBusy();

    /* Select EEPROM */
    SS = 0;               

    /* Send WRITE_ENABLE command */
    SPI1_transfer( WREN);  

    /* Release EEPROM */
    SS = 1;                

    /* Select EEPROM again after WREN cmd */
    SS = 0;            

    /* send CHIP_ERASE command */
    SPI1_transfer( CE);   

    /* Release EEPROM */
    SS = 1;                

} /* END eraseEEPROM() */

/*******************************************************************************
* Function Name: Init_uart()
********************************************g************************************
* Summary:
* Initialize UART4
*
* Parameters:
*  None
*
* Return:
*  None.
*
*******************************************************************************/
void Init_uart()
{
    /* Enable UART */
   U5MODEbits.ON = 1 ;

   /* set baud rate(9600) */
   U5BRG = 521;

   /* Set U4STA Register for Enabling tx and rx */
   U5STA=0x9400;

}

/*******************************************************************************
* Function Name: UART4PutChar(unsigned char Ch)
********************************************************************************
* Summary:
* Send data from controller to putty GUI
*
* Parameters:
* input
* unsigned char Ch -  To Send a byte of data over UART
*
* Return:
*  None.
*
*******************************************************************************/
void UART5PutChar(char Ch)
{
while(U5STAbits.UTXBF == 1);
U5TXREG=Ch;
}

/*******************************************************************************
* Function Name: Bitconfig_uart()
********************************************************************************
* Summary:
* UART Pin Configuration
*
* Parameters:
*  None
*
* Return:
*  None.
*
*******************************************************************************/
void Bitconfig_uart(void)
{
    /* UART4 Initialization */
   // OSCCON=0x00002200;

    /* Set pins as digital */
    ANSELBbits.ANSB2 = 0;
    ANSELBbits.ANSB0 = 0;

    /* Set UART Tx pin as Output */
    TRISBbits.TRISB0 = 0;  //in controler tx
    TRISBbits.TRISB2 = 1; // in controller RX    


    /* Peripheral Pin select for UART4 */
    U5RXR=0x07;
    RPB0R=0x04;   
}
1

1 Answers

2
votes

I faced the same problem for 3 long days until I found that there's a 18bytes long register called Block Protection Register BPR. You need to set its bits to 0, according to the memory area you want to write.

So I read the BPR (send command 0x72 followed by 18 byte read) and I found it was not at zero everywhere in my case. Reading on page 41 of the datasheet you can see that after a power on the BPR register is set to 5555 FFFFFFFF FFFFFFFF, so it protects from write the whole memory.

So for testing purpose I tried to clears it completely, and there's a specific command (0x98) for that purpose, allowing you to write anywhere in the whole memory.

But be sure to write enable the memory (command 0x06) before sending the clear BPR command (command 0x98).

At this point if you read the BPR (command 0x72) you will read 00 at every of its 10 bytes. (And this means the whole memory is now writeable)

In this state the write now finally works for me. (I sent WriteEnable - SectorErase - SectorRead - WriteEnable - SectorWrite - SectorRead and it now works!)

Hope it helps, the datasheet is very chaotic about that.

P.S. Somewhere the datasheet says that BPR is 18 bytes long, it is wrong, the BPR is only 10 bytes long