Forum Index
HomeZBasic Home   Forum RulesForum Rules   Forum FAQForum FAQ   MemberlistMemberlist   UsergroupsUsergroups   RSS FeedRSS Feed
Site SearchSite Search   LinksLinks   DownloadDownload   Digests and SubscriptionsDigests and Subscriptions
ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in   RegisterRegister
Ramtron FRAM I2C interface
Goto page 1, 2  Next
 
Post new topic   Reply to topic    Forum Index -> Files
Author Message
spamiam



Joined: 13 Nov 2005
Posts: 664

Posted: 13 November 2005, 14:49 PM    Post subject: Ramtron FRAM I2C interface Reply with quote

Here is an API to run Ramtron FRAM over the hardware I2C interface.

FRAM is similar in function to EEPROM, but has no delays on the writes, so is significantly faster to write. It also has essentially no limit on the number of times it can be written. EEPROM will burn out after a while.

-Tony



Ramtron_24C_API.bas
 Description:
I2C FRAM interface for the Ramtron 24CXXX family.

Download
 Filename:  Ramtron_24C_API.bas
 Filesize:  3.1 KB
 Downloaded:  3466 Time(s)

Back to top
mikep



Joined: 24 Sep 2005
Posts: 765
Location: Austin, TX

Posted: 13 November 2005, 16:07 PM    Post subject: Reply with quote

Tony - some comments.
1. The constants FRAM_Addr0, FRAM_Addr1, FRAM_Addr2 are not used in the code below.
2. There aren't any constants for the return codes -1001, -1002 , -1003

Mike
http://home.austin.rr.com/perks/micros/


Last edited by mikep on 04 December 2005, 22:31 PM; edited 1 time in total
Back to top
spamiam



Joined: 13 Nov 2005
Posts: 664

Posted: 14 November 2005, 13:40 PM    Post subject: Reply with quote

mikep wrote:
Tony - some comments.
1. The constants FRAM_Addr0, FRAM_Addr1, FRAM_Addr2 are not used in the code below.
2. There aren't any constants for the return codes -1001, -1002 , -1003

Mike


You are absolutely right. This is sort of a work in progress. I actually wrote code to test a little circuit board that I designed which, no surprise here, has 3 pieces of the FRAM, and a battery backed DS3231 precision RTC. They all are working on an I2C bus.

As for the error exit codes, they were primarily for debugging and they probably could be replaced with a generic "-1" error code. I left them in place so someone could get more detail on the errors if they wanted it. Otherwise zero or non-zero error results are what counts.

It was a design I made with only the datasheets in front of me. It just shows how easy these devices are to use that I was able to get everything working with no problem. I currently have only the prototype PCB, but I have a few V2.0 coming this week. Smaller, and slightly simplified. The v1.0 PCB was actually a test in more ways than 1. I wanted to see how hard it is to solder SOIC and 0603 size SMT devices. It is actually not a problem.

I really like the FRAM devices. Right now they are limited to 32K Bytes, I assume they will eventually be available in 64K bytes. That size ought to be able to be addressable without any changes in the programming of interfaces (except bounds checking) because the address can still be 2 bytes wide.

As I think you know, they are also available in smaller amounts of memory. I suspect that many ZX (and BX, Stamp) users may only need lesser amounts of RAM.

I see one use of FRAM is as a buffer for data until a full 512 bytes are ready to go for storage onto a flash card (e.g. the SD/MMC interface that I have started)

I am glad that you were interested in the API. If you were to actually use it, I am sure it could be improved. Just post the new, improved version!!

-Tony
Back to top
spamiam



Joined: 13 Nov 2005
Posts: 664

Posted: 11 January 2006, 17:05 PM    Post subject: Reply with quote

I got this message off the list, but it is such a good set of questions, I wanted to include the questions and the answers.

------------------------------------------------------------------------
I decided to take your advice and explore the I2C FRAM. I grabbed your
Ramtron_24C_API.bas.

