CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

FRAM ramtron RIC FM24C256

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

FRAM ramtron RIC FM24C256
PostPosted: Fri Aug 19, 2005 11:39 am     Reply with quote

http://www.ramtron.com/lib/literature/datasheets/FM24C256ds_r3.1.pdf
Code:

//////////////////////////////////////////////////////////////////
//Library for a Ramtron FM24C256 I2C FRAM 32768 int8 serial memory////
//init_fram();    Call before the other functions are used    ////
//write_fram(a,d);  Write the int8 d to the address a         ////
//d = read_fram(a);  Read the int8 d from the address a       ////
//multi_write_fram(a,char *d,size);//can cross chip boundry ////
//multi_read_fram(a,char *d,size);//can cross chip boundry  ////
//The main program may define FRAM_SDA, FRAM_SCL to override  ////
// 2^15=32768 address space.  2^3=8   3 bits for 8 chips      ////
// For a total of 18 bits  (using int32)
//////////////////////////////////////////////////////////////////
//8 chips, 32768 bytes per chip
//start addr 0,32768,65536,98304,131072,163840,196608,229376
//9/6/2005 9:05AM multi write working, now fixing multiread-fixed-

#ifndef FRAM_SDA
#define FRAM_SDA  PIN_C4
#define FRAM_SCL  PIN_C3
#endif
//#use I2C(MASTER,SDA=FRAM_SDA,SCL=FRAM_SCL,FORCE_HW,RESTART_WDT)
//you get software I2C unless you use FORCE_HW
//fast is 3X faster
#use I2C(MASTER,SDA=FRAM_SDA,SCL=FRAM_SCL,FORCE_HW,FAST,RESTART_WDT)
#define FRAM_ADDRESS int32
#define FRAM_SIZE    32768
#ifndef FRAM_CHIPS
#define FRAM_CHIPS   1
#endif
#define FRAM_MAX_ADDRESS (FRAM_SIZE*FRAM_CHIPS)-1 //4 chips 0,1,2,3
#define hi(x)  (*((int8 *)&x+1))  //data held at addr of x + 1
#define lo(x)  (*((int8 *)&x))     //data held at addr of x

