TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: PFCarrera en 05 de Marzo de 2010, 07:49:50

Título: Memoria externa SPI
Publicado por: PFCarrera en 05 de Marzo de 2010, 07:49:50
Buenas a todos!

Necesito escribir y leer  datos en una memoria externa SPI (25LC1024) y utilizo 18F4550.
El problema es que no me aclaro mucho con el SPI y por más que busco, no encuentro ejemplos de comunicación SPI con una memoria externa, todos los ejemplos que encuentro son con CSS y yo utilizo C18.

Espero que alguien pueda ayudarme!

un saludo!
Título: Re: Memoria externa SPI
Publicado por: migsantiago en 05 de Marzo de 2010, 11:51:23
Entonces tendrás que leer la datasheet de la memoria y configurar el módulo SPI del pic desde cero.

Ve publicando tus avances.
Título: Re: Memoria externa SPI
Publicado por: AngelGris en 05 de Marzo de 2010, 11:51:46
No si habrá ejemplos en el foro, pero en www.microchipc.com hay varios ejemplos de distintas cosas en C para el compilador Hitech.

De todos modos te va a ser necesario leer el datasheet de la memoria para saber bien como son los comandos para dicha memoria.
Título: Re: Memoria externa SPI
Publicado por: PFCarrera en 08 de Marzo de 2010, 09:08:19
Gracias chico!
he estado leyendo el datasheet....lo único que yo y el inglés no nos llevamos muy bien  :)
He averiguado algunas cosas, pero seguiré intentándolo.

Si encontrais algun ejemplo para poder guiarme os lo agradecería!!
Título: Re: Memoria externa SPI
Publicado por: AngelGris en 08 de Marzo de 2010, 11:17:34
Bueno, te dejo una explicación muy básica y los comando básicos del uso de la memoria. También te adjunto un programita hecho en C (HiTech) donde hay unas rutinitas de manejo de SPI y me comunico con la memoria en cuestión. Está simulado en Proteus y funciona bien. El programa es para un 16F876A.

---------------------------------------
Hay que tener en cuenta que el pin WP tiene que estar en 1 para poder escribir en la memoria.

Antes de intentar escribir en la memoria hay que habilitar la escritura enviando el comando correspondiente. Esto se
logra con la siguiente secuencia

    Se habilita el dispositivo (llevando el pin CS a 0)
    Enviamos la instruccion WREN (transmitimos el byte correspondiente que es "00000110")
    Deshabilitamos el dispositivo (llevando el pin CS a 1)

Una vez que hemos habilitado la escritura ya podemos escribir en la memoria.
Para escribir un Byte hay que hacer lo siguiente

    Habilitar el dispositivo (llevando el pin CS a 0)
    Enviamos la instruccion WRITE (transmitimos el byte correspondiente que es "00000010")
    Enviamos la direccion a escribir (la dirección es de 24 bits por lo tanto hay que enviar 3 bytes)
    Enviamos el dato a escribir
    Deshabilitamos el dispositivo (llevando el pin CS a 1)

Para escribir mas un Byte consecutivos y dentro de una misma pagina hay que hacer lo siguiente

    Habilitar el dispositivo (llevando el pin CS a 0)
    Enviamos la instruccion WRITE (transmitimos el byte correspondiente que es "00000010")
    Enviamos la direccion a escribir (la dirección es de 24 bits por lo tanto hay que enviar 3 bytes)
    Enviamos el dato a escribir
    Enviamos el dato a escribir
    ..... (Enviar cantidad de bytes que se quieren escribir)
    Deshabilitamos el dispositivo (llevando el pin CS a 1)

Se pueden enviar hasta 256 bytes antes que sea necesario un ciclo de escritura. Por cada ciclo de escritura hay
que esperar un máximo de 6ms antes de volver a escribir. El ciclo de escritura comienza a partir del momento en
que el pin CS se hace 1
Cada vez que termina el ciclo de escritura, se deshabilita la escritura automaticamente por lo tanto para volver
a escribir en la memoria hay volver a habilitar la escritura

Para deshabilitar la escritura hay que enviar la siguiente secuencia

    Se habilita el dispositivo (llevando el pin CS a 0)
    Enviamos la instruccion WRDI (transmitimos el byte correspondiente que es "00000100")
    Deshabilitamos el dispositivo (llevando el pin CS a 1)

Para leer un Byte hay que enviar la siguiente secuencia

    Habilitar el dispositivo (llevando el pin CS a 0)
    Enviamos la instruccion READ (transmitimos el byte correspondiente que es "00000011")
    Enviamos la direccion a leer (la dirección es de 24 bits por lo tanto hay que enviar 3 bytes)
    Hacemos una trasmisión (se puede enviar o no dato hacia el dispositivo) para poder leer la memoria.
    Deshabilitamos el dispositivo (llevando el pin CS a 1)

Para leer mas un Byte consecutivos hay que enviar la siguiente secuencia

    Habilitar el dispositivo (llevando el pin CS a 0)
    Enviamos la instruccion READ (transmitimos el byte correspondiente que es "00000011")
    Enviamos la direccion a leer (la dirección es de 24 bits por lo tanto hay que enviar 3 bytes)
    Hacemos una trasmisión (se puede enviar o no dato hacia el dispositivo) para poder leer la memoria.
    Hacemos una trasmisión (se puede enviar o no dato hacia el dispositivo) para poder leer la memoria.
    ..... (Una transmisión por cada byte que se quiera leer, la dirección se incrementa automáticamente)
    Deshabilitamos el dispositivo (llevando el pin CS a 1)
Título: Re: Memoria externa SPI
Publicado por: AngelGris en 08 de Marzo de 2010, 11:25:02
Había un error en la parte del for del programita que te mandé. Acá te lo subo reparado

Código: C
  1. /********************************************
  2. *
  3. * Prueba de protocolo SPI por HardWare
  4. *
  5. /********************************************/
  6.  
  7.  
  8. #include <htc.h>
  9. #include "Def16f87xa.h"
  10. #define PIC_CLK 20000000
  11.  
  12.  
  13. #include "Hardspi.c"
  14. #include "delayhd.h"
  15.  
  16. void main()
  17. {
  18.         unsigned char veces;
  19.         unsigned char Dato_leido;
  20.  
  21.         TRISC0 = 0;
  22.         RC0 = 1;
  23.         setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV16);
  24.  
  25.  
  26.         RC0 = 0;                // habilito el dispositivo
  27.         write_spi(6);   // habilito la escritura en la memoria
  28.         RC0 = 1;                // deshabilito el dispositivo
  29.  
  30.         RC0 = 0;                // habilito el dispositivo
  31.         write_spi(2);   // instruccion de escribir
  32.         write_spi(0);   // direccion, byte mas significativo
  33.         write_spi(0);   // direccion
  34.         write_spi(0);   // direccion, byte menos significativo
  35.         write_spi(128); // dato
  36.         write_spi(64);  // dato
  37.         RC0 = 1;                // deshabilito el dispositivo
  38.  
  39.        
  40.         for (veces = 24; veces > 0; veces--)
  41.         {
  42.                 DelayUs(250);
  43.         }
  44.  
  45.         //El ciclo (For...) anterior es para hacer una espera de 6ms que es
  46.         //el tiempo del ciclo de escritura de la memoria.
  47.        
  48.  
  49.         RC0 = 0;                // habilito el dispositivo
  50.         write_spi(3);   // instruccion de leer
  51.         write_spi(0);   // direccion, byte mas significativo
  52.         write_spi(0);   // direccion
  53.         write_spi(0);   // direccion, byte menos significativo
  54.         Dato_leido = read_spi();                // leo el dato de la direccion 000
  55.         Dato_leido = read_spi();                // leo el dato de la direccion 001
  56.         RC0 = 1;                // deshabilito el dispositivo
  57.  
  58.         while (1);
  59. }
Título: Re: Memoria externa SPI
Publicado por: migsantiago en 08 de Marzo de 2010, 20:41:53
Hoy en día el inglés no debería ser problema. Este link te será de mucha utilidad.

http://translate.google.com
Título: Re: Memoria externa SPI
Publicado por: Suky en 08 de Marzo de 2010, 20:53:15
he estado leyendo el datasheet....lo único que yo y el inglés no nos llevamos muy bien  :)

Uff! Entonces le erraste de camino!  :D Va a ser necesario que se comiencen a llevar bien  :D
Título: Re: Memoria externa SPI
Publicado por: PFCarrera en 09 de Marzo de 2010, 07:00:07
Muchísimas gracias AngelGris!

voy a ponerme en ello!!
ya os contaré mis progresos

Por lo del inglés....ya se que es muy importante...estoy en ello.
Gracias a los demás.

Un saludo
Título: Re: Memoria externa SPI
Publicado por: barral en 09 de Marzo de 2010, 08:21:35
En el ejemplo de TCP/IP hay rutinas para memorias SPI, el los archivos son Spieeprom.c, xeeprom.h

spieeprom.c
Código: [Seleccionar]
/*********************************************************************
 *
 *               Data SPI EEPROM Access Routines
 *
 *********************************************************************
 * FileName:        SPIEEPROM.c
 * Dependencies:    None
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 * Microchip C30 v3.12 or higher
 * Microchip C18 v3.30 or higher
 * HI-TECH PICC-18 PRO 9.63PL2 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 * used in conjunction with a Microchip ethernet controller for
 * the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Nilesh Rajbharti     5/20/02     Original (Rev. 1.0)
 * Howard Schlunder     9/01/04     Rewritten for SPI EEPROMs
 * Howard Schlunder     8/10/06     Modified to control SPI module
 *                                  frequency whenever EEPROM accessed
 *                                  to allow bus sharing with different
 *                                  frequencies.
********************************************************************/
#define __SPIEEPROM_C

#include "HardwareProfile.h"

// If the CS line is not defined, SPIEEPROM.c's content will not be compiled. 
// If you are using a serial EEPROM please define the CS pin as EEPROM_CS_TRIS
// in HardwareProfile.h
#if defined(EEPROM_CS_TRIS)

#include "TCPIP Stack/TCPIP.h"

// IMPORTANT SPI NOTE: The code in this file expects that the SPI interrupt
//      flag (EEPROM_SPI_IF) be clear at all times.  If the SPI is shared with
//      other hardware, the other code should clear the EEPROM_SPI_IF when it is
//      done using the SPI.

// SPI Serial EEPROM buffer size.  To enhance performance while
// cooperatively sharing the SPI bus with other peripherals, bytes
// read and written to the memory are locally buffered. Legal
// sizes are 1 to the EEPROM page size.
#define EEPROM_BUFFER_SIZE              (32)

// Must be the EEPROM write page size, or any binary power of 2 divisor.  If
// using a smaller number, make sure it is at least EEPROM_BUFFER_SIZE big for
// max performance.  Microchip 25LC256 uses 64 byte page size, 25LC1024 uses
// 256 byte page size, so 64 is compatible with both.
#define EEPROM_PAGE_SIZE (64)

// EEPROM SPI opcodes
#define OPCODE_READ    0x03    // Read data from memory array beginning at selected address
#define OPCODE_WRITE   0x02    // Write data to memory array beginning at selected address
#define OPCODE_WRDI    0x04    // Reset the write enable latch (disable write operations)
#define OPCODE_WREN    0x06    // Set the write enable latch (enable write operations)
#define OPCODE_RDSR    0x05    // Read Status register
#define OPCODE_WRSR    0x01    // Write Status register

#define EEPROM_MAX_SPI_FREQ     (10000000ul)    // Hz

#if defined (__18CXX)
    #define ClearSPIDoneFlag()  {EEPROM_SPI_IF = 0;}
    #define WaitForDataByte()   {while(!EEPROM_SPI_IF); EEPROM_SPI_IF = 0;}
    #define SPI_ON_BIT          (EEPROM_SPICON1bits.SSPEN)
#elif defined(__C30__)
    #define ClearSPIDoneFlag()
    static inline __attribute__((__always_inline__)) void WaitForDataByte( void )
    {
        while ((EEPROM_SPISTATbits.SPITBF == 1) || (EEPROM_SPISTATbits.SPIRBF == 0));
    }

    #define SPI_ON_BIT          (EEPROM_SPISTATbits.SPIEN)
#elif defined( __PIC32MX__ )
    #define ClearSPIDoneFlag()
    static inline __attribute__((__always_inline__)) void WaitForDataByte( void )
    {
        while (!EEPROM_SPISTATbits.SPITBE || !EEPROM_SPISTATbits.SPIRBF);
    }

    #define SPI_ON_BIT          (EEPROM_SPICON1bits.ON)
#else
    #error Determine SPI flag mechanism
#endif

static void DoWrite(void);

static DWORD EEPROMAddress;
static BYTE EEPROMBuffer[EEPROM_BUFFER_SIZE];
static BYTE vBytesInBuffer;

/*********************************************************************
 * Function:        void XEEInit(unsigned char speed)
 *
 * PreCondition:    None
 *
 * Input:           speed - not used (included for compatibility only)
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Initialize SPI module to communicate to serial
 *                  EEPROM.
 *
 * Note:            Code sets SPI clock to Fosc/16.
 ********************************************************************/
#if (defined(HPC_EXPLORER) || defined(PIC18_EXPLORER)) && !defined(__18F87J10) && !defined(__18F87J11) && !defined(__18F87J50)
    #define PROPER_SPICON1  (0x20)      /* SSPEN bit is set, SPI in master mode, FOSC/4, IDLE state is low level */
#elif defined(__PIC24F__)
    #define PROPER_SPICON1  (0x0013 | 0x0120)   /* 1:1 primary prescale, 4:1 secondary prescale, CKE=1, MASTER mode */
#elif defined(__dsPIC30F__)
    #define PROPER_SPICON1  (0x0017 | 0x0120)   /* 1:1 primary prescale, 3:1 secondary prescale, CKE=1, MASTER mode */
#elif defined(__dsPIC33F__) || defined(__PIC24H__)
    #define PROPER_SPICON1  (0x0003 | 0x0120)   /* 1:1 primary prescale, 8:1 secondary prescale, CKE=1, MASTER mode */
#elif defined(__PIC32MX__)
    #define PROPER_SPICON1  (_SPI2CON_ON_MASK | _SPI2CON_FRZ_MASK | _SPI2CON_CKE_MASK | _SPI2CON_MSTEN_MASK)
#else
    #define PROPER_SPICON1  (0x21)      /* SSPEN bit is set, SPI in master mode, FOSC/16, IDLE state is low level */
#endif

void XEEInit(void)
{
    EEPROM_CS_IO = 1;
    EEPROM_CS_TRIS = 0;     // Drive SPI EEPROM chip select pin

    EEPROM_SCK_TRIS = 0;    // Set SCK pin as an output
    EEPROM_SDI_TRIS = 1;    // Make sure SDI pin is an input
    EEPROM_SDO_TRIS = 0;    // Set SDO pin as an output

    ClearSPIDoneFlag();
    #if defined(__C30__)
        EEPROM_SPICON1 = PROPER_SPICON1; // See PROPER_SPICON1 definition above
        EEPROM_SPICON2 = 0;
        EEPROM_SPISTAT = 0;    // clear SPI
        EEPROM_SPISTATbits.SPIEN = 1;
    #elif defined(__C32__)
        EEPROM_SPIBRG = (GetPeripheralClock()-1ul)/2ul/EEPROM_MAX_SPI_FREQ;
        EEPROM_SPICON1 = PROPER_SPICON1;
    #elif defined(__18CXX)
        EEPROM_SPICON1 = PROPER_SPICON1; // See PROPER_SPICON1 definition above
        EEPROM_SPISTATbits.CKE = 1;     // Transmit data on rising edge of clock
        EEPROM_SPISTATbits.SMP = 0;     // Input sampled at middle of data output time
    #endif
}


/*********************************************************************
 * Function:        XEE_RESULT XEEBeginRead(DWORD address)
 *
 * PreCondition:    None
 *
 * Input:           address - Address at which read is to be performed.
 *
 * Output:          XEE_SUCCESS
 *
 * Side Effects:    None
 *
 * Overview:        Sets internal address counter to given address.
 *
 * Note:            None
 ********************************************************************/
XEE_RESULT XEEBeginRead(DWORD address)
{
    // Save the address and emptry the contents of our local buffer
    EEPROMAddress = address;
    vBytesInBuffer = 0;
    return XEE_SUCCESS;
}


/*********************************************************************
 * Function:        BYTE XEERead(void)
 *
 * PreCondition:    XEEInit() && XEEBeginRead() are already called.
 *
 * Input:           None
 *
 * Output:          BYTE that was read
 *
 * Side Effects:    None
 *
 * Overview:        Reads next byte from EEPROM; internal address
 *                  is incremented by one.
 *
 * Note:            None
 ********************************************************************/
BYTE XEERead(void)
{
    // Check if no more bytes are left in our local buffer
    if(vBytesInBuffer == 0u)
    {
        // Get a new set of bytes
        XEEReadArray(EEPROMAddress, EEPROMBuffer, EEPROM_BUFFER_SIZE);
        EEPROMAddress += EEPROM_BUFFER_SIZE;
        vBytesInBuffer = EEPROM_BUFFER_SIZE;
    }

    // Return a byte from our local buffer
    return EEPROMBuffer[EEPROM_BUFFER_SIZE - vBytesInBuffer--];
}

/*********************************************************************
 * Function:        XEE_RESULT XEEEndRead(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          XEE_SUCCESS
 *
 * Side Effects:    None
 *
 * Overview:        This function does nothing.
 *
 * Note:            Function is used for backwards compatability with
 *                  I2C EEPROM module.
 ********************************************************************/
XEE_RESULT XEEEndRead(void)
{
    return XEE_SUCCESS;
}


/*********************************************************************
 * Function:        XEE_RESULT XEEReadArray(DWORD address,
 *                                          BYTE *buffer,
 *                                          WORD length)
 *
 * PreCondition:    XEEInit() is already called.
 *
 * Input:           address     - Address from where array is to be read
 *                  buffer      - Caller supplied buffer to hold the data
 *                  length      - Number of bytes to read.
 *
 * Output:          XEE_SUCCESS
 *
 * Side Effects:    None
 *
 * Overview:        Reads desired number of bytes in sequential mode.
 *                  This function performs all necessary steps
 *                  and releases the bus when finished.
 *
 * Note:            None
 ********************************************************************/
