Picaxe Timing Accuracy

RNovember

Well-known member
Hello, I have a project that I am working on, and I need to run it for a year, and have it do a simple task, write to an EEPROM, four times a day (once every six hours).

I need to know how far off the picaxe will get if I run it for a year (how much time it will gain or lose), to decide if I should use the picaxe timer, or a RTC.

It can get off about 3 hours, but that is about maximum.

EDIT: By RTC I mean anything that will give me an accurate time reference.
 
Last edited:

hippy

Technical Support
Staff member
A year is 365*24 hours = 8760

3 hours is (3*100)/8760 = +/-0.034%

A PICAXE has an internal oscillator with +/-2% accuracy. I have never known it to be too far out from what's expected but that's looking at microsecond timings and only intantaneosly, not long term.

An external oscillator would have better accuracy, should meet the requirement, but things would depend on how you were determining elapsed time.

You would probably need to run one of the internal on-chip timers to be accurate. SETTIMER on an X2 could help there but I don't know if anyone has done long term tests.

I am not sure about using the TIME variable on an M2 long term. We know it does lose time in some circumstances.

You could possibly get away with using an M2 and an external 32kHz clock crystal with an internal timer. That should have reasonably good accuracy but some people have reported otherwise. It's also a bit tricky if using an M2.

You could also count mains cycles with an isolated input.

But all of those will have problems if power is ever lost.

Probably the best bet, especially for simplicity and ease of use, is to use an external RTC with its own battery backup. Even a pretty poor quality one shouldn't drift more than a minute or two a year.
 

cachomachine

Senior Member
I have use in the past on few occasions the DS3232 RTC with his battery backup, they are accurate to a few second a year (even on the battery backup)
 

MartinM57

Moderator
...I'd echo the DS3231/2 choice - accuracy is quoted as +/- 2ppm between 0C and 40C. There's about 31.5m seconds in a year, so around a minute a year, but you may get a good one.

Don't buy one on a board with a few other components from a chinese seller where the total delivered price is less that the price of a single chip from the likes of Farnell - it will almost certainly be a fake chip and all bets are off about it's accuracy (and/or functionality).

A CR2032 will keep a DS3231/2 alive, in terms of running the RTC element when the main supply to the chip is not present, for at least about 8 years.

I've used literally hundreds of (genuine - Farnell, Mouser, RS Components etc) DS3232 (the 236 bytes of battery backed RAM is also useful) over the last 8 years or so and never had one problem - the 20 pin SMD package version also survives being mounted upside down (well, rotated 180 degrees) on its PCB position and still works fine when re-mounted the right way round.

How are you going to power the PICAXE and if battery powered, do you have a strategy for minimising overall power consumption?
 

premelec

Senior Member
A method I have seen used is to record [in eeprom] start time data and then at the end of the run compare recorded end time of the run with external "real time" and prorate the difference over the total run time... ;-0
 

RNovember

Well-known member
How are you going to power the PICAXE and if battery powered, do you have a strategy for minimising overall power consumption?
Since this is going to be an outside project, I will use a solar panel and a backup battery.

I haven't got far enough into the project to think of power saving (I am just starting to organize a schematic).
 

RNovember

Well-known member
Hey, this is a great chip (DS3232)!

I have been reading the data sheet, and it is just what I have been looking for.

I just need to have one of the alarms connected so it runs every hour, and then every six times this happens, have the picaxe run the main program.
 
Last edited:

MartinM57

Moderator
I don't use the alarms as I use the ~INT/SQW pin in its SQW mode, outputting a 1Hz square wave to an interrupt pin that provides a (very) accurate time tick to the rest of my software.

I did consider using the alarms but I would have had to continuously poll the Alarm Flags to see if an alarm had happened.

In my investigations I came across https://gist.github.com/JChristensen/0359516e3780a819cbffef0db5419213 which has a slightly more friendly description of the alarms - the code examples are, unfortunately, for another processor.
 

RNovember

Well-known member
I have had a chance to look at the data sheet, and I think that I need some pointers about how to use this chip.