Here's my setup. I have one 24C256 on I2C channel 0 (We're talking ZX-24 here) with Write Protect(WP) implemented using pin 10. I have A0, A1, A2 all grounded giving device address 0. I want to be able to write data sequentially to the FRAM periodically throughout the duration of the program. This would be possibly 100 chunks of 16 bytes of data over 10 minutes. After all the chunks are written, the program will read them back and utilize them. This readback might occur 3 or 4 times.

In the SysLib I see Subroutine OpenI2C() which for my case I would call:
OpenI2C(0, 11, 12). Does this insure that the channel always remains open or does OpenI2c need to be called every time I wish to write to the FRAM?

Having opened the channel what must I do next. Say I wish to write one of those 16 byte chunks of data sequentially to the FRAM. I am not having much success understanding your API.

How do I write all those 16 byte chunks when I need to, how do I keep track of the last FRAM address written to with each chunk and, ultimately, how do I read them back when I need to? Can you give me the I2C for Dummies lecture on how do do this and how to understand your API?

Any enlightenment will be much appreciated!

Vic
Back to top
spamiam



Joined: 13 Nov 2005
Posts: 664

Posted: 11 January 2006, 18:12 PM    Post subject: Reply with quote

Quote:
I decided to take your advice and explore the I2C FRAM. I grabbed your
Ramtron_24C_API.bas.


Well, I can offer some insights on the use of the I2C FRAM, but I am not an expert in any way. Unfortunately, I have not had the opportunity to try out the SPI FRAM yet (lack of a sample), so I can not tell what sort of thru-put it will give on a ZX. Certainly the SPI will not give full SPI bus speed since it has to share the Bus with the ZX EEPROM. SPI might well end up slower than the 400K bits/second of the I2C bus.

Quote:
Here's my setup. I have one 24C256 on I2C channel 0 (We're talking ZX-24 here) with Write Protect(WP) implemented using pin 10. I have A0, A1, A2 all grounded giving device address 0. I want to be able to write data sequentially to the FRAM periodically throughout the duration of the program. This would be possibly 100 chunks of 16 bytes of data over 10 minutes. After all the chunks are written, the program will read them back and utilize them. This readback might occur 3 or 4 times.


OK, that is a very standard setup and standard requirement for writing and reading. Very feasible

Quote:
In the SysLib I see Subroutine OpenI2C() which for my case I would call:
OpenI2C(0, 11, 12). Does this insure that the channel always remains open or does OpenI2c need to be called every time I wish to write to the FRAM?


It only needs to be called once per channel. There is no "CloseI2C() command to undo the open. The open just initiates the necessary stuff inside the ZX. I think my API should have included a subroutine to initiate the I2C too. But since this bus could be shared, I thought it better to let the user decide what to do for the setup.

Quote:
Having opened the channel what must I do next. Say I wish to write one of those 16 byte chunks of data sequentially to the FRAM. I am not having much success understanding your API.


OK, this should be pretty easy. I am not sure what is going on to not have luck. I can post a test program that uses the FRAM API to give an example.

After setting up the I2C, the I2C channel should be ready to go. You can use the default standard speed, but I have had complete success at the highest ZX-supported speed of over 400K since the FRAM is rated for up to 1000Kbps. This will set it up for 410Kbps.

Code:
OpenI2C(0, 11, 12, 10)



Quote:
How do I write all those 16 byte chunks when I need to, how do I keep track of the last FRAM address written to with each chunk and, ultimately, how do I read them back when I need to? Can you give me the I2C for Dummies lecture on how do do this and how to understand your API?


The API I wrote is pretty bare-bones, and is intended to be compatible with sharing of the I2C bus. It will allow unexpected things to happen to the bus between FRAM accesses.

It seems that you have the logical question of "how do I control the locations of my sequential writes to the FRAM".

I learned everything I know about the FRAM from Ramtron's datasheet. It is surprisingly understandable!!!! I usually find datasheets unintelligible. They only make sense if I already know the answer. The Ramtron sheet is better than that.

Code:
FRAM_Write_Data (   ByVal FRAM_Device   as Byte, _
                        ByVal RAM_Addr      as Integer, _
                        byref Data()      as Byte, _
                        byval Num_Bytes      as Byte, _
                        byref Success      as Integer)