XEE_RESULT XEEReadArray(DWORD address,
                        BYTE *buffer,
                        WORD length)
{
    volatile BYTE Dummy;
    BYTE vSPIONSave;
    #if defined(__18CXX)
    BYTE SPICON1Save;
    #elif defined(__C30__)
    WORD SPICON1Save;
    #else
    DWORD SPICON1Save;
    #endif

    // Save SPI state (clock speed)
    SPICON1Save = EEPROM_SPICON1;
    vSPIONSave = SPI_ON_BIT;

    // Configure SPI
    SPI_ON_BIT = 0;
    EEPROM_SPICON1 = PROPER_SPICON1;
    SPI_ON_BIT = 1;

    EEPROM_CS_IO = 0;

    // Send READ opcode
    EEPROM_SSPBUF = OPCODE_READ;
    WaitForDataByte();
    Dummy = EEPROM_SSPBUF;

    // Send address
    #if defined(USE_EEPROM_25LC1024)
    EEPROM_SSPBUF = ((DWORD_VAL*)&address)->v[2];
    WaitForDataByte();
    Dummy = EEPROM_SSPBUF;
    #endif

    EEPROM_SSPBUF = ((DWORD_VAL*)&address)->v[1];
    WaitForDataByte();
    Dummy = EEPROM_SSPBUF;

    EEPROM_SSPBUF = ((DWORD_VAL*)&address)->v[0];
    WaitForDataByte();
    Dummy = EEPROM_SSPBUF;

    while(length--)
    {
        EEPROM_SSPBUF = 0;
        WaitForDataByte();
        Dummy = EEPROM_SSPBUF;
        if(buffer != NULL)
            *buffer++ = Dummy;
    };

    EEPROM_CS_IO = 1;

    // Restore SPI state
    SPI_ON_BIT = 0;
    EEPROM_SPICON1 = SPICON1Save;
    SPI_ON_BIT = vSPIONSave;


    return XEE_SUCCESS;
}


/*********************************************************************
 * Function:        XEE_RESULT XEEBeginWrite(DWORD address)
 *
 * PreCondition:    None
 *
 * Input:           address     - address to be set for writing
 *
 * Output:          XEE_SUCCESS
 *
 * Side Effects:    None
 *
 * Overview:        Modifies internal address counter of EEPROM.
 *
 * Note:            Unlike XEESetAddr() in xeeprom.c for I2C EEPROM
 *                  memories, this function is used only for writing
 *                  to the EEPROM.  Reads must use XEEBeginRead(),
 *                  XEERead(), and XEEEndRead().
 *                  This function does not use the SPI bus.
 ********************************************************************/
XEE_RESULT XEEBeginWrite(DWORD address)
{
vBytesInBuffer = 0;
    EEPROMAddress = address;
    return XEE_SUCCESS;
}


/*********************************************************************
 * Function:        XEE_RESULT XEEWrite(BYTE val)
 *
 * PreCondition:    XEEInit() && XEEBeginWrite() are already called.
 *
 * Input:           val - Byte to be written
 *
 * Output:          XEE_SUCCESS
 *
 * Side Effects:    None
 *
 * Overview:        Writes a byte to the write cache, and if full,
 * commits the write.  Also, if a write boundary is
 * reached the write is committed.  When finished
 * writing, XEEEndWrite() must be called to commit
 * any unwritten bytes from the write cache.
 *
 * Note:            None
 ********************************************************************/
XEE_RESULT XEEWrite(BYTE val)
{
EEPROMBuffer[vBytesInBuffer++] = val;
if(vBytesInBuffer >= sizeof(EEPROMBuffer))
DoWrite();
else if((((BYTE)EEPROMAddress + vBytesInBuffer) & (EEPROM_PAGE_SIZE-1)) == 0u)
DoWrite();

    return XEE_SUCCESS;
}


/*****************************************************************************
  Function:
    XEE_RESULT XEEWriteArray(BYTE *val, WORD wLen)

  Summary:
    Writes an array of bytes to the EEPROM part.

  Description:
    This function writes an array of bytes to the EEPROM at the address
    specified when XEEBeginWrite() was called.  Page boundary crossing is
    handled internally.
   
  Precondition:
    XEEInit() was called once and XEEBeginWrite() was called.

  Parameters:
    vData - The array to write to the next memory location
    wLen - The length of the data to be written

  Returns:
    None

  Remarks:
    The internal write cache is flushed at completion, so it is unnecessary
    to call XEEEndWrite() after calling this function.  However, if you do
    so, no harm will be done.
  ***************************************************************************/
void XEEWriteArray(BYTE *val, WORD wLen)
{
while(wLen--)
XEEWrite(*val++);

XEEEndWrite();
}


/*********************************************************************
 * Function:        XEE_RESULT XEEEndWrite(void)
 *
 * PreCondition:    XEEInit() && XEEBeginWrite() are already called.
 *
 * Input:           None
 *
 * Output:          XEE_SUCCESS
 *
 * Side Effects:    None
 *
 * Overview:        Commits any last uncommitted bytes in cache to
 * physical storage.
 *
 * Note:            Call this function when you no longer need to
 * write any more bytes at the selected address.
 ********************************************************************/
XEE_RESULT XEEEndWrite(void)
{
if(vBytesInBuffer)
DoWrite();

    return XEE_SUCCESS;
}

static void DoWrite(void)
{
    BYTE i;
    volatile BYTE vDummy;
    BYTE vSPIONSave;
    #if defined(__18CXX)
    BYTE SPICON1Save;
    #elif defined(__C30__)
    WORD SPICON1Save;
    #else
    DWORD SPICON1Save;
    #endif

    // Save SPI state
    SPICON1Save = EEPROM_SPICON1;
    vSPIONSave = SPI_ON_BIT;

    // Configure SPI
    SPI_ON_BIT = 0;
    EEPROM_SPICON1 = PROPER_SPICON1;
    SPI_ON_BIT = 1;

    // Set the Write Enable latch
    EEPROM_CS_IO = 0;
    EEPROM_SSPBUF = OPCODE_WREN;
    WaitForDataByte();
    vDummy = EEPROM_SSPBUF;
    EEPROM_CS_IO = 1;

    // Send WRITE opcode
    EEPROM_CS_IO = 0;
    EEPROM_SSPBUF = OPCODE_WRITE;
    WaitForDataByte();
    vDummy = EEPROM_SSPBUF;

    // Send address
    #if defined(USE_EEPROM_25LC1024)
    EEPROM_SSPBUF = ((DWORD_VAL*)&EEPROMAddress)->v[2];
    WaitForDataByte();
    vDummy = EEPROM_SSPBUF;
    #endif

    EEPROM_SSPBUF = ((DWORD_VAL*)&EEPROMAddress)->v[1];
    WaitForDataByte();
    vDummy = EEPROM_SSPBUF;

    EEPROM_SSPBUF = ((DWORD_VAL*)&EEPROMAddress)->v[0];
    WaitForDataByte();
    vDummy = EEPROM_SSPBUF;


    for(i = 0; i < vBytesInBuffer; i++)
    {
        // Send the byte to write
        EEPROM_SSPBUF = EEPROMBuffer[i];
        WaitForDataByte();
        vDummy = EEPROM_SSPBUF;
    }

    // Begin the write
    EEPROM_CS_IO = 1;

// Update write address and clear write cache
    EEPROMAddress += vBytesInBuffer;
    vBytesInBuffer = 0;

    // Restore SPI State
    SPI_ON_BIT = 0;
    EEPROM_SPICON1 = SPICON1Save;
    SPI_ON_BIT = vSPIONSave;


    // Wait for write to complete
    while( XEEIsBusy() );
}


/*********************************************************************
 * Function:        BOOL XEEIsBusy(void)
 *
 * PreCondition:    XEEInit() is already called.
 *
 * Input:           None
 *
 * Output:          FALSE if EEPROM is not busy
 *                  TRUE if EEPROM is busy
 *
 * Side Effects:    None
 *
 * Overview:        Reads the status register
 *
 * Note:            None
 ********************************************************************/
BOOL XEEIsBusy(void)
{
    volatile BYTE_VAL result;
    BYTE vSPIONSave;
    #if defined(__18CXX)
    BYTE SPICON1Save;
    #elif defined(__C30__)
    WORD SPICON1Save;
    #else
    DWORD SPICON1Save;
    #endif

    // Save SPI state
    SPICON1Save = EEPROM_SPICON1;
    vSPIONSave = SPI_ON_BIT;

    // Configure SPI
    SPI_ON_BIT = 0;
    EEPROM_SPICON1 = PROPER_SPICON1;
    SPI_ON_BIT = 1;

    EEPROM_CS_IO = 0;
    // Send RDSR - Read Status Register opcode
    EEPROM_SSPBUF = OPCODE_RDSR;
    WaitForDataByte();
    result.Val = EEPROM_SSPBUF;

    // Get register contents
    EEPROM_SSPBUF = 0;
    WaitForDataByte();
    result.Val = EEPROM_SSPBUF;
    EEPROM_CS_IO = 1;

    // Restore SPI State
    SPI_ON_BIT = 0;
    EEPROM_SPICON1 = SPICON1Save;
    SPI_ON_BIT = vSPIONSave;

    return result.bits.b0;
}


#endif //#if defined(EEPROM_CS_TRIS)

Código: [Seleccionar]
/*********************************************************************
 *
 *               External serial data EEPROM Access Defs.
 *
 *********************************************************************
 * FileName:        XEEPROM.h
 * Dependencies:    None
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 * Microchip C30 v3.12 or higher
 * Microchip C18 v3.30 or higher
 * HI-TECH PICC-18 PRO 9.63PL2 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 * used in conjunction with a Microchip ethernet controller for
 * the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Nilesh Rajbharti     5/20/02     Original (Rev. 1.0)
********************************************************************/
#ifndef __XEEPROM_H
#define __XEEPROM_H

#include "HardwareProfile.h"

typedef BOOL XEE_RESULT;
#define XEE_SUCCESS FALSE

#if defined(EEPROM_CS_TRIS)
void XEEInit(void);
XEE_RESULT XEEBeginWrite(DWORD address);
XEE_RESULT XEEWrite(BYTE val);
void XEEWriteArray(BYTE *val, WORD wLen);
XEE_RESULT XEEEndWrite(void);
XEE_RESULT XEEBeginRead(DWORD address);
BYTE XEERead(void);
XEE_RESULT XEEReadArray(DWORD address, BYTE *buffer, WORD length);
XEE_RESULT XEEEndRead(void);
BOOL XEEIsBusy(void);
#else
// If you get any of these linker errors, it means that you either have an
// error in your HardwareProfile.h or TCPIPConfig.h definitions.  The code
// is attempting to call a function that can't possibly work because you
// have not specified what pins and SPI module the physical SPI EEPROM chip
// is connected to.  Alternatively, if you don't have an SPI EERPOM chip, it
// means you have enabled a stack feature that requires SPI EEPROM hardware.
// In this case, you need to edit TCPIPConfig.h and disable this stack
// feature.  The linker error tells you which object file this error was
// generated from.  It should be a clue as to what feature you need to
// disable.
void You_cannot_call_the_XEEInit_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
XEE_RESULT You_cannot_call_the_XEEBeginWrite_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
XEE_RESULT You_cannot_call_the_XEEWrite_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
void You_cannot_call_the_XEEWriteArray_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
XEE_RESULT You_cannot_call_the_XEEEndWrite_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
XEE_RESULT You_cannot_call_the_XEEBeginRead_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
BYTE You_cannot_call_the_XEERead_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
XEE_RESULT You_cannot_call_the_XEEReadArray_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
XEE_RESULT You_cannot_call_the_XEEEndRead_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
BOOL You_cannot_call_the_XEEIsBusy_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first(void);
#define XEEInit() You_cannot_call_the_XEEInit_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#define XEEBeginWrite(a) You_cannot_call_the_XEEBeginWrite_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#define XEEWrite(a) You_cannot_call_the_XEEWrite_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#define XEEWriteArray(a,b) You_cannot_call_the_XEEWriteArray_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#define XEEEndWrite() You_cannot_call_the_XEEEndWrite_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#define XEEBeginRead(a) You_cannot_call_the_XEEBeginRead_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#define XEERead(a) You_cannot_call_the_XEERead_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#define XEEReadArray(a, b, c) You_cannot_call_the_XEEReadArray_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#define XEEEndRead() You_cannot_call_the_XEEEndRead_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#define XEEIsBusy() You_cannot_call_the_XEEIsBusy_function_without_defining_EEPROM_CS_TRIS_in_HardwareProfile_h_first()
#endif

#endif
Título: Re: Memoria externa SPI
Publicado por: PFCarrera en 09 de Marzo de 2010, 08:49:32
Buenas a todos!

Os comento, este es mi código:

#include <p18f4550.h>
#include <delays.h>
#include <spi.h>

#pragma config FOSC = XT_XT
#pragma config WDT= OFF
#pragma config MCLRE= ON
#pragma config LVP= OFF
#pragma config DEBUG= ON
#pragma config PWRT= OFF

#define   CS         PORTBbits.RB4

#define   RDSR   0b00000101
#define   WRSR   0b00000001
#define   WREN   0b00000110
#define   WRDI   0b00000100
#define   WRITE  0b00000010
#define   READ   0b00000011

unsigned char address,dato,longitud,valor;

void CMD_Write(unsigned char SPI_Cmd){
   SSPBUF=SPI_Cmd;
   Delay1KTCYx(6);

}


void SET_WREN(void){
   CS=0;
   CMD_Write(WREN);
   CS=1;
}


void Byte_Write(unsigned char address, unsigned char dato){             //Escribir en la memoria
   SET_WREN();
   CS=0;
   CMD_Write(WRITE);
   CMD_Write(address);
   CMD_Write(dato);
   CS=1;
   Delay1KTCYx(6);   //retardo de 6ms
}

void Byte_Read(unsigned char address, unsigned char *dato, unsigned char longitud){       //Leer de la memoria
   CS=0;
   CMD_Write(READ);
   CMD_Write(address);
   getsSPI(dato,longitud);
   CS=1;
   
   return(SSPBUF);
}

void main (void){
   PORTB=0X00;
   PORTC=0X00;
   CS=1;

   TRISBbits.TRISB4=0; //Define CS como salida
   TRISBbits.TRISB1=0; //Define SCK como salida
   TRISBbits.TRISB0=1; //Define SDI como entrada
   TRISCbits.TRISC7=0; //Define SDO como salida
   
   SSPSTAT= 0xC0; // SPI Bus mode 0,0
   SSPCON1 = 0x21; // Enable SSP, FOSC/16

   OpenSPI(SPI_FOSC_4, MODE_00, SMPEND);
   
   while(1){
   address=0x00;  //address
   dato=0xA5;
   longitud=0x01;
   Byte_Write(address,dato);
   Byte_Read(address,&dato,longitud);
   PORTD=SSPBUF;
   }
}

Cuando escribo en la memoria escribo directamente en el registro SSPBUF, no se si estará bien o tengo que escribir en el bus spi (instrucción WriteSPI) y cuando leo, leo desde el bus spi (instrucción getsSPI) y la función de lectura me devuelve el registro SSPBUF.

Y para visualizar el resultado de la lectura lo he puesto en el PORTD, pero.....me sale 0x00.....es decir....no me está leyendo nada!!

¿Qué es lo que hago mal?

Por cierto....gracias a todos
Título: Re: Memoria externa SPI
Publicado por: micronoob en 09 de Marzo de 2010, 09:10:06
hola,

buena esta memoria  de microchip es una tortuga ...

atención amigo!

escribir o leer en una memoria FLASH no es lo único que debes tener en cuenta sus tiempos de borrados y su vida por sector son muy importantes.

hace un par de años modifique una librería de microchip llamada SPIeprom.c   que era utilizada por el stack microchip para su modulo HTTP

microchip por aquellos tiempos aun no tenia memorias FLASH y ademas necesitaba adaptarlos a mis hardware  ST y MACRONIX  pues así hice  SPIflash esta librería permite usar una memoria FLASH NAND  como  si fuera una NOR  (básicamente como si fuera una eprom donde puedes cambiar solo un byte)

otra nota importante de esta librería es el uso selectivo de la opción LOW_RAM , explico:

si necesitamos guardar en RAM un sector entero de nuestra SPI FLASH vamos a necesitar 4096 bytes por ellos ..  bien no!,  

en esta librería hay un método que utiliza un sector denominado sector SWAP para ir trasladando lo que tiene que memorizar  borrar el sector y volver a volcar su contenido ...lento uhhhmmmm es bastante optimizado y sobre un 16 MIPs va de maravilla
también de notar que esta diseñado por FLASH algo mas rápidas que la de microchip (y mas  económicas)

también hay una versión modificada de el file system de microchip para invocar dicha librería.

Código: [Seleccionar]
/*********************************************************************
 *
 *               Data SPI FLASH Access Routines
 *
 *********************************************************************
 * FileName:        SPIFLASH.c
 * Dependencies:    None
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32MX
 * Compiler:        Microchip C32 v1.00 or higher
 * Microchip C30 v3.01 or higher
 * Microchip C18 v3.13 or higher
 * HI-TECH PICC-18 STD 9.50PL3 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright © 2002-2007 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product (“Device”) which is
 *      integrated into Licensee’s product; or
 * (ii) ONLY the Software driver source files ENC28J60.c and
 *      ENC28J60.h ported to a non-Microchip device used in
 *      conjunction with a Microchip ethernet controller for the
 *      sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Nilesh Rajbharti     5/20/02     Original (Rev. 1.0)
 * Howard Schlunder 9/01/04 Rewritten for SPI EEPROMs
 * Howard Schlunder 8/10/06 Modified to control SPI module
 * frequency whenever EEPROM accessed
 * to allow bus sharing with different
 * frequencies.
 * Maurizio Spoto       13/02/08     readapt for SPI FLASH MACRONIX
 * Maurizio Spoto        8/08/08     readapt for PIC32MX
 * Maurizio Spoto        5/08/09     mount LBA for MyDB table partition
 * Maurizio Spoto       10/10/08     adding method for LOW_RAM ,
 *                                   adding SWAP sector for LOW_RAM
 *                                   optimized and unifique Buffering RX and TX
 * Maurizio Spoto       11/10/08     adding method use NAND FLASH
 *                                   with Dynamic NOR FLASH and automatic
 *                                   partition in sequencial skip sector
********************************************************************/
//#define __SPIFLASH_C



#include "RootProject.h"
#include "GenericTypeDefs.h"
#include "SPIflash.h"


