• AVR Freaks

Helpful ReplyHot!Problem with CARRY Flag

Author
EverGreen_28
Starting Member
  • Total Posts : 39
  • Reward points : 0
  • Joined: 2018/08/14 11:09:01
  • Location: Argentina
  • Status: offline
2020/02/29 03:27:35 (permalink)
0

Problem with CARRY Flag

Hi guys i need a little help with this.
 
uint8_t ASCII_DIGIT[6];

volatile int16_t TMR1_Backup = 0; /* I need to declare this as volatile because without volatile, compiler consider is not used variable and not include in code */

TMR1L = 0x1F; // examples values
TMR1H = 0x14; // examples values 5151 Decimal. I only need values from 10000 to 10. Ignore the least significant digit.
    
    
    for(uint8_t h=0;h<4;h++) {
        ASCII_DIGIT[h] = 0; // clear character buffer
    }
    TMR1_Backup = (int16_t)(TMR1H * 256)+TMR1L;
    
    
    int16_t multiplier[]= {10000,1000,100,10};
    for (uint8_t i = 0 ;i<4;i++) {
        
        do {
            ASCII_DIGIT[i]++;
            TMR1_Backup = (int16_t)(TMR1_Backup-(multiplier[i])); // PROBLEM IN THIS LINE
        } while (CARRY);
        TMR1_Backup += multiplier[i];
        ASCII_DIGIT[i]--;
    }


The code build perfectly when compile, but CARRY flag don't take correctly value on while LOOP.
 
each iteraction explained:
1st : TMR1_Backup - 10000; // Loop after CARRY = 0 work's fine
2nd: TMR1_Backup - 1000;   // Loop after CARRY = 1 not work. Loop forever or abnormally
3rd: TMR1_Backup - 100;     // Loop after CARRY = 1 not work
4th: TMR1_Backup - 10;       // Loop after CARRY = 1 not work 
 
at the 6th iteraction, when the first 5 of "5151" is finally processed, next value is on vars:
TMR1_Backup = 0x97 - multiplier= 0x3E8;
 
151 - 1000 = -849; but for why CARRY is not Cleared at this time???
 
CARRY on XC8 not set/clear correctly on int16/long/double vars?
 
How to workaround this?
 
Please HELPPPPP!!!
 
PD: Processor is PIC16F88
post edited by EverGreen_28 - 2020/02/29 03:37:23
#1
ric
Super Member
  • Total Posts : 26090
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Problem with CARRY Flag 2020/02/29 03:39:29 (permalink) ☄ Helpfulby EverGreen_28 2020/02/29 03:54:25
+2 (2)
You can NOT reliably test CPU status flags from C code.
The compiler is entitled to do whatever it wants with them in between statements.
Why not just test if TMR1_Backup is negative?
 
