No conflicting commands, but timer1 playing up.

Buzby

Senior Member
Hi All,

I am playing around with the 'count' function of timer1.

Hardware is a 28X2-5v module, firmware B.2.

The setup is a PWM output hardwired to clock timer1 at 10KHz, with timer1 preloaded to increment every 10 clock pulses.

This means timer1 should increment every 1ms.

The attached code loops waiting for timer1 to be greater than 999.
The value should always be 1000, because at 32MHz the PICAXE reads the timer well before the next increment is due.

If the value is not 1000 then a line is sent to the terminal.

When the code runs it prints the 'not 1000' message at irregular intervals.

I know there are conflicting commands that can cause strange behaviour, but I don't think I'm using any.

What is causing this behaviour ?

Cheers,

Buzby
 

Attachments

hippy

Technical Support
Staff member
What is causing this behaviour ?
Pass, but I'd trim the code down to the bare minimum so it's easier to see what is going on, and also start with default speed to check if it's an issue related to speed. If all that does work, add things to see what breaks it. If it doesn't start looking to see what it could be.

This seems to work on a 28X2 firmware B.3 ...

Code:
#picaxe 28X2
#no_table
#no_data
#Terminal 38400

setfreq em32
pause 4000
sertxd ( "Started",CR,LF )

pwmout pwmdiv4, C.1, 199, 400 ' 10kHz

settimer count 65526 

tmr3setup %10000001