This is the subroutine in the API which does the write of the data. You need to give it the FRAM's I2C channel, and the starting address for the write. Also you supply the data array, and the size of the data array. It returns the success value. A positive number represents the number of bytes sent and should match the Num_Bytes value. A negative number denotes some sort of failure. There are various failure numbers in the API, but I did not do anything with them, and did not really document them. A positive success value is good, a negative value is a failure.

In your program you need to keep track of WHICH byte you are intending to write (use a simple counter, starting at zero?) and use this as the address of the data element you are writing. Remember that you need to increment with more than one when you are using non-byte type variables. Sizeof() should handle this for you.

If you can be positive that nothing else will ever happen on your I2C bus, then you can break up the writes to FRAM and not use the above subroutine. THis is easy to do because the subroutine only uses low-level I2C functions.

you need to do this to set up the sequential transfer:
Code:
'have to do this Transfer manually
I2CStart(FRAM_Channel)   'start the transfer
I2cPutByte(FRAM_Channel, FRAM_Address)
'select the starting address

I2cPutByte(FRAM_Channel, HiByte(RAM_Addr))
I2cPutByte(FRAM_Channel, LoByte(RAM_Addr))


This sets the FRAMS memory pointer to the desited starting location.

Then you sequentially write bytes (or words, or whatever) with this:
Code:
I2CPutByte(FRAM_Channel,data_byte)


Then you finish your sequential access with this:
Quote:
I2CStop(FRAM_Channel) 'End the transfer


This will work fine but does not cooperate with any other users of the I2C channel. There is less overhead on the channel because each write is not preceeded by the FRAM-address, and data address bytes.

The API will allow RANDOM accesses to the FRAM which could just happen to be sequential. It will also allow other users of the channel without screwing up.

Here is how I would do it. Random accesses that are sequential with a counter in the program keeps track of the starting address of the next 16 byte chunk. I am writing this off the top of my head, so it is likely to have many bugs in the syntax. The logic , of course, will be impecable! :@

Code:
Dim Current_Address as Integer
Dim Data_Array[0 to 15] as byte
Dim Success as Integer

OpenI2C(0, 11, 12, 10)            'open I2c at 410Kbps
Call FRAM_Set_Channel(0)
Current_Address = 0               'start at zero

'fill the data_array and do whatever you want then.....
'use FRAM device #0
FRAM_Write_Data (0,Current_Address, Data_Array,Sizeof(Data_Array), Success)

'now increment the FRAM address pointer
Current_Address = Current_Address + Sizeof(Data_Array)

'do more stuff, fill the data array, then..... write again
FRAM_Write_Data (0,Current_Address, Data_Array,Sizeof(Data_Array), Success)
Current_Address = Current_Address + Sizeof(Data_Array)


To read the data do this:

Code:
Dim Chunk_Number as Integer
Dim Current_Address as Integer
Dim Data_Array[0 to 15] as byte

'select the chunk number somehow, maybe a for/next loop

Chunk_Number = 3          'arbitrary selection of the 3rd chunk
Current_Address = Chunk_number * SizeOf(Data_Array)

FRAM_Read_Data(0, Current_Address, Data_Array, SizeOf(Data_Array), Success)



This should work. Famous last words.

I am sure there were many areas I glossed over. Please post a follow-up.

-Tony
Back to top
victorf



Joined: 01 Jan 2006
Posts: 342
Location: Schenectady, New York

Posted: 12 January 2006, 11:39 AM    Post subject: Reply with quote

I am beginning to understand how to use the 24C256. I certainly appreciate you taking time to share your knowledge and time with members, especially me Smile. Of course I have another question:

I do not get the significance of the three address pins (A0, A1, A2) on this chip. Obviously they are to allow for addressing several devices, but how do I use them. On my schematic I show all three pins tied to VSS. Can you explain how I should use them?

As always, any enlightenment will be appreciated.

Vic
Back to top
spamiam



Joined: 13 Nov 2005
Posts: 664

