what to do with ever changing values?

Discussion specific to the DIP and TQFP packaged ZX devices like the ZX-40, ZX-44, ZX-32 and ZX-328 series. The differences between these devices is primarily the packaging and pinout so most issues will apply to all devices.
Post Reply
cadillackid
Posts: 35
Joined: 22 August 2009, 16:34 PM

what to do with ever changing values?

Post by cadillackid »

In my HVAC project, I am trying to find a way to store ever changing values without ruining my persistent memory...

anytime a setting is changed I want to store it, so in the event of an electrical power failure the controller recovers to its previous settings...

obviously i can use persistent bytes... however it will eventually ruin the non volatile memory if i write to it each time a setting changes.. I realize a million writes is a lot.. is there an external chip I can use?

also how many bytes of persistent memory exist on a ZX-328n and a ZX-1281n that I can use? maybe I can rotate writing different bytes so that I dont ruin the memory as fast?
-Christopher
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: what to do with ever changing values?

Post by dkinzer »

cadillackid wrote:is there an external chip I can use?
An FRAM device like the FM25256B may be useful. It has an SPI interface and claims 10^14 cycles lifetime.
cadillackid wrote:how many bytes of persistent memory exist on a ZX-328n and a ZX-1281n that I can use?
Check the ZX Device Parameter web page. It is also available as an Excel spreadsheet.
cadillackid wrote:maybe I can rotate writing different bytes so that I dont ruin the memory as fast?
Wear leveling is a well-known procedure. I believe that Atmel and Microchip both have application notes on the topic.
- Don Kinzer
Don_Kirby
Posts: 341
Joined: 15 October 2006, 3:48 AM
Location: Long Island, New York

Post by Don_Kirby »

I used wear leveling in order to extend the life of a hour meter project. Using an array of 200 persistent variables I was able to extend the lifespan of the product from the advertised 100,000 writes, to 20,000,000 writes. It's been running for 2 years nonstop so far, writing once per minute, without any problems. I gather it will run for another 36 years before I see a failure.

The other method worth mentioning is power failure detection. Monitor the incoming power supply for a loss of power. Provide enough backup power (usually in the form of capacitance) to write the current value to persistent memory, but only do it when the power fails.

Neither of the above techniques require additional components, which is a plus.


-Don Kirby
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post by GTBecker »

http://www.atmel.com/dyn/resources/prod ... oc2526.pdf

Here's an example I wrote some time ago, from the BX-24 Yahoo list. Note that lTwoDaysInTicks applies a trick to the BX-24 RTC that probably does not work in ZBasic machines. Adjust accordingly.

Code: Select all

' Hobbs-like Running Time Meter on BX-24
'	0.001 hour resolution (or 0.01)
'	Resettable ~1165 hour maximum count (11650)
'	12000 hour minimum endurance (120000)

'	2006-03-28  Tom Becker  GTBecker@RighTime.com

 const Pin_Input_Reset_Count_Not as byte = 10
 const ilenCircularBuffer as integer = 120
 dim laCircularBuffer(1 to ilenCircularBuffer) as New PersistentLong
 dim iXMax as integer
 const lThousandthHourInTicks as Long = 1843	'0.001hr = 3.6seconds * 512ticks = ~1843 (0.01% error)
 const lTwoDaysInTicks as long = 88473600		'RTC T0, well beyond 24 hours; won't reset at midnight

sub Main()
	call PutPin (Pin_Input_Reset_Count_Not, bxInputPullup)	'reset switch pin
	if FirstTime then
		call Reset
	end if
	iXMax = iGetLargestRunningTimeIndex	'find index of largest in ring, resume
	call SetRTCTicks(laCircularBuffer(iXMax) * lThousandthHourInTicks)	'start timer from there
	call ShowRunningTime	'show start time

	do	'endless
		if &#40;lGetRTCTicks \ lThousandthHourInTicks&#41; <> &#40;laCircularBuffer&#40;iXMax&#41;&#41; then
			iXMax = iXMax mod ilenCircularBuffer + 1	'next in ring
			laCircularBuffer&#40;iXMax&#41; = lGetRTCTicks \ lThousandthHourInTicks	'store each 0.001 hour
			call ShowRunningTime
		end if
		if GetPin&#40;Pin_Input_Reset_Count_Not&#41; <> 1 then
			call Reset
			call ShowRunningTime
		end if
	loop