I didn't really understand what the alarms were, but they looked nice. It probably would be easier to use the square wave, but I don't know how to do that.

If anyone knows more about I2C interface with this chip (I assume that those using them do), I would appreciate it if you would tell me. Thanks.
 

cachomachine

Senior Member
You simply can read the hours register and compare its value with your target values.

Code:
Hi2csetup I2cmaster, %11010000, I2cfast_32, I2cbyte       ' Set the I2C to 400kbps

Hi2cin  $2 ,B0 'read the hours into b0

b0=b0/16*$FA+b0   'conversion BCD to binary of the hours
 

RNovember

Well-known member
What I mean is that I know nothing about how to use I2C. I know what it is, but I don't know how to code for it in picaxe basic, or how to get information from the DS3232.

What I need the picaxe to do is measure a temperature, convert it to binary, and store it in adress 0 of the EEPROM.

Next I need to get the time (military), convert it to binary and store it at Adress 1.

Then I need to get the day of month from the RTC, convert it to binary, and store it at adress 10.

The last step is to get the month number and last digit of the year, convert them to binary, and store them at adress 11.

I don't know how to get that information through I2C from the DS3232 to the Picaxe.
 

hippy

Technical Support
Staff member
It's not clear why you would be storing data at address 0 through 11, why there's so much data. Or why there's any need to store any date or time info per sample. Each sample will be six hours after the last so just the starting date and time would need to be stored.

If you are sampling four times a day for a year that's 1460 items of data. That's too much for internal Data EPROM if samples were byte-sized, but you might be able to store it as smaller temperature changes from the last reading. That would depend on what sort of temperature changes you were expecting and wouldn't have great resolution.

You might need to go to external I2C EPROM for your sample storage. One of those RTC+EPROM modules may be appropriate here.

It might be worth detailing exactly what you want to achieve before deciding upon the best way to achieve that.

I had assumed you would merely be using an RTC ( or whatever ) to determine when to take a sample, rather than to give each sample a timestamp. But either way you will have to read the RTC data.

That's pretty easy, whether DS1307, DS3232 or similar. There should be code on the forum for most devices. Basically what cachomachine showed in Post #12, but you would read more bytes of data to get the full date and time.
 

cachomachine

Senior Member
$02 is the hours register
you read it; Hi2cin $2 ,B0
$04 is the day register
you read it; Hi2cin $4 ,B1
$05 is the month register
you read it; Hi2cin $5 ,B2
$06 is the year register
you read it; Hi2cin $6 ,B3
Now that you have these 4 values, write them in the EEPROM locations
EI: write 0,b0
write 1,b1
etc.
 

RNovember

Well-known member
It's not clear why you would be storing data at address 0 through 11, why there's so much data. Or why there's any need to store any date or time info per sample. Each sample will be six hours after the last so just the starting date and time would need to be stored.
Sorry, I forgot to explain that I am going to use an external EEPROM (26C16). It has space for 2048 bites.

This project is to measure the ground temperature every six hours, for as long as possible.

Since the readADC command has 8 bit resolution, it should be easy to convert it to a binary value, set outpinsB to that value, and since it is an external EEPROM, the address is controlled by 11 address lines, so it is stored in 00000000000. The next one is stored in 00000000001. Next is 00000000010, and so on.

So if it is 18:00 o'clock on August 22, 2019, and the binary temperature reading is 01100101, then the data would be stored in this fashion;

address 00000000000:
bite = 01100101

address 00000000001:
bite = 00010010(binary for 18)

address 00000000010:
bite = 00010110(binary for 22)

address 00000000011:
bite = 1000(month)1001(last digit of year)

It would only be able to run for 128 days at a time, and then you would have to get the data, erase the EEPROM, and start again.

Another question about RTC. Do you have to set the time and date and all the other settings registers before it will work properly?
 

The bear

Senior Member
Question: Whilst on the subject of RTC alarms (DS3231 in my case), I've had the RTC for two years, but unfortunately, due to lack of brain power, I'm unable to set the alarm/s. I've read the datasheet many times, to no avail. I've also searched the forum many times. If someone could point me in the right direction (KISs) I would be very grateful. Pity the alarm info in post #11 was for the Arduino and not the Picaxe.
 

