EEPROM Corruption

Olly928

New Member
Hi there, I'm fairly new to the PICAXE world and I've built a system that in simple terms counts in real time when an input pin pulses above a certain speed. However I'm having some issues with it, I've built it on a 28X2 module.

This count is stored as variables in Hours, Minutes and Seconds for the duration of the device running. There are certain stages in the code where it checks the input voltage to check it isn't falling below a certain level, if it does it writes the Hrs, Mins and Secs variable values to the EEPROM to save them so on the next power up it continues counting in real time from the same saved time. I have a big capacitor to hold the voltage in the system when the power goes out to give the PICAXE time to run through the program to save.

Now I also have a check at the start for the value of a digital input which can be connected with a serial display attached so i can then plug in and read the time that is stored on the device. For the PICAXE to pick this display up I obviously need to power cycle it as the reading of the digital input is the first part of the main code.

The problem that I'm having is that the EEPROM seems to be getting corrupted, and the values for Hrs, Mins and Secs end up being 255. This can happen in a few ways from what I've found, from disconnecting the digital input and display while its on to the device loosing power and it coming back suddenly, or while unplugging the aux jack when connected to the PC. I think the route of the problem lies in the serial connections and that something happens when it is disconnected while the PICAXE is still on.

I've managed to minimize the chance of it happening by pulling the inputs that are connected to ground if they are disconnected, also by turning off the power supplies before plugging in or unplugging any of the connections. The device runs in a reasonably harsh environment, its within the tolerances for the chip but its hot and there is quite a lot of vibration, although the PICAXE is AV mounted to reduce this and all wire connections are silicon sealed to prevent movement.

Now I need the device to be robust software wise and this is a major bug because as soon as 255 shows up in the EEPROM the count is ruined. It needs to be able to survive the power losses and the display being plugged in while its on. I didn't think these things would be a problem when I designed the system and really its to late to change the PCB that they are connected on. (not that I know what I would change).

Has anyone had any issues like this before? I've searched but haven't turned up anything...

I can add code if need be, but apart from writing the hrs, mins and secs value to the EEPROM and reading them at the start there is nothing else using the EEPROM.

My biggest feeling is its serial related and the chip cant handle the sudden disconnect of it.
 

hippy

Technical Support
Staff member
Welcome to the PICAXE forum.

If you are using a jack plug and socket for your connections it is possible that insertion and disconnection may disrupt the power rails and cause the PICAXE to reset. Depending on how the 'backup capacitor' is wired into the circuit it is possible that could collapse more quickly than you expect.

Robust power-fail immune systems can be difficult to design, analyse and debug. Determining if it is power-fail, display connection, both, or even something else, causing the corruption would probably be a good start. If you can post your circuit diagram and code that will help others determine if there are any issues that they can see.
 

Olly928

New Member
The jack plug is only used for programming and the serial screen and digital input are on automotive style connectors. I will dig out the diagram for you.
 

Olly928

New Member
Here is the code, I will post the circuit diagram as soon as I can.

Code:
{ ;Symbols
symbol varA = b0 ' pulse count
symbol OilP = b1 ' Oil P
symbol RPM = w1 ' RPM Count
symbol varC = b2 ' RPM count
symbol varD = b3 ' RPM count
symbol Secs = b4 ' Secs
symbol Mins = b5 ' Mins
symbol Hrs = b6 ' Hrs
symbol VIn = b7 ' Voltage Level
symbol DIn = b8 ' Digital In Value
symbol varJ = b9 ' display Oil P
symbol varK = b10 ' display Oil P
symbol varL = b11 ' display Oil P
symbol varM = b12 ' display RPM
symbol varN = b13 ' display RPM
symbol varO = b14 ' display RPM
symbol varP = b15 ' display RPM
symbol varQ = b16 ' display RPM
symbol varR = b17 ' display Secs
symbol varS = b18 ' display Secs
symbol varT = b19 ' display Secs
symbol varU = b20 ' display Mins
symbol varV = b21 ' display Mins
symbol varW = b22 ' display Mins
symbol varX = b23 ' display Hrs
symbol varY = b24 ' display Hrs
symbol varZ = b25 ' display Hrs
symbol Msecs = b26 ' Msecs           
symbol varTEMPBYTE1 = b50 ' pulse count
symbol varTEMPBYTE2 = b51 ' pulse count
symbol varTEMPBYTE3 = b52
symbol varTEMPBYTE4 = b53
symbol varTEMPBYTE5 = b54
symbol varTEMPBYTE6 = b55
symbol varTEMPWORD1 = w25 ' pulse count
symbol varTEMPWORD2 = w26
symbol varTEMPWORD3 = w27
}


