I have a function which is searching for series of nine "1" in 64-bits variable(RFID tag number) and if found, moves them to the MSB. I have a huge problem with understanding why it does not work properly.
This is my variable
uint64_t volatile RFID_data2= 0b1111111110000000000000000000000000000000000000000000000000000000;
and i send it as pointer to function
test_flag= header_align(&RFID_data2);
uint8_t header_align(uint64_t *data){
uint64_t bit_mask=(uint64_t)
0b1111111110000000000000000000000000000000000000000000000000000000;
if((*data&bit_mask)==bit_mask){
PORTA ^= (1<<PORTA2);
return 1;
}
This condition is never fulfilled, but if i changed the conition to this :
if((*data==bit_mask){
PORTA ^= (1<<PORTA2);
return 1;
}
it appears to work good.
What is more i write another condition - which is working.
if((*data&bit_mask)>(bit_mask-1) && (*data&bit_mask)<(bit_mask+1 )){
PORTA ^= (1<<PORTA2);
return 1
As i can see it is a problem with AND '&' operation. In addition there are not any problems when i change RFID_data to 32 bits variable. I am working with Attiny441 and GCC compiler, Atmel Studio Is there any way to make it works on 64 bits?
I changed function to take uint64t (non-pointer) but the problem still persists. I also tried to create global varaible, and remove volatile modifer but it still does not working properly. Using a macro UINT64_C does not help also. It looks like :
uint64_t RFID_data;// global var
int main(void)
{
RFID_data=(0xFF80000000000000);// write into global var
uint64_t RFID_data2=(0xFF80000000000000);
while(1)
{
test_flag=header_align(RFID_data2);// send local variable
}
}
uint8_t header_align(uint64_t data){
uint64_t bit_mask = UINT64_C(0xFF80000000000000);
if((data&bit_mask)==bit_mask){
PORTA ^= (1<<PORTA2);//nothink
return 1;
}
I also tried to check if-condtion by global var:
if((RFID_data&bit_mask)==bit_mask){
PORTA ^= (1<<PORTA2);///nothink
return 1;
}
In both ways it does not returning 1, neither changing PORTA2 state.
It works only when i create a new local variable in header_allgin, like this:
uint8_t header_align(uint64_t data){
uint64_t RFID_data3 = UINT64_C(0xFF80000000000000);
uint64_t bit_mask = UINT64_C(0xFF80000000000000);
if((RFID_data3&bit_mask)==bit_mask){
PORTA ^= (1<<PORTA2);// here i can see signal
return 1;
}}
Is it way to make it work by global variable or byargument of function ?
Just use the proper suffixes.
L for int32
LL for int64
UL for uint32
ULL for uint64
Seems like you caught a real compiler bug here!
GCC version:
avr-gcc (GCC) 4.8.1
(with -O1 or -O2 optimizations enabled, at -O0 the problem doesn't seem to be present)
Reduced test case:
#include <stdint.h>
uint8_t volatile tmp;
__attribute__((noinline)) void test_64(uint64_t d64)
{
if ((d64 & 0xFF800000UL) == 0xFF800000UL){
tmp ++;
}
}
__attribute__((noinline)) void test_32(uint32_t d32)
{
if ((d32 & 0xFF800000UL) == 0xFF800000UL){
tmp ++;
}
}
int main(void)
{
test_64(0);
test_32(0);
while(1);
}
Assembler output for the critical part:
00000228 <test_64>:
228: 08 95 ret
0000022a <test_32>:
22a: 66 27 eor r22, r22
22c: 77 27 eor r23, r23
22e: 80 78 andi r24, 0x80 ; 128
230: 61 15 cp r22, r1
232: 71 05 cpc r23, r1
234: 80 48 sbci r24, 0x80 ; 128
236: 9f 4f sbci r25, 0xFF ; 255
238: 09 f0 breq .+2 ; 0x23c <test_32+0x12>
23a: 08 95 ret
23c: 80 91 00 20 lds r24, 0x2000
240: 8f 5f subi r24, 0xFF ; 255
242: 80 93 00 20 sts 0x2000, r24
246: 08 95 ret
00000248 <main>:
248: 20 e0 ldi r18, 0x00 ; 0
24a: 30 e0 ldi r19, 0x00 ; 0
24c: 40 e0 ldi r20, 0x00 ; 0
24e: 50 e0 ldi r21, 0x00 ; 0
250: 60 e0 ldi r22, 0x00 ; 0
252: 70 e0 ldi r23, 0x00 ; 0
254: 80 e0 ldi r24, 0x00 ; 0
256: 90 e0 ldi r25, 0x00 ; 0
258: 0e 94 14 01 call 0x228 ; 0x228 <test_64>
25c: 60 e0 ldi r22, 0x00 ; 0
25e: 70 e0 ldi r23, 0x00 ; 0
260: cb 01 movw r24, r22
262: 0e 94 15 01 call 0x22a ; 0x22a <test_32>
266: ff cf rjmp .-2 ; 0x266 <main+0x1e>
Observation
For 32 bits the correct code is generated. For 64 bits, no comparison is performed at all, the code compiles as if the result of the if
was always false. A native GCC compiles both functions correctly.
You should probably avoid using 64 bits variables in your code.
The bug is now confirmed on the GCC bugtracker, you may follow it here:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85805
So at the time of writing all sufficiently modern avr-gcc versions are affected until this gets fixed.
Casting a constant to uint64_t
is not a correct way of making uint64_t
literal. You should use UINT64_C
macro instead:
uint64_t bit_mask = UINT64_C(0b1111111110000000000000000000000000000000000000000000000000000000);
or if you prefer hex
uint64_t bit_mask = UINT64_C(0xFF80000000000000);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.