// FLASH SPI opcodes
#define READ 0x03 // Read data from memory array beginning at selected address
#define WRITE 0x02 // Write data to memory array beginning at selected address
#define WRDI 0x04 // Reset the write enable latch (disable write operations)
#define WREN 0x06 // Set the write enable latch (enable write operations)
#define RDSR 0x05 // Read Status register
#define WRSR 0x01 // Write Status register

#define DYFM    0x00    // Dummy byte
#define RDID    0x9F    // Read ID Manufactured
#define SEFM    0x20    // Erase Sector (500ms)
#define BEFM    0x52    // Erase Block  (1sec)
#define CEFM    0x60    // Erase Chip   (3sec)
#define FREAD   0x0B    // Fast Read    (max 50Mhz)  es: FREAD > ADD1 > ADD2 > ADD3 > DYFM

#define ALL_OPEN 0x02   // Write Enable && no protect Blocks

//#define FLASH_HIGH_SPEED      //read max 50Mhz (other operation 25Mhz)
#define FLASH_LOW_SPEED       //read max 25Mhz (other operation 50Mhz)

#define FLASH_ST_VIRTUAL_SECTOR  (0x000FF000)  
#define FLASH_EN_VIRTUAL_SECTOR  (0x00100000)
#define FLASH_BIT_SPEED          (8E6)    //8Mhz
#define FLASH_CS_WAIT            (INSTR_FREQ / FLASH_BIT_SPEED)


#define FLASH_SMALL_RAM

//#define INCLUDE_EXTENDS_METHOD

#define _CONTROL_LBA_


/* PROTOTYPE */
#if defined (INCLUDE_EXTENDS_METHOD)
  static void DoWriteF(void);
#endif
static void FLASHSetReg(void);
static void FLASHSetWEL(BYTE mode);
static BOOL LocalizeAddress(DWORD dwAddressL);

void DynamicWriteF(DWORD dwAddress);
void DynamicWriteLenF(DWORD dwAddress,WORD lenBuf);
void SetFSHSetting(void);

#if defined (FLASH_SMALL_RAM)
  #define FLASH_BUFFER_SIZE  ((WORD)(PAGE_LEN+1))     //LIMIT 256 Bytes
  unsigned long tempVirtualAddress=0;     //swap sector address
  unsigned int iA=0,iB=0,iC=0,iD=0,iE=0;  //unknowns
#else
  #define FLASH_BUFFER_SIZE  ((WORD)(SECTOR_LEN+1))   //LIMIT 4096 Bytes
#endif


#if defined(__PIC24F__)
    #define PROPER_SPICON1 (0x013B) //1:1 (1ºpre) 2:1 (2ºpre) 8Mhz  CKE=1, MASTER mode
#elif defined(__PIC32MX__)
    #define PROPER_SPICON1 (_SPI2CON_ON_MASK | _SPI2CON_FRZ_MASK | _SPI2CON_CKE_MASK | _SPI2CON_MSTEN_MASK)
#else  //24H
#define PROPER_SPICON1 (0x21)
#endif


//Dummy RAM
unsigned char DummyMaster=0;
unsigned char tmpOut=0;
unsigned char ctny=0;

BYTE    XFSHRAMBuf[FLASH_BUFFER_SIZE]={0x0};

//read pointer
static WORD  SPICON1Save;
static DWORD FLASHAddress=0;
static BYTE *FLASHBufferPtr=0;

unsigned int LimitBytesToWrite=0;
unsigned int BytesWritten=0;
unsigned int BlockNumber;
unsigned int SectorNumber;
unsigned int PageNumber;
unsigned int SectorIndex;
unsigned int myPtr=0;
DWORD   StoredAddress;
DWORD   BlockStart;
DWORD   BlockEnd;
DWORD   SectorStart;
DWORD   SectorEnd;
DWORD   PageStart;
DWORD   PageEnd;
DWORD   SaveSectorStart;




/* FAST MACROS */
/*
|  These macros avoid the so-called "RCALL" and "CALL"
|  saving instructions and increasing the speed
|__________________________________________________*/
#define CSON  (0)
#define CSOFF (1)

#define SetCS(x)  ctny=FLASH_CS_WAIT; \
                  if(x){ while(ctny--); FLASH_CS_IO=x; }else{ FLASH_CS_IO=x; while(ctny--);}


#if defined (__PIC32MX__)

static inline  __attribute__((always_inline)) void putcSPI(unsigned int data_out)
{ mSPI2BusyWait(); putcSPI2(data_out);}

static inline  __attribute__((always_inline)) unsigned int getcSPI(void)
{ mSPI2BusyWait(); return getcSPI2();}

#define writeXSFHSPI(x)  putcSPI(x)
#define readXSFHSPI(x)   x = getcSPI();

#else


//8bits method with flush buffer
#define writeXSFHSPI(x) \
                    FLASH_SSPBUF = x; \
                    while(!FLASH_SPI_IF); \
                    DummyMaster = FLASH_SSPBUF; \
                    FLASH_SPI_IF = 0;

//8bits method with flush buffer
#define readXSFHSPI(x) \
                    FLASH_SSPBUF =0; \
                    while(!FLASH_SPI_IF); \
                    x = FLASH_SSPBUF; \
                    FLASH_SPI_IF = 0;


#endif

//allows the simultaneous use of several devices on the same bus with different speeds
#define saveSPISPEED()    SPICON1Save = FLASH_SPICON1; FLASH_SPICON1 = FLASH_SPICON1
#define restoreSPISPEED()   FLASH_SPICON1 = SPICON1Save



#if defined (_CONTROL_LBA_)

/* MyDB LBA */
/*
|   LBA control is executed at another level
|__________________________________________________*/
FSHSettings FSHSetting;
unsigned long FlashSPEED;


void SetFSHSetting(void)
{

   FlashSPEED                        =  FLASH_MAX_SPI_FREQ;

   FSHSetting.FSHSWAPFLAGSADDRESS    = (UInt32)(FSH_SWAP_FLAGS_ADDRESS);
   FSHSetting.FSHSWAPSIZE            = (UInt16)(FSH_SWAP_SIZE);
   FSHSetting.FSHVIRTUALPAGEADDRESS  = (UInt32)(FSH_VIRTUAL_PAGE_ADDRESS);  
   FSHSetting.FSHVIRTUALPAGESIZE     = (UInt16)(FSH_VIRTUAL_PAGE_SIZE);  
   FSHSetting.FSHSETTINGADDRESS      = (UInt32)(FSH_SETTING_ADDRESS);
   FSHSetting.FSHSETTINGSIZE         = (UInt16)(FSH_SETTING_SIZE);
   FSHSetting.FSHBACKUPADDRESS       = (UInt32)(FSH_BACKUP_ADDRESS);
   FSHSetting.FSHBACKUPSIZE          = (UInt16)(FSH_BACKUP_SIZE);
   FSHSetting.FSHREGISTRYADDRESS     = (UInt32)(FSH_REGISTRY_ADDRESS);
   FSHSetting.FSHREGISTRYSIZE        = (UInt16)(FSH_REGISTRY_SIZE);
   FSHSetting.FSHLBAADDRESS          = (UInt32)(FSH_LBA_ADDRESS);  
   FSHSetting.FSHLBASIZE             = (UInt16)(FSH_LBA_SIZE);
#if defined (_LBA_FILESYSTEM_)
   FSHSetting.FSHFSDATAADDRESS       = (UInt32)(FSH_FS_DATA_ADDRESS);
   FSHSetting.FSHFSDATASIZE          = (UInt32)(FSH_FS_DATA_SIZE);
   FSHSetting.FSHFSMAPADDRESS        = (UInt32)(FSH_FS_MAP_ADDRESS);  
   FSHSetting.FSHFSMAPSIZE           = (UInt32)(FSH_FS_MAP_SIZE);
#endif
}
#endif //defined (_CONTROL_LBA_)

/* XFSHInit(*perifericals frequency*) */
/*
|   pbclk , use for PIC32
|__________________________________________________*/
void XFSHInit(int pbclk)
{
      
   // SetFSHSetting();  //LBA set

FLASH_CS_TRIS = 0;  // Drive SPI FLASH chip select pin
SetCS(CSOFF);

Setup_SCK(0); // Set SCK pin as an output
Setup_SDI(1); // Make sure SDI pin is an input
Setup_SDO(0); // Set SDO pin as an output

#if defined(__C30__)
FLASH_SPICON1 = PROPER_SPICON1; // See PROPER_SPICON1 definition above
   FLASH_SPICON2 = 0;
   FLASH_SPISTAT = 0;    // clear SPI
   SPI1CON1bits.MODE16 =0;
   FLASH_SPISTATbits.SPIEN = 1;
#elif defined(__PIC32MX__)
   FLASH_SPIBRG = (pbclk/8)/2ul/FLASH_MAX_SPI_FREQ;
   FLASH_SPICON1bits.CKE = 1;
   FLASH_SPICON1bits.MSTEN = 1;
FLASH_SPICON1bits.ON = 1;
#endif
    
    //WP first set
    FLASHSetReg();
}



/* XFSHBeginRead(*start address read*) */
/*
|   start read with LBA control
|__________________________________________________*/
XFSH_RESULT XFSHBeginRead(unsigned long raddress)
{

#if defined (_CONTROL_LBA_)
   // LBA_XFSHBeginRead(raddress);  //control sectors partition
#endif

//read address storage
FLASHAddress = raddress;
//set limit of buffer
FLASHBufferPtr = XFSHRAMBuf + FLASH_BUFFER_SIZE;
return XFSH_SUCCESS;
}
/* XFSHRead() */
/*
|  
|__________________________________________________*/
BYTE XFSHRead(void)
{
// Check if no more bytes are left in our local buffer
if( FLASHBufferPtr == (XFSHRAMBuf + FLASH_BUFFER_SIZE) )
{//if first call or read another page

// Get a new set of bytes
XFSHDynamicRead(FLASHAddress,XFSHRAMBuf,FLASH_BUFFER_SIZE);
FLASHAddress += FLASH_BUFFER_SIZE;
FLASHBufferPtr = XFSHRAMBuf;
  breakpoint();
}

// Return a byte from our RAM buffer
return *FLASHBufferPtr++;
}

/* XFSHEndRead() */
/*
|   end read with LBA control
|__________________________________________________*/
XFSH_RESULT XFSHEndRead(void)
{
#if defined (_CONTROL_LBA_)
   // LBA_XFSHEndRead(raddress);  //close open sectors
#endif
    return XFSH_SUCCESS;
}




/*  */
/*
|  
|__________________________________________________*/
XFSH_RESULT XFSHDynamicRead(DWORD addressD,
                        BYTE *bufferD,
                        WORD lengthD)
{


    while( XFSHIsBusy() );

SetCS(CSON);

   #if defined(FLASH_HIGH_SPEED)
     // Send FAST READ opcode
   writeXSFHSPI(FREAD);
   #else  
     // Send READ opcode
   writeXSFHSPI(READ);
   #endif
    
// Send address
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[0]);

   #if defined(FLASH_HIGH_SPEED)
     // Send Dummy 8bit cycle opcode
   writeXSFHSPI(DYFM);
   #endif


while(lengthD--)
{
if(bufferD != 0){
readXSFHSPI(*bufferD);
*bufferD++;
   }  
};

SetCS(CSOFF);

restoreSPISPEED();

return XFSH_SUCCESS;
}

/*  */
/*
|  
|__________________________________________________*/
 XFSH_RESULT XFSHBeginWrite(DWORD address)
{
#if defined (FLASH_SMALL_RAM)

unsigned int j;
   unsigned long dym=0;
   
LocalizeAddress(address);                //Localize Start Sector

//set limit byte in selected sector
LimitBytesToWrite = (SectorStart + (SECTOR_LEN+1)) - address;
BytesWritten=0;

FLASHEraseSector(FLASH_ST_VIRTUAL_SECTOR);  //Erase Virtual(swap) Sector

//bytes saved, before starting to write
iA = (unsigned int)(address - SectorStart);

iE = (PAGE_LEN+1);

if(iA<=iE)
{//is first page

SectorIndex=0;
if(iA)
{
            XFSHDynamicRead(SectorStart,
                            XFSHRAMBuf,
                            iA);               //Export data in RAM  
                                               //volcate RAM in swap sector
            DynamicWriteLenF(FLASH_ST_VIRTUAL_SECTOR,iA);
            tempVirtualAddress = FLASH_ST_VIRTUAL_SECTOR + iA;
       }else{
            tempVirtualAddress = FLASH_ST_VIRTUAL_SECTOR;
       }      

   }
   else
   {
   //pages saved
iC = (unsigned int) floor(iA / iE);
//bytes to write in broken page
iD = (unsigned int) iA - ( iC * iE);

tempVirtualAddress = FLASH_ST_VIRTUAL_SECTOR;

PageStart=0;

       for(j=0;j<iC;j++)
   {      
           PageStart=dym + SectorStart;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iE);          //Export data in RAM  
                                         //volcate RAM in swap sector
           DynamicWriteLenF(tempVirtualAddress,iE);
           tempVirtualAddress += iE;              
                           
           dym=(PAGE_LEN*(j+1))+(j+1);      
       }
       
       if(iD)
       {//if exist bytes in broken page
       
       PageStart=dym + SectorStart;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iD);          //Export data in RAM  
                                         //volcate RAM in swap sector
           DynamicWriteLenF(tempVirtualAddress,iD);
           tempVirtualAddress += iD;
   
   }
                                          
}
FLASHBufferPtr = XFSHRAMBuf;
return XFSH_SUCCESS;

#else

   LocalizeAddress(address);       //Localize Start Sector              
   XFSHDynamicRead(SectorStart,
                    XFSHRAMBuf,
                   (SECTOR_LEN+1));   //Save  Sector in Buffer        
   FLASHEraseSector(SectorStart);  //Erase Sector

return XFSH_SUCCESS;

#endif

}

/*  */
/*
|  
|__________________________________________________*/
XFSH_RESULT XFSHWrite(BYTE val)
{
#if defined (FLASH_SMALL_RAM)
      
      
      if( FLASHBufferPtr == (XFSHRAMBuf + FLASH_BUFFER_SIZE) )
 {  
  FLASHBufferPtr = XFSHRAMBuf;
  //write in FLASH swap sector
  DynamicWriteLenF(tempVirtualAddress,FLASH_BUFFER_SIZE);
      tempVirtualAddress += FLASH_BUFFER_SIZE;
     
 }  

 //control sector partition
 if((BytesWritten++)>=LimitBytesToWrite)
 {//format a new sector
 XFSHEndWrite();                //close current sector
 //SaveSectorStart = SectorStart;
 XFSHBeginWrite(SectorStart); //start new sector
      }  
              
 *FLASHBufferPtr++ = val;

      return XFSH_SUCCESS;
#else

//write in ram
   XFSHRAMBuf[SectorIndex] = val;
   SectorIndex++;
   return XFSH_SUCCESS;
#endif
}

/*  */
/*
|  
|__________________________________________________*/
XFSH_RESULT XFSHEndWrite(void)
{
 #if defined (FLASH_SMALL_RAM)
 
   unsigned int j;
   unsigned long dym=0;
       
   //pre STEP)  volcate pending RAM buffer in FLASH Swap Sector
   
   if( FLASHBufferPtr != (&XFSHRAMBuf[0]) )
   {
   //bytes in RAM buffer
   iA = ((unsigned int) FLASHBufferPtr) - ((unsigned int)(&XFSHRAMBuf[0]));
   //volcate RAM in FLASH swap sector
   DynamicWriteLenF(tempVirtualAddress,iA);
       tempVirtualAddress += iA;
}
   
   
   //1º STEP) ORIGIN DATA FLASH SECTOR -> RAM -> SWAP DATA FLASH SECTOR
   
   //bytes written
   iA = (unsigned int)tempVirtualAddress - FLASH_ST_VIRTUAL_SECTOR;
   //bytes to write
   iB = (unsigned int)FLASH_EN_VIRTUAL_SECTOR - tempVirtualAddress;
   
   if(tempVirtualAddress < FLASH_EN_VIRTUAL_SECTOR)
   {
   
   if(iB < (PAGE_LEN + 1))
   {//if lack a single page
   
   SectorIndex=0;
   XFSHDynamicRead((DWORD)SectorStart+iA,
                        XFSHRAMBuf,
                        iB);          //Export data in RAM  
                                      //volcate RAM in FLASH swap sector
       DynamicWriteLenF(tempVirtualAddress,iB);              
                       
}
else
{
if(iA<=(PAGE_LEN+1))
{
   //written only in broken page
   iC = 1;
  //bytes to write in broken page
   iE = (unsigned int) (PAGE_LEN + 1) - iA;
}
else
{
//pages written
iC = (unsigned int) floor(iA / (PAGE_LEN + 1));
//bytes written in broken page
iD = (unsigned int) iA - ( iC * (PAGE_LEN + 1));
//bytes to write in broken page
   iE = (unsigned int) (PAGE_LEN + 1) - iD;
}


if(iE)
{
if(iC>1)iC+=1;
SectorIndex=0;
XFSHDynamicRead((DWORD)SectorStart+iA,
                           XFSHRAMBuf,
                           iE);          //Export data in RAM  
                                         //volcate RAM in FLASH swap sector
           DynamicWriteLenF(tempVirtualAddress,iE);
           tempVirtualAddress += iE;
       }
             
       iE = (PAGE_LEN+1);
       
       dym = iE*iC;
       
       for(j=iC;j<16;j++){
     
           PageStart=dym + SectorStart;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iE);          //Export data in RAM  
                                         //volcate RAM in swap sector
           DynamicWriteLenF(tempVirtualAddress,iE);
           tempVirtualAddress += iE;              
                           
           dym=(PAGE_LEN*(j+1))+(j+1);      
       }          
}
}


//2º STEP) SWAP DATA FLASH SECTOR -> RAM -> DESTINY DATA FLASH SECTOR

FLASHEraseSector(SectorStart);          //Erase Sector

PageStart=0;
dym=0;

for(j=0;j<16;j++)
   {
     
           PageStart=dym + FLASH_ST_VIRTUAL_SECTOR;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iE);          //Export data in RAM  
                                         //volcate RAM in destiny sector
           DynamicWriteLenF(SectorStart,iE);
           SectorStart += iE;              
                           
           dym=(PAGE_LEN*(j+1))+(j+1);      
   }

   return XFSH_SUCCESS;

