|
|
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
|