hippy

Technical Support
Staff member
If someone could point me in the right direction (KISs)
Never used the DS3221 or alarm functions but I'll have a read of the datasheet and see what I would would best guess at. Others are more than welcome to chime in they have an answer.
 

hippy

Technical Support
Staff member
Sorry, I forgot to explain that I am going to use an external EEPROM (26C16). It has space for 2048 bites.

Since the readADC command has 8 bit resolution, it should be easy to convert it to a binary value, set outpinsB to that value, and since it is an external EEPROM, the address is controlled by 11 address lines, so it is stored in 00000000000. The next one is stored in 00000000001. Next is 00000000010, and so on.
I couldn't even find a 26C16 datasheet via Google, but if it is a good old fashioned parallel EPROM I would suggest you would be better off using an I2C EEPROM, particularly an RTC+EEPROM module as suggested earlier.

You won't need 11 address lines and 8 data lines, whatever RD and WR lines are required; plus two more lines for I2C, you could do it all with an 08M2.
 

RNovember

Well-known member
I couldn't even find a 26C16 datasheet via Google
You can find a datasheet here.

Looking through the PDF that cachomachine uploaded, it looks like the RTC doesn't have any way to set the time and date to where it actually is.

It seems to me that that would be an important feature. Am I missing something, or is there really no way?
 
Last edited:

cachomachine

Senior Member
The PDF program does it:

; Caution, the following line provides some date and time data to demonstrate the time of day alarm ; It is recommend that the reader try first to observe before setting with the current/actual date and time ;
secs,mins,hrs, day,date,month,year
HI2COUT 0, ($45, $53, $23, $01, $31, $03, $13) ;set the date and time as 23:53:45 31/Mar/2013
SERTXD ("Demo time is now set",CR,LF)
 

hippy

Technical Support
Staff member
Looking through the PDF that cachomachine uploaded, it looks like the RTC doesn't have any way to set the time and date to where it actually is.
An RTC doesn't have the current local time programmed into it when delivered but it can have its time programmed. That can either be done with a program download and by providing some other means for the time to be set; LCD plus buttons, GPS input, etc.
 

The bear

Senior Member
@cachomachine, Thanks for the pdf. Working on it.