do
	do
	  w1 = timer
	loop until w1 > 999
	timer = 0
	sertxd ( #w1, CR, LF )
loop
Would be interesting to see what happens on the 28X2-5V. Will test on my own later.
 

Buzby

Senior Member
Hi hippy,

I'm running your code, it's printing 1000 every loop.

But you are running timer1 and using sertxd at the same time, so why is it not going pear-shaped ?.

My code only uses sertxd (a) before the timer is started, and (b) when the count is not 1000.

I'll add bits to your code until it goes wrong !.

Cheers,

Buzby

Edit : Spoke too soon !!!. It just printed a 1023.
 

Buzby

Senior Member
I'm now running this code, and it printed '1023' three times in four minutes.

Code:
#picaxe 28X2
#no_table
#no_data
#Terminal 38400

setfreq em32
pause 4000
sertxd ( "Started",CR,LF )

pwmout pwmdiv4, C.1, 199, 400 ' 10kHz

settimer count 65526 

tmr3setup %10000001

do
	do
	  w1 = timer
	loop until w1 > 999
	timer = 0
	if w1 <> 1000 then
		sertxd ( #w1, CR, LF )
	endif
loop
 

hippy

Technical Support
Staff member
Edit : Spoke too soon !!!. It just printed a 1023.
Only printing when not 1000 I also get that, on 28X2 (B.3) and 28X2-5V (B.1). Only rarely though; about four in the last hour or so using version B.3

Always 1000 or 1023. Odd it's $3FF which might be significant.

I've left it running, printing w1 and timer before setting timer=0 to see what happens. Sod's law of course says it's never going to be anything but 1000 now :)

The reason it didn't all go pear-shaped when I was always using SERTXD is probably internal interrupts while doing that being ignored so 'timer' running slow but not enough to notice visually.
 

Buzby

Senior Member
Only rarely though; about four in the last hour
I've not seen a 1023 for 15 minutes !.

The $3FF does seem significant, and the fact you see it on B.1 and B.3.

I have a suspicion about the serial connection.

I'm going to write a 'stand alone' version which will just set an LED on when it sees the first non-1000.

We'll get to the bottom of this !.

Cheers,

Buzby
 

hippy

Technical Support
Staff member
Code:
do
	do
	  w1 = timer
	loop until w1 > 999
	If w1 <> 1000 Then
	  sertxd ( #w1, " [", #timer, "]", CR, LF )
	end if
	timer = 0
loop
After 15 minutes of only 1000 in w1, a "1023 [768]" result. Interestingly "$3FF [$300]". I guess we'll look deeper into that.
 

Technical

Technical Support
Staff member
Not sure on this one, but why use the w1 variable at all? - what happens if you use
loop until timer > 999
directly instead?
 

Buzby

Senior Member
The idea of using a variable is because when I print it I want the value at the 'compare' time, not the 'print' time.

I was caught out many years ago with a PLC program where I read a 1s timer twice within a few ms, expecting it to have the same value.
Unbeknown to me the timers on this particular PLC could change between instructions, not at the end of the scan like every other I'd used.

The plant was moving barrels of oil, and after days of troubleshooting an error that only occurred every few thousand barrels, but had significant consequences, I learn't my lesson !.
 

Buzby

Senior Member
Code:
a "1023 [768]" result.
I did see a few 768's earlier, when my code was more complex ,but they were very rare.

How 'w1 > 999' can result in w1 printing 768 is beyond me !.

The plot thickens.

Cheers,

Buzby
 

Technical

Technical Support
Staff member
Suspect it is the timer value 2FF overflowing to 300 via the silicon activated event.

'w1 = timer' is a firmware PICAXE command, whereas 2FF incrementing to 300 is silicon based on an internal interrupt.

However as w1 and timer are words, they cannot be transferred in one hit, it has to be two consequative bytes, which takes a distinct time to happen.

So at some points during the processing of 'w1 = timer'

- timer currently = 2ff, low-byte FF copied across to low byte of w1
- timer interrupt fires, timer increments to 300
- high byte gets copied across to w1, but is now 3 not the expected 2

so w1 ends up at 3FF, when it should of been 2FF (or 300)

The only way to avoid this is to turn timer off whilst copying the variable across to w1. But that would mean you may then miss events.... so a no-win situation.
The workaround here is quite simple, either do the test "> 999" on timer directly instead of w1, or simply ignore the value w1=3FF completely via

Code:
    loop until w1 > 999 and w1 <> $3FF
 
Last edited:

Buzby

Senior Member
Hi Technical,

That sounds like a very plausible explanation.

I'm now running code with 'w1 > 99'. This fits in one byte, so we should never see the problem.

do the test "> 999" on timer directly
Would this not have the same issue, because the ">" is firmware comparing 16 bit values, but timer is still two separate bytes ?.

I've not done assembly level programming for a while, but I do remember one chip had a two byte capture buffer 'in parallel' with a two byte counter. The buffer was loaded from the counter in a single action, but was read with two, thus avoiding rollovers during reading. Do PICs have similar ?.

There must be hundreds of programs out there where 'timer' is copied to a variable, maybe for datalogging or race timing.
More worryingly, does it apply to every read of a two byte hardware value, such an ADC ?

It was purely by chance I saw this, as I've only ever used the timer overflow before, not the actual timer value, but I shall be aware in the future.

Cheers,

Buzby
 

MartinM57

Moderator
I've often wondered about atomicity in PICAXE BASIC and always assumed that "under the covers" the PICAXE firmware deals with it appropriately....in assembler/C/compiled BASIC you nearly always need to take special care with copying greater-than-one-byte values from hardware maintained registers (especially timer value registers) into code variables (reading bytes in a certain order, temporarily turning off interrupts etc)
 

Buzby

Senior Member
I've often wondered about atomicity in PICAXE BASIC ...
Well now you know !.

It's a veritable trap for the uninformed.
The vast majority of programmers never get near hardware, and the textbook description of 'Let X = Y' doesn't have ", usually." added on the end.

I think a few atomicity tests on other aspects of PICAXE are in order, but I've had enough for tonight !.

Cheers,

Buzby
 

Buzby

Senior Member
Hi,

A new morning, and a review of last night's conversations opens up a new question.

In posts #8 and #11 both hippy and myself saw occassional results of 768 mixed in with the 1000's and 1023's.

Technical has explained how 'w1 = timer" can put the wrong value in w1, but the 768 is something different.

Consider this,
Code:
Line 1, do
Line 2, w1 = timer
Line 3, loop until w1 > 999
Even if w1 gets the wrong value assigned in Line2, it should not exit the loop at Line3 until w1 is *greater than* 999.
So why did w1 sometimes have a value of 768 after the loop end comparison ?

Cheers,

Buzby
 

Buzby

Senior Member
Hi hippy & Technical,

Extract from PIC18F2520 datasheet :
12.2 Timer1 16-Bit Read/Write Mode
Timer1 can be configured for 16-bit reads and writes
(see Figure 12-2). When the RD16 control bit
(T1CON<7>) is set, the address for TMR1H is mapped
to a buffer register for the high byte of Timer1. A read
from TMR1L will load the contents of the high byte of
Timer1 into the Timer1 high byte buffer. This provides
the user with the ability to accurately read all 16 bits of
Timer1 without having to determine whether a read of
the high byte, followed by a read of the low byte, has
become invalid due to a rollover between reads.
So I've answered my question from post #13, the PIC does have a way to read timer1 without rollover problems occuring.

Does the PICAXE firmware use this facility ?

Cheers,

Buzby
 

hippy

Technical Support
Staff member
]Even if w1 gets the wrong value assigned in Line2, it should not exit the loop at Line3 until w1 is *greater than* 999.

So why did w1 sometimes have a value of 768 after the loop end comparison ?
That's what initially intrigued me, and more so than why 'timer' may have been wrong. With the trimmed-down test code neither of us have seen that happen, so with the tangent of 'timer' values out of the way, it's time to return to analysing that.


the PIC does have a way to read timer1 without rollover problems occuring.

Does the PICAXE firmware use this facility ?
From the outcome seen I'd guess not but would defer to Technical's response on that.

More worryingly, does it apply to every read of a two byte hardware value, such an ADC ?
The answer to that is no, READADC/10 won't be affected. There can only ever be a potential issue when a word entity is being read at the same time as it is being updated by something else and that would not happen with ADC. READADC/10 selects the channel, triggers the conversion, waits for it to obtain a result, reads that into a variable then continues. Nothing would be altering that result while being determined or being read.

Atomicity is an fun subject. I bet there are loads of Basic programs out there which have something like -

Code:
today$ = date$ + " " + time$
where no one has spotted the potential flaw but I expect few have fallen foul of it.

It is a similar issue as speculated with the MSB/LSB of timer, if there's a midnight rollover between reading date$ and reading time$ you get an incorrect value in today$.

The standard safety trap is -

Code:
Do
  today$ = date$ + " " + time$
Loop Until today$ = date$ + " " + time$
The same can be applied to the timer in this case -

Code:
Do
  Do
    w1 = timer
  Loop Until w1 = timer
Loop until w1 > 999
I've not tested that, but it should resolve any rollover issue.
 

Buzby

Senior Member
Hi hippy,

I left a 'complex' version running for the last 6 hours. It gave a dozen 1023's, and no 768's.

Not much chance to try any more tests till tonight, but if you can replicate the 768 scenario that would be good.

Cheers,

Buzby
 

hippy

Technical Support
Staff member
I left a 'complex' version running for the last 6 hours. It gave a dozen 1023's, and no 768's.
I'm wondering if it ever did give a result of 768 ? Whether that was a result of adding or changing debugging info and then getting confused over what was being seen ?

A variable being assigned a value > 999 and then holding a value <= 999 would be most remarkable if there was nothing to change the variable in the intervening period. I haven't seen any evidence of that and, IMO, it's far more likely to have mistakenly believed the variable was holding a wrong value when it wasn't which looks like the mistake I made.

In my case it was thinking 'w1' held the timer value read in the original code when it didn't. I misinterpreted what the screenshot was showing.
 

Buzby

Senior Member
it's far more likely to have mistakenly believed the variable was holding a wrong value when it wasn't
I'm not so sure. My 768's occured many seconds after the PICAXE was reset, well after every variable had been re-written hundreds of times.
 

Buzby

Senior Member
Well, I've been trying to replicate the 768 result for hours - no joy.

I have concur with hippy that we both must have made some kind of observational error.

Regarding the rollover error, it's easy to replicate, and works on other FF to 00 boundarys.

I'm going to get back to my original experiments, bearing in mind this new knowledge.

Cheers,

Buzby
 

Buzby

Senior Member
Hi hippy and Technical,

I just couldn't resist trying one more experiment with this timer rollover issue.

Replaced external clock from PWM with internal clock from pre-scaler, expecting issue to still exist.

It does, so no surprise there.


But then the 768 thing that I tried for hours to replicate yesterday happened !. And I got a screen shot !

This is not an observational error, or finger trouble, or programming error.

But there must be some explanation, and I'd like to find out what it is.


I do know sertxd might be causing some issue, as hippy explained, it might be causing the count to slow because of missed interupts.

That still doesn't explain how 768 gets past the > 999 test.

So maybe its not 768 at the test time, maybe it changes to 768 later, maybe at the print time ?

I need a break !.

( Oh, and you probably saw I'm all at sea again, but this time with a good subset of my PICAXE kit !. )

Cheers,

Buzby
 

Attachments

Buzby

Senior Member
Hi again,

The code that generated the 768 only did this rarely, so I tried to tweak it to make it more consistent.

The result a bit messy, and it generates 770 ( not 768 ), but a lot more frequently.
The code it doesn't need are the PWM, timer3, and the stuff after the last loop.
Also, the comments are a bit out of date.
I've not tidied it up in case it stops doing it !.

Code:
' x768_v1

#picaxe 28X2 ' 5v version

#no_table
#no_data

Symbol timer_1    = w0	' Copy of 'timer' value
Symbol loop_count = w1  ' Count the loops
Symbol lc10       = w2	' Loop_count MOD 10, just for testing
Symbol timer3dif  = w3	' Difference in timer3 value for each loop
Symbol timer3old  = w4	' Used to calculate timer3dif

Symbol timer_clk  = C.0	' Timer 1 clock input :: Link these two pins together
Symbol PWMoutput	= C.1 ' PWM output pin      :: PWM out feeds into timer_clk  
Symbol StatusLED  = C.2	' LED to show code is running
Symbol ErrorLED   = C.3 ' LED to show an error has occured 

' Run fast
setfreq em32

' Say hello
sertxd ( "x768_v1",CR,LF )

' Start PWM at 10KHz with duty 50%
'pwmout pwmdiv4, PWMoutput, 199, 400
pwmout PWMoutput, 79, 160
' Set timer3 on, with 1:1 prescalar
tmr3setup %10000001 

' Set timer 1 Divide by 10
settimer 65526 

' Main loop
do
	do
		' empty loop	
	loop until timer > 999
	    sertxd ( "T ", #Loop_Count, " ", #timer_1, " ", #timer, 13,10 )  
	timer = 0
loop	
	
	' Test only, print every 10th loop
'	lc10 = loop_count // 10
'	if lc10 = 0 then'
'		sertxd ( "T ", #w1, " ", #timer_1, " ", #timer3dif,13,10 )
'	endif


	
	' Timer should always be 100, print details if not.	
	if timer_1 <> 1000 then
		sertxd ( "  ", #w1, " ", #timer_1, " ", #timer3dif, 13,10 )
		high C.3
	endif	
	
	' 
	inc loop_count	
	toggle StatusLED
As you can see, the code does not assign the timer to a variable, it is just used as 'timer' or '#timer'.

The code is 'slower', in that the print is relatively much later than the test, that's why the normal result is 2 or 3 counts above the 1000/768.


Studying the PIC datasheet I can't see any interrupt which is involved in the actual counting, only one for the final FFFF-0000 rollover, which we never get to.

I really would like to know what's causing this, so I don't ever do it a real project.

Cheers,

Buzby
 

Attachments

Buzby

Senior Member
Hi hippy & Technical,

I made a boo boo :eek:

It was late last night when I posted my findings. I should have been asleep, and maybe I was !.

The '>' comparison and the 'sertxd' will be expected give different results, this is correct operation.
The rollover problem just highlights a few times it happens.

I think, again, that the problem is nothing more than the firmware misreading the counter.

Cheers,

Buzby
 

boriz

Senior Member
Could it be the PC losing part of the serial data due to timing issues? Does tweaking the Picaxe serial frequency change anything? Could some other software running on your PC be interrupting your serial receive?
 

Buzby

Senior Member
Hi boriz,

I've spent a lot of time testing different things, including running the PICAXE with no PC, and reporting the results by flashing LEDs.

It is highly probable that the rollover fault is in the firmware, as per Technical's explanation a few days ago.

The other issue I thought existed, 768/770, is not real. It was a combination of overwork and not enough sleep !.

You can run the code yourself if you've got an X2.
The 'z768_v1' code does not use the PMW to C.0 link, so you can run this just on the chip, with no extra wiring.
Although I used a 28X2-5v it should run on any X2. ( I've got a 20X2 here, but no download socket !!! )

If you, or anyone else, runs this code and gets the same results, then we can rule out something on my PC.

Cheers,

Buzby
 

hippy

Technical Support
Staff member
The other issue I thought existed, 768/770, is not real. It was a combination of overwork and not enough sleep !.
It happens :)

I think you've recognised what is happening now - the timer is going from $2FF to $300, but gets misread as $3FF (1023) so exits the DO-LOOP as > 1000, but when it's subsequently printed it's the correct $300 (768) value that's shown.

A fix here is likely to be -

Do
Loop Until timer > 1000 And timer > 1000

The rollover misread ($3FF) won't happen during both comparisons so the loop won't exit until timer really is > 1000
 

Technical

Technical Support
Staff member
Hi hippy & Technical,

Extract from PIC18F2520 datasheet :

So I've answered my question from post #13, the PIC does have a way to read timer1 without rollover problems occuring.

Does the PICAXE firmware use this facility ?

Cheers,

Buzby
Yes it does. But the issue here is not to do with that timer1 register anyway. It is to do with the timer word variable, which are two completely different registers.
The issue will only apply to 'timer', not anything else such as readadc, w1 etc. It's a unqiue issue to the 'timer' variable as it can change 'in the background' when other things are going on.

The 'is it a bug' argument is simply that you could argue that the timer variable should be prevented from changing when it is being read/written during any other BASIC mathematical command (such as w1 = timer). The problem with that is you can then end up missing events, and timer becomes less accurate. However the current situation is admittedly not ideal and so now we are aware of it we will look into it further.
 
Last edited:

Buzby

Senior Member
Hi Technical & hippy,

It's good to know that the PIC '16 bit register read' is being used, that eliminates one source of the rollover problem, but the problem is still there !.

I can envisage two ways that the PICAXE firmware could be written :

1 - The PIC 16 bit register is copied to the PICAXE 'timer' variable only when a 'timer' or '#timer' instruction is evaluated in an expression.
The copy can take any number of PIC instructions to execute, but the 16 bit value will be fixed throughout each 'timer' or '#timer' evaluation, because it has been read once with a single PIC instruction.
This does mean that a single expression with multiple 'timer' or '#timer' elements could have different values in each element, but they would all be consistent, with no rollovers.

2 - The PIC 16 bit register is copied to the PICAXE 'timer' variable in the background, at some level that can overlap the evaluation of the 'timer' instruction.
Evaluation of the 'timer' instruction then involves normal firmware byte-by-byte transfers from the 'timer' variable, but the variable could change between these, so rollover artifacts are possible.

The two methods have pros and cons.
Method 1 has specific firmware requirements for when an operation on the 'timer' variable is required, which means a departure from the 'normal' instruction interpreter flow, but has no drawbacks for the user.
Method 2 allows the 'timer' variable to be treated just the same as any other variable ( for reads anyway ), which does not add any complexity to the interpreter, but has the rollover issue.

This second method seem similar to what Technical says here :
It's a unqiue issue to the 'timer' variable as it can change 'in the background' when other things are going on.
But I do not agree with what the below statement says :
... you could argue that the timer variable should be prevented from changing when it is being read/written during any other BASIC command (such as w1 = timer). The problem with that is you can then end up missing events, and timer becomes less accurate.
Setting a flag in the intepreter to inhibit changes to the 'timer' variable, as opposed to the PIC timer register, will :

(a) not stop the PIC hardware from counting, so timer accuracy is not affected.
(b) not prevent the FFFF-0000 interrupt, so the usual 'timer' overflow still occurs.
(c) not miss any events, unless the user writes expressions like 'IF timer = ', which could be seen as bad practice anyway.

Anyway, it's good that we've found this issue, and Rev-ed are taking it on board.

And for hippy :
I think you've recognised what is happening now - the timer is going from $2FF to $300, but gets misread as $3FF (1023) so exits the DO-LOOP as > 1000, but when it's subsequently printed it's the correct $300 (768) value that's shown.
Yes that's it, and there is a way to prove it.

The loop should run a fairly fixed number of times if it always exits correctly at 999. At 768 it will be 25% low, so putting a count inside the loop, then test it after exit, would show this.
Another method would be to continuously sertxd #timer out to a PC, which would then compare the incoming values and spot discrepancies. ( But it's cool to get the PICAXE to diagnose itself ! )

Don't you just love debugging 'under the hood' ? :D
 
Top