Compiler doesn't honour "volatile"

30 views
Skip to first unread message

Oliver Seitz

unread,
Nov 27, 2020, 1:51:12 AM11/27/20
to Jallib
Sorry... This isn't in fact the proper list for compiler issues, is it?

This one is probably more severe. I'll start with the example. This is the data I've received:

?2807   2808    1
?2807   2809    2
?2807   2810    2
?2807   2811    4
?2807   2812    4
?2807   2813    6
?2807   2814    7
?2807   2815    8
?2807   2816    264

It's generated from this part of code, running on an PIC18F27K42. extra_time is increased in an interrupt every 16 seconds. It is declared as var volatile word, so the compiler should make sure that the bytes of the variable are in a consistent state:

  diff=word(extra_time-last_pulse_time_uw)

  if print_debug then
    print_debug=false
    serial="?"
    print_word_dec(serial,last_pulse_time_uw)
    serial="    "
    print_word_dec(serial,extra_time)
    serial="    "
    print_dword_dec(serial,diff)
    print_crlf(serial)
  end if

Let me repeat some of the results above in hex:


AFE-AF7    =7
AFF-AF7    =8
B00-AF7    =108

So, what has happened? The last line is clearly wrong. The subtraction was done just as extra_time was in the process of increasing. The low byte was processed before, the high byte was processed after the interrupt fired. So the actual subtraction done was BFF-AF7, with the result of 108.

I've had a look at the asm file. Both bytes of the variable are just handled one after the other, both in the main program and in the interrupt service routine. The "volatile" declaration does not seem to do anything.

Greets,
Kiste

Rob CJ

unread,
Nov 27, 2020, 5:39:04 AM11/27/20
to jal...@googlegroups.com
Hi Kiste,

Hmm, my next puzzle for the weekend. Can you send a complete sample program that I can use? It will save me time.

BTW. Did you already test the new build compiler that solves the memory issue?

Thanks.

Kind regards,

Rob


Van: 'Oliver Seitz' via jallib <jal...@googlegroups.com>
Verzonden: vrijdag 27 november 2020 07:44
Aan: Jallib <jal...@googlegroups.com>
Onderwerp: [jallib] Compiler doesn't honour "volatile"
 
--
You received this message because you are subscribed to the Google Groups "jallib" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jallib+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jallib/1713803051.2007385.1606459457507%40mail.yahoo.com.

Oliver Seitz

unread,
Nov 27, 2020, 6:28:35 AM11/27/20
to jal...@googlegroups.com
Hi!

Yes, thanks, memory is fine, the data logger is up and running, storing 2048 values at 24 bit resolution, great! :-)

I have a program, but it uses a watch crystal and counts external pulses. And, for saving time... I've now seen the error three times within ten days. 

Thinking again about the issue, I'm not really sure if "volatile" is the right term to describe the problem. "volatile" specifies, that for every read/write in the source code, exactly one read/write in the machine code is done. 

Perhaps it is up to the program author to ensure the correct reading outside of the interrupt if a variable is modified inside the interrupt and vice versa. Then it would be a subject of documentation. Which, by the way, I didn't read :-D

But, while disgressing already, a bit to make JAL popular and usable...
Where is the official documentation? I lately had to place byte variables over dword variables and couldn't find the syntax in any document, only placing bits. I kind of tried luckily with var byte name1 at name2+byte_offset. 

(Ok, found the website and the language reference. But no byte offsets :-) )

Greets,
Kiste

Am Freitag, 27. November 2020, 11:39:06 MEZ hat Rob CJ <rob...@hotmail.com> Folgendes geschrieben:


Rob CJ

unread,
Nov 27, 2020, 12:54:07 PM11/27/20
to jal...@googlegroups.com
Hi Kiste,

Some answers to the things you mention.

About volatile variables. This is what the JAL documentation says about is.

"The VOLATILE keyword guarantees that a variable that is either used or assigned will not be optimized away, and the variable will be only read (or written) once when evaluating an expression.Normally, if a variable is assigned a value that is never used, the assignment is removed and the variable is not allocated any space. If the assignment is an expression, the expression *will* be fully evaluated. If a variable is used, but never assigned, all instances of the variable will be replaced with the constant 0 (of the appropriate type) and the variable will not be allocated any space."

Volatile is especially needed if a perhiperal would update a variable since the compiler does not know that and so it would optimize it away since it does not 'see' that the variable is used by the program

About documentation. The JAL documentation is in the 'compiler' directory that is present in the install or the bee-package.

You are right that the documentation does not talk about mapping bytes onto words. I could add that as an example since it is something which is used quite often.

Then my thoughts about the issue you mention. I see that you are updating a word value (not a byte value) and since the PIC is byte oriented a word consists of two bytes. Updating a word value requires several instructions and I can imagine that if an interrupt occurs exactly in between these instructions that things go wrong. What you would need is a semaphore but since we do not have that, a way around is that you before printing your word you disable that specific interrupt that is also updating that same word. If you do not want to delay the interrupt too much because of the print function you could also do the following:
-) Disable the interrupt
-) Copy the word value to a local word variable
-) Enable the interrupt