Posted: 12 January 2006, 13:50 PM    Post subject: Reply with quote

victorf wrote:
I am beginning to understand how to use the 24C256. I certainly appreciate you taking time to share your knowledge and time with members, especially me Smile. Of course I have another question:

I do not get the significance of the three address pins (A0, A1, A2) on this chip. Obviously they are to allow for addressing several devices, but how do I use them. On my schematic I show all three pins tied to VSS. Can you explain how I should use them?

As always, any enlightenment will be appreciated.

Vic


Again, the datasheet will explain this pretty well. The A0:2 pins are to allow up to 8 of these devices to happily share the same I2C bus.

Originally I had thought that the upper byte of the address was different between the various size FRAM devices, but they are all the same. So, you have to KNOW what size the FRAM device is, and can not tell it from the high byte of the address.

Grounding A0:2 will make this device address number be zero.
If all the pins are tied high, then it is #7. Just plain old binary counting.

-Tony
Back to top
victorf



Joined: 01 Jan 2006
Posts: 342
Location: Schenectady, New York

Posted: 12 January 2006, 15:11 PM    Post subject: Reply with quote

I understand how the addressing works but I do not see how this is used from the software (ZX-24) side. If I have one device with A0:2 all grounded (0) then the device's address is 0. Where does this fit into the software side of things. Suppose I had 2 devices at address 0 and 1 and I wanted to write to the one at address 1 how is this done from the ZX-24. I seem to be missing something. Confused

Vic
Back to top
spamiam



Joined: 13 Nov 2005
Posts: 664

Posted: 12 January 2006, 15:30 PM    Post subject: Reply with quote

victorf wrote:
I understand how the addressing works but I do not see how this is used from the software (ZX-24) side. If I have one device with A0:2 all grounded (0) then the device's address is 0. Where does this fit into the software side of things. Suppose I had 2 devices at address 0 and 1 and I wanted to write to the one at address 1 how is this done from the ZX-24. I seem to be missing something. Confused

Vic


Look at the API code. You give the write subroutine the device number. THis is appended to the generic device name, and is sent over the I2C to notify the device in question that the next commands are intended for it. The commands are ignored by all the other devices.

The devices look for an I2C start sequence, directly followed by thier own unique device "name", then that unique device will receive the subsequent commands and act accordingly.

So, the binary code you had set in pins A0:2 will be the device number you need to gve the write subroutine.

-Tony
Back to top
mikep



Joined: 24 Sep 2005
Posts: 765
Location: Austin, TX

Posted: 12 January 2006, 17:21 PM    Post subject: Reply with quote

victorf wrote:
I do not get the significance of the three address pins (A0, A1, A2) on this chip. Obviously they are to allow for addressing several devices, but how do I use them. On my schematic I show all three pins tied to VSS. Can you explain how I should use them?


ZBasic needs two things to talk to a I2C device:
  • The channel number as defined by the call to OpenI2C. ZBasic allows up to five different channels.
  • The slave address (slaveID) as defined by the actual device. Slave addresses in I2C are normally 7 bits with a 1 bit read/write indicator. This allows for up to 127 devices per I2C bus (channel).


Ranges of I2C addresses are allocated to a particular device type and usually there is some way to support multiple devices of the same type. Manufacturers have different ways to set the address of an individual device but using 3 pins (A2, A1, A0) for device select is a one way.

It looks like I2C FRAMs have slave addresses in the range 0xA0 to 0xAE where the device select address is bits 1-3 of the address.
Back to top
mikep



Joined: 24 Sep 2005
Posts: 765
Location: Austin, TX

Posted: 12 January 2006, 17:32 PM    Post subject: Reply with quote

spamiam wrote:
So, the binary code you had set in pins A0:2 will be the device number you need to gve the write subroutine.


Are you sure this works? As noted above I think the address is more like one of A0, A2, A4, A6, A8, AA, AC or AE based on the FRAM datasheets - see figure 4 on page 4 of http://ramtron.com/lib/literature/datasheets/FM24C256ds_r3.1.pdf.

