Autor Tema: Memoria externa SPI  (Leído 10764 veces)

0 Usuarios y 2 Visitantes están viendo este tema.

micronoob

  • Visitante
Re: Memoria externa SPI
« Respuesta #15 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.



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)



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



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

« Última modificación: 10 de Marzo de 2010, 11:35:41 por micronoob »

micronoob

  • Visitante
Re: Memoria externa SPI
« Respuesta #16 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.

« Última modificación: 10 de Marzo de 2010, 19:43:19 por micronoob »

Desconectado PFCarrera

  • PIC10
  • *
  • Mensajes: 32
Re: Memoria externa SPI
« Respuesta #17 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)

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Memoria externa SPI
« Respuesta #18 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í, hay un tuto de C18.

Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado PFCarrera

  • PIC10
  • *
  • Mensajes: 32
Re: Memoria externa SPI
« Respuesta #19 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

micronoob

  • Visitante
Re: Memoria externa SPI
« Respuesta #20 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(;;){ };


}





saludos.



Desconectado PFCarrera

  • PIC10
  • *
  • Mensajes: 32
Re: Memoria externa SPI
« Respuesta #21 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!

micronoob

  • Visitante
Re: Memoria externa SPI
« Respuesta #22 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.


Desconectado PFCarrera

  • PIC10
  • *
  • Mensajes: 32
Re: Memoria externa SPI
« Respuesta #23 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