CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

int64 with PIC18F87J50
Goto page Previous  1, 2, 3
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 08, 2017 3:20 am     Reply with quote

The original code "main.c" last line has " delay_ms(800);".
I mean the last code posted by "ntrungtruc2003", which I supposed to be the last modified and working version.
But I will try to follow your advice starting with reducing the 800ms delay.
Ttelmah



Joined: 11 Mar 2010
Posts: 12524

View user's profile Send private message

PostPosted: Wed Nov 08, 2017 4:52 am     Reply with quote

It still won't work reliably unless you either program for continuous mode, or re-trigger.

Read the data sheet.

A reading does not trigger a conversion.

You either program it to run and convert automatically, or you have to trigger the conversion yourself.

Using the 'Begin' code, triggers a conversion. However it wastes a lot of time re-writing the same configuration values each time. So just write the register to trigger a conversion, wait for this to complete, and read. Not exactly hard.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 08, 2017 5:22 am     Reply with quote

You are right.
I have done some more tests.
First I reduced all the delays to be summed up under 250ms and the Begin() was placed outside of the while(1) loop and it did not work. Obviously needs the re-trigger as you mentioned.
Then I looked into the Begin() subroutine, I copied all the code from there and put it in while(1) loop and then I started to delete one by one the instructions to see which one has effect.
I arrived to BME280SetSampling(); as subroutine inside the BME280Begin();.
If I call that BME280SetSampling(); instead of BME280Begin(); then is good enough. Then BME280Begin(); may be placed outside of the while(1) loop.
As you mentioned already, I wanted to avoid the whole BME280Begin(); because inside there is reset for sensor, new initialization, reading the calibration again, waiting long time and is not needed neither wanted.
Then I went one step further and looking inside to BME280SetSampling(); I see 3 instructions.
I copied those 3 instructions in the while(1) loop instead of BME280SetSampling(); and then I eliminated one by one and I noticed the helpful one is “BME280WriteByte(0xF4,0x6E);// 011 011 10 temperature oversampling x 4, pressure oversampling x 4, force mode”.
If I call that instruction, which is register F4, meaning ctrl_meas – as you said yesterday, then the code works.
But I do not mind to call the entire BME280SetSampling();
That triggers a new reading and is good enough for me.
I read only temperature and humidity for the moment and the code used in the main.c is below, the BME280 code is the same as above.

It remains only one question that puzzles me:
- How come the user "ntrungtruc2003" says “All of sensors in BME280 work perfect for me” with his last posted code main.c where I cannot identify how the reading is re-triggered in his while(true) loop?

Code:
//main code
//PIC16F1829 with BME280 address 0x76
#include <16F1829.h>
#use delay(internal=32000000)

#FUSES NOPUT                    //No Power Up Timer
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOCPD                    //No EE protection
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOCLKOUT                 //I/O function on OSC2
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES NOFCMEN                  //Fail-safe clock monitor disabled
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOSTVREN                 //Stack full/underflow will not cause reset
#FUSES BORV19                   //Brownout reset at 1.9V
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWDT

//#define BME280_SDA  PIN_B4
//#define BME280_SCL  PIN_B6
#use i2c(master, sda=PIN_B4, scl=PIN_B6, FORCE_HW)

#include <flex_lcd.c>
#include "BME280.c"
#include<stdlib.h>

void main(void)
{
float temp, hu;

init_BME280();
BME280Begin();
delay_ms(200);
     
while(true)
   {             

      BME280SetSampling();
      delay_ms(200);
     
      BurstRead();
      delay_ms(100);
     
      temp = BME280ReadTemperature();
      delay_ms(100);

      hu = BME280ReadHumidity();
      delay_ms(100);
   
      lcd_init();
      lcd_gotoxy(1,1);
      printf(lcd_putc, "%3.1f",hu);
      lcd_putc(" %");
           
      lcd_gotoxy(1,2);
      printf(lcd_putc, "%3.2f",temp);
      lcd_putc(" C");
      delay_ms(700);   
    }
}