#else

   int j;
   long dym=0;
   
   PageStart=0;

   for(j=0;j<16;j++){
     
      PageStart=dym + SectorStart;
      DynamicWriteF(PageStart);
      dym=(PAGE_LEN*(j+1))+(j+1);      
   }

   return XFSH_SUCCESS;
#endif
}
/*  */
/*
|  
|__________________________________________________*/

void DynamicWriteLenF(DWORD dwAddress,WORD lenBuf)
{
WORD DynamicBytes =lenBuf;

myPtr=0;

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

    saveSPISPEED();

SetCS(CSON);  //ON

// Send WRITE opcode
writeXSFHSPI(WRITE);

// Send address
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

while(DynamicBytes--)
{
// Send the byte to write
writeXSFHSPI(XFSHRAMBuf[myPtr]);
        myPtr++;
}

SetCS(CSOFF);  //OFF

restoreSPISPEED();

// Wait for write to complete
while( XFSHIsBusy() );
}



/* NAND FLASH ALGORITHMIC FUNCTIONS */
/*
|  
|__________________________________________________*/
BOOL FLASHReadID(void)
{
    static BYTE tempB[3];

saveSPISPEED();

// Activate chip select
SetCS(CSON);// SetCS(CSON);  //ON

//send Read ID opcode
    writeXSFHSPI(RDID);

   //Read ID Manufactured
   readXSFHSPI(tempB[0]);

   // Read Memory Type
   readXSFHSPI(tempB[1]);

   // Read Memory Density
   readXSFHSPI(tempB[2]);

SetCS(CSOFF);

restoreSPISPEED();
    
    if((tempB[0]==IDMF)&&(tempB[1]==TYMF)) //control ID & Type Memory
       return TRUE;
    else
       return FALSE;

}


/*
|  
|__________________________________________________*/
XFSH_RESULT FLASHEraseSector(DWORD dwAddress)
{

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

saveSPISPEED();

// Activate chip select
SetCS(CSON); //ON

   // Send Erase Sector opcode
   writeXSFHSPI(SEFM);

   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

SetCS(CSOFF); //OFF
 
restoreSPISPEED();

    while(XFSHIsBusy());

    return XFSH_SUCCESS;
}


/*
|  
|__________________________________________________*/

XFSH_RESULT FLASHEraseBlock(DWORD dwAddress)
{
    
    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

saveSPISPEED();

// Activate chip select
SetCS(CSON); //ON

   // Send Erase Block opcode
   writeXSFHSPI(BEFM);

   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

SetCS(CSOFF); //OFF
 
restoreSPISPEED();

    while(XFSHIsBusy());

    return XFSH_SUCCESS;
}

/*
|  
|__________________________________________________*/
XFSH_RESULT FLASHEraseChip(void)
{

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

    saveSPISPEED();

// Activate chip select
SetCS(CSON); //ON

   // Send Erase Chip opcode
   writeXSFHSPI(CEFM);

SetCS(CSOFF); //OFF

restoreSPISPEED();
    
    while(XFSHIsBusy());

    return XFSH_SUCCESS;

}

/*
|     0x00 free after write action
|      0x02 free after others actions
|__________________________________________________*/
BOOL XFSHIsBusy(void)
{
   if((FLASHReadCheck()==0x00)||(FLASHReadCheck()==0x02))
      return 0;

   return 1;
}

/*
|    
|      
|__________________________________________________*/
BYTE FLASHReadCheck(void)
{
BYTE Dummy;
    
    saveSPISPEED();

SetCS(CSON);

// send Read Status register
    writeXSFHSPI(RDSR);

    // Read Registry Byte
    readXSFHSPI(Dummy);
    
    SetCS(CSOFF);

restoreSPISPEED();
  
    return Dummy;
}

/*
|    
|      
|__________________________________________________*/
static void FLASHSetReg(void)
{

FLASHSetWEL(1);
    
    saveSPISPEED();
    
    SetCS(CSON);

// Send Write Status Register opcode
    writeXSFHSPI(WRSR);
  
    // Send All Memory Write permit
    writeXSFHSPI(ALL_OPEN);

    SetCS(CSOFF);

restoreSPISPEED();
  
}
/*
|    
|      
|__________________________________________________*/
static void FLASHSetWEL(BYTE mode)
{
    saveSPISPEED();
    
    SetCS(CSON);

if(mode)
{
   // Send Enable Write Status Register opcode
   writeXSFHSPI(WREN);
}
else
{
// Send Disable Write Status Register opcode
   writeXSFHSPI(WRDI);
}

SetCS(CSOFF);

restoreSPISPEED();
}
/*
|    
|      !REVISE THIS CODE!  
|      !cambiar con divisor!  
|__________________________________________________*/
static BOOL LocalizeAddress(DWORD dwAddressL)
{
   int i;

   if(dwAddressL<=MAX_CHIP_ADDRESS)
   {
       BlockNumber=1;
       SectorNumber=1;
       PageNumber=1;
       SectorStart=0;
       SectorEnd=0;
       PageStart=0;
       PageEnd=0;
       myPtr=0;
      
       SectorIndex=0;

       for(i=0;i<16;i++){
          BlockEnd = (long)(BLOCK_LEN * BlockNumber)+i;
          if(dwAddressL<=BlockEnd)break;
          BlockStart = BlockEnd + 1;
          BlockNumber++;
       }
      
       BlockNumber -= 1;

       for(i=0;i<256;i++){
          SectorEnd = (long)(SECTOR_LEN * SectorNumber)+i;
          if(dwAddressL<=SectorEnd)break;
          SectorStart = SectorEnd + 1;
          SectorNumber++;
       }
  
       SectorNumber -= 1;
  
       PageStart += SectorStart;
  
       for(i=0;i<16;i++){
          PageEnd =(long)((PAGE_LEN * PageNumber)+i) + SectorStart;
          if(dwAddressL<=PageEnd)break;
          PageStart = PageEnd + 1;
          PageNumber++;
       }
    
       PageNumber -= 1;
       StoredAddress = dwAddressL;
       SectorIndex = StoredAddress - SectorStart;

       return TRUE;
   }
   else
   {
       return FALSE;
   }

}

/*  INCLUDE_EXTENDS_METHOD */


#if defined(INCLUDE_EXTENDS_METHOD)

/* XFSHReadArray() */
/*
|   microchip method use for Microchip File System
|   not use for MyKOS File System
|__________________________________________________*/
XFSH_RESULT XFSHReadArray(DWORD address,
                          BYTE *buffer,
                          BYTE length)
{
saveSPISPEED();

SetCS(CSON);

    #if defined(FLASH_HIGH_SPEED)
     // Send FAST READ opcode
   writeXSFHSPI(FREAD);
   #else  
     // Send READ opcode
   writeXSFHSPI(READ);
   #endif
    
// Send address
writeXSFHSPI(((DWORD_VAL*)&address)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&address)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&address)->v[0]);

   #if defined(FLASH_HIGH_SPEED)
     // Send Dummy 8bit cycle opcode
   writeXSFHSPI(DYFM);
   #endif


while(length--)
{
if(buffer != 0){
readXSFHSPI(*buffer);
*buffer++;
   }  
};

SetCS(CSOFF);

restoreSPISPEED();

return XFSH_SUCCESS;
}
/*  */
/*
|  
|__________________________________________________*/
BYTE XFSHReadByte(DWORD addressD)
{
BYTE Dummy;


    while( XFSHIsBusy() );

SetCS(CSON);

   #if defined(FLASH_HIGH_SPEED)
     // Send FAST READ opcode
   writeXSFHSPI(FREAD);
   #else  
     // Send READ opcode
   writeXSFHSPI(READ);
   #endif
    
// Send address
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[0]);


   #if defined(FLASH_HIGH_SPEED)
     // Send Dummy 8bit cycle opcode
   writeXSFHSPI(DYFM);
   #endif

readXSFHSPI(Dummy);

SetCS(CSOFF);

restoreSPISPEED();

return Dummy;
}

/*  */
/*
|  
|__________________________________________________*/
void DynamicWriteF(DWORD dwAddress)
{
WORD DynamicBytes =0x100;

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

    saveSPISPEED();

// Activate chip select
SetCS(CSON);  //ON

// Send WRITE opcode
writeXSFHSPI(WRITE);

// Send address
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

while(DynamicBytes--)
{
// Send the byte to write
writeXSFHSPI(XFSHRAMBuf[myPtr]);
        myPtr++;
}

SetCS(CSOFF);  //OFF

restoreSPISPEED();

// Wait for write to complete
while( XFSHIsBusy() );
}
/*  */
/*
|  
|__________________________________________________*/
void XFSHWriteByte(DWORD dwAddress,BYTE wByte)
{
myPtr=0;

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

    saveSPISPEED();
    
// Activate chip select
SetCS(CSON);  //ON

// Send WRITE opcode
writeXSFHSPI(WRITE);

// Send address
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

// Send the byte to write
writeXSFHSPI(wByte);

SetCS(CSOFF);  //OFF

restoreSPISPEED();

// Wait for write to complete
while( XFSHIsBusy() );
}
/*  */
/*
|  
|__________________________________________________*/

static void DoWriteF(void)
{
BYTE BytesToWrite;

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

    saveSPISPEED();

SetCS(CSON);  //ON

// Send WRITE opcode
writeXSFHSPI(WRITE);

// Send address
writeXSFHSPI(((DWORD_VAL*)&FLASHAddress)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&FLASHAddress)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&FLASHAddress)->v[0]);


BytesToWrite = (BYTE)(FLASHBufferPtr - XFSHRAMBuf);

FLASHAddress += BytesToWrite;
FLASHBufferPtr = XFSHRAMBuf;

while(BytesToWrite--)
{
// Send the byte to write
   writeXSFHSPI(*FLASHBufferPtr++);
}

SetCS(CSOFF);  //OFF

FLASHBufferPtr = XFSHRAMBuf;

restoreSPISPEED();

// Wait for write to complete
while( XFSHIsBusy() );
}


#endif //defined(INCLUDE_EXTENDS_METHOD)





aqui un ejemplo de lectura

XFSHBeginRead(DIRECCION_PARA_LEER);
DAME_UN_BYTE =  XFSHRead();
..
DAME_MAS =  XFSHRead();
XFSHEndRead();

Código: [Seleccionar]

void PartitionXFSHchargeLBA(void)
{
      UInt8 ix=0;
  
      XFSHBeginRead(MYDB_P_LBA_ADDRESS);
      
      for(ix=0;ix<MYDB_P_LBA_FLAGS_SIZE;ix++)
      {
        MyDBXFlashLBA[ix] = XFSHRead();
      }
      
      XFSHEndRead();

     ...

}



aqui un ejemplo de escritura

XFSHBeginWrite(DIRECCION_PARA_ESCRIBIR);
XFSHWrite(UN_BYTE_CUALQUIERA);
..
XFSHWrite(MAS_BYTES_SIQUIERES);
XFSHEndWrite();

Código: [Seleccionar]

...

 dPointer = XFSHMYDBPartition.Tables[jx].RAMAddress;
   
 XFSHBeginWrite(XFSHMYDBPartition.Tables[jx].XFSHAddress);

 for(ix=0;ix<(XFSHMYDBPartition.Tables[jx].SizeTable);ix++)
{
               XFSHWrite(*dPointer++);
         }          
           
         XFSHEndWrite();

     ...

}


el código hay que limpiarlo un poco de comentarios y todo esto
es que cuando pase a la version 2 de la librería deje de actualizar esta y así se quedo

Saludos
desde Micronoob  ....muy noob!
Título: Re: Memoria externa SPI
Publicado por: PFCarrera en 09 de Marzo de 2010, 09:49:38
madre mia mirconoob!
me acabas de liar aun más!

que se supone que tengo que utilizar la librería que me has dejado?
¿pero esa librería funciona con 25lc1024?
Título: Re: Memoria externa SPI
Publicado por: micronoob en 09 de Marzo de 2010, 10:34:36
madre mia mirconoob!
me acabas de liar aun más!

que se supone que tengo que utilizar la librería que me has dejado?
¿pero esa librería funciona con 25lc1024?


jejej hola,
haber si el truco esta en no leer el contenido de la librerías solo hay que llamar sus funciones ....si no  uno se acaba asustando jejej es broma amigo!

dame unas horas que acabo con el trabajo para un cliente,

me leo datasheet de microchip y antes que el sol anda a buscar la luna te publico una librería para tu memoria (me refiero a la 25ls1024)

saludos.



Título: Re: Memoria externa SPI
Publicado por: AngelGris en 09 de Marzo de 2010, 12:48:54
Lo que yo veo mal es que cuando envias el address, tanto para escritura como para lectura, estás enviando sólo un byte y el address que hay que enviar es de 3 bytes. Fijate que está aclarado en el texto que había enviado previamente.
Título: Re: Memoria externa SPI
Publicado por: micronoob en 09 de Marzo de 2010, 22:19:56
hola ,

lo prometido o a un mejor voy a explicarte paso a paso lo que hay que hacer porque la dichosa información  
entre y salga de esta araña de 8 patas que tienes cerca de tu micro

Suponiendo que todo el hardware esta en su lugar.
Y que con tu osciloscopio has visto salir bits por las patitas de tu micro.

procedemos con explicar 2 conceptos básicos de las memorias flash
a diferencia de la nuestra cara eeprom, las memorias flash son mas rápidas
también debido a que su borrado se efectúa por sectores y no por bytes
así que en realidad ganamos tiempo en escribir gran cantidad de datos ,
pero perdemos mas tiempo si nuestra cantidad de datos a escribir es inferior
al tamaño de un sector.

pero como en la mayoría de los proyectos lo que cuenta es el dinero que nos podemos gastar en el
o lo que nuestros clientes están dispuestos a gastarse,
nos vemos obligados a utilizar una sola memoria
para alojar tanto datos de gran tamaño que las pequeñas estructuras de datos que hacen ir nuestro
firmware.

(http://www.todopic.com.ar/foros/index.php?action=dlattach;topic=29729.0;attach=11365)

esto hace que en el caso de querer escribir un solo byte en un sector  y querer mantener lo demás bytes debemos
emplear un método de respaldo de memoria y esto cambia algo en nuestras secuencia de entrada de datos

secuencia de escritura de una memoria EEprom  (los procesos de borrado y escritura internos al IC son explicado muy por encima sin explicar el pre y post borrado)

1)enviamos comando para habilitar la escritura
2)enviamos comando de escritura
2)enviamos la dirección del byte que queremos escribir (suelen ser 3 bytes dato que las EEprom son pequeñitas y hay un byte fantasma)
3)el ic borra la locación de memoria
4)enviamos el byte
5)esperamos que acabe de escribir

y ya esta!!

secuencia de escritura de una memoria Flash en el caso de querer borrar todo el contenido del sector


1)enviamos comando para habilitar la escritura
2)enviamos comando de borrado de sector
3)enviamos la dirección del sector que contiene nuestro byte
     si la dirección de nuestro byte es 0x00000A01  la dirección de nuestro sector es 0x00000000
     si la dirección de nuestro byte es 0x00001A01  la dirección de nuestro sector es 0x00001000
4)esperamos que el ic acabe de borrar el sector
5)enviamos comando para habilitar la escritura (la mayoría de la memorias flash suelen deshabilitar la escritura después de un borrado)
6)enviamos comando de escritura
7)enviamos la dirección del byte que queremos escribir
8)enviamos el byte
9)esperamos que acabe de escribir

como se ve desde lejo hay que finalizar muchos mas procesos para escribir una flash, pero también hay de explicar
que en la mayorías de memorias flash hay la escritura secuencial de una pagina esto permite enviar una sola vez
la dirección y cada 256 bytes (en el caso de nuestra memoria con paginacion de 256bytes) enviamos la dirección

mas adelante analizamos la secuencia de escritura queriendo guardar los datos presentes en la flash

procedemos con la escritura de nuestro código

PASO 1) la primera cosa debemos hacer un mapa de  nuestro hardware

ATTENCION! en los ejemplos uso unos pines que seguramente no corresponden con tu hardware

Código: [Seleccionar]

            /* EJEMPLO CON UN MICRO 32BITS (de microchip claro esta!) */

           //SPI FLASH MACRONIX
           //#define MX25L8005        //Macronix 8mbit (1Mb)
           #define FLASH_CS_TRIS (TRISGbits.TRISG13)
           #define FLASH_CS_IO   (LATGbits.LATG13)
           #define FLASH_SCK_TRIS (TRISGbits.TRISG6)
           #define FLASH_SDI_TRIS (TRISGbits.TRISG7)
           #define FLASH_SDO_TRIS (TRISGbits.TRISG8)
      #define Setup_SCK(rw)     FLASH_SCK_TRIS=rw
           #define Setup_SDI(rw) FLASH_SDI_TRIS=rw
           #define Setup_SDO(rw)     FLASH_SDO_TRIS=rw
           #define FLASH_SPI_IF     (IFS1bits.SPI2RXIF)
           #define FLASH_SSPBUF     (SPI2BUF)
           #define FLASH_SPICON1 (SPI2CON)
           #define FLASH_SPICON1bits (SPI2CONbits)
           #define FLASH_SPIBRG (SPI2BRG)


           /* EJEMPLO CON UN MICRO 16BITS E PPS */

      //SPI FLASH MACRONIX  with PPS
//  #define MX25L8005           //Macronix 8mbit (1Mb)
  #define FLASH_CS_TRIS   (TRISAbits.TRISA7)
  #define FLASH_CS_IO       (LATAbits.LATA7)
  #define FLASH_SCK_TRIS      (TRISBbits.TRISB13)
  #define Setup_SCK(rw)        TRISBbits.TRISB13=rw; RPOR6bits.RP13R = 8
  #define FLASH_SDI_TRIS      (TRISBbits.TRISB14)
  #define Setup_SDI(rw)    TRISBbits.TRISB14=rw; RPINR20bits.SDI1R = 14
  #define FLASH_SDO_TRIS      (TRISBbits.TRISB15)
  #define Setup_SDO(rw)        TRISBbits.TRISB15=rw; RPOR7bits.RP15R = 7
  #define FLASH_SPI_IF       (IFS0bits.SPI1IF)
  #define FLASH_SSPBUF       (SPI1BUF)
  #define FLASH_SPICON1   (SPI1CON1)
  #define FLASH_SPICON1bits   (SPI1CON1bits)
  #define FLASH_SPICON2   (SPI1CON2)
  #define FLASH_SPISTAT   (SPI1STAT)
  #define FLASH_SPISTATbits   (SPI1STATbits)


            /* EJEMPLO CON UN MICRO 8BITS */

           //SPI FLASH MACRONIX
        //   #define MX25L8005           //Macronix 8mbit (1Mb)
           #define FLASH_CS_TRIS   (TRISGbits.TRISG13)
           #define FLASH_CS_IO     (LATGbits.LATG13)
           #define FLASH_SCK_TRIS   (TRISGbits.TRISG6)
           #define FLASH_SDI_TRIS   (TRISGbits.TRISG7)
           #define FLASH_SDO_TRIS   (TRISGbits.TRISG8)
      #define Setup_SCK(rw)       FLASH_SCK_TRIS=rw
           #define Setup_SDI(rw)   FLASH_SDI_TRIS=rw
           #define Setup_SDO(rw)       FLASH_SDO_TRIS=rw