end sub

function lGetRTCTicks&#40;&#41; as long
	lGetRTCTicks = register.RTCTick - lTwoDaysInTicks	'RTC count is offset to avoid midnight
end function

sub SetRTCTicks&#40;byval lTicks as long&#41;
	register.RTCTick = lTicks + lTwoDaysInTicks
end sub

sub ShowRunningTime&#40;&#41;
	debug.print strRunningTimeInHours&#40;laCircularBuffer&#40;iXMax&#41;&#41;
end sub

function strRunningTimeInHours&#40;byval lT as long&#41; as string	'1165.210hr max; &#40;2^31-1/512/3600&#41;-48hrs
	dim strH as string*5, strF as string*4
	strF = cStr&#40;lT mod 1000 + 1000&#41;	'hour fraction
	lT = lT \ 1000	'discard fraction
	strH = cStr&#40;lT + 10000&#41;	'hours
	strRunningTimeInHours = mid&#40;strH, 2, 4&#41; &"."& mid&#40;strF, 2, 3&#41;
end function

sub Reset&#40;&#41;
		call ResetRunningTime	'zero ring
		call SetRTCTicks&#40;0&#41;	'zero RTC
end sub

sub ResetRunningTime&#40;&#41;
	dim iX as integer
	debug.print " Reset"
	for iX = 1 to ilenCircularBuffer	'this takes about four seconds on BX-24
		laCircularBuffer&#40;iX&#41; = 0
	next
end sub

function iGetLargestRunningTimeIndex &#40;&#41; as integer
	dim iX as integer
	debug.print " Resume"
	iGetLargestRunningTimeIndex = 1
	for iX = 1 to ilenCircularBuffer	'get index of largest value
		if laCircularBuffer&#40;iGetLargestRunningTimeIndex&#41; < laCircularBuffer&#40;iX&#41; then
			iGetLargestRunningTimeIndex = iX
		end if
	next
end function
Like Don, I have one of these running without a failure for several years.
Tom
cadillackid
Posts: 35
Joined: 22 August 2009, 16:34 PM

Post by cadillackid »

I think im going to go the route of rotating data in the persistent areas... I realized that even if the thermostat settings changed 1000 times per day(which is an awful lot of adjusting...roughly once every 1.4 minutes).. I would hit close to the 1 million mark little less than once a year... im only using about 10 bytes of persistent memory.. so if I rotate in 100 bytes It should last about 10 years.... but then who is going to adjust their settings 1000 times / day...

I dont want the controller to stay active during a power failure as in HVAC its not a good idea to "bang" equipment... however the controller is powered by the A/C unit which is 5 volts so I could just read a pin and have a capacitor as suggested earlier to hold power up long enough for me to start the time delay and save the settings....
-Christopher
spamiam
Posts: 739
Joined: 13 November 2005, 6:39 AM

Post by spamiam »

I have also had good results with FRAM (from Ramtron), though now some other products incorporate this type of memory. For instance the Dallas DS32X35 incorporates a VERY accurate RTC and FRAM in the same package. The two currently available have 2K and 8K of FRAM. Fram wil not wear out, so you do not have to worry about wear levelling. I beleive you already have an I2C bus on your device, and these are I2C devices, though Ramtron also offers SPI FRAM devices.

If you are going to need an RTC, then the Dallas chip might make sense.

-Tony
stevech
Posts: 715
Joined: 22 February 2006, 20:56 PM

Post by stevech »

I have a ZX that uses the rotating fixed length data record approach. Each record is numbered (ascending). So at startup, the code looks for the highest numbered record. The writing code uses circular buffer and overwrites the lowest numbered record.

THis has been running here for 2 years or so - with 4 or so records added per day. Using onboard EEPROM
Post Reply