Как читать и писать в EEPROM в суде SPI

Я использую микроконтроллер PIC32MX350F128L для чтения и записи в EEPROM (SST26VF032B) с использованием связи SPI. Связь SPI в этой программе работает, я проверил это, отправив код JEDEC, который указан в таблице данных SST26VF032B. Поэтому, когда я отправляю 0x9F, я получаю 3 байта данных, как указано в таблице данных. Когда я бегу сейчас, я отправляю строку данных на определенный адрес eeprom и получаю взамен 0xff. Я стираю EEPROM перед записью в нее. Итак, я думаю, что получаю 0xff после стирания EEPROM. Операции записи и чтения не работают. Если я отправляю строку значения или БАЙТ, я получаю взамен 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;   
}

person Sandesh upadhyaya    schedule 19.02.2016    source источник


Ответы (1)


Я столкнулся с той же проблемой в течение 3 долгих дней, пока не обнаружил, что существует регистр длиной 18 байт, который называется Block Protection Register BPR. Вам нужно установить его биты в 0 в соответствии с областью памяти, которую вы хотите записать.

Итак, я прочитал BPR (отправьте команду 0x72 с последующим чтением 18 байтов) и обнаружил, что в моем случае он не везде равен нулю. Читая страницу 41 таблицы данных, вы можете увидеть, что после включения питания регистр BPR устанавливается на 5555 FFFFFFFF FFFFFFFF, поэтому он защищает от записи всю память.

Поэтому в целях тестирования я попытался полностью очистить его, и для этой цели есть специальная команда (0x98), позволяющая писать где угодно во всей памяти.

Но не забудьте записать enable the memory (команда 0x06) перед отправкой команды clear BPR (команда 0x98).

На этом этапе, если вы читаете BPR (команда 0x72), вы будете читать 00 в каждом из его 10 байтов. (А это значит, что теперь можно записывать всю память)

В этом состоянии у меня наконец-то работает запись. (Я отправил WriteEnable - SectorErase - SectorRead - WriteEnable - SectorWrite - SectorRead, и теперь он работает!)

Надеюсь, это поможет, таблица данных об этом очень хаотична.

P.S. Где-то в даташите написано, что BPR имеет длину 18 байт, это неверно, BPR имеет длину всего 10 байт.

person Merlin    schedule 13.10.2016