#define FLASH_SPI_IF (PIR1bits.SSPIF)
#define FLASH_SSPBUF (SSPBUF)
#define FLASH_SPISTAT     (SSPSTAT)
#define FLASH_SPISTATbits   (SSPSTATbits)
#define FLASH_SPICON1     (SSPCON1)
#define FLASH_SPICON1bits   (SSPCON1bits)
#define FLASH_SPICON2     (SSPCON2)


PASO 2)  creamos un define que nos permitirá compilar solo el código fuente relacionado a nuestro hardware  asi se podra mantener el código
         par otras memoria SPI FLASH con solo comentar este define


Código: [Seleccionar]

#define MC25AA1024



PASO 3)  creamos nuestro defines de opcode (esto sirve para que el código mantenga legibilidad)

(http://www.todopic.com.ar/foros/index.php?action=dlattach;topic=29729.0;attach=11367)

Código: [Seleccionar]

// FLASH SPI opcodes
#define READ 0x03 // lectura
#define WRITE 0x02 // escritura
#define WRDI 0x04 // deshabilitamos la escritura
#define WREN 0x06 // habilitamos la escritura
#define RDSR 0x05 // registro de lectura
#define WRSR 0x01 // registro de escritura

#define DYFM    0x00    // byte nulo

#if defined(MC25AA1024)
  #define RDID    0xAB    // lettura ID de el fabricante
  #define PEFM    0x42    // borrado de una pagina
  #define SEFM    0xD8    // borrado de un sector
  #define CEFM    0xC7    // borrado de el Chip
#else
  #define RDID    0x9F    // lettura ID de el fabricante
  #define SEFM    0x20    // borrado de un sector
  #define BEFM    0x52    // borrado de un block
  #define CEFM    0x60    // borrado de el Chip
  #define FREAD   0x0B    // lectura rapida
#endif


#define ALL_OPEN 0x02   // escritura habilitada + zona protegida en modalidad abierta



PASO 4) creamos unos defines de atributos

Código: [Seleccionar]

//este define activa la alta velocidad de lectura en memoria que la permiten
//#define FLASH_HIGH_SPEED      //lectura max 50Mhz (other operation 25Mhz)
#define FLASH_LOW_SPEED       //lectura max 25Mhz (other operation 25Mhz)

//este define activa el processo de ottimizacion de la ram y hace que el driver gaste solo 256bytes de ram y no 4096bytes
#define FLASH_SMALL_RAM

#define XFSH_SUCCESS (1u)

#if defined(MC25AA1024)
#define FLASH_ST_VIRTUAL_SECTOR  (0x0001F000)  
#define FLASH_EN_VIRTUAL_SECTOR  (0x0001FFFF)  
#define FLASH_CS_WAIT            (1u)
#else
#define FLASH_ST_VIRTUAL_SECTOR  (0x000FF000)  
#define FLASH_EN_VIRTUAL_SECTOR  (0x00100000)
#define FLASH_BIT_SPEED          (8E6)    //8Mhz
#define FLASH_CS_WAIT            (INSTR_FREQ / FLASH_BIT_SPEED)
#endif

#if defined(MX25L8005)
    #define MAX_CHIP_ADDRESS    (0x0FFFFF)
    #define BLOCK_LEN           (65535ul)
    #define SECTOR_LEN          (4095ul)
    #define PAGE_LEN            (255ul)
    #define IDMF                (0xC2)   //MACRONIX
    #define TYMF                (0x20)
    #define DSMF                (0x14)
#elif defined(MC25AA1024)
    #define MAX_CHIP_ADDRESS    (0x01FFFF)
    #define BLOCK_LEN           (65535ul)
    #define SECTOR_LEN          (4095ul)
    #define PAGE_LEN            (255ul)
    #define IDMF                (0x29)  //MICROCHIP
    #define TYMF                (0x20)
    #define DSMF                (0x14)
#else
    #error "NOT DEFINE FLASH MODEL"
#endif


#if defined(__PIC24F__)
    #define PROPER_SPICON1 (0x013B) //1:1 (1ºpre) 2:1 (2ºpre) 8Mhz  CKE=1, MASTER mode
#elif defined(__PIC32MX__)
    #define PROPER_SPICON1 (_SPI2CON_ON_MASK | _SPI2CON_FRZ_MASK | _SPI2CON_CKE_MASK | _SPI2CON_MSTEN_MASK)
#else  //24H
#define PROPER_SPICON1 (0x21)
#endif



el define FLASH_ST_VIRTUAL_SECTOR identifica el sector utilizado da el driver para respaldar los datos

(http://www.todopic.com.ar/foros/index.php?action=dlattach;topic=29729.0;attach=11369)

PASO 5) creamos unos tipos de datos utilizados en nuestro driver

Código: [Seleccionar]

typedef unsigned char       BYTE;               // 8-bit
typedef unsigned short int  WORD;               // 16-bit
typedef unsigned long       DWORD;              // 32-bit

typedef enum _BOOL { FALSE = 0, TRUE } BOOL;
typedef BOOL XFSH_RESULT;


typedef struct
{
    BYTE    b0:     1;
    BYTE    b1:     1;
    BYTE    b2:     1;
    BYTE    b3:     1;
    BYTE    b4:     1;
    BYTE    b5:     1;
    BYTE    b6:     1;
    BYTE    b7:     1;

}BYTE_BITS;
typedef struct
{
    WORD    b0:     1;
    WORD    b1:     1;
    WORD    b2:     1;
    WORD    b3:     1;
    WORD    b4:     1;
    WORD    b5:     1;
    WORD    b6:     1;
    WORD    b7:     1;
    WORD    b8:     1;
    WORD    b9:     1;
    WORD    b10:    1;
    WORD    b11:    1;
    WORD    b12:    1;
    WORD    b13:    1;
    WORD    b14:    1;
    WORD    b15:    1;
}WORD_BITS;

typedef union _BYTE_VAL
{
    BYTE_BITS bits;
    BYTE Val;
} BYTE_VAL;


typedef union _WORD_VAL
{
    WORD Val;
    WORD_BITS   bits;
    struct
    {
        BYTE LB;
        BYTE HB;
    } byte;
    struct
    {
        BYTE_VAL    low;
        BYTE_VAL    high;
    }byteUnion;

    BYTE v[2];
} WORD_VAL;

typedef union _DWORD_VAL
{
    DWORD Val;
    struct
    {
        BYTE LB;
        BYTE HB;
        BYTE UB;
        BYTE MB;
    } byte;
    struct
    {
        WORD LW;
        WORD HW;
    } word;
    struct
    {
        WORD_VAL    low;
        WORD_VAL    high;
    }wordUnion;
    struct
    {
        BYTE_VAL    lowLSB;
        BYTE_VAL    lowMSB;
        BYTE_VAL    highLSB;
        BYTE_VAL    highMSB;
    }byteUnion;
    BYTE v[4];
    WORD w[2];  
} DWORD_VAL;


PASO 6) creamos unos defines con casting basado en los tipos recien creados en el paso 5

Código: [Seleccionar]

#if defined (FLASH_SMALL_RAM)
  #define FLASH_BUFFER_SIZE  ((WORD)(PAGE_LEN+1))     //LIMIT 256 Bytes
#else
  #define FLASH_BUFFER_SIZE  ((WORD)(SECTOR_LEN+1))   //LIMIT 4096 Bytes
#endif



...continua

Título: Re: Memoria externa SPI
Publicado por: micronoob en 09 de Marzo de 2010, 22:31:06
PASO 7) definimos nuestra ram


Código: [Seleccionar]

#if defined (FLASH_SMALL_RAM)
  unsigned long tempVirtualAddress=0;     //swap sector address
  unsigned int iA=0,iB=0,iC=0,iD=0,iE=0;  //unknowns
#endif

//Dummy RAM
unsigned char DummyMaster=0;
unsigned char tmpOut=0;
unsigned char ctny=0;

static WORD  SPICON1Save;
static DWORD FLASHAddress=0;
static BYTE *FLASHBufferPtr=0;

unsigned int LimitBytesToWrite=0;
unsigned int BytesWritten=0;
unsigned int BlockNumber;
unsigned int SectorNumber;
unsigned int PageNumber;
unsigned int SectorIndex;
unsigned int myPtr=0;
DWORD   StoredAddress;
DWORD   BlockStart;
DWORD   BlockEnd;
DWORD   SectorStart;
DWORD   SectorEnd;
DWORD   PageStart;
DWORD   PageEnd;
DWORD   SaveSectorStart;

#pragma idata sectionBUFFERS
BYTE    XFSHRAMBuf[FLASH_BUFFER_SIZE]={0x0};



PASO 8 )  CREAMOS UNAS MACROS PARA GENERAR CÓDIGO INLINE

Código: [Seleccionar]


#define CSON  (0)
#define CSOFF (1)

#if defined (__PIC32MX__)
#define SetCS(x)  ctny=FLASH_CS_WAIT; \
                 if(x){ while(ctny--); FLASH_CS_IO=x; }else{ FLASH_CS_IO=x; while(ctny--);}
#else
        #define  SetCS(x)   FLASH_CS_IO=x
#endif


#if defined (__PIC32MX__)

static inline  __attribute__((always_inline)) void putcSPI(unsigned int data_out)
{ mSPI2BusyWait(); putcSPI2(data_out);}

static inline  __attribute__((always_inline)) unsigned int getcSPI(void)
{ mSPI2BusyWait(); return getcSPI2();}

#define writeXSFHSPI(x)  putcSPI(x)
#define readXSFHSPI(x)   x = getcSPI()

#else


//8bits method with flush buffer
#define writeXSFHSPI(x) \
                   FLASH_SSPBUF = x; \
                   while(!FLASH_SPI_IF); \
                   DummyMaster = FLASH_SSPBUF; \
                   FLASH_SPI_IF = 0;

//8bits method with flush buffer
#define readXSFHSPI(x) \
                   FLASH_SSPBUF =0; \
                   while(!FLASH_SPI_IF); \
                   x = FLASH_SSPBUF; \
                   FLASH_SPI_IF = 0;


#endif


#define saveSPISPEED()    SPICON1Save = FLASH_SPICON1; FLASH_SPICON1 = FLASH_SPICON1
#define restoreSPISPEED()   FLASH_SPICON1 = SPICON1Save



PASO 9) PUBLICAMOS NUESTROS TIPOS

Código: [Seleccionar]

static BOOL XFSHIsBusy(void);
static BYTE FLASHReadCheck(void);
static void FLASHSetReg(void);
static void FLASHSetWEL(BYTE mode);
static BOOL LocalizeAddress(DWORD dwAddressL);

void DynamicWriteF(DWORD dwAddress);
void DynamicWriteLenF(DWORD dwAddress,WORD lenBuf);
XFSH_RESULT XFSHDynamicRead(DWORD addressD,BYTE *bufferD,WORD lengthD);
void SetFSHSetting(void);
XFSH_RESULT XFSHEndWrite(void);




PASO 10) CREAMOS NUESTROS MÉTODOS PRIVADOS


Código: [Seleccionar]

/*
|      FUNCIÓN PARA DETERMINAR EL ESTADO DE NUESTRA MEMORIA
|      
|__________________________________________________*/
static BOOL XFSHIsBusy(void)
{
   //              ESCRIBIENDO                                            PROTEGIDA
   if((FLASHReadCheck()==0x00)||(FLASHReadCheck()==0x02))
      return 0;

   return 1;
}

/*
|       ESTE METODO NOS DEVUELVE LA LECTURA DEL REGISTRO
|      DE NUESTRA   MEMORIA
|      
|__________________________________________________*/
static BYTE FLASHReadCheck(void)
{
BYTE Dummy;
    
    saveSPISPEED();

SetCS(CSON);

// ENVIAMOS LECTURA DEL REGISTRO
    writeXSFHSPI(RDSR);

    // LEEMOS INFORMACION
    readXSFHSPI(Dummy);
    
    SetCS(CSOFF);

restoreSPISPEED();
  
    return Dummy;
}

/*
|      ESTA FUNCIÓN HABILITA LA ESCRITURA TOTAL DE LA
|      MEMORIA FLASH  INCLUYENDO LOS SECTORES PROTEGIDOS
|      
|__________________________________________________*/
static void FLASHSetReg(void)
{

FLASHSetWEL(1);
    
    saveSPISPEED();
    
    SetCS(CSON);

// ENVIAMOS ESCRITURA DE REGISTRO
    writeXSFHSPI(WRSR);
  
    // TODO PERMITIDO
    writeXSFHSPI(ALL_OPEN);

    SetCS(CSOFF);

restoreSPISPEED();
  
}
/*
|      ESTA FUNCIÓN CONFIGURA EL REGISTRO DE ESCRITURA
|      
|__________________________________________________*/
static void FLASHSetWEL(BYTE mode)
{
    saveSPISPEED();
    
    SetCS(CSON);

if(mode)
{
   // HABILITAMOS EL REGISTRO DE  ESCRITURA
   writeXSFHSPI(WREN);
}
else
{
// DESHABILITAMOS EL REGISTRO DE ESCRITURA
   writeXSFHSPI(WRDI);
}

SetCS(CSOFF);

restoreSPISPEED();
}



/*
|      ESTA FUNCIÓN SIRVE PARA LOCALIZAR UNA DIRECCIÓN
|      Y DEVOLVER SU BLOCK , SECTOR Y PAGINA
|      
|      EN LA VERSIÓN 2 DE LA LIBRERÍA HAY UN MÉTODO OPTIMIZADO
|      PERO MUY PESADO PARA UN MICROS DE 8 BITS
|__________________________________________________*/
static BOOL LocalizeAddress(DWORD dwAddressL)
{
   int i;

   if(dwAddressL<=MAX_CHIP_ADDRESS)
   {
       BlockNumber=1;
       SectorNumber=1;
       PageNumber=1;
       SectorStart=0;
       SectorEnd=0;
       PageStart=0;
       PageEnd=0;
       myPtr=0;
      
       SectorIndex=0;

       for(i=0;i<16;i++){
          BlockEnd = (long)(BLOCK_LEN * BlockNumber)+i;
          if(dwAddressL<=BlockEnd)break;
          BlockStart = BlockEnd + 1;
          BlockNumber++;
       }
      
       BlockNumber -= 1;

       for(i=0;i<256;i++){
          SectorEnd = (long)(SECTOR_LEN * SectorNumber)+i;
          if(dwAddressL<=SectorEnd)break;
          SectorStart = SectorEnd + 1;
          SectorNumber++;
       }
  
       SectorNumber -= 1;
  
       PageStart += SectorStart;
  
       for(i=0;i<16;i++){
          PageEnd =(long)((PAGE_LEN * PageNumber)+i) + SectorStart;
          if(dwAddressL<=PageEnd)break;
          PageStart = PageEnd + 1;
          PageNumber++;
       }
    
       PageNumber -= 1;
       StoredAddress = dwAddressL;
       SectorIndex = StoredAddress - SectorStart;

       return TRUE;
   }
   else
   {
       return FALSE;
   }

}


PASO 10)CREAMOS NUESTRO MÉTODOS PÚBLICOS  DE BORRADOS Y IDENTIFICACIÓN


Código: [Seleccionar]

/*
|   ESTA FUNCIÓN  SIRVE PARA COMPROBAR  LOS DATOS IDENTIFICATIVOS
|          DE NUESTRA MEMORIA QUE CORRESPONDAN A LOS DECLARADOS
|__________________________________________________*/
BOOL FLASHReadID(void)
{
    static BYTE tempB[3];

saveSPISPEED();


SetCS(CSON);

//ENVIAMOS RDID OPCODE
    writeXSFHSPI(RDID);

   //LEEMOS EL FABRICANTE
   readXSFHSPI(tempB[0]);

   //LEEMOS EL TIPO
   readXSFHSPI(tempB[1]);

   // LEEMOS LA DENSIDAD
   readXSFHSPI(tempB[2]);

SetCS(CSOFF);

restoreSPISPEED();
    
    if((tempB[0]==IDMF)&&(tempB[1]==TYMF))
       return TRUE;
    else
       return FALSE;

}


/*
|   BORRADO DE UN SECTOR
|__________________________________________________*/
XFSH_RESULT FLASHEraseSector(DWORD dwAddress)
{

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

saveSPISPEED();


SetCS(CSON);

   writeXSFHSPI(SEFM);

   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

SetCS(CSOFF);
 
restoreSPISPEED();

    while(XFSHIsBusy());

    return XFSH_SUCCESS;
}


/*
|   BORRADO DE UN BLOCK
|__________________________________________________*/

XFSH_RESULT FLASHEraseBlock(DWORD dwAddress)
{
    
    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

saveSPISPEED();

SetCS(CSON);

   writeXSFHSPI(BEFM);

   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

SetCS(CSOFF);
 
restoreSPISPEED();

    while(XFSHIsBusy());

    return XFSH_SUCCESS;
}

/*
|   BORRADO DE EL CHIP
|__________________________________________________*/
XFSH_RESULT FLASHEraseChip(void)
{

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

    saveSPISPEED();

SetCS(CSON);

   writeXSFHSPI(CEFM);

SetCS(CSOFF);

restoreSPISPEED();
    
    while(XFSHIsBusy());

    return XFSH_SUCCESS;

}




PASO 11) CREAMOS NUESTROS METODOS PUBLICOS DE ESCRITURA


Código: [Seleccionar]

