View previous topic :: View next topic |
Author |
Message |
Sarek
Joined: 15 Oct 2009 Posts: 72
|
Posted: Tue Apr 29, 2014 4:04 pm Post subject: Warning: accessing bit variables are not atomic |
|
|
If you use bit variables in your program, the code generated by bascom compiler could cause strange problems.
the compiler reserves the space for bit variables at the same sram-byte.
This could cause problems with using bits in interrupts.
Code: |
for example:
DIM mybit_mainloop As Bit
DIM ...... As Long
DIM ...... As Long
DIM ...... As Long
DIM ...... As Long
DIM ...... As Long
DIM mybit_interrupt As Bit
Do
...
...
...
Reset mybit_mainloop
...
...
Loop
Int_abc_isr:
Set mybit_interrupt
Return
Int_xyz_isr:
If mybit_interrupt = 1 Then
Reset mybit_interrupt
...
... do something
End If
Return
|
In this code above in interrupt Int_abc_isr there is bit set for the
second Interrupt Int_xyz_isr as Marker to do something.
If the mainloop was interrupted at the line:
Reset mybit_mainloop
it will happen that the bit => mybit_interrupt is reseted immediately when
the program goes back to main loop.
So bit variables should never be used in interrupts !!!
There could be a consistency problem because the compiler reserves SRAM at the same byte.
imho this could be a compiler bug
(BASCOM-AVR version : 2.0.7.7 ) |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Apr 29, 2014 7:17 pm Post subject: Re: Warning: accessing bit variables are not atomic |
|
|
Sarek wrote: | imho this could be a compiler bug |
Surprise, surprise - the bug is behind the screen
It's a moot issue and well known.
Quote: | So bit variables should never be used in interrupts !!! |
Any access, even to 8 bit variables, which is translated to more than a single opcode, for example any read/modify/write, must be made atomar in the main code, if also accessed by ISR code.
It's not the compiler's duty to take care of that. |
|
Back to top |
|
|
Neill
Joined: 08 Dec 2008 Posts: 50
|
Posted: Thu May 01, 2014 6:04 am Post subject: |
|
|
I like to use bits, they can be very useful.
What I do is ensure that each bit has it's own RAM location like this:
DIM tick as bit
DIM dummy_tick_1 as bit
DIM dummy_tick_2 as bit
DIM dummy_tick_3 as bit
DIM dummy_tick_4 as bit
DIM dummy_tick_5 as bit
DIM dummy_tick_6 as bit
DIM dummy_tick_7 as bit
Yes it's clumsy but for me it's the easiest way around the issue.
You can use the Show Result feature in the IDE to check where the bits are stored. |
|
Back to top |
|
|
StefanHamburg
Joined: 02 Mar 2008 Posts: 73 Location: Germany
|
Posted: Thu May 01, 2014 11:32 am Post subject: |
|
|
Then you also could use Byte-Variables.
But this is a matter of storage while the threadowners concern was related to timing and writing to variables from different code segments. |
|
Back to top |
|
|
Evert :-)
Joined: 18 Feb 2005 Posts: 2156
|
Posted: Thu May 01, 2014 8:37 pm Post subject: |
|
|
StefanHamburg wrote: | Then you also could use Byte-Variables.
|
It's also faster then using a bit
Code: |
Dim Mybit as bit
Dim Mybytebit as Byte
Mybit=1 'Takes 5 cycles
Mybytebit =1 'Takes 3 cycles
|
_________________ www.evertdekker.com Bascom code vault |
|
Back to top |
|
|
Paulvk
Joined: 28 Jul 2006 Posts: 1257 Location: SYDNEY
|
Posted: Thu May 01, 2014 11:31 pm Post subject: |
|
|
"It's also faster then using a bit "
I found that it used less flash when working with the matrix clock where I had to get as much out of the Mega8 as I could
Regards Paul |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Fri May 02, 2014 9:23 pm Post subject: |
|
|
there is no single instruction that can alter a bit of a variable. so a read/write instruction on any memory location is not atomic by default. it is not a bug.
the same thing applies to bytes, ints, etc.
the alternative would be to disable interrupts before writing to a variable used in an ISR and enable it afterwards. I could add such an option. But then one looses control on where/when interrupts are enabled/disabled.
And since the compiler can not know if interrupts are active at that stage, extra code is need to be used instead of a simple cli/sei. sreg need to be read to know the I status and must only be enabled when it was active otherwise interrupts would be enabled even when they were not active.
But TS is right that for bits a warning is important since it is not obvious that these bits are shared in one byte. i will think about a good solution. _________________ Mark |
|
Back to top |
|
|
Arera
Joined: 23 Sep 2007 Posts: 386 Location: Wuppertal, Germany
|
Posted: Tue May 06, 2014 12:20 pm Post subject: |
|
|
I'm confused, and I do not understand a thing.....
I may not use bit-vars in ISRs? I may not change any vars in ISRr.
I have to care to make vars atomic???? What does that mean? I read the interrupt chapter of the help again, but all I understand is, when using SAVEALL I don't need to worry about a thing. |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Tue May 06, 2014 1:09 pm Post subject: |
|
|
when you update a byte to say 1 there is code like :
ldi r24,1
sts {b},r24
when there is an ISR it will save R24.
and restores it when done.
So no problem.
When we write a word like w=1
there is code like :
ldi r26, &H2 ; address of w &H302
ldi r27,&H3
ldi r24,1 ; value for w
ldi r25,0
st x+,r24 ; write to address
st x,r25
in this case an interrupt will save/restore everything as well, and even the fact that an ISR can interrupt at all times, it will not matter since all regs are saved as restored.
But of course when the ISR runs and it also writes to W, it will set W to a new value. And that value you loose when the code above continues. So you need to make sure yourself if this is possible. and how it should be handled. while the compiler could disable interrupts when writing to a variables in the main code and enable them afterwards, it might be the case the interrupt does not run at all times. that is why it is the programmers task to make the proper logic. It is the same as using the UART in the main code and the iSR. What happens if you print "ABCDEFG" in the main and "123" in the ISR? most likely it will not give the desired result.
But only the programmer can decide how it should work.
but a bit is stored in a byte. this means that when you have bit0 and say bit1 they are stored in the byte space BYTE.
Now to alter a bit one must load the data, alter the bit and write the data back.
example :
lds r24,{BYTE}
sbr r24,1 ; set bit 0
sts {byte},r24
but now when the ISR want to write to bit1 it has similar code :
lds r24,{BYTE}
sbr r24,2 ; set bit 1
sts {byte},r24
and if the ISR executes just after the register is loaded (lds r24,{BYTE} )
it will save r24 with value of r24 , say 0.
then it will set the value of the byte to 2 , restores r24 and returns. but r24 was 0 !
so setting bit0 will work but the change of bit1 is lost.
the alternative is to use a byte instead of a bit.
or to disable interrupts when writing to the bit in the main code.
So in practical way, only a bit can give a problem. _________________ Mark |
|
Back to top |
|
|
EDC
Joined: 26 Mar 2014 Posts: 971
|
|
Back to top |
|
|
kema
Joined: 20 Sep 2004 Posts: 5 Location: Sweden
|
Posted: Tue Jun 17, 2014 1:30 pm Post subject: |
|
|
Hi!
I had a similar problem or actually the problem has been around for 1,5 years and triggered 3 times in total among 25 delivered units. So I would say it is hard to find!
Mark Alberts answered very good, as he would knowing everything about BASCOM, and as he states the danger lies in using bit variables both in interrupt routines and in the main loop as they might share the same byte address.
In the documentation there is no mentioning of this problem, in fact in the segmen "ON INTERRUPT" we are actually encouraged to use "simple flags" and in my world this is bit variables, so maybe this would be a good place to enter a warning text to make sure the bit variables you use inside interrupt routines are not in the same byte as the ones you use in your main loop.
I came to the same conclusion in a workaround as Neill to dimension dummy bits to fill up a byte and then to verify this with the compiler reports memory map of the variables.
I would class this as a compiler bug, due to the fact that it is not documented at all in the manual, and the only way to find it out is by dissassemble the code and make a time consuming deep analysis.
But I would fully accept that the bug fix for this is to add information about this in the documentation in the section "ON INTERRUPT", Memory Usage, Language fundamentals and Newbie problems or a new section describing hard-to-find problems.
On a side note to MWS: saying
"Surprise, surprise - the bug is behind the screen
It's a moot issue and well known."
Its OK coming from you, especially since you did add a smile, but I beg to differ on the ground stated above that it is not documented.
Apart for this small bug(?) I haven't had much problems with BASCOM for the last couple of years, but this one tooko more than a few hours to find.
Best regards, Kent _________________ Kent Andersson |
|
Back to top |
|
|
MikeCraven
Joined: 15 Aug 2009 Posts: 3
|
Posted: Mon Aug 18, 2014 5:37 am Post subject: Bit Variables |
|
|
Has anyone considered / tried using bit variables in the General Purpose I/O registers? GPIOR0 for example.
It appears that the assembler directives SBI and CBI can be used to set and reset only one bit with only one processor instruction using 2 cycles. In most cases it appears that the General Purpose registers are within the range of the SBI type instructions.
The normal If / Then instructions can be used to test the bit condition if the name is aliased in the variable definitions. MyVariable Alias GPIOR0.0 - and then - If MyVariable = 1 Then Something - will work. But you cannot use SBI MyVariable,0 to set or reset, you have to write SBI GPIOR0,0 to set a bit.
This should / would prevent an interrupt from corrupting a bit variable write.
Also, since these instructions (and the corresponding test instructions SBIC & SBIS) do not affect the status register or use any registers you can do simple things in the interrupt routine with the NoSave option set. And is much faster.
I realize this mixes assembly into the code, but might be useful. I have tried this in a simple program and it seems to work.
Any comments?
Mike |
|
Back to top |
|
|
|