The test setup may be seen here:

viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 08, 2017 5:37 am     Reply with quote

Now I have seen my mistake finally and the answer to my last question above.
He used:
BME280WriteByte(0xF4,0x6E); to re-trigger the reading and I missed that.
Everything is clear now.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Tue Nov 14, 2017 7:17 am     Reply with quote

Few more observations to the initial provided code:

1) The next subroutine:
Code:
int8 BME280ReadID()
//----------------------------------------------
{
int8 data;

   i2c_start();
   i2c_write(0xEC); // 0X77 11101110X IS IC ADDRESS, 0X76 IS 1110 110
   i2c_write(0xD0);
   i2c_start();
   i2c_write(0xED);
   data=i2c_read(0);
   i2c_stop();
   delay_us(20);
   return(data);
}

is written for the BME280 with the address 0x76 (EC), but we should have it general as all other subroutines used:
Code:
int8 BME280ReadID()
//----------------------------------------------
{
int8 data;

   i2c_start();
   i2c_write(BME280_ADDRESS);
   i2c_write(0xD0);
   i2c_start();
   i2c_write(BME280_ADDRESS | 0x01);
   data=i2c_read(0);
   i2c_stop();
   delay_us(20);
   return(data);
}

2)There is next subroutine never used:
Code:
void BME280TakeForcedMeasurement()
{   
   
     BME280WriteByte(0xF4,0x6E); //011 011 01 pressure oversampling x 4, temperature oversampling x 4, forced mode
     while (BME280ReadByte(0xF4) & 0x08)  // wait until measurement has been completed, otherwise we would read the values from the last measurement
      delay_us(10);
    }

Actually it gets stuck, I do not know why, but I think it should be 0xF3 and not 0xF4 above – not tested, only suppose, and if we need a re-trigger for forced mode, then is enough:
Code:
BME280WriteByte(0xF4,0x6E); // re-trigger the reading in forced mode

3)As was discussed and recommended here http://www.ccsinfo.com/forum/viewtopic.php?p=215649#215649
the subroutines for compensation should have int32 instead of float.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 6:29 am     Reply with quote

BME280 pressure subroutine – tests on the same hardware.
CCS float gives 1022.4 hPa
XC8 float gives 1022.4 hPa
Then
XC8 long int gives 1022.4 hPa
CCS int32 gives 1021.1 hPa
So, there is a small bug in the CCS int32.
I find it very difficult to trace it due to many operations that are involved.
Here is the XC8 signed long int:
Code:
signed long int var1, var2;
unsigned long int p;

var1 = (((signed long int)FCL_TFINE)>>1) - (signed long int)64000;
var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed long int)FCL_P6);
var2 = var2 + ((var1*((signed long int)FCL_P5))<<1);
var2 = (var2>>2)+(((signed long int)FCL_P4)<<16);
var1 = ((((signed long int)FCL_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((signed long int)FCL_P2) * var1)>>1))>>18;
var1 = (((((unsigned long int)32768+var1))*((unsigned long int)FCL_P1))>>15);
if (var1 == 0)
{
    return 0;
}   
p = (((unsigned long int)(((signed long int)1048576)-FCL_ADC_P)-(var2>>12)))*(unsigned long int)3125;
if(p<0x80000000)
{
   p = (p << 1) / ((unsigned long int) var1);   
}
else
{
   p = (p / (unsigned long int)var1) * 2;   
}
var1 = (((signed long int)FCL_P9) * ((signed long int)(((p>>3) * (p>>3))>>13)))>>12;
var2 = (((signed long int)(p>>2)) * ((signed long int)FCL_P8))>>13;
p = (unsigned long int)((signed long int)p + ((var1 + var2 + (signed long int)FCL_P7) >> 4));
return p;


And here is the CCS signed int32:
Code:
signed int32 math_shift(signed int32 x, signed int32 y)
{ //Perform a mathematical right shift on a signed value
   if (bit_test(x,31)) //if -ve
      return -(-x>>y); //convert sign, shift, and convert back
   return x>>y; //otherwise simple shift
}