/*
|   ESTA FUNCION PREPARA NUESTRO DRIVER A RECIVIR DATOS
|          PARA ESCRIBIR EN NUSTRA MEMORIA
|__________________________________________________*/
 XFSH_RESULT XFSHBeginWrite(DWORD address)
{
#if defined (FLASH_SMALL_RAM)

unsigned int j;
   unsigned long dym=0;
   
LocalizeAddress(address);                //LOCALIZAMOS EL SECTOR

//CONFIGURAMOS EL LIMITE DE ESTE SECTOR
LimitBytesToWrite = (SectorStart + (SECTOR_LEN+1)) - address;
BytesWritten=0;

FLASHEraseSector(FLASH_ST_VIRTUAL_SECTOR);  //BORRAMOS EL SECTOR DE RESPALDO

//CALCULAMOS EL NUMERO DE BYTES A ESCRIBIR ANTES DE LA DIRECCION DE ORIGEN
iA = (unsigned int)(address - SectorStart);

iE = (PAGE_LEN+1);

if(iA<=iE)
{//SI ES LA PRIMERA PAGINA DEL SECTOR

SectorIndex=0;
if(iA)
{
            XFSHDynamicRead(SectorStart,
                            XFSHRAMBuf,
                            iA);               //IMPORTAMOS LOS DATOS EN RAM
                                               //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
            DynamicWriteLenF(FLASH_ST_VIRTUAL_SECTOR,iA);
            tempVirtualAddress = FLASH_ST_VIRTUAL_SECTOR + iA;
       }else{
            tempVirtualAddress = FLASH_ST_VIRTUAL_SECTOR;
       }      

   }
   else
   {
   //CALCULAMOS LA PAGINAS GUARDADAS EN EL SECTOR DE RESPALDO
iC = (unsigned int) floor(iA / iE);
//CALCULAMOS EL NUMERO DE BYTE QUE TENEMOS QUE ESCRIBIR EN LA PAGINA ANTES DE LLEGAR A SU FIN
iD = (unsigned int) iA - ( iC * iE);

tempVirtualAddress = FLASH_ST_VIRTUAL_SECTOR;

PageStart=0;

       for(j=0;j<iC;j++)
   {      
           PageStart=dym + SectorStart;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iE);          //IMPORTAMOS LOS DATOS EN RAM
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
           DynamicWriteLenF(tempVirtualAddress,iE);
           tempVirtualAddress += iE;              
                           
           dym=(PAGE_LEN*(j+1))+(j+1);      
       }
       
       if(iD)
       {//SI HAY BYTES DA ESCRIBIR EN LA PAGINA
       
       PageStart=dym + SectorStart;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iD);          //IMPORTAMOS LOS DATOS EN RAM
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
           DynamicWriteLenF(tempVirtualAddress,iD);
           tempVirtualAddress += iD;
   
   }
                                          
}
FLASHBufferPtr = XFSHRAMBuf;
return XFSH_SUCCESS;

#else  //METODO FULL RAM

   LocalizeAddress(address);       //LOCALIZAMOS EL SECTOR          
   XFSHDynamicRead(SectorStart,
                    XFSHRAMBuf,
                   (SECTOR_LEN+1));  //GUARDAMOS EL SECTOR EN RAM    
   FLASHEraseSector(SectorStart);    //BORRAMOS EL SECTOR

return XFSH_SUCCESS;

#endif

}


/*
|   FUNCION DE ENTRADA PARA ESCRIBIR EN LA FLASH
|__________________________________________________*/
XFSH_RESULT XFSHWrite(BYTE val)
{
#if defined (FLASH_SMALL_RAM)
      
      
      if( FLASHBufferPtr == (XFSHRAMBuf + FLASH_BUFFER_SIZE) )
 {  
  FLASHBufferPtr = XFSHRAMBuf;
  //ESCRIBIMOS EN EL SECTOR DE RESPALDO
  DynamicWriteLenF(tempVirtualAddress,FLASH_BUFFER_SIZE);
      tempVirtualAddress += FLASH_BUFFER_SIZE;
     
 }  

 //CONTROLAMOS QUE LA DIRECCION NO EXCEDA  DEL ACTUAL SECTOR
 if((BytesWritten++)>=LimitBytesToWrite)
 {//SI ES UN NUEVO SECTOR
 XFSHEndWrite();                //CERRAMOS EL ACTUAL SECTOR

 XFSHBeginWrite(SectorStart);  //ARRANCAMOS UN NUEVO SECTOR
      }  
              
 *FLASHBufferPtr++ = val;

      return XFSH_SUCCESS;
#else

//ESCRIBIMOS EN RAM
   XFSHRAMBuf[SectorIndex] = val;
   SectorIndex++;
   return XFSH_SUCCESS;
#endif
}


/*
|   FUNCION DE  FINALIZACION DE ESCRITURA
|__________________________________________________*/
XFSH_RESULT XFSHEndWrite(void)
{
 #if defined (FLASH_SMALL_RAM)
 
   unsigned int j;
   unsigned long dym=0;
       
   //PASO PREVIO)  VOLCAMOS EL BUFFER EN EL SECTOR DE RESPALDO
   
   if( FLASHBufferPtr != (&XFSHRAMBuf[0]) )
   {
   //BYTE QUE HAY EN RAM
   iA = ((unsigned int) FLASHBufferPtr) - ((unsigned int)(&XFSHRAMBuf[0]));
   //VOLCAMOS LA RAM EN EL SECTOR DE RESPALDO
   DynamicWriteLenF(tempVirtualAddress,iA);
       tempVirtualAddress += iA;
}
   
   
   //1º PASO) SECTOR DE ORIGEN -> RAM -> SECTOR DE RESPALDO
   
   //BYTES ESCRITOS
   iA = (unsigned int)tempVirtualAddress - FLASH_ST_VIRTUAL_SECTOR;
   //BYTES PARA ESCRIBIR
   iB = (unsigned int)FLASH_EN_VIRTUAL_SECTOR - tempVirtualAddress;
   
   if(tempVirtualAddress < FLASH_EN_VIRTUAL_SECTOR)
   {
   
   if(iB < (PAGE_LEN + 1))
   {//SI ES SOLO UNA PAGINA
   
   SectorIndex=0;
   XFSHDynamicRead((DWORD)SectorStart+iA,
                        XFSHRAMBuf,
                        iB);          //IMPORTAMOS LOS DATOS EN RAM
                                      //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
       DynamicWriteLenF(tempVirtualAddress,iB);              
                       
}
else
{
if(iA<=(PAGE_LEN+1))
{
   //ESCRITOS EN LA PAGINA ACTUAL
   iC = 1;
  //PARA ESCRIBIR EN LA PAGINA ACTUAL
   iE = (unsigned int) (PAGE_LEN + 1) - iA;
}
else
{
//PAGINAS ESCRITAS
iC = (unsigned int) floor(iA / (PAGE_LEN + 1));
//ESCRITOS EN LA PAGINA ACTUAL
iD = (unsigned int) iA - ( iC * (PAGE_LEN + 1));
//PARA ESCRIBIR EN LA PAGINA ACTUAL
   iE = (unsigned int) (PAGE_LEN + 1) - iD;
}


if(iE)
{
if(iC>1)iC+=1;
SectorIndex=0;
XFSHDynamicRead((DWORD)SectorStart+iA,
                           XFSHRAMBuf,
                           iE);          //IMPORTAMOS LOS DATOS EN RAM
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
           DynamicWriteLenF(tempVirtualAddress,iE);
           tempVirtualAddress += iE;
       }
             
       iE = (PAGE_LEN+1);
       
       dym = iE*iC;
       
       for(j=iC;j<16;j++){
     
           PageStart=dym + SectorStart;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iE);          //IMPORTAMOS LOS DATOS EN RAM  
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
           DynamicWriteLenF(tempVirtualAddress,iE);
           tempVirtualAddress += iE;              
                           
           dym=(PAGE_LEN*(j+1))+(j+1);      
       }          
}
}


//2º PASO) SECTOR DE RESPALDO-> RAM -> SECTOR DE DESTINACION

FLASHEraseSector(SectorStart);          //BORADO DE SECTOR

PageStart=0;
dym=0;

for(j=0;j<16;j++)
   {
     
           PageStart=dym + FLASH_ST_VIRTUAL_SECTOR;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iE);          ////IMPORTAMOS LOS DATOS EN RAM  
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE DESTINACION
           DynamicWriteLenF(SectorStart,iE);
           SectorStart += iE;              
                           
           dym=(PAGE_LEN*(j+1))+(j+1);      
   }

   return XFSH_SUCCESS;

#else

   int j;
   long dym=0;
   
   PageStart=0;

   for(j=0;j<16;j++){
     
      PageStart=dym + SectorStart;
      DynamicWriteF(PageStart);
      dym=(PAGE_LEN*(j+1))+(j+1);      
   }

   return XFSH_SUCCESS;
#endif
}

/*
|   FUNCION DE ESCRITURA
|__________________________________________________*/

void DynamicWriteLenF(DWORD dwAddress,WORD lenBuf)
{
WORD DynamicBytes =lenBuf;

myPtr=0;

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

    saveSPISPEED();

SetCS(CSON);  

// ENVIO WRITE OPCODE
writeXSFHSPI(WRITE);

// ENVIAMOS DIRECCION
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

while(DynamicBytes--)
{
//ENVIAMOS BYTE PARA ESCRIBIR
writeXSFHSPI(XFSHRAMBuf[myPtr]);
        myPtr++;
}

SetCS(CSOFF);

restoreSPISPEED();

// ESPERAMOS QUE ACABE
while( XFSHIsBusy() );
}





ahora nos tomamos una pausa de tanto escribir código y vamos a explicar dos algoritmos de escritura

sequencia de escritura de una memoria Flash en el caso de querer guardar los datos del sector y de tener a disposición mucha ram

sequencia de alto nivel
1)enviamos al driver la dirección que queremos escribir
2)enviamos los bytes que queremos escribir
3)comunicamos al driver que hemos acabado de escribir

secuencia de medio nivel
1)borramos sector de respaldo
2)localizamos sector de origen
3)importamos datos del el sector de origen y lo copiamos en ram
4)escribimos lo nuevos datos en ram
5)borramos el sector de origen
6)volcamos todo el sector conteido en ram en el sector de destinación

sequencia de bajo nivel
...uy mejor no! se intuye que hay muchissima operaciones no?

sequencia de escritura de una memoria Flash en el caso de querer guardar los datos del sector y de NO tener a dispocicion mucha ram

secuencia de alto nivel
1)enviamos al driver la direccion que queremos escribir
2)enviamos los bytes que queremos escribir
3)comunicamos al driver que hemos acabado de escribir

sequencia de medio nivel
1)borramos sector de respaldo
2)localizamos sector de origen

  (n*16)
n)importamos una pagina desde el sector de origen a la RAM
n)volcamos el contenido de la RAM en el sector de respaldo


19)escribimos lo nuevos datos en ram
20)borramos el sector de origen

  (n*16)
n)importamos una pagina desde el sector de respaldo a la RAM
n)volcamos el contenido de la RAM en el sector de destinacion


sequencia de bajo nivel
...uy uy uy aun peor!


como ves para el usuario final que interoga el driver no cambia nada solo hace 3 llamadas al driver
tanto con el metodo FULL_RAM  que con el método SMALL_RAM

una nota importante es que la memoria de microchip suporta el borrado de una pagina esto hace que se pueda
ahorrar algo de codigo ....pero tu no te líes jejejej de momento

bien volvemos al código


PASO 12) CREAMOS NUESTROS MÉTODOS PUBLICOS DE LECTURA

Código: [Seleccionar]

/*
|   FUNCION QUE PREPARA EL DRIVER PARA LEER DESDE
|         LA MEMORIA
|__________________________________________________*/
XFSH_RESULT XFSHBeginRead(unsigned long raddress)
{

//GUARDAMOS LA DIRECCION
FLASHAddress = raddress;
//CONFIGURAMOS EL BUFFER EN RAM
FLASHBufferPtr = XFSHRAMBuf + FLASH_BUFFER_SIZE;
return XFSH_SUCCESS;
}

/*
|     FUNCION DE SALIDA
|__________________________________________________*/
BYTE XFSHRead(void)
{
// CONTROLAMOS QUE NO HAY NADA EN EL BUFFER
if( FLASHBufferPtr == (XFSHRAMBuf + FLASH_BUFFER_SIZE) )
{//SI ES LA PRIMERA LLAMADA

//  LEEMOS UNA PAGINA
XFSHDynamicRead(FLASHAddress,XFSHRAMBuf,FLASH_BUFFER_SIZE);
FLASHAddress += FLASH_BUFFER_SIZE;
FLASHBufferPtr = XFSHRAMBuf;

}

// DEVOLVEMOS UN BYTE DESDE LA RAM
return *FLASHBufferPtr++;
}


/*
|   FUNCION  CIERRE DE  LECTURA
|         ESTA FUNCION SE USA EN EL CASO DE DEBER UTILIZAR
|         EL DRIVER EN UN RTOS CON SEMAFOROS
|__________________________________________________*/
XFSH_RESULT XFSHEndRead(void)
{
#if defined (_CONTROL_LBA_)
    LBA_XFSHEndRead(raddress);
#endif
    return XFSH_SUCCESS;
}



/*
|   FUNCIÓN DE ESCRITURA EN LA MEMORIA
|__________________________________________________*/
XFSH_RESULT XFSHDynamicRead(DWORD addressD,
                        BYTE *bufferD,
                        WORD lengthD)
{


    while( XFSHIsBusy() );

SetCS(CSON);

   #if defined(FLASH_HIGH_SPEED)
     // ENVIO FAST READ OPCODE
   writeXSFHSPI(FREAD);
   #else  
     // ENVIO READ OPCODE
   writeXSFHSPI(READ);
   #endif
    
// ENVIO DE LA DIRECCION
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[0]);

   #if defined(FLASH_HIGH_SPEED)
     // DUMMY CYCLE
   writeXSFHSPI(DYFM);
   #endif


while(lengthD--)
{
if(bufferD != 0){
readXSFHSPI(*bufferD);
*bufferD++;
   }  
};

SetCS(CSOFF);

restoreSPISPEED();

return XFSH_SUCCESS;
}




PASO 13) CREAMOS NUESTRO MÉTODO PUBLICO DE SETUP INICIAL

Código: [Seleccionar]

void XFSHInit(int pbclk)
{
      
FLASH_CS_TRIS = 0; 
SetCS(CSOFF);

Setup_SCK(0);
Setup_SDI(1);
Setup_SDO(0);

#if defined(__C30__)
FLASH_SPICON1 = PROPER_SPICON1;
    FLASH_SPICON2 = 0;
    FLASH_SPISTAT = 0;   
    SPI1CON1bits.MODE16 =0;
    FLASH_SPISTATbits.SPIEN = 1;
#elif defined(__PIC32MX__)
    FLASH_SPIBRG = (pbclk/8)/2ul/FLASH_MAX_SPI_FREQ;
    FLASH_SPICON1bits.CKE = 1;
    FLASH_SPICON1bits.MSTEN = 1;
FLASH_SPICON1bits.ON = 1;
#elif defined(__18CXX)
FLASH_SPICON1 = 0x21;
FLASH_SPI_IF = 0;
FLASH_SPISTATbits.CKE = 1;
FLASH_SPISTATbits.SMP = 0;
#endif
   
   
    FLASHSetReg();
}
 


y en fin ya esta todo el codigo del el driver en un solo fichero
ahora acabamos con un ejemplo de llamada al driver

Código: [Seleccionar]

void main(void)
{
     BYTE C,ix;


    XFSHInit(0);  //inicializamos el driver
   
    FLASHReadID(); //para debug llamamos esta funcion para ver si nuestra memoria contesta

//ESCRIBIMOS 10 bytes
XFSHBeginWrite(0x00000000);

XFSHWrite('E');
XFSHWrite('S');
XFSHWrite('T');
XFSHWrite('O');
XFSHWrite('Y');
XFSHWrite(' ');
XFSHWrite('V');
XFSHWrite('I');
XFSHWrite('V');
XFSHWrite('A');

XFSHEndWrite();

//LEEMOS 10 bytes
XFSHBeginRead(0x00000000);
for(ix=0;ix<10;ix++)
{
    C = XFSHRead();
//aqui envias el la variable "C" por una serial o lcd o lo que sea
}
   
XFSHEndRead();
       
        for(;;){ };

}




por favor hay de recordar que esta es una modificación de una librería de microchip y en ningún le voy a quitar este reconocimiento a microchip y sus programadores aunque del código original (que por cierto el amigo "borral" a publicado en este post) decía del código original queda muy muy poco

alla va el header descript de esta libreria

Código: [Seleccionar]

/*********************************************************************
 *
 *               Data SPI FLASH Access Routines
 *
 *********************************************************************
 * FileName:        SPIFLASH.c
 * Dependencies:    None
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32MX
 * Compiler:        Microchip C32 v1.00 or higher
 * Microchip C30 v3.01 or higher
 * Microchip C18 v3.13 or higher
 * HI-TECH PICC-18 STD 9.50PL3 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright © 2002-2007 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product (“Device”) which is
 *      integrated into Licensee’s product; or
 * (ii) ONLY the Software driver source files ENC28J60.c and
 *      ENC28J60.h ported to a non-Microchip device used in
 *      conjunction with a Microchip ethernet controller for the
 *      sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Nilesh Rajbharti     5/20/02     Original (Rev. 1.0)
 * Howard Schlunder 9/01/04 Rewritten for SPI EEPROMs
 * Howard Schlunder 8/10/06 Modified to control SPI module
 * frequency whenever EEPROM accessed
 * to allow bus sharing with different
 * frequencies.
 * Maurizio Spoto       13/02/08     readapt for SPI FLASH MACRONIX
 * Maurizio Spoto        8/08/08     readapt for PIC32MX
 * Maurizio Spoto        5/08/09     mount LBA for MyDB table partition
 * Maurizio Spoto       10/10/08     adding method for LOW_RAM ,
 *                                   adding SWAP sector for LOW_RAM
 *                                   optimized and unifique Buffering RX and TX
 * Maurizio Spoto       11/10/08     adding method use NAND FLASH
 *                                   with Dynamic NOR FLASH and automatic
 *                                   partition in sequencial skip sector
 * Maurizio Spoto       09/03/10   readapt for SPI FLASH MICROCHIP
********************************************************************/


espero sea lo suficientemente facil

saludos.

Título: Re: Memoria externa SPI
Publicado por: PFCarrera en 10 de Marzo de 2010, 08:14:13
Muchas gracias micronoob!
ahora me queda más claro.     :)

He copiado paso a paso la libreria para poder aclararme mejor, pero al compilar el programa me sale este error:
Error - could not find definition of symbol 'main' in file 'C:\MCC18\lib/c018i.o'.
Errors    : 1