main:


	let dirsA = 16
	let dirsB = 255
	let dirsC = 0
	
wait 1

READ 0, Secs
READ 8, Mins
READ 16, Hrs ' read from memory

Cell_7_4:
Readadc C.6, DIn ' Digital In
	If DIn < 60 then
		goto Cell_7_5 ' counts
	Else
		If DIn >= 60 And DIn <= 78 then
			pause 1000
			goto Cell_7_7 ' Digital In Position 1 
		Else
			If DIn >= 91 And DIn <= 155 then
				pause 1000
				goto Cell_7_8 ' Digital In Position 2
			Else
				If DIn >= 158 And DIn <= 255 then
					pause 1000
					goto Cell_7_9 ' Digital In Position 3
				Else
				Endif
			Endif
		Endif
	Endif

Cell_7_5:
Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
		goto Cell_7_6	
	End If	

Cell_7_6: ' counts
count C.0, 600 , varTEMPWORD1 ' pulse count
	let varA = varTEMPWORD1 max 255
	let RPM = varA * 10 * 2 * 60 / 3 ' RPM calc
Readadc A.0, OilP ' Oil P
Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	
 ' count conditions
If RPM >= 2000 OR OilP > 70 then
	let Msecs = Msecs + 1
		if Msecs = 2 then
			let Msecs = 0
			Secs = Secs + 1
				if Secs = 60 then
					let Secs = 0
					Mins = Mins + 1
						if Mins = 60 then
							let Mins = 0
							Hrs = Hrs + 1
							else 
						end if
					else
				end if
			else
		end if	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
      Else
	End if
	pauseus 5000     ' 5000
	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	pauseus 5000     ' 10000
	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	pauseus 5000     ' 15000
	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	pauseus 3570    ' 18570
	
	Else
	goto Cell_7_5
End If	
goto Cell_7_5
	

