1

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

此致

桑德什

#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;   
}
4

1 回答 1

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,它现在可以工作了!)

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

PS 数据表某处说 BPR 是 18 字节长,这是错误的,BPR 只有 10 字节长

于 2016-10-13T13:54:33.250 回答