EEPROM value written using BS2 Functions but not retained/not read properly after restart - Spin, P1
Jufra
Posts: 24
Hi all,
I've got a P1 spin application that reads water flow rates from an ultrasonic flowmeter. As this code goes into a number of different products (the products differ by maximum flow rate), the software can be configured to set the correct maximum flow rate. This is done via a serial interface, and once the value is received, it is written to EEPROM using the Write_CodeMem routine from BS2 Functions ( https://github.com/parallaxinc/propeller/commit/8113778fa5586512d7282070d20d487ad6a8239f ). It all works fine except that in certain situations it does not read the EEPROM value back when it restarts. The following spin code is there at startup to see if there is an EEPROM value stored, and if not, it assigns the default value of 50.
if (max_flow_rate == 0) 'check if EEPROM value exists, if not, assign default 50l unit size)
max_flow_rate := 50
99% of the times it works, ie, if I have set another value then 50 somewhere else in the code it gets written to EEPROM and upon restart the value is read back. Except in a few niggly cases this doesn't work and it defaults back to 50 (which means it reads EEPROM value as 0 in the above if statement, even though it was written to EEPROM before).
And yes, I've checked the variable size and the size of the BS2 command,
BS2[0].Write_CodeMem(@max_flow_rate, max_flow_rate, 2) 'word size
So my question is: If there is a brown out or loss of power for a short time and the prop restarts, could it be the EEPROM is not read back into RAM but the variable is still somehow cleared? Or something along those lines?
This happens only rarely and I believe it does happen when brown outs occur (but not 100% sure, we got this out in the field).
Thanks a lot for your help
Cheers
Frank
I've got a P1 spin application that reads water flow rates from an ultrasonic flowmeter. As this code goes into a number of different products (the products differ by maximum flow rate), the software can be configured to set the correct maximum flow rate. This is done via a serial interface, and once the value is received, it is written to EEPROM using the Write_CodeMem routine from BS2 Functions ( https://github.com/parallaxinc/propeller/commit/8113778fa5586512d7282070d20d487ad6a8239f ). It all works fine except that in certain situations it does not read the EEPROM value back when it restarts. The following spin code is there at startup to see if there is an EEPROM value stored, and if not, it assigns the default value of 50.
if (max_flow_rate == 0) 'check if EEPROM value exists, if not, assign default 50l unit size)
max_flow_rate := 50
99% of the times it works, ie, if I have set another value then 50 somewhere else in the code it gets written to EEPROM and upon restart the value is read back. Except in a few niggly cases this doesn't work and it defaults back to 50 (which means it reads EEPROM value as 0 in the above if statement, even though it was written to EEPROM before).
And yes, I've checked the variable size and the size of the BS2 command,
BS2[0].Write_CodeMem(@max_flow_rate, max_flow_rate, 2) 'word size
So my question is: If there is a brown out or loss of power for a short time and the prop restarts, could it be the EEPROM is not read back into RAM but the variable is still somehow cleared? Or something along those lines?
This happens only rarely and I believe it does happen when brown outs occur (but not 100% sure, we got this out in the field).
Thanks a lot for your help
Cheers
Frank
Comments
Is DIRA[29] accidentally set to high by another cog ?
I wonder why you did not say "BS2" but "BS2[0]"...
Are there Some BS2 objects at once ?
@Publison I am using a 32K EEPROM
@yisiguro I will check if another COG can change pin 29 at the same time, I don't think so, but will double check. YEs, there are a few BS2 objects there for other things, but writecodemem is not used concurrently
What you’re probably seeing is leftover values in RAM.
Does the prop check this checksum when booting? I don't think it does...
I got Tachyon to check the EEPROM, write a zero to 5 and then rebooted.
I have never written any values to EEPROMS > 32k, in fact I 've never used >32K chips with propeller chips. Writing to EEPROM always worked the way I described... well, except in this case.
So is it picking up artefacts in RAM as Cluso99 said?
I've done it before.
I'm not really sure what your issue is. Somebody suggested multiple cogs might be using the same pins?
I would define a maximum write attempt at say 10.
Then, try to write. Read it back and see if OK.
Repeat trying this 10 times or until successful and then give up... Until next time...
Something must be wrong... If it's your own board, I'd check solder connections. Also, make sure you have 10k pullups on SDA and SCL.
Also, double check for code errors, crystal settings, etc.
Peter is usually correct, so I guess that the checksum doesn't need updating (I haven't had time to check yet).
Anyway, I note your mention of 0 to 5.
What address(es) in EEPROM are you writing to?
I was simply setting address 5 in EEPROM to 0. Here is another quick test dumping EE memory (without the EE it would access hub), writing location 5, reading it back and checking that pbase = $0010. If I changed location 6 from $0010 then the booter will shut the cog down.
the EEPROM lower 32k are exactly at the same address as a Spin DAT variable, VAR will not work as well.
So if you write the EEPROM at address @datLocation with a new value of datLocation it will be there at the next reboot.
But it has to be a DAT declared Variable not VAR. So it is stored in the code/binary and has a initial value at boot time.
The Checksum is just verified when programming the binary into EEPROM, not when booting from it, as far as I experienced it.
Enjoy!
Mike
So going forward, I would need to declare two variables (one in VAR, the other in DAT) like that
VAR
word max_flow_rate_var
DAT
max_flow_rate_dat word 0
and in the code:
if (max_flow_rate_dat == 0) 'check if EEPROM value exists, if not, assign default 50l unit size)
max_flow_rate_var := 50
else
max_flow_rate_var := max_flow_rate_dat
And I'd be writing the DAT as before:
BS2[0].Write_CodeMem(@max_flow_rate_dat, max_flow_rate_var, 2) 'word size
Is that what you're saying? I guess I could also only have the DAT variable and assign values to it in the code using @max_flow_rate := <newvalue> which would write to RAM and use the WriteCodeMem to commit to EEPROM
Thanks
Frank
The main difference between VAR and DAT is that DAT has predefined values and is saved in the program binary. Var is different as if you use more then one copy of the object, each object shares (has the same) code and DAT section(s), but each instance of a object has its own VAR section(s).
Say two copies of FullduplexSerial will share the code in RAM but have their own buffer in RAM (in VAR)
And yes you would write it as before.
But if you reprogram it will be lost. If you write in the upper 32K (if you have 64K EEPROM) then it stays there because programming just writes the first 32K.
Mike
VAR is strange. I don't think you can count on initialization... Is there a "Global" VAR? I don't think so...
Also I think the term "global" means the symbols which has global scope per-file basis.
Sorry, I overlooked some posts.
so maybe before the if statement I would need to read the value back from EEPROM to make sure I'm checking the EEPROM value?:
max_flow_rate := BS2.Read_CodeMem(@max_flow_rate, 2) 'word size
if (max_flow_rate == 0)
Haven't got time to test this now as I'm about to go for 2 weeks of camping ;-)
But I will once I'm back
If somebody inherits that code, they may have a hard time understanding what is going on, unless it's well documented in the code...
Actually, the Manual does say this is OK:
Still, what if you compile with Fastspin or BST? Will it still work? What about if you do Spin2Cpp on it? There are a lot of questions about this usage...
Checking that "Initialize" is a good idea. That might cause low frequency failures...
I'm guessing that means it is initialized to zero because it was initialized to zero before it was loaded to EEPROM, not because it tries to do this every time it boots.
So changing the VAR in EEPROM is all that is required to "preset" that variable. I used to use the Spin tool for this method before BST so it has nothing to do with the compiler.