(If you examined the assembly code output by the compiler, you'd probably see what it is doing behind the scenes)
post edited by ric - 2020/02/29 03:40:41

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#2
EverGreen_28
Starting Member
  • Total Posts : 39
  • Reward points : 0
  • Joined: 2018/08/14 11:09:01
  • Location: Argentina
  • Status: offline
Re: Problem with CARRY Flag 2020/02/29 03:50:35 (permalink)
0
ric "Why not just test if TMR1_Backup is negative?"
You really make me feel silly hahaha. You are right.
It wouldn't have occurred to me to compare negative. Thanks men!!!
 
"(If you examined the assembly code output by the compiler, you'd probably see what it is doing behind the scenes)"
Yes i look in dissasemble tab and find a strange SUBLW, MOVFW, etc... .
 
"You can NOT reliably test CPU status flags from C code."
Isn't good practice work with STATUS flags on XC8?
I used CARRY on I2C library's to shift register throw CARRY to send data and works good.
 
#3
EverGreen_28
Starting Member
  • Total Posts : 39
  • Reward points : 0
  • Joined: 2018/08/14 11:09:01
  • Location: Argentina
  • Status: offline
Re: Problem with CARRY Flag 2020/02/29 03:54:08 (permalink)
0
 I change this:
 
 
while (CARRY);

 
to this:
 
while (TMR1_Backup > 0);

 
Thanks again!!!
 
#4
ric
Super Member
  • Total Posts : 26090
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Problem with CARRY Flag 2020/02/29 04:08:55 (permalink)
+2 (2)
EverGreen_28
...
"You can NOT reliably test CPU status flags from C code."
Isn't good practice work with STATUS flags on XC8?

No. As I mentioned, they belong to the compiler, so you can NOT trust them to survive until you test them.

I used CARRY on I2C library's to shift register throw CARRY to send data and works good.

Dumb luck.
If there's no math, comparison etc. done, then they MIGHT survive, but you can't be sure of that.

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#5
1and0
Access is Denied
  • Total Posts : 10550
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Problem with CARRY Flag 2020/02/29 04:18:37 (permalink)
+2 (2)
EverGreen_28
"You can NOT reliably test CPU status flags from C code."
Isn't good practice work with STATUS flags on XC8?

It is not recommended, because status flags can change between statements.
 

I used CARRY on I2C library's to shift register throw CARRY to send data and works good.

You've been lucky. ;)
 

Here's a tip -- you can remove this
ASCII_DIGIT[i]--;

if it's initialized with this
ASCII_DIGIT[h] = 255; // clear character buffer

;)
#6
EverGreen_28
Starting Member
  • Total Posts : 39
  • Reward points : 0
  • Joined: 2018/08/14 11:09:01
  • Location: Argentina
  • Status: offline
Re: Problem with CARRY Flag 2020/02/29 04:19:37 (permalink)
0
Dumb luck.
If there's no math, comparison etc. done, then they MIGHT survive, but you can't be sure of that.

 
I share with you the code.
 
 
void I2C_Write(unsigned char data){
    
// I2C_Set_Port();
        BufferI2C = data;
// I2C_SEN();
        CARRY = 0;
        
        int i;
    for (i = 0; i < 8; i++) {
        
        BufferI2C <<=1;
        if (CARRY) {
            _SDA = 1;
            __delay_us(I2C_tSU);
            _SCL = 1;
            __delay_us(I2C_tHIGH);
            _SCL = 0;
            __delay_us(I2C_tLOW);
        } else {
            _SDA = 0;
            __delay_us(I2C_tSU);
            _SCL = 1;
            __delay_us(I2C_tHIGH);
            _SCL = 0;
            __delay_us(I2C_tLOW);
               }
    }
        /*Extra pulse for receive _ACK*/
        

        _SDA = 1;
        __delay_us(I2C_tSU);
        _SCL = 1;
        __delay_us(I2C_tHIGH);
        if (P_SDA) {
            I2C_STATUSbit.ACK_ = 1; // ACK no recibido
        } else {
            I2C_STATUSbit.ACK_ = 0; // ACK recibido
               }
        _SCL = 0;
        __delay_us(I2C_tLOW);
        
}

 
Part is extracted from plib of microchip for PIC18F and i modified for working on PIC16F.
 
Evidently, when shift, XC8 uses RRF/RLF instructions and "if(CARRY)" is a simple BTFSS/BTFSC next to RRF/RLF. Because this, works fine i assum.
post edited by EverGreen_28 - 2020/02/29 04:21:54
#7
ric
Super Member
  • Total Posts : 26090
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Problem with CARRY Flag 2020/02/29 04:25:54 (permalink)
+1 (1)
Whoever wrote that was being naughty, but as I said, it's done straight after an 8 bit shift operation, so the compiler is very unlikely to do anything to trash the Carry flag there.
Just as efficient code could be done perfectly legally, by testing bit 7 of the BufferI2C variable instead of Carry (exactly the same number of instructions), and doing the left shift after setting the SDA state.
The brute force repeated code in that "if (CARRY)" test is just silly, and the compiler would probably discard it at most optimisation levels.

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#8
1and0
Access is Denied
  • Total Posts : 10550
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Problem with CARRY Flag 2020/02/29 04:30:33 (permalink)
+1 (1)
It would be safer to do this instead:
if (BufferI2C & 0x80) {
    _SDA = 1;
    __delay_us(I2C_tSU);
    _SCL = 1;
    __delay_us(I2C_tHIGH);
    _SCL = 0;
    __delay_us(I2C_tLOW);
} else {
    _SDA = 0;
    __delay_us(I2C_tSU);
    _SCL = 1;
    __delay_us(I2C_tHIGH);
     _SCL = 0;
    __delay_us(I2C_tLOW);
}
BufferI2C <<=1;