y no se a que es debido.

creo que es por algo de la libreria, pero no tengo ni idea!

a alguien le ha pasado?

(gracias a todos por ayudarme)
Título: Re: Memoria externa SPI
Publicado por: Suky en 10 de Marzo de 2010, 09:21:59
Para crear un proyecto en C18 hay que seguir ciertos pasos, uno de ellos es especificar la ubicación de las carpetas necesarias para el proyecto. Busca aquí (http://www.infopic.comlu.com), hay un tuto de C18.

Saludos!
Título: Re: Memoria externa SPI
Publicado por: PFCarrera en 10 de Marzo de 2010, 09:34:03
Suky....he creado bien el proyecto y las carpetas estan ubicadas
pero....me da ese error
por lo tanto esa no es la solucion

pero gracias de todas formas
Título: Re: Memoria externa SPI
Publicado por: micronoob en 10 de Marzo de 2010, 11:23:14
hola,

amigo no desespere había algún define de 16bit que molestaban

aquí el nuevo cogido compilado

RECUERDA DE PONER TUS PIN EN EL CÓDIGO

Código: [Seleccionar]



#include <p18f4550.h>
#include <math.h>


//SPI FLASH MACRONIX
//#define MX25L8005           //Macronix 8mbit (1Mb)
#define FLASH_CS_TRIS   (TRISAbits.TRISA1)
#define FLASH_CS_IO     (LATAbits.LATA1)
#define FLASH_SCK_TRIS   (TRISAbits.TRISA2)
#define FLASH_SDI_TRIS   (TRISAbits.TRISA3)
#define FLASH_SDO_TRIS   (TRISAbits.TRISA4)
#define Setup_SCK(rw)       FLASH_SCK_TRIS=rw
#define Setup_SDI(rw)    FLASH_SDI_TRIS=rw
#define Setup_SDO(rw)       FLASH_SDO_TRIS=rw
#define FLASH_SPI_IF (PIR1bits.SSPIF)
#define FLASH_SSPBUF (SSPBUF)
#define FLASH_SPISTAT    (SSPSTAT)
#define FLASH_SPISTATbits   (SSPSTATbits)
#define FLASH_SPICON1    (SSPCON1)
#define FLASH_SPICON1bits   (SSPCON1bits)
#define FLASH_SPICON2    (SSPCON2)


#define MC25AA1024

// FLASH SPI opcodes
#define READ 0x03 // lectura
#define WRITE 0x02 // escritura
#define WRDI 0x04 // deshabilitamos la escritura
#define WREN 0x06 // habilitamos la escritura
#define RDSR 0x05 // registro de lectura
#define WRSR 0x01 // registro de escritura

#define DYFM    0x00    // byte nulo

#if defined(MC25AA1024)
  #define RDID    0xAB    // lettura ID de el fabricante
  #define PEFM    0x42    // borrado de una pagina
  #define SEFM    0xD8    // borrado de un sector
  #define CEFM    0xC7    // borrado de el Chip
#else
  #define RDID    0x9F    // lettura ID de el fabricante
  #define SEFM    0x20    // borrado de un sector
  #define BEFM    0x52    // borrado de un block
  #define CEFM    0x60    // borrado de el Chip
  #define FREAD   0x0B    // lectura rapida
#endif


#define ALL_OPEN 0x02   // escritura habilitada + zona protegida en modalidad abierta



//este define activa la alta velocidad de lectura en memoria que la permiten
//#define FLASH_HIGH_SPEED      //lectura max 50Mhz (other operation 25Mhz)
#define FLASH_LOW_SPEED       //lectura max 25Mhz (other operation 25Mhz)

//este define activa el processo de ottimizacion de la ram y hace que el driver gaste solo 256bytes de ram y no 4096bytes
#define FLASH_SMALL_RAM

#define XFSH_SUCCESS (1u)

#if defined(MC25AA1024)
#define FLASH_ST_VIRTUAL_SECTOR  (0x0001F000)  
#define FLASH_EN_VIRTUAL_SECTOR  (0x0001FFFF)  
#define FLASH_CS_WAIT            (1u)
#else
#define FLASH_ST_VIRTUAL_SECTOR  (0x000FF000)  
#define FLASH_EN_VIRTUAL_SECTOR  (0x00100000)
#define FLASH_BIT_SPEED          (8E6)    //8Mhz
#define FLASH_CS_WAIT            (INSTR_FREQ / FLASH_BIT_SPEED)
#endif

#if defined(MX25L8005)
    #define MAX_CHIP_ADDRESS    (0x0FFFFF)
    #define BLOCK_LEN           (65535ul)
    #define SECTOR_LEN          (4095ul)
    #define PAGE_LEN            (255ul)
    #define IDMF                (0xC2)   //MACRONIX
    #define TYMF                (0x20)
    #define DSMF                (0x14)
#elif defined(MC25AA1024)
    #define MAX_CHIP_ADDRESS    (0x01FFFF)
    #define BLOCK_LEN           (65535ul)
    #define SECTOR_LEN          (4095ul)
    #define PAGE_LEN            (255ul)
    #define IDMF                (0x29)  //MICROCHIP
    #define TYMF                (0x20)
    #define DSMF                (0x14)
#else
    #error "NOT DEFINE FLASH MODEL"
#endif



typedef unsigned char       BYTE;               // 8-bit
typedef unsigned short int  WORD;               // 16-bit
typedef unsigned long       DWORD;              // 32-bit

typedef enum _BOOL { FALSE = 0, TRUE } BOOL;
typedef BOOL XFSH_RESULT;


typedef struct
{
    BYTE    b0:     1;
    BYTE    b1:     1;
    BYTE    b2:     1;
    BYTE    b3:     1;
    BYTE    b4:     1;
    BYTE    b5:     1;
    BYTE    b6:     1;
    BYTE    b7:     1;

}BYTE_BITS;
typedef struct
{
    WORD    b0:     1;
    WORD    b1:     1;
    WORD    b2:     1;
    WORD    b3:     1;
    WORD    b4:     1;
    WORD    b5:     1;
    WORD    b6:     1;
    WORD    b7:     1;
    WORD    b8:     1;
    WORD    b9:     1;
    WORD    b10:    1;
    WORD    b11:    1;
    WORD    b12:    1;
    WORD    b13:    1;
    WORD    b14:    1;
    WORD    b15:    1;
}WORD_BITS;

typedef union _BYTE_VAL
{
    BYTE_BITS bits;
    BYTE Val;
} BYTE_VAL;


typedef union _WORD_VAL
{
    WORD Val;
    WORD_BITS   bits;
    struct
    {
        BYTE LB;
        BYTE HB;
    } byte;
    struct
    {
        BYTE_VAL    low;
        BYTE_VAL    high;
    }byteUnion;

    BYTE v[2];
} WORD_VAL;

typedef union _DWORD_VAL
{
    DWORD Val;
    struct
    {
        BYTE LB;
        BYTE HB;
        BYTE UB;
        BYTE MB;
    } byte;
    struct
    {
        WORD LW;
        WORD HW;
    } word;
    struct
    {
        WORD_VAL    low;
        WORD_VAL    high;
    }wordUnion;
    struct
    {
        BYTE_VAL    lowLSB;
        BYTE_VAL    lowMSB;
        BYTE_VAL    highLSB;
        BYTE_VAL    highMSB;
    }byteUnion;
    BYTE v[4];
    WORD w[2];  
} DWORD_VAL;


#if defined (FLASH_SMALL_RAM)
  #define FLASH_BUFFER_SIZE  ((WORD)(PAGE_LEN+1))     //LIMIT 256 Bytes
#else
  #define FLASH_BUFFER_SIZE  ((WORD)(SECTOR_LEN+1))   //LIMIT 4096 Bytes
#endif



#if defined (FLASH_SMALL_RAM)
  unsigned long tempVirtualAddress=0;     //swap sector address
  unsigned int iA=0,iB=0,iC=0,iD=0,iE=0;  //unknowns
#endif

//Dummy RAM
unsigned char DummyMaster=0;
unsigned char tmpOut=0;
unsigned char ctny=0;

static WORD  SPICON1Save;
static DWORD FLASHAddress=0;
static BYTE *FLASHBufferPtr=0;

unsigned int LimitBytesToWrite=0;
unsigned int BytesWritten=0;
unsigned int BlockNumber;
unsigned int SectorNumber;
unsigned int PageNumber;
unsigned int SectorIndex;
unsigned int myPtr=0;
DWORD   StoredAddress;
DWORD   BlockStart;
DWORD   BlockEnd;
DWORD   SectorStart;
DWORD   SectorEnd;
DWORD   PageStart;
DWORD   PageEnd;
DWORD   SaveSectorStart;

#pragma idata sectionBUFFERS
BYTE    XFSHRAMBuf[FLASH_BUFFER_SIZE]={0x0};


#define CSON  (0)
#define CSOFF (1)

#if defined (__PIC32MX__)
#define SetCS(x)  ctny=FLASH_CS_WAIT; \
                 if(x){ while(ctny--); FLASH_CS_IO=x; }else{ FLASH_CS_IO=x; while(ctny--);}
#else
    #define  SetCS(x)   FLASH_CS_IO=x;
#endif

#if defined (__PIC32MX__)

static inline  __attribute__((always_inline)) void putcSPI(unsigned int data_out)
{ mSPI2BusyWait(); putcSPI2(data_out);}

static inline  __attribute__((always_inline)) unsigned int getcSPI(void)
{ mSPI2BusyWait(); return getcSPI2();}

#define writeXSFHSPI(x)  putcSPI(x)
#define readXSFHSPI(x)   x = getcSPI()

#else


//8bits method with flush buffer
#define writeXSFHSPI(x) \
                   FLASH_SSPBUF = x; \
                   while(!FLASH_SPI_IF); \
                   DummyMaster = FLASH_SSPBUF; \
                   FLASH_SPI_IF = 0;

//8bits method with flush buffer
#define readXSFHSPI(x) \
                   FLASH_SSPBUF =0; \
                   while(!FLASH_SPI_IF); \
                   x = FLASH_SSPBUF; \
                   FLASH_SPI_IF = 0;


#endif


#define saveSPISPEED()    SPICON1Save = FLASH_SPICON1; FLASH_SPICON1 = FLASH_SPICON1
#define restoreSPISPEED()   FLASH_SPICON1 = SPICON1Save

static BOOL XFSHIsBusy(void);
static BYTE FLASHReadCheck(void);
static void FLASHSetReg(void);
static void FLASHSetWEL(BYTE mode);
static BOOL LocalizeAddress(DWORD dwAddressL);

void DynamicWriteF(DWORD dwAddress);
void DynamicWriteLenF(DWORD dwAddress,WORD lenBuf);
XFSH_RESULT XFSHDynamicRead(DWORD addressD,BYTE *bufferD,WORD lengthD);
void SetFSHSetting(void);
XFSH_RESULT XFSHEndWrite(void);



/*
|      FUNCIÓN PARA DETERMINAR EL ESTADO DE NUESTRA MEMORIA
|      
|__________________________________________________*/
static BOOL XFSHIsBusy(void)
{
   //              ESCRIBIENDO                                            PROTEGIDA
   if((FLASHReadCheck()==0x00)||(FLASHReadCheck()==0x02))
      return 0;

   return 1;
}

/*
|       ESTE METODO NOS DEVUELVE LA LECTURA DEL REGISTRO
|      DE NUESTRA   MEMORIA
|      
|__________________________________________________*/
static BYTE FLASHReadCheck(void)
{
BYTE Dummy;
    
    saveSPISPEED();

SetCS(CSON);

// ENVIAMOS LECTURA DEL REGISTRO
    writeXSFHSPI(RDSR);

    // LEEMOS INFORMACION
    readXSFHSPI(Dummy);
    
    SetCS(CSOFF);

restoreSPISPEED();
  
    return Dummy;
}

/*
|      ESTA FUNCIÓN HABILITA LA ESCRITURA TOTAL DE LA
|      MEMORIA FLASH  INCLUYENDO LOS SECTORES PROTEGIDOS
|      
|__________________________________________________*/
static void FLASHSetReg(void)
{

FLASHSetWEL(1);
    
    saveSPISPEED();
    
    SetCS(CSON);

// ENVIAMOS ESCRITURA DE REGISTRO
    writeXSFHSPI(WRSR);
  
    // TODO PERMITIDO
    writeXSFHSPI(ALL_OPEN);

    SetCS(CSOFF);

restoreSPISPEED();
  
}
/*
|      ESTA FUNCIÓN CONFIGURA EL REGISTRO DE ESCRITURA
|      
|__________________________________________________*/
static void FLASHSetWEL(BYTE mode)
{
    saveSPISPEED();
    
    SetCS(CSON);

if(mode)
{
   // HABILITAMOS EL REGISTRO DE  ESCRITURA
   writeXSFHSPI(WREN);
}
else
{
// DESHABILITAMOS EL REGISTRO DE ESCRITURA
   writeXSFHSPI(WRDI);
}

SetCS(CSOFF);

restoreSPISPEED();
}



/*
|      ESTA FUNCIÓN SIRVE PARA LOCALIZAR UNA DIRECCIÓN
|      Y DEVOLVER SU BLOCK , SECTOR Y PAGINA
|      
|      EN LA VERSIÓN 2 DE LA LIBRERÍA HAY UN MÉTODO OPTIMIZADO
|      PERO MUY PESADO PARA UN MICROS DE 8 BITS
|__________________________________________________*/
static BOOL LocalizeAddress(DWORD dwAddressL)
{
   int i;

   if(dwAddressL<=MAX_CHIP_ADDRESS)
   {
       BlockNumber=1;
       SectorNumber=1;
       PageNumber=1;
       SectorStart=0;
       SectorEnd=0;
       PageStart=0;
       PageEnd=0;
       myPtr=0;
      
       SectorIndex=0;

       for(i=0;i<16;i++){
          BlockEnd = (long)(BLOCK_LEN * BlockNumber)+i;
          if(dwAddressL<=BlockEnd)break;
          BlockStart = BlockEnd + 1;
          BlockNumber++;
       }
      
       BlockNumber -= 1;

       for(i=0;i<256;i++){
          SectorEnd = (long)(SECTOR_LEN * SectorNumber)+i;
          if(dwAddressL<=SectorEnd)break;
          SectorStart = SectorEnd + 1;
          SectorNumber++;
       }
  
       SectorNumber -= 1;
  
       PageStart += SectorStart;
  
       for(i=0;i<16;i++){
          PageEnd =(long)((PAGE_LEN * PageNumber)+i) + SectorStart;
          if(dwAddressL<=PageEnd)break;
          PageStart = PageEnd + 1;
          PageNumber++;
       }
    
       PageNumber -= 1;
       StoredAddress = dwAddressL;
       SectorIndex = StoredAddress - SectorStart;

       return TRUE;
   }
   else
   {
       return FALSE;
   }

}


/*
|   ESTA FUNCIÓN  SIRVE PARA COMPROBAR  LOS DATOS IDENTIFICATIVOS
|          DE NUESTRA MEMORIA QUE CORRESPONDAN A LOS DECLARADOS
|__________________________________________________*/
BOOL FLASHReadID(void)
{
    static BYTE tempB[3];

saveSPISPEED();


SetCS(CSON);

//ENVIAMOS RDID OPCODE
    writeXSFHSPI(RDID);

   //LEEMOS EL FABRICANTE
   readXSFHSPI(tempB[0]);

   //LEEMOS EL TIPO
   readXSFHSPI(tempB[1]);

   // LEEMOS LA DENSIDAD
   readXSFHSPI(tempB[2]);

SetCS(CSOFF);

restoreSPISPEED();
    
    if((tempB[0]==IDMF)&&(tempB[1]==TYMF))
       return TRUE;
    else
       return FALSE;

}


/*
|   BORRADO DE UN SECTOR
|__________________________________________________*/
XFSH_RESULT FLASHEraseSector(DWORD dwAddress)
{

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

saveSPISPEED();


SetCS(CSON);

   writeXSFHSPI(SEFM);

   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

SetCS(CSOFF);
 
restoreSPISPEED();

    while(XFSHIsBusy());

    return XFSH_SUCCESS;
}


#if !defined(MC25AA1024)

/*
|   BORRADO DE UN BLOCK
|__________________________________________________*/

XFSH_RESULT FLASHEraseBlock(DWORD dwAddress)
{
    
    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

saveSPISPEED();

SetCS(CSON);

   writeXSFHSPI(BEFM);

   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
   writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

SetCS(CSOFF);
 
restoreSPISPEED();

    while(XFSHIsBusy());

    return XFSH_SUCCESS;
}

#endif

/*
|   BORRADO DE EL CHIP
|__________________________________________________*/
XFSH_RESULT FLASHEraseChip(void)
{

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

    saveSPISPEED();

SetCS(CSON);

   writeXSFHSPI(CEFM);

SetCS(CSOFF);

restoreSPISPEED();
    
    while(XFSHIsBusy());

    return XFSH_SUCCESS;

}



/*
|   ESTA FUNCION PREPARA NUESTRO DRIVER A RECIVIR DATOS
|          PARA ESCRIBIR EN NUSTRA MEMORIA
|__________________________________________________*/
 XFSH_RESULT XFSHBeginWrite(DWORD address)
{
#if defined (FLASH_SMALL_RAM)

unsigned int j;
   unsigned long dym=0;
   
LocalizeAddress(address);                //LOCALIZAMOS EL SECTOR

//CONFIGURAMOS EL LIMITE DE ESTE SECTOR
LimitBytesToWrite = (SectorStart + (SECTOR_LEN+1)) - address;
BytesWritten=0;

FLASHEraseSector(FLASH_ST_VIRTUAL_SECTOR);  //BORRAMOS EL SECTOR DE RESPALDO

//CALCULAMOS EL NUMERO DE BYTES A ESCRIBIR ANTES DE LA DIRECCION DE ORIGEN
iA = (unsigned int)(address - SectorStart);

iE = (PAGE_LEN+1);

if(iA<=iE)
{//SI ES LA PRIMERA PAGINA DEL SECTOR

SectorIndex=0;
if(iA)
{
            XFSHDynamicRead(SectorStart,
                            XFSHRAMBuf,
                            iA);               //IMPORTAMOS LOS DATOS EN RAM
                                               //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
            DynamicWriteLenF(FLASH_ST_VIRTUAL_SECTOR,iA);
            tempVirtualAddress = FLASH_ST_VIRTUAL_SECTOR + iA;
       }else{
            tempVirtualAddress = FLASH_ST_VIRTUAL_SECTOR;
       }      

   }
   else
   {
   //CALCULAMOS LA PAGINAS GUARDADAS EN EL SECTOR DE RESPALDO
iC = (unsigned int) floor(iA / iE);
//CALCULAMOS EL NUMERO DE BYTE QUE TENEMOS QUE ESCRIBIR EN LA PAGINA ANTES DE LLEGAR A SU FIN
iD = (unsigned int) iA - ( iC * iE);

tempVirtualAddress = FLASH_ST_VIRTUAL_SECTOR;

PageStart=0;

       for(j=0;j<iC;j++)
   {      
           PageStart=dym + SectorStart;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iE);          //IMPORTAMOS LOS DATOS EN RAM
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
           DynamicWriteLenF(tempVirtualAddress,iE);
           tempVirtualAddress += iE;              
                           
           dym=(PAGE_LEN*(j+1))+(j+1);      
       }
       
       if(iD)
       {//SI HAY BYTES DA ESCRIBIR EN LA PAGINA
       
       PageStart=dym + SectorStart;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iD);          //IMPORTAMOS LOS DATOS EN RAM
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
           DynamicWriteLenF(tempVirtualAddress,iD);
           tempVirtualAddress += iD;
   
   }
                                          
}
FLASHBufferPtr = XFSHRAMBuf;
return XFSH_SUCCESS;