unsigned int32 BME280_compensate_P_int32()
{
signed int32 var1, var2;
unsigned int32 p;


 //signed int32 adc_P = BME280Read24(0xF7); //FA THE TEMPERATURE REGISTER
if (adc_P == 0x800000) // value in case temp measurement was disabled
        return 0;
adc_P >>= 4;

var1 = math_shift(((signed int32)t_fine), 1) - (signed int32)64000;
var2 = math_shift(math_shift(var1, 2)*math_shift(var1, 2), 11)* ((signed int32)dig_P6);
var2 = var2 + ((var1*((signed int32)dig_P5))<<1);
var2 = math_shift(var2,2)+(((signed int32)dig_P4)<<16);
var1 = math_shift(math_shift(((signed int32)dig_P3 * math_shift((math_shift(var1, 2)*math_shift(var1, 2)), 13)), 3) + (((signed int32)dig_P2) * var1), 18);
var1 = math_shift(((((unsigned int32)32768 + var1))*((signed int32)dig_P1)), 15);
if (var1 == 0)
{
    return 0;
}   
p = (((unsigned int32)(((unsigned int32)1048576)-adc_P) - math_shift(var2, 12)))*(unsigned int32)3125;
if(p<0x80000000)
{
   p = (p << 1) / ((unsigned int32) var1);   
}
else
{
   p = (p / (unsigned int32)var1) * 2;   
}
var1 = math_shift(((signed int32)dig_P9) * (signed int32)math_shift((math_shift(p, 3) * math_shift(p,3)), 13), 12);
var2 = math_shift(((signed int32)math_shift(p, 2)) * ((signed int32)dig_P8), 13);
p = (unsigned int32)((signed int32)p + math_shift((var1 + var2 + (signed int32)dig_P7), 4));
return p;
}
jeremiah



Joined: 20 Jul 2010
Posts: 966

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 7:28 am     Reply with quote

With your given code it is difficult to tell if there actually is a compiler bug. You are violating the C standard with your code and also leveraging implementation defined operations.

Shifting Signed Integers:
1. Right Shifting a signed integer is (per the C standard) "Implementation Defined". This means that microchip xc8 and the ccs are free to choose how to implement it. They can choose totally different methods and it is completely ok. They can choose to sign extend or not to sign extend. If you right shift signed integers, it is up to you as the programmer to verify how the compiler handles that.

2. Left Shifting a signed integer is (per the C standard) "Undefined". This means that you are violating the C standard by trying to shift a signed number left. The compiler is free to do almost anything with it (including replacing your code with whatever they heck they want to or even taking out entire blocks of code that depend on it....I don't believe CCS is this aggressive though). Never left shift signed integers.

You should only be shifting unsigned numbers. If you need signed shifting, you should define that yourself (there was a recent thread on how to do this). Your math_shift() function does that, but then you mix it with intrinsic shifts that implement the behavior I described above.

It'll be easier to spot a bug if you clean out the undefined and implementation defined behavior.

So the short answer is with your given code, the two compilers are allowed to give different answers, and, additionally, both compilers are allowed to give you the wrong answer.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 8:14 am     Reply with quote

I solved the problem.
The shifting was defined above the main code.
Code:
signed int32 math_shift(signed int32 x, signed int32 y)
{ //Perform a mathematical right shift on a signed value
   if (bit_test(x,31)) //if -ve
      return -(-x>>y); //convert sign, shift, and convert back
   return x>>y; //otherwise simple shift
}

The error was on this impossible long line:
Code:
var1 = math_shift(math_shift(((signed int32)dig_P3 * math_shift((math_shift(var1, 2)*math_shift(var1, 2)), 13)), 3) + math_shift((((signed int32)dig_P2) * var1),1), 18);


The good working code, for who is interested, which gives the same result as XC8 code:
Code:
unsigned int32 BME280_compensate_P_int32()
{
signed int32 var1, var2;
unsigned int32 p;

//signed int32 adc_P = BME280Read24(0xF7); //FA THE TEMPERATURE REGISTER
if (adc_P == 0x800000) // value in case temp measurement was disabled
        return 0;
adc_P >>= 4;

var1 = math_shift(((signed int32)t_fine), 1) - (signed int32)64000;
var2 = math_shift(math_shift(var1, 2)*math_shift(var1, 2), 11)* ((signed int32)dig_P6);
var2 = var2 + ((var1*((signed int32)dig_P5))<<1);
var2 = math_shift(var2, 2) + (((signed int32)dig_P4)<<16);
var1 = math_shift(math_shift(((signed int32)dig_P3 * math_shift((math_shift(var1, 2)*math_shift(var1, 2)), 13)), 3) + math_shift((((signed int32)dig_P2) * var1), 1), 18);
var1 = math_shift(((((unsigned int32)32768 + var1))*((signed int32)dig_P1)), 15);
if (var1 == 0)
{
    return 0;
}   
p = (((unsigned int32)(((unsigned int32)1048576)-adc_P) - math_shift(var2, 12)))*(unsigned int32)3125;
if(p<0x80000000)
{
   p = (p << 1) / ((unsigned int32) var1);   
}
else
{
   p = (p / (unsigned int32)var1) * 2;   
}
var1 = math_shift(((signed int32)dig_P9) * (signed int32)math_shift((math_shift(p, 3) * math_shift(p,3)), 13), 12);
var2 = math_shift(((signed int32)math_shift(p, 2)) * ((signed int32)dig_P8), 13);
p = (unsigned int32)((signed int32)p + math_shift((var1 + var2 + (signed int32)dig_P7), 4));
return p/100;
}
jeremiah



Joined: 20 Jul 2010
Posts: 966

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 8:46 am     Reply with quote

viki2000 wrote:
I solved the problem.
The shifting was defined above the main code.
Code:
signed int32 math_shift(signed int32 x, signed int32 y)
{ //Perform a mathematical right shift on a signed value
   if (bit_test(x,31)) //if -ve
      return -(-x>>y); //convert sign, shift, and convert back
   return x>>y; //otherwise simple shift
}


Glad that you got it working. I get that it "works" currently, but the things I said still do apply. In particular:

Code:

var2 = var2 + ((var1*((signed int32)dig_P5))<<1);
var2 = math_shift(var2, 2) + (((signed int32)dig_P4)<<16);


both of these lines are "undefined" due to the "<<" operations on signed types. I get that they work, but it can bite you later.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 1:08 pm     Reply with quote

The problem was with signed shift right.
The shift left it works with <<, it seems that does not need a dedicated function as signed shift right.
Ttelmah



Joined: 11 Mar 2010
Posts: 12524

View user's profile Send private message

PostPosted: Wed Nov 15, 2017 3:10 pm     Reply with quote

That depends on the value involved.
If the source value is always +ve, and never moves it's top bit into the top bit of the destination value, no problem.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Thu Nov 16, 2017 1:39 am     Reply with quote

Then to be on the safe side, I think a dedicated arithmetical left shift should be used in case of negative numbers, similar with above right shift function.
Any proposals?
Ttelmah



Joined: 11 Mar 2010
Posts: 12524

View user's profile Send private message

PostPosted: Thu Nov 16, 2017 2:34 am     Reply with quote

You'd have to code as follows:
Code:

signed int32 math_leftshift(signed int32 x, int8 y)
{ //Perform a mathematical left shift in a 32bit space
   if (bit_test(x,31)) //if source -ve
      return -((-x)<<y); //convert sign
      //shift, and convert back
   return x<<y; //otherwise simple shift
}

Basically if the -ve is -ve, it converts it to +ve, then shifts, then changes the result back to -ve.

However I don't think you need to do this. The source values though returned as 'signed', only have bits put into the low 16bits from the chip. Hence they can never be -ve, so a maths shift and an arithmetic shift in this case will both return the same value. Smile
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3
Page 3 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group