#9
ric
Super Member
  • Total Posts : 26090
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Problem with CARRY Flag 2020/02/29 04:33:42 (permalink)
+1 (1)
I'd prefer
_SDA=1;
if ((BufferI2C & 0x80) == 0)
{    _SDA = 0;}
__delay_us(I2C_tSU);
_SCL = 1;
__delay_us(I2C_tHIGH);
_SCL = 0;
__delay_us(I2C_tLOW);
BufferI2C <<=1;


 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#10
1and0
Access is Denied
  • Total Posts : 10550
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Problem with CARRY Flag 2020/02/29 04:42:46 (permalink)
+1 (1)
ric
I'd prefer

Agreed. I did not even look at the if-else bodies. I think the optimizer will do this to the code in Post #9:
if (BufferI2C & 0x80) {
    _SDA = 1;
} else {
    _SDA = 0;
}
__delay_us(I2C_tSU);
_SCL = 1;
__delay_us(I2C_tHIGH);
_SCL = 0;
__delay_us(I2C_tLOW);
BufferI2C <<=1;

#11
EverGreen_28
Starting Member
  • Total Posts : 39
  • Reward points : 0
  • Joined: 2018/08/14 11:09:01
  • Location: Argentina
  • Status: offline
Re: Problem with CARRY Flag 2020/02/29 04:42:55 (permalink)
0
Yes
 
if (BufferI2C & 0x80)
suggested by 1and0 are same effect of
 
if ((BufferI2C & 0x80) == 0)
suggested by ric, but inverted and apparently more reduced.
 
 
Thanks for the suggestions guys. I probably take modifications on this I2C function later with your suggestions!!!
#12
1and0
Access is Denied
  • Total Posts : 10550
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Problem with CARRY Flag 2020/02/29 04:45:57 (permalink)
0
.
 
#13
EverGreen_28
Starting Member
  • Total Posts : 39
  • Reward points : 0
  • Joined: 2018/08/14 11:09:01
  • Location: Argentina
  • Status: offline
Re: Problem with CARRY Flag 2020/02/29 19:47:46 (permalink)
0
Here's a tip -- you can remove this

ASCII_DIGIT--;

if it's initialized with this

ASCII_DIGIT[h] = 255; // clear character buffer

;)

 
 
Thx 1and0 for the tip.
post edited by EverGreen_28 - 2020/02/29 19:48:57
#14
pcbbc
Super Member
  • Total Posts : 1641
  • Reward points : 0
  • Joined: 2014/03/27 07:04:41
  • Location: 0
  • Status: offline
Re: Problem with CARRY Flag 2020/03/01 00:37:00 (permalink)
+1 (1)
1and0
EverGreen_28
"You can NOT reliably test CPU status flags from C code."
Isn't good practice work with STATUS flags on XC8?

It is not recommended, because status flags can change between statements.

For the OP, in case it wasn’t clear: ...and not just restricted to XC8. No C compiler is going to guarantee the status flags. You’re at the complete mercy of the compiler and optimiser if you try and rely on them.
#15
Gort2015
Klaatu Barada Nikto
  • Total Posts : 3835
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: Problem with CARRY Flag 2020/03/01 08:01:20 (permalink)
0
I have not seen this attempted.
 
How long have you been writing code?
 

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#16
Jump to:
© 2020 APG vNext Commercial Version 4.5