Kind regards,

Rob



Van: 'Oliver Seitz' via jallib <jal...@googlegroups.com>
Verzonden: vrijdag 27 november 2020 12:28
Aan: jal...@googlegroups.com <jal...@googlegroups.com>
Onderwerp: Re: [jallib] Compiler doesn't honour "volatile"
 

Oliver Seitz

unread,
Nov 27, 2020, 3:17:38 PM11/27/20
to jal...@googlegroups.com
Hi Rob!

So we *do* have REPEAT/UNTIL, I thought to miss it just today :-D

Thanks for the hint. Earlier today I only found an older version of the documentation which contained just that problematic example: increasing a word variable inside an interrupt, but that example is gone (or shortened) in the current version.

Yes, stopping the interrupt before reading the variable would be a simpe solution, but I wanted to time my pulses as accurate as possible. I can't disable just the timer update interrupt, as another interrupt copies the timer value. The hardware timer keeps running, and so the timer values may become inconsistent for the interrupt-on-change. Ok, I already handled that inconsistency for it can occur very rarely even without stopping the interrupt, but I did not want to stop it. Well, and I did not think of just stopping that very interrupt, I only thought about stopping all interrupts. 

As the place where the actual problem was right now is a very unimportant one, I have two very simple solutions:

If the low-byte value is larger than 253, just skip that part of the program this time.

Or, what I did now:

var volatile word check_value
REPEAT
  check_value=changing_value
  result=changing_vaue-whatever
UNTIL check_value==changing_value

It would be sufficient to only check the high-byte.

Thanks again for answering even my stupid questions ;-)

Greets,
Kiste
 

Am Freitag, 27. November 2020, 18:54:08 MEZ hat Rob CJ <rob...@hotmail.com> Folgendes geschrieben:


zmafoox

unread,
Nov 27, 2020, 6:19:11 PM11/27/20
to jallib
You seem to be confusing a volatile operation from an atomic one - volatile means just what it says, the results will not be cached, and a write will happen once. Since the PIC is byte oriented, any read of a value greater than a byte has to be done in multiple operations. There is no way to make these operations atomic, so you need to do this yourself. It's been a while, but if I recall the order is:
read the LSB
read the MSB
read the LSB2 (read the LSB again)
if LSB2 < LSB
  read MSB
again, I might be wrong. It's been a long time...

Oliver Seitz

unread,
Nov 28, 2020, 2:09:04 AM11/28/20
to jal...@googlegroups.com
Hi!

You're right, thats what I meant, and I also was in the (now obviously wrong) belief that the compiler had to take care of that problem. At first, I thought there must be a simple solution, but smarter people than me haven't found one ;-)

Perhaps one of th cheapest solutions in PICs is like that:

var word changing
var bit change_happened

procedure isr
pragma interrupt
  changing=new_value
  change_happened=true
end procedure

...

REPEAT
  change_happened=false
  value=changing
UNTIL ! change_happened

It costs only one bit of RAM, one (or at most three) code words in the interrupt and also the reading does not have to compare bytes.

Greets,
Kiste


Am Samstag, 28. November 2020, 00:24:23 MEZ hat zmafoox <googl...@casadeyork.com> Folgendes geschrieben:


--
You received this message because you are subscribed to the Google Groups "jallib" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jallib+un...@googlegroups.com.

Rob CJ

unread,
Nov 28, 2020, 2:12:24 AM11/28/20
to jal...@googlegroups.com
Hi Kiste,

They always tell me that there are no stupid questions 😊

Can you send me the text you found from an older document? Yesterday I updated the JAL manual with one of your remarks that the mapping of byte variables was not mentioned. I also added the little-endium issue that was not clear (reported by Fraser). This update will be in the next bee package.

Another suggestion, can you use some kind of ring buffer? As long as you can keep up the reading with the writing then you could write data in the ring buffer, adjust the write pointer, read the data (if write pointer and read pointer are different) and read the data. So the interrupt routine only writes data to a location which is not read.

Kind regards,

Rob



Van: 'Oliver Seitz' via jallib <jal...@googlegroups.com>
Verzonden: vrijdag 27 november 2020 21:10

Oliver Seitz

unread,
Nov 28, 2020, 2:43:06 AM11/28/20
to jal...@googlegroups.com
Hi Rob,

strange... I don't find it anymore. It was something like word variables named bb and cc which were incremented in an example for "pragma interrupt".

That other suggestion is quite interesting. If I had to read the value frequently and quickly, I'd go that way. About like this:

I'd have one counter, and two buffer variables which are written by the interrupt. As the "ring" has only two places, it's called a ping-pong buffer. Then, there's a bit which indicates which of the two buffers will be written next by the interrupt. The main program would be reading the other buffer, that is not sceduled for writing.

Inside the interrupt, the counter is incremented, the value is copied to the indicated buffer, and the buffer pointer bit is toggled.

Greets,
Kiste
Am Samstag, 28. November 2020, 08:12:27 MEZ hat Rob CJ <rob...@hotmail.com> Folgendes geschrieben:


Reply all
Reply to author
Forward
0 new messages