| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| treitmey 
 
 
 Joined: 23 Jan 2004
 Posts: 1094
 Location: Appleton,WI   USA
 
 
			      
 
 | 
			
				| FRAM ramtron RIC FM24C256 |  
				|  Posted: Fri Aug 19, 2005 11:39 am |   |  
				| 
 |  
				| 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
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Mar 21, 2007 3:00 am |   |  
				| 
 |  
				| 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
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Wed Mar 28, 2007 12:56 pm |   |  
				| 
 |  
				| YES, this is only for I2C |  |  
		|  |  
		| gribas 
 
 
 Joined: 21 Feb 2008
 Posts: 21
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Feb 21, 2008 11:05 am |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Feb 21, 2008 12:55 pm |   |  
				| 
 |  
				|  	  | 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Feb 21, 2008 1:52 pm |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Feb 21, 2008 2:16 pm |   |  
				| 
 |  
				| 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.
 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |