PDA

View Full Version : BS2pe EEPROM sequential write of data series



Andy McLeod
11-15-2006, 03:07 AM
I have a stand alone pressure data logger which will be activated be a single push button. When the button is pushed, the stamp collects data through the LTC1298 for a fixed period of time determined by the total number of samples programmed.

My question is this - How do I write the data in the format xxxx (0-4095) to eeprom for each capture sequence and have the stamp recognize where in eeprom (bank vs. address) it must start to write to on the next sequence, which may be minutes to days later.

Chris Savage
11-15-2006, 03:21 AM
Andy,

When you say a “fixed length of time”, are you using an RTC? Many have RAM on-board which can be battery-backed to hold the counter value for the EEPROM. If power outage isn’t an issue, you can simply store the counter value in a variable and WRITE it to EEPROM at the end of the sequence (specific location). That way when the system comes up later it can retrieve that value for the next sequence. The counter location can be reset using a DATA statement during program download. Take care.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support

Andy McLeod
11-15-2006, 03:51 AM
Chris-

I am using the DS1302 for real time stamping at the start of the acquisition. I'm guessing that I can WRITE to the DS1302 RAM a value for STORE and WRITE and retreive those values? Ever done something like that? Got code?

Chris Savage
11-15-2006, 04:04 AM
Andy,

That is correct! You can store up to 31 bytes into the RAM. If you are using a battery it will be backed up. I do have some example code linked below for accessing the RAM. I also have another example I can try to find which actually loads the RAM on startup for certain values. It’s pretty painless.

http://forums.parallax.com/showthread.php?p=531080

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support

Chris Savage
11-15-2006, 04:23 AM
Andy,

I’ll tell you what…Looking back at my other code I am a little embarrassed at how I did things. Very efficient at the time, but I’ve since learned a lot. Let me post three routines for you…The first is the Initialization routine for my Digital Alarm Clock program. It calls the Get_RAM routine. I also posted the Set_RAM routine. The Get_RAM routine is called during initialization only. Set_RAM is called whenever one of the affected variables is updated. There are 10 bytes being saved here. The names should give you an idea what they are. I hope this helps. Take care.



' -----[ EEPROM Data ]-----------------------------------------------------
Defaults: DATA $30, $06, $30, $07, $00, $21, $55, $05, $02, $C3

' -----[ Initialization - DS1302 ]-----------------------------------------
GOSUB Get_RAM ' Initialize DS1302

' -----[ Initialization - MAX7219 ]----------------------------------------
GOSUB Display_Test ' For Debugging Purposes
FOR index = 0 TO 7 ' 4 Registers & 4 Values
LOOKUP index, [Scan, 5, Brite, 15, Decode, $FF, ShutDn, 1], ioByte
SHIFTOUT DataIO, Clock, MSBFIRST, [ioByte]
IF (idxOdd = No) THEN No_Load ' Wait For Value To Be Shifted
PULSOUT MAX7219, 5
No_Load:
NEXT

' -----[ Initialization - DS1804 ]-----------------------------------------
GOSUB Reset_Volume ' Make Sure Volume Is Down

' -----[ Initialization - Other ]------------------------------------------
GOSUB Dimmer ' Restore Dimming State





' -----[ Subroutines - DS1302 ]--------------------------------------------
Set_RAM:
index = CWPr ' Write Protect Register
ioByte = WPr0 ' Clear Write Protect
GOSUB RTC_Out ' Send Command
ioByte = 0 ' Address Of Alarm 1 Minutes
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = a1Mins ' Set Alarm 1 Minutes
GOSUB RTC_Out ' Write Value
ioByte = 1 ' Address Of Alarm 1 Hours
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = a1Hrs ' Set Alarm 1 Hours
GOSUB RTC_Out ' Write Value
ioByte = 2 ' Address Of Alarm 2 Minutes
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = a2Mins ' Set Alarm 2 Minutes
GOSUB RTC_Out ' Write Value
ioByte = 3 ' Address Of Alarm 2 Hours
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = a2Hrs ' Set Alarm 2 Hours
GOSUB RTC_Out ' Write Value
ioByte = 4 ' Address Of Dimmer Start Minute
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = d1Mins ' Set Dimmer Start Minute
GOSUB RTC_Out ' Write Value
ioByte = 5 ' Address Of Dimmer Start Hour
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = d1Hrs ' Set Dimmer Start Hour
GOSUB RTC_Out ' Write Value
ioByte = 6 ' Address Of Dimmer End Minute
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = d2Mins ' Set Dimmer End Minute
GOSUB RTC_Out ' Write Value
ioByte = 7 ' Address Of Dimmer End Hour
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = d2Hrs ' Set Dimmer End Hour
GOSUB RTC_Out ' Write Value
ioByte = 8 ' Address Of Dimmer Level Setting
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = dSet ' Set Dimmer Level Setting
GOSUB RTC_Out ' Write Value
ioByte = 9 ' Address Of Flags
index = WrRam | (ioByte << 1) ' Write RAM Mode + Address
ioByte = flags ' Set Flags
GOSUB RTC_Out ' Write Value
RETURN