//======================init_fram===========================//
void init_fram(){
  output_float(FRAM_SCL);
  output_float(FRAM_SDA);
}
//======================write_fram===========================//
void write_fram(int32 address,int8 data){
  if(address>FRAM_MAX_ADDRESS){
    bit_set(ERRORS,4);
    //fprintf(DEBUG,"ERROR address too big!\n\r%lu\n\r",address);
  }
  i2c_start();
  i2c_write((0xA0|(int8)(address>>14))&0xFE);//&0xFE forces to write
  i2c_write(hi(address));
  i2c_write(lo(address));
  i2c_write(data);
  i2c_stop();
}
//======================read_fram===========================//
int8 read_fram(int32 address) {
  int8 data;
  if(address>FRAM_MAX_ADDRESS){
    bit_set(ERRORS,4);
    //fprintf(DEBUG,"ERROR address too big!\n\r%lu\n\r",address);
  }
  i2c_start();
  i2c_write((0xA0|(int8)(address>>14))&0xFE);//&0xFE forces to write
  i2c_write(hi(address));
  i2c_write(lo(address));
  i2c_start();
  i2c_write((0xA0|(int8)(address>>14))|1);//|1 forces to read
  data=i2c_read(0);
  i2c_stop();
  return(data);
}
//======================multi_write_fram===========================//
BOOLEAN multi_write_fram(int32 address,char *data,int32 size)
{
  int32 start_size;
  start_size=size;
  //fprintf(DEBUG,"-mw- %lu %lu\n\r",address,size);
  for(;size;data++,size--,address++){
    if(address>FRAM_MAX_ADDRESS){
      bit_set(ERRORS,4);
      //fprintf(DEBUG,"ERROR address too big!\n\r%lu\n\r",address);
    }
    if(address%FRAM_SIZE==0 || size==start_size){

      //fprintf(DEBUG,"I2c stop\n\r");
      i2c_stop();
      //fprintf(DEBUG,"I2c start\n\r");
      i2c_start();
      //fprintf(DEBUG,"sending slave address=%lu\n\r",address);
      i2c_write((0xA0|(int8)(address>>14))&0xFE);
      i2c_write(hi(address));
      i2c_write(lo(address));
    }
    i2c_write(*data);
    //fprintf(DEBUG,"wrote %u\n\r",*data);
  }
  i2c_stop();
  //fprintf(DEBUG,"dmw\n\r");
  return(TRUE);
}
//======================multi_read_fram===========================//
//start addr 0,32768,65536,98304,131072,163840,196608,229376
BOOLEAN multi_read_fram(int32 address,char *data,int32 size){
  int32 start_size;
  //fprintf(DEBUG,"-mr-");
  start_size=size;
  for(;size;data++,size--,address++)
  {
    if(address>FRAM_MAX_ADDRESS){
      bit_set(ERRORS,4);
      //fprintf(DEBUG,"ERROR address too big!\n\r%lu\n\r",address);
    }
    if(address%FRAM_SIZE==0 || size==start_size){
      //fprintf(DEBUG,"sending slave address=%lu\n\r",address);
      i2c_start();
      i2c_write((0xA0|(int8)(address>>14))&0xFE);//&0xFE forces to write
      i2c_write(hi(address));
      i2c_write(lo(address));
      i2c_start();
      i2c_write((0xA0|(int8)(address>>14))|1);//|1 forces to read
    }
    if((address+1)%FRAM_SIZE && size!=1)
    {
      *data=i2c_read(1);//The ack will put next data on bus
      //fprintf(DEBUG,"read with ack %lu=%u\n\r",address,*data);
    }
    else
    {
      *data=i2c_read(0);//No ack on last read of chip
      //fprintf(DEBUG,"read without ack %lu=%u\n\r",address,*data);
      //fprintf(DEBUG,"I2c stop\n\r");
      i2c_stop();
    }
  }
  //fprintf(DEBUG,"-mr- done!\n\r");
  return(TRUE);
}
//======================clr_fram===========================//
BOOLEAN clr_fram(int32 address,int32 size,char data)  //fill/clear fram with a given int8
{
  int32 start_size;
  //fprintf(DEBUG,"-c-\n\r");
  start_size=size;
  i2c_start();
  i2c_write((0xA0|(int8)(address>>14))&0xFE);
  i2c_write(hi(address));
  i2c_write(lo(address));
  for(;size;size--,address++){
    if(address>FRAM_MAX_ADDRESS){
      bit_set(ERRORS,4);
      //fprintf(DEBUG,"ERROR address too big!\n\r%lu\n\r",address);
    }
    if(address%FRAM_SIZE==0 && size!=start_size && size!=1){
      //fprintf(DEBUG,"chip boundry -c- addr=%lu\n\r",address);
      //reisue I2C for next chip
      i2c_stop();
      output_float(FRAM_SCL);
      output_float(FRAM_SDA);
      i2c_start();
      i2c_write((0xA0|(int8)(address>>14))&0xFE);
      i2c_write(hi(address));
      i2c_write(lo(address));
    }
    i2c_write(data);
  }
  i2c_stop();
  return(TRUE);
}
//=======================fram_chksum============================//
int8 fram_chksum(int32 address,int32 size)
{
  int8 chksum=0;
  int32 start_size;
  //fprintf(DEBUG,"-cs-\n\r");
  if(size==0){
    chksum=0;
    return(chksum);
  }
  start_size=size;
  i2c_start();
  i2c_write((0xA0|(int8)(address>>14))&0xFE);//&0xFE forces to write
  i2c_write(hi(address));
  i2c_write(lo(address));
  i2c_start();
  i2c_write((0xA0|(int8)(address>>14))|1);//|1 forces to read
  for(;size;size--,address++)
  {
    if(address>FRAM_MAX_ADDRESS){
      bit_set(ERRORS,4);
      //fprintf(DEBUG,"ERROR address too big!\n\r%lu\n\r",address);
    }
    if(size==1){
      //fprintf(DEBUG,"last addr=%lu\n\r",address);
      chksum+=i2c_read(0);//last read requires no ack
      i2c_stop();
      return(chksum);
    }
    if(address%(FRAM_SIZE-1)==0 && size!=start_size){
      //fprintf(DEBUG,"chip boundry addr=%lu\n\r",address);
      chksum+=i2c_read(0);//last read requires no ack
      i2c_stop();
      //fprintf(DEBUG,"-cs-noack-%lu=%u\n\r",address,chksum);
      size--;address++;
      i2c_start();
      i2c_write((0xA0|(int8)(address>>14))&0xFE);//&0xFE forces to write
      i2c_write(hi(address));
      i2c_write(lo(address));
      i2c_start();
      i2c_write((0xA0|(int8)(address>>14))|1);//|1 forces to read
    }
    chksum+=i2c_read(1);//The ack will put next data on bus
    //fprintf(DEBUG,"-cs-%lu=%u\n\r",address,chksum);
  }
  //fprintf(DEBUG,"wrong exit\n\r");
}