Cell_7_7: ' Digital In Position 1
serout A.4, N2400, (254, 1)
serout A.4, N2400, (254, 128, "        Counter         ") 
serout A.4, N2400, (254, 192, "          EHC            ")
pause 2000
serout A.4, N2400, (254, 192, "    Hrs:Mins:Secs    ")
do {
	bintoascii Secs, varR, varS, varT 
	bintoascii Mins, varU, varV, varW 
	bintoascii Hrs, varX, varY, varZ
	serout A.4, N2400, (254, 148, "    ", varX, varY, varZ, ": ", varV, varW, " :", varS, varT,"       ")
	Readadc C.6, DIn ' Digital In
loop while DIn >= 60 And DIn <= 78
serout A.4, N2400, (254,1)
pause 30 
goto Cell_7_4

Cell_7_8: ' Digital In Position 2
serout A.4, N2400, (254, 1)
serout A.4, N2400, (254, 128, "        Counter         ") 
serout A.4, N2400, (254, 192, "  EHC Serial Check    ")
pause 2000
serout A.4, N2400, (254, 192, " EHC Serial Number  ") 
serout A.4, N2400, (254, 148, "           008           ")
serout A.4, N2400, (254, 212, "   EHC-005 V1.03    ")
do {
	
	Readadc C.6, DIn ' Digital In
loop while DIn >= 91 And DIn <= 155
serout A.4, N2400, (254,1)
pause 30 
goto Cell_7_4

Cell_7_9: ' Digital In Position 3
serout A.4, N2400, (254, 1)
serout A.4, N2400, (254, 128, "        Counter         ") 
serout A.4, N2400, (254, 192, "    EHC Test Mode   ")
pause 2000
	serout A.4, N2400, (254, 1)
	serout A.4, N2400, (254, 128, "    Hrs:Mins:Secs    ") 
	serout A.4, N2400, (254, 148, "    RPM      Oil P   ")
	bintoascii Secs, varR, varS, varT 
	bintoascii Mins, varU, varV, varW 
	bintoascii Hrs, varX, varY, varZ 
	bintoascii RPM, varM, varN, varO, varP, varQ
	bintoascii W14, varJ, varK, varL, b30, b31
	serout A.4, N2400, (254, 192, "    ", varX, varY, varZ, ": ", varV, varW, " :", varS, varT,"       ") 
	serout A.4, N2400, (254, 212, "   ", varM, varN, varO, varP, varQ, "      ", varL, ".", b30, b31, "   ")
do {
Cell_7_9_1:
Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
		goto Cell_7_9_2	
	End If	
Cell_7_9_2: ' counts
count C.0, 400 , varTEMPWORD1 ' pulse count
	let varA = varTEMPWORD1 max 255
	let RPM = varA * 5 * 2 * 60 ' RPM calc
Readadc A.0, OilP ' Oil P
	
 ' count conditions
If RPM >= 1800 OR OilP > 70 then
	let Msecs = Msecs + 1
		if Msecs = 2 then
			let Msecs = 0
			Secs = Secs + 1
				if Secs = 60 then
					let Secs = 0
					Mins = Mins + 1
						if Mins = 60 then
							let Mins = 0
							Hrs = Hrs + 1
							else 
						end if
					else
				end if
			else
		end if	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	pauseus 2978
	
	Else
	goto Cell_7_9_3
End If	
goto Cell_7_9_3

Cell_7_9_3:
	let W14 = OilP * 545 - 28259 / 100 ' Oil P calc
	bintoascii Secs, varR, varS, varT 
	bintoascii Mins, varU, varV, varW 
	bintoascii Hrs, varX, varY, varZ 
	bintoascii RPM, varM, varN, varO, varP, varQ
	bintoascii W14, varJ, varK, varL, b30, b31
	serout A.4, N2400, (254, 192, "    ", varX, varY, varZ, ": ", varV, varW, " :", varS, varT,"       ") 
	serout A.4, N2400, (254, 212, "   ", varM, varN, varO, varP, varQ, "      ", varL, ".", b30, b31, "   ")
	Readadc C.6, DIn ' Digital In
loop while DIn >= 158 And DIn <= 255
serout A.4, N2400, (254,1)
pause 30 
goto Cell_7_10

Cell_7_10: ' write to memory
WRITE 0, Secs
WRITE 8, Mins
WRITE 16, Hrs
goto Cell_7_4


#no_data	'reduce download time
 

Olly928

New Member
Having done a bit more testing I think its the variables that are getting compromised, and then they are being written to the EEPROM as when I take the write command out the end of the code and then try and induce the error it doesn't seem to happen. This suggests to me that the variable values are getting compromised and then as the unit looses power it saves that value to the EEPROM..
 

hippy

Technical Support
Staff member
Part of the problem may be that it seems you go to your 'power failed write' and after that continue the main program loop, end up going to your 'power failed write' again, and keep doing so all the while power is fading away. It seems reasonable to suppose that at some point in time you may be writing as power fails badly enough to corrupt that data.

After a 'power failed write' you probably need to wait until power has recovered before continuing a loop or the PICAXE loses power and restarts from the beginning.

You might also need some additional checks that power is present and stable when you turn on and the program starts so you don't read data as corrupted values and then write that back again.

It would also be wise to store some checksum data so you can tell if what looks like real data has been corrupted, and possibly even writing multiple sets of checksummed data so you stand some chance of determining what is correct data even if one set gets corrupted. The code to do that can get pretty complicated, and flowcharting could get quite complex.

It really depends on how mission critical the project is as to how hardened and robust it has to be.
 

Olly928

New Member
okay so I've added in a little bit, and its in bold, is that the sort of thing you meant?

Code:
{ ;Symbols
symbol varA = b0 ' pulse count
symbol OilP = b1 ' Oil P
symbol RPM = w1 ' RPM Count
symbol varC = b2 ' RPM count
symbol varD = b3 ' RPM count
symbol Secs = b4 ' Secs
symbol Mins = b5 ' Mins
symbol Hrs = b6 ' Hrs
symbol VIn = b7 ' Voltage Level
symbol DIn = b8 ' Digital In Value
symbol varJ = b9 ' display Oil P
symbol varK = b10 ' display Oil P
symbol varL = b11 ' display Oil P
symbol varM = b12 ' display RPM
symbol varN = b13 ' display RPM
symbol varO = b14 ' display RPM
symbol varP = b15 ' display RPM
symbol varQ = b16 ' display RPM
symbol varR = b17 ' display Secs
symbol varS = b18 ' display Secs
symbol varT = b19 ' display Secs
symbol varU = b20 ' display Mins
symbol varV = b21 ' display Mins
symbol varW = b22 ' display Mins
symbol varX = b23 ' display Hrs
symbol varY = b24 ' display Hrs
symbol varZ = b25 ' display Hrs
symbol Msecs = b26 ' Msecs           
symbol varTEMPBYTE1 = b50 ' pulse count
symbol varTEMPBYTE2 = b51 ' pulse count
symbol varTEMPBYTE3 = b52
symbol varTEMPBYTE4 = b53
symbol varTEMPBYTE5 = b54
symbol varTEMPBYTE6 = b55
symbol varTEMPWORD1 = w25 ' pulse count
symbol varTEMPWORD2 = w26
symbol varTEMPWORD3 = w27
}


main:


	let dirsA = 16
	let dirsB = 255
	let dirsC = 0
	
wait 1

[B]Cell_7_2:
Readadc A.2, VIn ' check voltage
	If VIn > 120 then
		goto Cell_7_3
	Else
		goto Cell_7_2
	Endif

Cell_7_3:
READ 0, Secs
READ 8, Mins
READ 16, Hrs ' read from memory[/B]

Cell_7_4:
Readadc C.6, DIn ' Digital In
	If DIn < 60 then
		goto Cell_7_5 ' counts
	Else
		If DIn >= 60 And DIn <= 78 then
			pause 1000
			goto Cell_7_7 ' Digital In Position 1 
		Else
			If DIn >= 91 And DIn <= 155 then
				pause 1000
				goto Cell_7_8 ' Digital In Position 2
			Else
				If DIn >= 158 And DIn <= 255 then
					pause 1000
					goto Cell_7_9 ' Digital In Position 3
				Else
				Endif
			Endif
		Endif
	Endif

Cell_7_5:
Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
		goto Cell_7_6	
	End If	

Cell_7_6: ' counts
count C.0, 600 , varTEMPWORD1 ' pulse count
	let varA = varTEMPWORD1 max 255
	let RPM = varA * 10 * 2 * 60 / 3 ' RPM calc
Readadc A.0, OilP ' Oil P
Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	
 ' count conditions
If RPM >= 2000 OR OilP > 70 then
	let Msecs = Msecs + 1
		if Msecs = 2 then
			let Msecs = 0
			Secs = Secs + 1
				if Secs = 60 then
					let Secs = 0
					Mins = Mins + 1
						if Mins = 60 then
							let Mins = 0
							Hrs = Hrs + 1
							else 
						end if
					else
				end if
			else
		end if	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
      Else
	End if
	pauseus 5000     ' 5000
	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	pauseus 5000     ' 10000
	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	pauseus 5000     ' 15000
	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	pauseus 3570    ' 18570
	
	Else
	goto Cell_7_5
End If	
goto Cell_7_5
	

Cell_7_7: ' Digital In Position 1
serout A.4, N2400, (254, 1)
serout A.4, N2400, (254, 128, "        Counter         ") 
serout A.4, N2400, (254, 192, "          EHC            ")
pause 2000
serout A.4, N2400, (254, 192, "    Hrs:Mins:Secs    ")
do {
	bintoascii Secs, varR, varS, varT 
	bintoascii Mins, varU, varV, varW 
	bintoascii Hrs, varX, varY, varZ
	serout A.4, N2400, (254, 148, "    ", varX, varY, varZ, ": ", varV, varW, " :", varS, varT,"       ")
	Readadc C.6, DIn ' Digital In
loop while DIn >= 60 And DIn <= 78
serout A.4, N2400, (254,1)
pause 30 
goto Cell_7_4

Cell_7_8: ' Digital In Position 2
serout A.4, N2400, (254, 1)
serout A.4, N2400, (254, 128, "        Counter         ") 
serout A.4, N2400, (254, 192, "  EHC Serial Check    ")
pause 2000
serout A.4, N2400, (254, 192, " EHC Serial Number  ") 
serout A.4, N2400, (254, 148, "           008           ")
serout A.4, N2400, (254, 212, "   EHC-005 V1.03    ")
do {
	
	Readadc C.6, DIn ' Digital In
loop while DIn >= 91 And DIn <= 155
serout A.4, N2400, (254,1)
pause 30 
goto Cell_7_4

Cell_7_9: ' Digital In Position 3
serout A.4, N2400, (254, 1)
serout A.4, N2400, (254, 128, "        Counter         ") 
serout A.4, N2400, (254, 192, "    EHC Test Mode   ")
pause 2000
	serout A.4, N2400, (254, 1)
	serout A.4, N2400, (254, 128, "    Hrs:Mins:Secs    ") 
	serout A.4, N2400, (254, 148, "    RPM      Oil P   ")
	bintoascii Secs, varR, varS, varT 
	bintoascii Mins, varU, varV, varW 
	bintoascii Hrs, varX, varY, varZ 
	bintoascii RPM, varM, varN, varO, varP, varQ
	bintoascii W14, varJ, varK, varL, b30, b31
	serout A.4, N2400, (254, 192, "    ", varX, varY, varZ, ": ", varV, varW, " :", varS, varT,"       ") 
	serout A.4, N2400, (254, 212, "   ", varM, varN, varO, varP, varQ, "      ", varL, ".", b30, b31, "   ")
do {
Cell_7_9_1:
Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
		goto Cell_7_9_2	
	End If	
Cell_7_9_2: ' counts
count C.0, 400 , varTEMPWORD1 ' pulse count
	let varA = varTEMPWORD1 max 255
	let RPM = varA * 5 * 2 * 60 ' RPM calc
Readadc A.0, OilP ' Oil P
	
 ' count conditions
If RPM >= 1800 OR OilP > 70 then
	let Msecs = Msecs + 1
		if Msecs = 2 then
			let Msecs = 0
			Secs = Secs + 1
				if Secs = 60 then
					let Secs = 0
					Mins = Mins + 1
						if Mins = 60 then
							let Mins = 0
							Hrs = Hrs + 1
							else 
						end if
					else
				end if
			else
		end if	
	Readadc A.2, VIn ' check voltage
	If VIn < 120 then
		goto Cell_7_10
	Else
	End if
	pauseus 2978
	
	Else
	goto Cell_7_9_3
End If	
goto Cell_7_9_3

Cell_7_9_3:
	let W14 = OilP * 545 - 28259 / 100 ' Oil P calc
	bintoascii Secs, varR, varS, varT 
	bintoascii Mins, varU, varV, varW 
	bintoascii Hrs, varX, varY, varZ 
	bintoascii RPM, varM, varN, varO, varP, varQ
	bintoascii W14, varJ, varK, varL, b30, b31
	serout A.4, N2400, (254, 192, "    ", varX, varY, varZ, ": ", varV, varW, " :", varS, varT,"       ") 
	serout A.4, N2400, (254, 212, "   ", varM, varN, varO, varP, varQ, "      ", varL, ".", b30, b31, "   ")
	Readadc C.6, DIn ' Digital In
loop while DIn >= 158 And DIn <= 255
serout A.4, N2400, (254,1)
pause 30 
goto Cell_7_10

Cell_7_10: ' write to memory
WRITE 0, Secs
WRITE 8, Mins
WRITE 16, Hrs
[B]goto Cell_7_2
[/B]

#no_data	'reduce download time
 

hippy

Technical Support
Staff member
Yes, that seems to be the sort of thing.

Watch out for comparisons like "Vin > 120" and "Vin < 120" as when Vin is 120 it will slip by both of those. In this case it probably does not matter, in fact it would be better to have the 'present' value greater than the 'lost' value to give some hysteresis to voltage being there and not.

One interesting aspect is how the voltage read is affected by collapsing power. As the capacitor voltage drops, the voltage measured will appear to increase against that voltage. It probably has little effect but could if power loss is not instant but decays.
 
Top