#else  //METODO FULL RAM

   LocalizeAddress(address);       //LOCALIZAMOS EL SECTOR          
   XFSHDynamicRead(SectorStart,
                    XFSHRAMBuf,
                   (SECTOR_LEN+1));  //GUARDAMOS EL SECTOR EN RAM    
   FLASHEraseSector(SectorStart);    //BORRAMOS EL SECTOR

return XFSH_SUCCESS;

#endif

}


/*
|   FUNCION DE ENTRADA PARA ESCRIBIR EN LA FLASH
|__________________________________________________*/
XFSH_RESULT XFSHWrite(BYTE val)
{
#if defined (FLASH_SMALL_RAM)
      
      
      if( FLASHBufferPtr == (XFSHRAMBuf + FLASH_BUFFER_SIZE) )
 {  
  FLASHBufferPtr = XFSHRAMBuf;
  //ESCRIBIMOS EN EL SECTOR DE RESPALDO
  DynamicWriteLenF(tempVirtualAddress,FLASH_BUFFER_SIZE);
      tempVirtualAddress += FLASH_BUFFER_SIZE;
     
 }  

 //CONTROLAMOS QUE LA DIRECCION NO EXCEDA  DEL ACTUAL SECTOR
 if((BytesWritten++)>=LimitBytesToWrite)
 {//SI ES UN NUEVO SECTOR
 XFSHEndWrite();                //CERRAMOS EL ACTUAL SECTOR

 XFSHBeginWrite(SectorStart);  //ARRANCAMOS UN NUEVO SECTOR
      }  
              
 *FLASHBufferPtr++ = val;

      return XFSH_SUCCESS;
#else

//ESCRIBIMOS EN RAM
   XFSHRAMBuf[SectorIndex] = val;
   SectorIndex++;
   return XFSH_SUCCESS;
#endif
}


/*
|   FUNCION DE  FINALIZACION DE ESCRITURA
|__________________________________________________*/
XFSH_RESULT XFSHEndWrite(void)
{
 #if defined (FLASH_SMALL_RAM)
 
   unsigned int j;
   unsigned long dym=0;
       
   //PASO PREVIO)  VOLCAMOS EL BUFFER EN EL SECTOR DE RESPALDO
   
   if( FLASHBufferPtr != (&XFSHRAMBuf[0]) )
   {
   //BYTE QUE HAY EN RAM
   iA = ((unsigned int) FLASHBufferPtr) - ((unsigned int)(&XFSHRAMBuf[0]));
   //VOLCAMOS LA RAM EN EL SECTOR DE RESPALDO
   DynamicWriteLenF(tempVirtualAddress,iA);
       tempVirtualAddress += iA;
}
   
   
   //1º PASO) SECTOR DE ORIGEN -> RAM -> SECTOR DE RESPALDO
   
   //BYTES ESCRITOS
   iA = (unsigned int)tempVirtualAddress - FLASH_ST_VIRTUAL_SECTOR;
   //BYTES PARA ESCRIBIR
   iB = (unsigned int)FLASH_EN_VIRTUAL_SECTOR - tempVirtualAddress;
   
   if(tempVirtualAddress < FLASH_EN_VIRTUAL_SECTOR)
   {
   
   if(iB < (PAGE_LEN + 1))
   {//SI ES SOLO UNA PAGINA
   
   SectorIndex=0;
   XFSHDynamicRead((DWORD)SectorStart+iA,
                        XFSHRAMBuf,
                        iB);          //IMPORTAMOS LOS DATOS EN RAM
                                      //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
       DynamicWriteLenF(tempVirtualAddress,iB);              
                       
}
else
{
if(iA<=(PAGE_LEN+1))
{
   //ESCRITOS EN LA PAGINA ACTUAL
   iC = 1;
  //PARA ESCRIBIR EN LA PAGINA ACTUAL
   iE = (unsigned int) (PAGE_LEN + 1) - iA;
}
else
{
//PAGINAS ESCRITAS
iC = (unsigned int) floor(iA / (PAGE_LEN + 1));
//ESCRITOS EN LA PAGINA ACTUAL
iD = (unsigned int) iA - ( iC * (PAGE_LEN + 1));
//PARA ESCRIBIR EN LA PAGINA ACTUAL
   iE = (unsigned int) (PAGE_LEN + 1) - iD;
}


if(iE)
{
if(iC>1)iC+=1;
SectorIndex=0;
XFSHDynamicRead((DWORD)SectorStart+iA,
                           XFSHRAMBuf,
                           iE);          //IMPORTAMOS LOS DATOS EN RAM
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
           DynamicWriteLenF(tempVirtualAddress,iE);
           tempVirtualAddress += iE;
       }
             
       iE = (PAGE_LEN+1);
       
       dym = iE*iC;
       
       for(j=iC;j<16;j++){
     
           PageStart=dym + SectorStart;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iE);          //IMPORTAMOS LOS DATOS EN RAM  
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE RESPALDO
           DynamicWriteLenF(tempVirtualAddress,iE);
           tempVirtualAddress += iE;              
                           
           dym=(PAGE_LEN*(j+1))+(j+1);      
       }          
}
}


//2º PASO) SECTOR DE RESPALDO-> RAM -> SECTOR DE DESTINACION

FLASHEraseSector(SectorStart);          //BORADO DE SECTOR

PageStart=0;
dym=0;

for(j=0;j<16;j++)
   {
     
           PageStart=dym + FLASH_ST_VIRTUAL_SECTOR;
           
           SectorIndex=0;
XFSHDynamicRead(PageStart,
                           XFSHRAMBuf,
                           iE);          ////IMPORTAMOS LOS DATOS EN RAM  
                                         //VOLCAMOS LOS DATOS EN RAM EN EL SECTOR DE DESTINACION
           DynamicWriteLenF(SectorStart,iE);
           SectorStart += iE;              
                           
           dym=(PAGE_LEN*(j+1))+(j+1);      
   }

   return XFSH_SUCCESS;

#else

   int j;
   long dym=0;
   
   PageStart=0;

   for(j=0;j<16;j++){
     
      PageStart=dym + SectorStart;
      DynamicWriteF(PageStart);
      dym=(PAGE_LEN*(j+1))+(j+1);      
   }

   return XFSH_SUCCESS;
#endif
}

/*
|   FUNCION DE ESCRITURA
|__________________________________________________*/

void DynamicWriteLenF(DWORD dwAddress,WORD lenBuf)
{
WORD DynamicBytes =lenBuf;

myPtr=0;

    while(FLASHReadCheck()!=ALL_OPEN)
{FLASHSetWEL(1);}

    saveSPISPEED();

SetCS(CSON);  

// ENVIO WRITE OPCODE
writeXSFHSPI(WRITE);

// ENVIAMOS DIRECCION
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&dwAddress)->v[0]);

while(DynamicBytes--)
{
//ENVIAMOS BYTE PARA ESCRIBIR
writeXSFHSPI(XFSHRAMBuf[myPtr]);
        myPtr++;
}

SetCS(CSOFF);

restoreSPISPEED();

// ESPERAMOS QUE ACABE
while( XFSHIsBusy() );
}


/*
|   FUNCION QUE PREPARA EL DRIVER PARA LEER DESDE
|         LA MEMORIA
|__________________________________________________*/
XFSH_RESULT XFSHBeginRead(unsigned long raddress)
{

//GUARDAMOS LA DIRECCION
FLASHAddress = raddress;
//CONFIGURAMOS EL BUFFER EN RAM
FLASHBufferPtr = XFSHRAMBuf + FLASH_BUFFER_SIZE;
return XFSH_SUCCESS;
}

/*
|     FUNCION DE SALIDA
|__________________________________________________*/
BYTE XFSHRead(void)
{
// CONTROLAMOS QUE NO HAY NADA EN EL BUFFER
if( FLASHBufferPtr == (XFSHRAMBuf + FLASH_BUFFER_SIZE) )
{//SI ES LA PRIMERA LLAMADA

//  LEEMOS UNA PAGINA
XFSHDynamicRead(FLASHAddress,XFSHRAMBuf,FLASH_BUFFER_SIZE);
FLASHAddress += FLASH_BUFFER_SIZE;
FLASHBufferPtr = XFSHRAMBuf;
}

// DEVOLVEMOS UN BYTE DESDE LA RAM
return *FLASHBufferPtr++;
}


/*
|   FUNCION  CIERRE DE  LECTURA
|         ESTA FUNCION SE USA EN EL CASO DE DEBER UTILIZAR
|         EL DRIVER EN UN RTOS CON SEMAFOROS
|__________________________________________________*/
XFSH_RESULT XFSHEndRead(void)
{
#if defined (_CONTROL_LBA_)
    LBA_XFSHEndRead(raddress);
#endif
    return XFSH_SUCCESS;
}



/*
|   FUNCIÓN DE ESCRITURA EN LA MEMORIA
|__________________________________________________*/
XFSH_RESULT XFSHDynamicRead(DWORD addressD,
                        BYTE *bufferD,
                        WORD lengthD)
{


    while( XFSHIsBusy() );

SetCS(CSON);

   #if defined(FLASH_HIGH_SPEED)
     // ENVIO FAST READ OPCODE
   writeXSFHSPI(FREAD);
   #else  
     // ENVIO READ OPCODE
   writeXSFHSPI(READ);
   #endif
    
// ENVIO DE LA DIRECCION
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[2]);
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[1]);
writeXSFHSPI(((DWORD_VAL*)&addressD)->v[0]);

   #if defined(FLASH_HIGH_SPEED)
     // DUMMY CYCLE
   writeXSFHSPI(DYFM);
   #endif


while(lengthD--)
{
if(bufferD != 0){
readXSFHSPI(*bufferD);
*bufferD++;
   }  
};

SetCS(CSOFF);

restoreSPISPEED();

return XFSH_SUCCESS;
}


void XFSHInit(int pbclk)
{
      

FLASH_CS_TRIS = 0;  
SetCS(CSOFF);

Setup_SCK(0);
Setup_SDI(1);
Setup_SDO(0);

#if defined(__C30__)
FLASH_SPICON1 = PROPER_SPICON1;
   FLASH_SPICON2 = 0;
   FLASH_SPISTAT = 0;    
   SPI1CON1bits.MODE16 =0;
   FLASH_SPISTATbits.SPIEN = 1;
#elif defined(__PIC32MX__)
   FLASH_SPIBRG = (pbclk/8)/2ul/FLASH_MAX_SPI_FREQ;
   FLASH_SPICON1bits.CKE = 1;
   FLASH_SPICON1bits.MSTEN = 1;
FLASH_SPICON1bits.ON = 1;
#elif defined(__18CXX)
FLASH_SPICON1 = 0x21;
FLASH_SPI_IF = 0;
FLASH_SPISTATbits.CKE = 1;
FLASH_SPISTATbits.SMP = 0;
#endif
    
    
    FLASHSetReg();
}








void main(void)
{
    BYTE C,ix;


    XFSHInit(0);  //inicializamos el driver
    
    FLASHReadID(); //para debug llamamos esta funcion para ver si nuestra memoria contesta

//ESCRIBIMOS 10 bytes
XFSHBeginWrite(0x00000000);

XFSHWrite('E');
XFSHWrite('S');
XFSHWrite('T');
XFSHWrite('O');
XFSHWrite('Y');
XFSHWrite(' ');
XFSHWrite('V');
XFSHWrite('I');
XFSHWrite('V');
XFSHWrite('A');

XFSHEndWrite();

//LEEMOS 10 bytes
XFSHBeginRead(0x00000000);
for(ix=0;ix<10;ix++)
{
   C = XFSHRead();
//aqui envias el la variable "C" por una serial o lcd o lo que sea
}
 
XFSHEndRead();



for(;;){ };


}



(http://www.todopic.com.ar/foros/index.php?action=dlattach;topic=29729.0;attach=11375)

saludos.


Título: Re: Memoria externa SPI
Publicado por: PFCarrera en 11 de Marzo de 2010, 07:55:59
muchas gracias micronoob!!
ahora me compila perfectamente!

una pregunta?
para mostrarlo por pantalla....yo puedo hacer lo siguiente?:

defino un array:  char mensaje[];
y luego le asigno a este la constante C (que es un BYTE)

mensaje[]= C;

es que...¿sino como la muestro por pantalla?

lo siento por molestarte tanto.....me cuesta un poquito (bastante) :)

gracias!!

un saludo!
Título: Re: Memoria externa SPI
Publicado por: micronoob en 11 de Marzo de 2010, 08:50:21
hola,

según lo que tu quieras imprimir en pantalla si es un numero un carácter un bcd lo que sea
el LCD solo quera recibir caracteres que se puedan imprimir por esto antes de pasarlos a el LCD hay que convertirlos en ascii

por ellos el C brinda de una serie de funciones de printing que desenvuelven esta tarea "print", "printf", "sprintf"

pero si en tu memoria has escrito unos caracteres simplemente tal como lo lees lo puedes enviar en pantalla

en el ejemplo hay un "for" que por cada ciclo lee un caracter de la memoria y en la linea siguiente
tu las envias a el LCD

con putcLCD(C);
o con las funciones que tengas para escribir en el LCD


aqui unos cuantos métodos de conversión sin utilizar las librerías de C :
Código: [Seleccionar]

void UInt32toByteArray(UInt32 Value, Byte *Buffer)
{
Byte i;
UInt32 Digit;
UInt32 Divisor;
Bool Printed = False;

if(Value)
{
for(i = 0, Divisor = 1000000000; i < 10; i++)
{
Digit = Value/Divisor;
if(Digit || Printed)
{
*Buffer++ = '0' + Digit;
Value -= Digit*Divisor;
Printed = True;
}
Divisor /= 10;
}
}
else
{
*Buffer++ = '0';
}

*Buffer = '\0';
}

void UInt32toEndianByteArray(UInt32 Value, Byte *Buffer, UInt8 maxLen)
{
Byte ix,yx=0;
UInt32 Digit;
UInt32 Divisor;
Byte endianData[10] ={0x0};
Bool Printed = False;
Bool StartEndian = False;

if(Value)
{
for(ix = 0, Divisor = 1000000000; ix < 10; ix++)
{
Digit = Value/Divisor;
if(Digit || Printed)
{
endianData[ix] = '0' + Digit;
Value -= Digit*Divisor;
Printed = True;
}

Divisor /= 10;
}

for(ix=(10-maxLen);ix<10;ix++)
{
if(endianData[ix]>='0')
       *Buffer++ = endianData[ix];
    else
       *Buffer++ = '0';
}    
}
else
{
*Buffer++ = '0';
}

*Buffer = '\0';
}

inline Byte AToB(Char inA)
{
if ((inA >= 0x30) && (inA <= 0x39))
{
        return (inA - 0x30);
    }
    else if ((inA >= 0x41) && (inA <= 0x46))
{
        return (inA - 0x37);
    }
    else if ((inA >= 0x61) && (inA <= 0x66))
{
        return (inA - 0x57);
    }
    else
{
        return 0;
    }
}

inline Char BToA(Byte inB)
{
   if(inB<=9)
      return (inB + 0x30);
   if((inB>9)&&(inB<=15))
      return (inB + 0x37);
     
   return 0;
}

char nibbleToHex(int nibble)
{
    const int ascii_zero = 48;
    const int ascii_a = 65;
   
    if((nibble >= 0) && (nibble <= 9))
    {
        return (char) (nibble + ascii_zero);
    }
    if((nibble >= 10) && (nibble <= 15))
    {
        return (char) (nibble - 10 + ascii_a);
    }
    return '?';
}

unsigned char bcd(unsigned char dec)
{
return ((dec/10)<<4)+(dec%10);
}

unsigned char decimal(unsigned char bcd)
{
return ((bcd>>4)*10)+bcd%16;
}

Bool isPrint(char c){
Byte _c=(Byte)c;
   if ((_c>=0x20) && (_c<=0x7F)){
      return 1;
   }
   return 0;
}



saludos.

Título: Re: Memoria externa SPI
Publicado por: PFCarrera en 16 de Marzo de 2010, 09:45:49
buenas micronoob!

he estado intentando muchísimas veces que me funcione el programa y no hay manera.
Esto no está hecho para mi.... :(

Estoy intentando con el ejemplo que me dejaste (que me compila perfectamente) ver el valor de C, que es donde se guarda la lectura:  C=Read();

lo pongo en modo debugg y por más que espero nunca llega a esta instrucción, es más, he puesto un debugg al principio y otro a mediante y solo me llega al principio....nose si es que se hace un bucle infinito porque me llega hasta la instrucción BeginWrite(); y luego pongo otro debugg en write(); y no llega nunca.

y otra cosa es lo de mostrar por pantalla,....que no lo he entendido del todo.
Tu me dijiste que:
en el ejemplo hay un "for" que por cada ciclo lee un caracter de la memoria y en la linea siguiente
tu las envias a el LCD con el comando de mi libreria, pero....no me deja me da error
y las funciones que me pusiste no las entiendo bien.

muchas gracias por todo.......lo siento por ser tan atascadito    :oops:

un saludo