TEST PROGRAM
Code:

#include <18F452>
#CASE
#USE DELAY(CLOCK=40000000)
#FUSES H4,NOWDT,NOPROTECT,NOLVP
#DEFINE VER_MAJOR 2
#DEFINE VER_MINOR 01
#USE RS232(BAUD=19200,XMIT=PIN_C0,INVERT,STREAM=DEBUG,DISABLE_INTS) // STDERR(same as DEBUG)
#USE RS232(BAUD=19200,ENABLE=PIN_C5,XMIT=PIN_C6,RCV=PIN_C7,STREAM=RS485)

#ZERO_RAM
#define BUFF_SZ 256
#define FRAM_CHIPS   4

int8 ERRORS;
#include "FM24C256.C"

//======================= MAIN ============================//
void main(void)
{
  int32 addr;
  int16 idx;

  int8 read_data=0;
  int8 wr[BUFF_SZ];
  int8 rd[BUFF_SZ];
  setup_adc_ports(NO_ANALOGS);
  set_tris_a(0);set_tris_b(0);set_tris_c(0);set_tris_d(0);set_tris_e(0);
  fprintf(DEBUG,"STARTING FRAM Test.\n\r");
  fprintf(DEBUG,"FIRMWARE VERSION %u.%02u\n\r",VER_MAJOR,VER_MINOR);
  init_fram();//float the I2C lines
  fprintf(DEBUG,"finished with init_fram\n\r");
  for (idx=0;idx<BUFF_SZ;idx++)wr[idx]=idx;//fill wr[x]

  for (addr=0;addr<FRAM_MAX_ADDRESS;addr+=BUFF_SZ){
    fprintf(DEBUG,".");
    multi_write_fram(addr,&wr[0],BUFF_SZ);
    multi_read_fram (addr,&rd[0],BUFF_SZ);
    for (idx=0;idx<BUFF_SZ;idx++)
      if (rd[idx]!=wr[idx])
        fprintf(DEBUG,"idx=%lu,w=%u,r=%u ",idx,wr[idx],rd[idx]);
  }

  fprintf(DEBUG,"DONE !\n\r");
  while(1)
  {
  }
}

UPDATE: Updated the hi() lo() macro defines for the newer compilers.


Last edited by treitmey on Fri Mar 28, 2008 1:10 pm; edited 6 times in total
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Wed Mar 21, 2007 3:00 am     Reply with quote

Hi,

does this driver work with:
FM24CL64 - 64K Serial FRAM Memory

this driver is using the 2wire interface: I2C ?
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Mar 28, 2007 12:56 pm     Reply with quote

YES, this is only for I2C
gribas



Joined: 21 Feb 2008
Posts: 21

View user's profile Send private message

PostPosted: Thu Feb 21, 2008 11:05 am     Reply with quote

Hi,

I had some problems while using this driver with compiler version 4.068. The problem is that the macros are returning int32 integers to the i2c_write() functions, leading to an unpredictable behaviour.
I changed the hi() and lo() definitions to:

Code:

#define hi(x)  make8(x,1)  //data held at addr of x + 1
#define lo(x)  make8(x,0)  //data held at addr of x


and everything started to work. The code size is also smaller.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Feb 21, 2008 12:55 pm     Reply with quote

Quote:
#define hi(x) (*(&x+1)) //data held at addr of x + 1
#define lo(x) (*(&x)) //data held at addr of x

The hi(x) macro in the driver code will work with all CCS compiler
versions up to vs. 4.020. In those versions, CCS assumes the address
is always a byte-pointer.

