如何读取和写入EEPROM通信SPI通信

时间:2016-02-19 07:01:44

标签: spi flash-memory eeprom

我正在使用PIC32MX350F128L微控制器使用SPI通信读取和写入EEPROM(SST26VF032B)。该程序中的SPI通信正在工作,我已经通过发送SST26VF032B数据表中提供的JEDEC代码进行了检查。因此,当我发送0x9F时,我得到3个字节的数据,如数据表中所述。当我现在运行时,我将一串数据发送到eeprom的特定地址并获得0xff作为回报。我在写入之前擦除了eeprom。所以我想我在删除eeprom后得到了0xff。写作,阅读操作不起作用。如果我发送一个值字符串或BYTE我得到0xff作为回报。那么你们可以建议我哪里出错了。我正在使用UART进行调试,以读取通过spi通信收到的值。完整的代码如下,我使用的是MPLAB X.

最好的问候

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 个答案:

答案 0 :(得分:2)

我遇到了长达3天的同样问题,直到我发现有一个18字节长的寄存器称为块保护寄存器BPR。 您需要根据要写入的内存区域将其位设置为0。

所以我读了BPR(发送命令0x72后跟18字节读取),我发现在我的情况下它并不是零。 在数据表的第41页上读取,您可以看到在BPR寄存器上电后设置为5555 FFFFFFFF FFFFFFFF,因此它可以防止写入整个存储器。

因此,出于测试目的,我试图完全清除它,并且为此目的有一个特定的命令(0x98),允许你在整个内存中的任何地方写入。

但是一定要在发送清除BPR命令(命令0x98)之前写入启用内存(命令0x06)。

此时如果您读取BPR(命令0x72),则每10个字节读取00。 (这意味着整个内存现在都可以写入)

在这种状态下,写作现在终于适合我了。 (我发送了WriteEnable - SectorErase - SectorRead - WriteEnable - SectorWrite - SectorRead,它现在可以工作了!)

希望它有所帮助,数据表对此非常混乱。

P.S。 在某个地方,数据表说BPR长18个字节,这是错误的,BPR只有10个字节长