This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Programming to external EEPROM

Hello. I need some help.
I'm trying to write, read and erase an external EEPROM (25AA040 MICROCHIP) via SPI from XC164CS board, for example, one byte at 0x00 adress of the eeprom, but i don't know how to do it.
Into the datasheet, I can see some instructions but i don't know what to do with them:
img28.imagevenue.com/img.php
Could anyone help me?
Thank you very much. :)

Parents
  • John,
    First allow me to recommend that you refer to a C text book to extend your understanding of pointers. I don't know what kind of application your are writing, but do remember that making a mistake with pointers is likely to kill your controller, and could risk lives in the process!
    as to your question:

    eeprom.txptr   = (S8 *)(&eeprom);
    

    'eeprom' is a data structure that contains a member pointer to a 8 bit data type (that is 'txptr'. we can assume it is a unsigned char). that member is pointed to the beginning of 'eeprom'. that means that dereference of 'txptr' will be an unsigned char, or the first byte of the 'eeprom' structure, where I guess some text is stored (see the structure layout). note that incrementing the value of txptr by 1 will point it to the next unsigned char of the structure.

    &eeprom
    

    returns the address of 'eeprom', and that address is then casted to a unsigned char pointer so that the assignment will not cause the compiler to complain.

Reply
  • John,
    First allow me to recommend that you refer to a C text book to extend your understanding of pointers. I don't know what kind of application your are writing, but do remember that making a mistake with pointers is likely to kill your controller, and could risk lives in the process!
    as to your question:

    eeprom.txptr   = (S8 *)(&eeprom);
    

    'eeprom' is a data structure that contains a member pointer to a 8 bit data type (that is 'txptr'. we can assume it is a unsigned char). that member is pointed to the beginning of 'eeprom'. that means that dereference of 'txptr' will be an unsigned char, or the first byte of the 'eeprom' structure, where I guess some text is stored (see the structure layout). note that incrementing the value of txptr by 1 will point it to the next unsigned char of the structure.

    &eeprom
    

    returns the address of 'eeprom', and that address is then casted to a unsigned char pointer so that the assignment will not cause the compiler to complain.