There is some sample I2C code in the application note (AN208) on interfacing to the Devantech Ultrasomic Range Finder. Its range of addresses are E0 to EE.
Back to top
spamiam



Joined: 13 Nov 2005
Posts: 664

Posted: 12 January 2006, 18:17 PM    Post subject: Reply with quote

mikep wrote:
spamiam wrote:
So, the binary code you had set in pins A0:2 will be the device number you need to gve the write subroutine.


Are you sure this works? As noted above I think the address is more like one of A0, A2, A4, A6, A8, AA, AC or AE based on the FRAM datasheets - see figure 4 on page 4 of http://ramtron.com/lib/literature/datasheets/FM24C256ds_r3.1.pdf.

There is some sample I2C code in the application note (AN208) on interfacing to the Devantech Ultrasomic Range Finder. Its range of addresses are E0 to EE.


This is correct. The FRAM device address is:
1-0-1-0-A2-A1-A0-RW in binary form.

But the subroutine already knows the general device address prefix in the line in the code:
Code:
Private Const FRAM_ID as Byte = bx1010_0000   'top 4 bits are the 256Kb identIfier


(NB: this identifier is for ALL I2C FRAM devices)

Then you pass the device number 0-7 (which matches A0:2) to the API write subroutine. The subroutine then manipulates this to get the full device address with the following:
Code:
FRAM_Address = FRAM_ID + (FRAM_Device  * 2)


So, all you need to supply is the device number, which should match the A0:2 pin configuration that you set in the circuit, and the subroutine takes care of the rest. Admittedly, I have only tested for device #0 but the technique used is as specified in the Ramtron datasheet.


-Tony
Back to top
victorf



Joined: 01 Jan 2006
Posts: 342
Location: Schenectady, New York

Posted: 12 January 2006, 18:44 PM    Post subject: Reply with quote

spamiam,

This is great Exclamation

I actually get it. Thanks for clearing up this matter for me. I should be able to use your API now. Smile

Vic
Back to top
spamiam



Joined: 13 Nov 2005
Posts: 664

Posted: 12 January 2006, 18:55 PM    Post subject: Reply with quote

victorf wrote:
spamiam,

This is great Exclamation

I actually get it. Thanks for clearing up this matter for me. I should be able to use your API now. Smile

Vic


Did you already test the existing API in a test circuit with the FRAM and have no success? If so, what error code did the "Success" variable return (if any)?

When I first tested the FRAM, I just mounted the SOIC (wider than the standard) to a SOIC-to-DIP adapter, dropped it into a breadboard, along the the already existing RTC, and it worked immediately.

I did not actually use it for anything productive. But, I used that design to make a PCB. I then used that general purpose RTC/FRAM PCB in a design with a larger ATMega (programmed in C) and it, too, works perfectly. I am about to re-write the persistent memory code to use the FRAM instead of the ATMega's EEPROM. It will be faster, and it will have virtually infinite re-writing capability.

-Tony
Back to top
victorf



Joined: 01 Jan 2006
Posts: 342
Location: Schenectady, New York

Posted: 13 January 2006, 12:01 PM    Post subject: Reply with quote

spamiam wrote:
Quote:
Did you already test the existing API in a test circuit with the FRAM and have no success? If so, what error code did the "Success" variable return (if any)?

No, I haven't. I have incorporated the FRAM into the ExpressPCB board layout for my current project. This should go for fabrication next week after I give everything the once-over (for the 100th time - hundredth-over Smile ). Software writing is under way!

I like your idea of replacing the EEPROM with the FRAM. What is the application you intend for the ATMega/FRAM?

I appreciate your help with this. Thanks

Vic
Back to top
Display posts from previous:   
Post new topic   Reply to topic    Forum Index -> Files Time synchro. with the server - Timezone/DST with your computer
Goto page 1, 2  Next
Page 1 of 2

 


All content Copyright © 2005-2012 Elba Corp. All Rights Reserved.
Opinions expressed in posts are those of the author and not necessarily those of Elba Corp.
Powered by phpBB © 2001, 2005 phpBB Group