But beginning with vs. 4.021, CCS changed the interpretation of the '&'
operator so that it's now done correctly, according to the C specification.
Now, if the value is 16 or 32 bits, when you add 1 to it, it increases the
address by 2 or 4 bytes respectively, so that it points to the next
element. That's the way pointer arithmetic is supposed to work in C.
Here's the line from the CCS versions page that documented this change:
Quote:

4.021 The & unary operator by default no longer returns a generic (int8 *)


So if you're using the old version of the hi(x) macro with a new version
of the compiler (4.021 and later), then you will have a problem.
You posted one solution. Another solution that you will see in some of
the CCS driver files, is to cast the address to a byte-pointer, before
adding 1 to it. Example:
Code:
#define hi(x)  (*((int8 *)&x+1))
gribas



Joined: 21 Feb 2008
Posts: 21

View user's profile Send private message

PostPosted: Thu Feb 21, 2008 1:52 pm     Reply with quote

Hello,

Many thanks for the explanation. I've noticed it was returning a 32 bit value but I failed to realize that it was 4 bytes ahead and that was the real problem. Thanks again for pointing it out.

I've compared both definitions and I'm going to stick with the make8() one, for the code size is indeed smaller.


Code:

#define _hi_(x)  make8(x,1)  //data held at addr of x + 1
#define _lo_(x)  make8(x,0)  //data held at addr of x
....................     i2c_write(_hi_(address));
0B1C:  MOVFF  39,3D
0B20:  CLRF   18
0B22:  BTFSC  FF2.7
0B24:  BSF    18.7
0B26:  BCF    FF2.7
0B28:  MOVFF  39,6B
0B2C:  CALL   02CA
0B30:  BTFSC  18.7
0B32:  BSF    FF2.7
....................     i2c_write(_lo_(address));
0B34:  MOVFF  38,3D
0B38:  CLRF   18
0B3A:  BTFSC  FF2.7
0B3C:  BSF    18.7
0B3E:  BCF    FF2.7
0B40:  MOVFF  38,6B
0B44:  CALL   02CA
0B48:  BTFSC  18.7
0B4A:  BSF    FF2.7
0B4C:  CLRF   18
0B4E:  BTFSC  FF2.7
0B50:  BSF    18.7
0B52:  BCF    FF2.7

///////////////////////////////////////////////////////////////////////////
#define _hi_(x)  (*((int8 *)&x+1))  //data held at addr of x + 1
#define _lo_(x)  (*((int8 *)&x))  //data held at addr of x
....................     i2c_write(_hi_(address));
0B1C:  CLRF   3E
0B1E:  MOVLW  38
0B20:  MOVWF  3D
0B22:  MOVLW  01
0B24:  ADDWF  3D,W
0B26:  MOVWF  01
0B28:  MOVLW  00
0B2A:  ADDWFC 3E,W
0B2C:  MOVWF  03
0B2E:  MOVFF  01,FE9
0B32:  MOVWF  FEA
0B34:  MOVFF  FEF,3F
0B38:  CLRF   18
0B3A:  BTFSC  FF2.7
0B3C:  BSF    18.7
0B3E:  BCF    FF2.7
0B40:  MOVFF  3F,6B
0B44:  CALL   02CA
0B48:  BTFSC  18.7
0B4A:  BSF    FF2.7
....................     i2c_write(_lo_(address));
0B4C:  CLRF   3E
0B4E:  MOVLW  38
0B50:  MOVFF  3E,03
0B54:  MOVWF  FE9
0B56:  MOVFF  3E,FEA
0B5A:  MOVFF  FEF,3F
0B5E:  CLRF   18
0B60:  BTFSC  FF2.7
0B62:  BSF    18.7
0B64:  BCF    FF2.7
0B66:  MOVFF  3F,6B
0B6A:  CALL   02CA
0B6E:  BTFSC  18.7
0B70:  BSF    FF2.7
0B72:  CLRF   18
0B74:  BTFSC  FF2.7
0B76:  BSF    18.7
0B78:  BCF    FF2.7
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Feb 21, 2008 2:16 pm     Reply with quote

I emailed CCS a few days ago about the code size difference.
In vs. 3, the hi(x) macro produced the same small code size as
make8(). In vs. 4 the code size for hi(x) got larger. Hopefully
they will fix it.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group