Children
  • Ok Tamir,
    I understand your text. I have a new question.
    If I have to increase the pointer "x" times, is necessary to intriduce a new parameter in the function? For example:

    _inline void EepromStartTx(U16  MY_ADRESS) {
            CS_EEPROM      = low;
            eeprom.bytesTx = 1;                                     /* decrement the transmit count by one */
            eeprom.bytesRx = 0;
            eeprom.txptr   = (S8 *)(&eeprom);                   /* reset pointer to first element */
            eeprom.txptr   =  eeprom.txptr + MY_ADRESS;     /* put the pointer in my first element */
            SSC0_TB        = *eeprom.txptr++;                       /* write the first byte to the SSC0 tx buffer */
    }
    

  • eeprom.txptr   = (S8 *)(&eeprom);                   /* reset pointer to first element */
    eeprom.txptr   =  eeprom.txptr + MY_ADRESS;     /* put the pointer in my first element */
    

    can be compacted to

    eeprom.txptr = (S8 *)(&eeprom) + MY_ADRESS ;
    

    I would expect a function prototype like this:

    void EepromStartTx(U16  MY_ADRESS, unsigned  char *ap_buffer, unsigned int a_buffer_length)
    

    note that I removed the inline directive as it might probably be required to insert a loop into your function.

  • Its imposible. If I modify anything in EepromStartTxthe EEPROM only returns zeros. Any suggestion?? I just need to know this :(

  • how then do you expect to solve your problem is you cannot change anything? there is a logical empirical explanation as to why it does not work anymore. why don't you post a revision that does not work.

  • The code is too long to post here. Take the proyect at this adress:
    rapidshare.com/.../eeprom.rar.html

  • I am not installing any of this rapidshare junk on my PC, and anyway I don't have time to review your code. The product hits the market by the end of this week!
    depart from a working revision, change your EEPROM write function, and post it here if it does not work.

  • I am not sure how you are going to maintain code that you didn't write or don't understand. The driver starts with the serial command and address then switches to the user address by a counter in the interrupt routine.

    typedef enum {
      WRSR  = 0x0100,  /* Write Status Register             */
      WRITE = 0x0200,  /* Write Data to Memory Array  */
      READ  = 0x0300,  /* Read Data from Memory Array */
      WRDI  = 0x0400,  /* Reset Write Enable Latch  */
      RDSR  = 0x0500,  /* Read Status Register              */
      WREN  = 0x0600,  /* Set Write Enable Latch      */
    } EepromCommandType;
    
    _inline void EepromStartTx(void) {
      CS_EEPROM      = low;
      eeprom.bytesTx = 1;                        /* decrement the transmit count by one */
      eeprom.bytesRx = 0;
      eeprom.txptr   = (S8 *)(&eeprom)+1;  /* reset pointer to first element */
      SSC0_TB         = *eeprom.txptr++;     /* write the first byte to the SSC0 tx buffer */
    }
    

  • #include <XC164.h>
    #include <intrins.h>
    #include "types.h"
    #include "utilities.h"
    #include "ssc0.h"
    #include "variables.h"

    const S8 txBuf[] = "Welcome";
    const U16 txSize = (sizeof(txBuf) - 1);
    S8 rxBuf[64];

    /**/
    void main (void) {
    U16 address = 0; /* EEPROM address */
    U16 my_adress1 = 0; /* Write Adress */
    U16 my_adress2 = 3; /* Read Adress */

    SSC0_Init(); /* initialize the SSC peripheral */
    ASC0_vInit(); /* initialize the ASC peripheral */
    PSW_IEN = 1; /* globally enable interrupts */

    DP9 = 0x0010; // load direction register

    flag = 0;

    /* write bytes to the EEPROM */
    EepromWriteEnable(0);
    while(EepromBusy());

    /* max page size if 64 bytes in a write */
    EepromWrite(address, (S8 *) &txBuf[0], (U16) txSize,0);
    while(EepromBusy());

    /* wait for WRITE command to complete */
    while((EepromReadStatus(0) & RDY_) == true);

    /* read back the bytes we wrote to the EEPROM */
    EepromRead(address, &rxBuf[0], 6, 0);
    while(EepromBusy());

    while(1) { _nop_(); /* loop forever */ }
    }

  • What you have said, I understand it. What I don't know to do is how to modify the pointer to change the writing/reading start adress that I want.

  • _inline void EepromStartTx(U16  MY_ADRESS) {
      CS_EEPROM      = low;
      eeprom.bytesTx = 1;                        /* decrement the transmit count by one */
      eeprom.bytesRx = 0;
      eeprom.txptr   = (S8 *)(&eeprom)+1;  /* reset pointer to first element */
      SSC0_TB         = *eeprom.txptr++;     /* write the first byte to the SSC0 tx buffer */
      }
    
    /**/
    void SSC0_viTx(void) interrupt SSC0TINT
    {
      if (eeprom.bytesTx < eeprom.txCnt) {
              eeprom.bytesTx++;
              if (TxMode == WRITE) /* write mode */
              {
            if ((eeprom.cmd == WRITE) && (eeprom.bytesTx == START_TX_MSG))
                    {
                    eeprom.txptr = eeprom.baseptr; /* switch pointer to data */
            }
                SSC0_TB = *eeprom.txptr++;  /* write user data */
          }
            else
            {               /* ok READ mode */
    
            if ((eeprom.cmd == READ) && (eeprom.bytesTx >= START_TX_MSG))
                    {
                    SSC0_TB = 0; /* when reading data just send zeros */
                    }
                    else
                    {
            SSC0_TB = *eeprom.txptr++; /* send command and address */
                    }
            }
      }
    }
    
    /**/
    void SSC0_viRx(void) interrupt SSC0RINT
    {
      if (eeprom.bytesRx < eeprom.rxCnt)
      {
              eeprom.bytesRx++;
              if ((eeprom.cmd == READ) && (eeprom.bytesRx >= START_RX_MSG))
              {
    /////////////////////////////////////////////////
                    mi_array[j] = SSC0_RB;
                    j++;
                    if (j == NUMERO)
                    {
                            flag = 1;
                            ASC0_TBIC_IR = 1;
                    }
    /////////////////////////////////////////////////
                    *eeprom.rxptr++ = (S8) (SSC0_RB);  /* read user data */
              }
              else
              {
            eeprom.data = (S8) (SSC0_RB);  /* used for non-user data */
              }
              if (eeprom.bytesRx >= eeprom.rxCnt)
              {
                eeprom.busy = false; /* indicate the resource is free */
                    CS_EEPROM = high;        /* all data sent, release /CS */
              }
      }
    }
    
    
    

  • U8 EepromWrite(U16 address, S8 *src, U16 cnt, U16 MY_ADRESS) {
    
      U8 result = failure;
    
      if (eeprom.busy == false) {
        TxMode         = WRITE;
        eeprom.busy    = true;
    
        eeprom.cmd     = WRITE;
        eeprom.baseptr = src;
            eeprom.lb      = (U8) (address);
              eeprom.hb      = (U8) (address >> 8u);
        eeprom.txCnt   = eeprom.rxCnt = cnt + 3;
        EepromStartTx(MY_ADRESS);
              result         = success;
      }
      return (result);
    }
    
    /**/
    U8 EepromRead(U16 address, S8 *des, U16 cnt, U16 MY_ADRESS) {
      U8 result = failure;
    
      if (eeprom.busy == false) {
        TxMode         = READ;
        eeprom.busy    = true;
    
            eeprom.cmd     = READ;
        eeprom.rxptr   = des;
              eeprom.lb      = (U8) (address);
              eeprom.hb      = (U8) (address >> 8);
        eeprom.txCnt   = eeprom.rxCnt = cnt + 3;
              EepromStartTx(MY_ADRESS);
            result         = success;
      }
    
      return (result);
    }
    
    /**/
    U8 EepromWriteEnable(U16 MY_ADRESS) {
    
      U8 result = failure;
    
      if (eeprom.busy == false) {
        TxMode       = WRITE;
        eeprom.busy  = true;
    
        eeprom.cmd   = WREN;
        eeprom.rxptr = &eeprom.data;
        eeprom.txCnt = eeprom.rxCnt = 1;
              EepromStartTx(MY_ADRESS);
              result       = success;
      }
    
      return (result);
    }
    
    /**/
    U8 EepromReadStatus(U16 MY_ADRESS) {
    
      while(eeprom.busy == true);    /* wait for transfer to complete */
    
      TxMode       = WRITE;
      eeprom.busy  = true;
    
      eeprom.cmd = RDSR;       /* write RDSR command in eeprom tx buffer */
      eeprom.txCnt = eeprom.rxCnt = 2;
      EepromStartTx(MY_ADRESS);         /* kick start the SSC transmission */
    
            /* Wait for the result, this should be changed to be part of the OS so it
             * is not a waiting task
             */
      while(eeprom.busy == true);    /* wait for transfer to complete */
    
            return(eeprom.data);  /* return the status byte read from the EEPROM */
    }
    
    /**/
    U8 EepromBusy(void) {
    
      if (eeprom.busy == true) {
        return(true);
      }
      else {
        return(false);
      }
    }
    

  • #ifndef _SSC0_H
    #define _SSC0_H 1
    
    typedef enum {
      WRSR  = 0x0100,  /* Write Status Register             */
      WRITE = 0x0200,  /* Write Data to Memory Array  */
      READ  = 0x0300,  /* Read Data from Memory Array */
      WRDI  = 0x0400,  /* Reset Write Enable Latch  */
      RDSR  = 0x0500,  /* Read Status Register              */
      WREN  = 0x0600,  /* Set Write Enable Latch      */
      } EepromCommandType;
    
    enum eepromStatus {
      RDY_ = 0x01, /* "1" indicates the write cycle is in progress */
      WEN  = 0x02, /* "1" indicates the device is WRITE ENABLED */
      BP0  = 0x04, /* protection range */
      BP1  = 0x08, /* protection range */
      WPEN = 0x80, /* Write enable see data sheet table */
    };
    
    typedef struct {
      EepromCommandType cmd;
      U8  hb;
      U8  lb;
      volatile BoolFalseTrueType busy;
      U16 bytesRx;
      U16 bytesTx;
    
      U16 txCnt;
      S8 *txptr;
    
      U16 rxCnt;
      S8 *rxptr;
      S8 data;
      S8 *baseptr;
    } EEPROM_CONTROL_TYPE;
    
    /* prototypes */
    void SSC0_Init(void);
    void ASC0_vInit(void);
    U8 EepromRead(U16 address, S8 *des, U16 cnt, U16 my_adress2);
    U8 EepromWrite(U16 address, S8 *src, U16 cnt, U16 my_adress1);
    U8 EepromReadStatus(U16 my_adress1);
    U8 EepromBusy(void);
    U8 EepromWriteEnable(U16 my_adress1);
    
    /* interrupt vector numbers */
    #define SSC0TINT    0x2D
    #define SSC0RINT    0x2E
    #define ASC0_TBINT   0x47
    #define ASC0_RINT    0x2B
    
    #endif  /* ifndef _SSC0_H */
    

  • didn't you say that 'EepromStartTx' cannot be changed without disabling your EEPROM? let me ask again: post the modified version of it, and only that function, that does not work. that is the source of the problem, isn't it (at least, according to you)?

  • In opinion of Chris, only the enum EepromCommandType must be changed (I have already changed it) and modify the start address of pointer, but i don't know how to do it. This is the modified version by me.

    _inline void EepromStartTx(U16  MY_ADRESS) {
      CS_EEPROM      = low;
      eeprom.bytesTx = 1;                        /* decrement the transmit count by one */
      eeprom.bytesRx = 0;
      eeprom.txptr   = (S8 *)(&eeprom)+MY_ADRESS;  /* reset pointer to first element */
      SSC0_TB         = *eeprom.txptr++;     /* write the first byte to the SSC0 tx buffer */
      }