Its all very technical (The RTC's). Ideally, I would like to put switches on the RTC to set the alarm/s, when I understand how things work.
I'm a hardware guy, but enjoying the Picaxe & forum.
 

hippy

Technical Support
Staff member
If someone could point me in the right direction (KISs) I would be very grateful.
The alarm setup seems quite straightforward though complicated by a variety of options.

There are two alarms which specify date and time information, including bits which along with DY/DT determines what sets off the alarm.

For Alarm 1 the following options are available -

Alarm once per second
Alarm when seconds match
Alarm when minutes and seconds match
Alarm when hours, minutes, and seconds match
Alarm when day, hours, minutes, and seconds match
Alarm when day of week, hours, minutes, and seconds match

Alarm 2 does not have any seconds value, is taken to have been "00", so only allows -

Alarm once per minute
Alarm when minutes match
Alarm when hours and minutes match
Alarm when day, hours, and minutes match
Alarm when day of week, hours, and minutes match

There are two status bits which are set high when an alarm fires, which need to be cleared by software.

In addition there are two control bits which allow each alarm to trigger the INT/SQW pin when an alarm fires if the INTCN control bit is set.

The hardware alarm function will be useful when it's powering up something from a powered-down state, or waking something from a deep sleep, but for most PICAXE uses it is likely easier to just read the date and time info and do any alarm activation matching in software. That also means one isn't reliant on using a particular RTC to provide alarm functions.

I would start with the following PICAXE code to set alarms if I were thinking of playing with the DS3231, all untested and unproven -
Code:
; DS3231 Definition

Symbol DS3231    = $D0 ; I2C Device

Symbol DAT_A1    = $07 ; Alarm 1 Registers
Symbol DAT_A2    = $0B ; Alarm 2 Registers

Symbol CTR       = $0E ; Control Register
Symbol CTR_A1IE  = bit0
Symbol CTR_A2IE  = bit1
Symbol CTR_INTCN = bit2
Symbol CTR_RS1   = bit3
Symbol CTR_RS2   = bit4
Symbol CTR_CONV  = bit5
Symbol CTR_BBSQW = bit6
Symbol CTR_EOSC  = bit7

Symbol STS       = $0F ; Status Register
Symbol STS_A1IF  = bit0
Symbol STS_A2IF  = bit1
Symbol STS_BSY   = bit2
Symbol STS_EN32K = bit3
Symbol STS_OSF   = bit7

; Alarm 1

#Macro A1(x,d,h,m,s)
  ; Disable Alarm 1
  HI2cIn  CTR, (b0)
  CTR_A1IE  = 0
  HI2cOut CTR, (b0)
  ; Clear Alarm 1 Flags
  HI2cIn  STS, (b0)
  STS_A1IF  = 0
  HI2cOut STS, (b0)
  ; Set Alarm 1
  b0 = x
  b1 = s / 10 * 6 + s : b1 = bit0 * $80 | b1 
  b2 = m / 10 * 6 + m : b2 = bit1 * $80 | b2
  b3 = h / 10 * 6 + h : b3 = bit2 * $80 | b3
  b4 = d / 10 * 6 + d : b4 = bit3 * $80 | b4 : b4 = bit4 * $40 | b4
  HI2cOut DAT_A1, (b1,b2,b3,b4)
  ; Enable Alarm 1
  HI2cIn  CTR, (b0)
  CTR_A1IE  = 1
  CTR_INTCN = 1
  HI2cOut CTR, (b0)
#EndMacro

#Define A1_EVERY_S()        A1(%11111,0,0,0,0) ; per second
#Define A1_S(s)             A1(%11110,0,0,0,s) ; seconds match
#Define A1_MS(m,s)          A1(%11100,0,0,m,s) ; minutes and seconds match
#Define A1_HMS(h,m,s)       A1(%11000,0,h,m,s) ; hours, minutes, and seconds match
#Define A1_DAY_HMS(d,h,m,s) A1(%00000,d,h,m,s) ; day, hours, minutes, and seconds match
#Define A1_DOW_HMS(w,h,m,s) A1(%10000,w,h,s,s) ; day of week, hours, minutes, and seconds match

; Alarm 2

#Macro A2(x,d,h,m)
  ; Disable Alarm 2
  HI2cIn  CTR, (b0)
  CTR_A2IE  = 0
  HI2cOut CTR, (b0)
  ; Clear Alarm 2 Flags
  HI2cIn  STS, (b0)
  STS_A2IF  = 0
  HI2cOut STS, (b0)
  ; Set Alarm 2
  b0 = x
  b1 = m / 10 * 6 + m : b1 = bit0 * $80 | b1
  b2 = h / 10 * 6 + h : b2 = bit1 * $80 | b2
  b3 = d / 10 * 6 + d : b3 = bit2 * $80 | b3 : b3 = bit3 * $40 | b3
  HI2cOut DAT_A2, (b1,b2,b3)
  ; Enable Alarm 2
  HI2cIn  CTR, (b0)
  CTR_A2IE  = 1
  CTR_INTCN = 1
  HI2cOut CTR, (b0)
#EndMacro

#Define A2_EVERY_M()     A2(%1111,0,0,0) ; per minute
#Define A2_M(m)          A2(%1110,0,0,m) ; minutes match
#Define A2_HM(h,m)       A2(%1100,0,h,m) ; hours and minutes match
#Define A2_DAY_HM(d,h,m) A2(%0000,d,h,m) ; day, hours and minutes match
#Define A2_DOW_HM(w,h,m) A2(%1000,w,h,m) ; day of week, hours and minutes match

; Example code

HI2cSetup I2CMASTER, DS3231, I2CSLOW, I2CBYTE
  
A1_MS(10,30) ; Alarm 1 once an hour at xx:10:30
A2_EVERY_M() ; Alarm 2 every minute
 
Last edited:

The bear

Senior Member
@RNovember, Apologies for butting in on your "Post".
Deep down, I hope my questions will help to give us both some understandable answers.
Its' been bugging me for two years.
@ hippy, thank you, but that (Post #26) I've no chance of deciphering. I will study it, to see if there are any snippets I can salvage.
 

hippy

Technical Support
Staff member
@ hippy, thank you, but that (Post #26) I've no chance of deciphering. I will study it, to see if there are any snippets I can salvage.
Best approach is to sit down with a datasheet and concentrate on two things; the register layout which shows which bits are used for what, and the section on setting alarms.

Then, take the code as is but a chunk at a time. For example -
Code:
  ; Disable Alarm 1
  HI2cIn  CTR, (b0)
  CTR_A1IE  = 0
  HI2cOut CTR, (b0)
Which stops Alarm 1 from triggering. It reads the Control Register ( register $0E from the SYMBOL and in the datasheet ), clears the A1IE bit ( bit0 ), then updates the Control Register with the new configuration. The same but setting A1IE to 1 will enable Alarm 1.

Get to grips with it a little at a time and it will hopefully all start to become clearer. You should start to see how the code does what the datasheet says to do. And do ask if there are things you don't understand, but don't expect to understand it all from the start.

Don't worry about not knowing from the off. It took me a few reads of the datasheet to get a good understanding of what it was saying.
 

RNovember

Well-known member
@RNovember, Apologies for butting in on your "Post".
No problem. You have helped me know how it works too.

If I understand right, if I were to write the picaxe program, it would go something like this.

pseudo code:

1. set time and date to current time and date
2. count 1 every time the square wave out goes high, until the number = 21,600
3. get the temperature, set it in the EEPROM
4. read from the addresses that you are interested in
5. set them in the EEPROM
6. loop to second line

I have just one more question.

I know the chip has a temperature sensor inside it. Can I the temperature from the chip?
 
Last edited:

hippy

Technical Support
Staff member
know the chip has a temperature sensor inside it. Can I the temperature from the chip?
You can. It should be as simple as -
Code:
HI2cSetup I2CMASTER, $D0, I2CSLOW, I2CBYTE
HI2cIn $11,(b1,b0)
That's a 9-bit msb aligned result in 'w0' so to turn that into an 8-bit value in 'b0' ...
Code:
b0 = w0 / $80
Then to write it to eeprom -
Code:
HI2cSetup I2CMASTER, $A0, I2CSLOW, I2CWORD
addr = addr + 1
HI2cOut addr, (b0)
But note the on-chip temperature sensor is only rated +/-3% so it's not going to be that accurate.
 

lbenson

Senior Member
1. set time and date to current time and date
Next, comment out that line and reprogram with the rest of your code. The time should be right ever after. You don't want an unexpected power off and on to reset to the wrong date and time.
 

RNovember

Well-known member
I have just one more question.
Sorry, I lied. I have one more Question.

Is there an I2C EEPROM that has 6kb of memory organized into 6000 8 bit pages?

If not, what EEPROM chip should I use?

(I lied again. That was two questions.)
 
Last edited:

hippy

Technical Support
Staff member
Is there and I2C EEPROM that has 6kb of memory organized into 6000 8 bit pages?
The 24LC64 and equivalents have 8KB. But you could, as noted, get away with 2K, or even go larger and store more samples -

24LC16 2KB
24LC32 4KB
24LC64 8KB
24LC128 16KB
24LC256 32KB
24LC512 64KB
 

MartinM57

Moderator
If I understand right, if I were to write the picaxe program, it would go something like this.

pseudo code:

1. set time and date to current time and date
2. count 1 every time the square wave out goes high, until the number = 21,600
3. get the temperature, set it in the EEPROM
4. read from the addresses that you are interested in
5. set them in the EEPROM
6. loop to second line
If you are just going to count the SQW going high transitions (i.e not use any alarm features, any kind of date/time comparisons or any of the battery backed up SRAM) then you don't need:
- line 1 at all
- a backup battery
...both giving considerable simplifications :)

The D3232 will start at 00:00:00 (for the time) at each power up, but as you're not using it, that doesn't matter

However, you do need to make sure that the SQW pin is enabled each time you power it up and at the correct frequency i.e 1Hz. All the details are in the datasheet, but ask if you're not sure how to do it.

HOWEVER, if your algorithm is just based on counting (accurate) 1Hz pulses and not relying on the other "Real Time Clock" features of the DS3232 then there may be other chips/subsystems (e.g. in the extreme. a GPS sensor with a 1PPS (pulse per second) very accurate output) that may be simpler and/or cheaper. I've not Googled it for you though :)
 

RNovember

Well-known member
What I meant in that code, in line three and four was get temperature, time and date from the RTC, and write them to the EEPROM.

I will use the SQW pin to time the picaxe so that it reads the temperature exactly every six hours.
 

MartinM57

Moderator
In that case, I can't see why you are using IMHO a somewhat risky strategy (needing to reliably count to 21600 100's of times per year to get an "every 6 hour event" in a presumably remote environment, putting your faith in power supply variations and xyx etc) when you have a top of the range battery backed RTC with alarms and day/month/year counting that you are not making any use of.

If you're wanting to record stuff at specific times e.g 0000, 0600, 1200 and 1800, then it would be a shame to come back after a year and find that it went wrong in month 2 and, although you got values every 6 hours for months 3 to 12, they went out of sync and were at the wrong times.

Anyway, good luck with your endeavours.

Martin
 

hippy

Technical Support
Staff member
If this temperature recorder is battery powered, then you might want to consider things which will maximise the lifetime of the battery.

The obvious solution would be to run at a low clock speed and to sleep as much as possible. Given the sleep period is about 2 seconds it won't be possible to catch all one second pulses, but you can mostly sleep for pretty long periods, minimising current draw, waking up more frequently and reading the RTC time as one gets to the time you want to take a sample to ensure it's smack-on. Something like -
Code:
Do
  Go into low power mode
  Read RTC time
  Calculate how long to the next sample time
  Subtract a small amount
  Do
    Sleep for as long as possible
    Subtract that from the amount we want to be sleeping for
  Loop until the sleep period has expired
  Read RTC
  Until a couple of seconds from sampling
    Sleep for a couple of seconds
    Read RTC
  Loop
  Come out of low power mode
  Do
    Read RTC
  Loop until exact sampling time
  Take sample, store it
Loop
 

RNovember

Well-known member
In that case, I can't see why you are using IMHO a somewhat risky strategy (needing to reliably count to 21600 100's of times per year to get an "every 6 hour event" in a presumably remote environment, putting your faith in power supply variations and xyx etc) when you have a top of the range battery backed RTC with alarms and day/month/year counting that you are not making any use of.
Because I thought that what you meant with...
I don't use the alarms as I use the ~INT/SQW pin in its SQW mode, outputting a 1Hz square wave to an interrupt pin that provides a (very) accurate time tick to the rest of my software.
was that it was better to use the SQW output for projects.
 
Last edited:

MartinM57

Moderator
OK, maybe my wording was not the best...I meant more like...

I don't use the alarms. I use the ~INT/SQW pin in its SQW mode, outputting a 1Hz square wave to an interrupt pin that provides a (very) accurate time tick to the rest of my software to do certain tasks every second, one of the many of them being reading and displaying the current RTC time value....

If I did have a requirement to do something periodically, with the period being say 6 hrs, and at certain times of the day, say 0000, 0600, 1200 and 1800 I would either:

1. use the alarm feature, use the INT/SQW pin as an INT pin to generate an interrupt to my software to say the alarm had fired (and then resetting the alarm to the next required time)

2. use the alarm feature, use the INT/SQW pin as an SQW pin at 1Hz to generate an interrupt to my software to poll the alarm flags (and if the alarm flag was set, clearing it and resetting the alarm to the next required time)

3. not use the alarm feature at all, but use the INT/SQW pin as an SQW pin at 1Hz to generate an interrupt to my software to read the RTC (time) and compare it with the time that I wanted to do the task at

I'd probably start my investigations/prototyping with #1.

;)
 
Top