Get_RAM:
index = CWPr ' Write Protect Register
ioByte = WPr1 ' Set Write Protect
GOSUB RTC_Out ' Send Command
ioByte = 0 ' Address Of Alarm 1 Minutes
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
a1Mins = ioByte ' Restore Alarm 1 Minutes
ioByte = 1 ' Address Of Alarm 1 Hours
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
a1Hrs = ioByte ' Restore Alarm 1 Hours
ioByte = 2 ' Address Of Alarm 2 Minutes
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
a2Mins = ioByte ' Restore Alarm 2 Minutes
ioByte = 3 ' Address Of Alarm 2 Hours
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
a2Hrs = ioByte ' Restore Alarm 2 Hours
ioByte = 4 ' Address Of Dimmer Start Minutes
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
d1Mins = ioByte ' Restore Dimmer Start Minutes
ioByte = 5 ' Address Of Dimmer Start Hours
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
d1Hrs = ioByte ' Restore Dimmer Start Hours
ioByte = 6 ' Address Of Dimmer End Minutes
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
d2Mins = ioByte ' Restore Dimmer End Minutes
ioByte = 7 ' Address Of Dimmer End Hours
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
d2Hrs = ioByte ' Restore Dimmer End Hours
ioByte = 8 ' Address Of Dimmer Level Setting
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
dSet = ioByte ' Restore Dimmer Level Setting
ioByte = 9 ' Address Of Flags
index = RdRam | (ioByte << 1) ' Read RAM Mode + Address
GOSUB RTC_In ' Get Value
flags = ioByte ' Restore Flags
RETURN




▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support

Andy McLeod
11-15-2006, 08:56 PM
Chris-

Very elegant code. I have only3 bytes of programspace left, though.

Consider: SHIFTOUT Dta, Clk, LSBFIRST, [%0\1,RTCCmd\5,%11\2,Value]

Which of those values are the byte addresses?

Tracy Allen
11-15-2006, 11:12 PM
Hi Andy,

If you are using a BS2pe, you have 8 slots available for program. When you say you have only 3 bytes of program space left, do you mean in slot 0 only, or in all 8 slots?

Also, the BS2pe has a total of 16 slots, and 8 of them are available for programs and all 16 can be available for storing data (total of 32k bytes). Are you using that to store your data sequences, or are you storing the data sequences in an external eeprom?

concerning:
> SHIFTOUT Dta, Clk, LSBFIRST, [%0\1,RTCCmd\5,%11\2,Value]

The address is the 5 bits, RTCCmd. The command frames the 5 bit address in a couple of other bits and sends the whole thing lsb first. It might be easier to see with simple examples:

To write a single byte to the RAM, the address can be from 0 to 30 decimal.

SHIFTOUT Dta, Clk, LSBFIRST, [%11000000,Value] 'writes value to location 0.

SHIFTOUT Dta, Clk, LSBFIRST, [%11000010,Value] 'writes value to location 1. Etc. OR....

SHIFTOUT Dta, Clk, LSBFIRST, [%11000000 + (location<<1),Value] 'writes a value to "location", which is shifted left one to put it in the proper place. And...



Note lsb=0 for a write and it will =1 for a read. The msb is always 1. The bit next to the lsb selects either 1:RAM 0:clock&control

All writes to the clock register and RAM have to be done with the write protect bit set to zero:
SHIFTOUT Dta, Clk, LSBFIRST, [$8E,0] ' enable writes
' ....
SHIFTOUT Dta, Clk, LSBFIRST, [$8E,$80] ' disable writes

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com (http://www.emesystems.com)

Post Edited (Tracy Allen) : 11/15/2006 4:16:06 PM GMT

Andy McLeod
11-16-2006, 01:02 AM
Tracy-

1. Based on the memory map in the editor, I appear to have only 3 bytes left to work with. This comes after I got an "out of variable space" (?) error and reworked my code to fit better.

2. My original code uses STORE 8 to STORE 15 to put data. I do this to guarentee the 0 - 8 banks are available for programmng. I know you use the BS2pe extensively, do you use external eeprom in addition to the internal?

3. Thank you for the descrition of the SHIFTOUT command. I'll get on a rewrite this afternoon using your description.

Chris Savage
11-16-2006, 01:18 AM
Andy,

The slots are not available as one contiguous block in the Memory Map so what you’re seeing is a single 2K slot that is full. As with the upper data banks you’re using you need to switch banks in order to run the next program. In the help file see the RUN command. This of course will require you to do a little re-thinking on organization of your program. You will have to split main functions up into two slots. Common subroutines will need to be in both slots, and to preserve variables across slots you need to declare them all exactly the same in all slots you use. There is a Nuts & Volts article that covers multi-bank programming as well. I hope this helps. Take care.

http://www.parallax.com/dl/docs/cols/nv/vol3/col/nv87.pdf


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support

Tracy Allen
11-16-2006, 01:40 AM
Chris answered the question. Lucky you have a lot more program space to expand into! I recommend putting initialization code into slot 0, then RUN into slot 1 for the main program loop. You can put routines for setting the clock and other such setup/configuration in their own slot too.

I do use an external flash memory on my data loggers, but that may not be necessary on your system if the additional slots of the BS2pe are sufficient.

I do concur with Chris on using the DS1302 (battery or capacitor backed) to hold the memory pointers.
In order to spread out the wear on the eeprom, I store a couple of pointers. One to the base location of the current session, and one to the next free location, where you will write the next data byte. When starting a new run, the basepointer is set equal to the next free location pointer. The logging wraps around from the end of the available memory and back to the beginning, and with successive sessions, the two pointers chase one another around the memory array.

You asked about memory pointers, to select slot and address. If the memory pointer goes from 16384 to 32767 (in slots 8 to 15), then the slot and address for writing a byte is:


STORE pointer/2048 + 8
WRITE pointer//2048, value ' the //2048 is really not necessary, but that is the effect
pointer=pointer+1
if pointer>32767 THEN pointer=16384 ' wrap around
IF pointer = basepointer THEN ?? ' memory is full, and you can either stop logging, or wrap, or ???



To store 12 bit values, you will be storing word values, so the pointer might be incremented by 2. There are lots of ways you can tune this.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com (http://www.emesystems.com)