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 CCS Technical Support

prom ms5611 i2c reading
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
m4k



Joined: 27 Mar 2018
Posts: 29

View user's profile Send private message

prom ms5611 i2c reading
PostPosted: Sun May 20, 2018 6:31 am     Reply with quote

Hi...i try to read ms5611 prom barometric sensor but i do'nt know how to read multiple bytes from the sensor.

I know the write and read sequence of i2c.

For example :

Code:

i2c_start();
i2c_write(addw);
i2c_start();
i2c_write(addr);
var=i2c_read();
i2c_stop();


But how to read prom memory of ms5611?

This table show register map of the sensor:


ms5611 datasheet link
http://s8.picofile.com/file/8326933418/ENG_DS_MS5611_01BA03_B.pdf.html



0xA0 to 0xAE

Anybody can help me?
Ttelmah



Joined: 11 Mar 2010
Posts: 19480

View user's profile Send private message

PostPosted: Sun May 20, 2018 7:17 am     Reply with quote

Are you using a PIC24/30?.
If not, you have a problem. The sensor requires 64bit integer arithmetic for it's compensation arithmetic.

Honestly far easier to use one of the (more expensive) sensors that has internal compensation. Otherwise you are going to have to write your own 64bit arithmetic routines.
Chips like the MPL3115A2.
Also as another alternative, the Honeywell similar sensors do offer a 16bit arithmetic library.

The sequencing only gives the register sequence you show immediately after a reset. You can just do sequential reads (without a NACK) to get all the values. After this you just trigger the ADC cycles and read the 24bit ADC result. Problem is though that the offset and sensitivity calculations require signed int64 maths.
m4k



Joined: 27 Mar 2018
Posts: 29

View user's profile Send private message

PostPosted: Sun May 20, 2018 8:24 am     Reply with quote

Ttelmah wrote:
Are you using a PIC24/30?.
If not, you have a problem. The sensor requires 64bit integer arithmetic for it's compensation arithmetic.


Tnx for reply.

Yes...I am using 33fj series.

When i want to read 16 bit value with i2c protocol i do it:
Code:

i2c_start();
i2c_write(addw);
i2c_start();
i2c_write(addr);
varh=i2c_read(1);
varl=i2c_read(0);
i2c_stop();


I can read 16 bit value with ack, but i don't know how to read 6 byte with 1 i2c sequence.
According to the register map the prom address is 0xa0 to 0xae. How to do coding to read prom memory?

Do you have an example code ?
I am beginner in ccs, it's difficult understand for me.


tnx
Ttelmah



Joined: 11 Mar 2010
Posts: 19480

View user's profile Send private message

PostPosted: Sun May 20, 2018 9:07 am     Reply with quote

Read bytes. Put them together into the values you want after reading. Problem is that chip actually does different numbers of bytes for different things. The ADC values (which you need to read to actually get a reading), are sent as 24bit values. 3 8bit transfers. The configuration values are a mix of 32bit values and 16bit values. Some have to be stored as signed. So you declare a structure containing the same pattern of registers as are in the device, then do a repeated byte transfer for all the bytes (using i2c_read(0) for all but the lats read), into the bytes represented by this structure. You then have the data stored in the format required. For the ADC value transfer it into the top three bytes of an int32 (bottom zero), and divide by 256. This way the sign will correctly be handled.
m4k



Joined: 27 Mar 2018
Posts: 29

View user's profile Send private message

PostPosted: Sun May 20, 2018 9:42 am     Reply with quote

Ttelmah wrote:
Read bytes. Put them together into the values you want after reading. Problem is that chip actually does different numbers of bytes for different things. The ADC values (which you need to read to actually get a reading), are sent as 24bit values. 3 8bit transfers. The configuration values are a mix of 32bit values and 16bit values. Some have to be stored as signed. So you declare a structure containing the same pattern of registers as are in the device, then do a repeated byte transfer for all the bytes (using i2c_read(0) for all but the lats read), into the bytes represented by this structure. You then have the data stored in the format required. For the ADC value transfer it into the top three bytes of an int32 (bottom zero), and divide by 256. This way the sign will correctly be handled.



For read pressure or temp according to datasheet i can read 3 byte and i don't have any problem.




My problem is read prom and big problem is that i don't know the right address of prom memory.


Can you give me any example ?

tnx
Ttelmah



Joined: 11 Mar 2010
Posts: 19480

View user's profile Send private message

PostPosted: Sun May 20, 2018 11:27 am     Reply with quote

The PROM contains six int16 values C1 to C6. Issue the Read_Prom command with the pattern 0b10100010. This returns the data from address 1. The int16's start at this address. Read 16 bits. This is the C1 coefficient. Use pattern 0b10100100 to get C2 etc... The table on page8, gives what the 16bit values coefficients 'are'.
Address 0 contains factory data and the setup, addresses 1-6 calibration coefficients and address 7 contains the serial code and CRC.
m4k



Joined: 27 Mar 2018
Posts: 29

View user's profile Send private message

PostPosted: Sun May 20, 2018 2:52 pm     Reply with quote

Ttelmah wrote:
The PROM contains six int16 values C1 to C6. Issue the Read_Prom command with the pattern 0b10100010. This returns the data from address 1. The int16's start at this address. Read 16 bits. This is the C1 coefficient. Use pattern 0b10100100 to get C2 etc... The table on page8, gives what the 16bit values coefficients 'are'.
Address 0 contains factory data and the setup, addresses 1-6 calibration coefficients and address 7 contains the serial code and CRC.


tnx a lot dear Ttelmah..its work properly...i try to read pressure and temp raw value but :

according to datasheet


this is my code

Code:
 i2c_start();
 i2c_write(0xee);
 i2c_write(0x58);
 i2c_stop();
 
 delay_ms(10);
 
  i2c_start();
 i2c_write(0xee);
 i2c_write(0x00);
 i2c_stop();
 
  i2c_start();
 i2c_write(0xee);
 i2c_write(0x48);
  i2c_start();
 i2c_write(0xef);
p1=i2c_read();
p2=i2c_read(0);
p3=i2c_read(0);
 i2c_stop();


but its not work Sad

What is my mistake?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun May 20, 2018 6:38 pm     Reply with quote

Quote:

i2c_start();
i2c_write(0xee);
i2c_write(0x48);
i2c_start();
i2c_write(0xef);
p1=i2c_read();
p2=i2c_read(0);
p3=i2c_read(0);
i2c_stop();

What is my mistake?

You have two NACK's at the end. Only the last byte should do the NACK.
Ttelmah



Joined: 11 Mar 2010
Posts: 19480

View user's profile Send private message

PostPosted: Mon May 21, 2018 12:30 am     Reply with quote

Just to reinforce this, look at the figure 15 you post. Look at the I2C transactions. You will see 'A' for acknowledge on all except the very last one for the data, that has 'N' for not acknowledge.

I notice something else. Comments inline:
Code:

2c_start();
 i2c_write(0xee);
 i2c_write(0x58);
 i2c_stop(); //This triggers a D2 conversion
 
 delay_ms(10);
 
  i2c_start();
 i2c_write(0xee);
 i2c_write(0x00);
 i2c_stop(); //Why?. This is the read command can't do this
//till after you have a value to read....
//You have the D2 value but then don't read this.....
 
  i2c_start();
 i2c_write(0xee);
 i2c_write(0x48);
//Er at this point you have triggered a D1 conversion. You need to
//wait at least 8.22mSec after this....

  i2c_start();
 i2c_write(0xef);
//Er what is this doing?. 0xEF is again not a legitimate command....
//Ah twigged the device read address. Give them names...

//You have not issued a read after the D1 conversion, or allowed time
//for it to complete
p1=i2c_read();
p2=i2c_read(0); //er only NACK the last byte
p3=i2c_read(0);
 i2c_stop();   //will return 0 since the conversion has not completed...


Code:

#DEFINE RESET 0x1E
#DEFINE CONV_D14096 0x48
#DEFINE CONV_D24096 0x58
#DEFINE READ_ADC 0x0
#DEFINE CHIP_ADDR 0xEE
#DEFINE READ 1

int32 read_conv(int8 cmd)
{
    int32 result;
    int8 LSB, MSB,MMSB;
    i2c_start();
    i2c_write(CHIP_ADDR);
    i2c_write(cmd); //send the specified command
    i2c_stop();
    delay_ms(10); //9.04mSec worst case
    //now get the reply
    i2c_start();
    i2c_write(CHIP_ADDR);
    i2c_write(READ_ADC); //ask to read the value
    i2c_stop();
    //The data sheet shows a stop being issued before the bus
    //is reversed, rather than a restart.
    delay_us(2); //I2C required minimum 1.2uSec between a stop
    //and start
    i2c_start();
    i2c_write(CHIP_ADDR | READ); //read command
    MMSB=i2c_read();
    MSB=i2c_read();
    LSB=i2c_read(0); //NACK the last byte
    i2c_stop(); //Figure 15 in the data sheet.
    result=make32(0,MMSB,MSB,LSB); //build 32bit result
    return result;
}

   //Then call
   D1=read_conv(CONV_D14096);
   D2=read_conv(CONV_D24096);

   //To get the two conversion values.


Untested but this follows what the data sheet shows.

Note also that the data sheet is very specific that you must get a proper chip reset on startup or it will return zero values.
m4k



Joined: 27 Mar 2018
Posts: 29

View user's profile Send private message

PostPosted: Tue May 22, 2018 12:32 am     Reply with quote

Ttelmah wrote:

Just to reinforce this, look at the figure 15 you post. Look at the I2C
transactions. You will see 'A' for acknowledge on all except the very last
one for the data, that has 'N' for not acknowledge.


tnx alot..its work properly

ms5611_prom.c
Code:
 
unsigned int8 c1h=0,c1l=0,c2h=0,c2l=0,c3h=0,c3l=0,c4h=0,c4l=0,c5h=0,c5l=0,c6h=0,c6l=0;
 unsigned int16 c1=0,c2=0,c3=0,c4=0,c5=0,c6=0;

unsigned int8 p1=0,p2=0,p3=0,t1=0,t2=0,t3=0;
unsigned int32 d1=0,d2=0,db=0;

signed int64 off=0,sens=0,p=0,temp=0;

void ms5611_prom(){
 
 i2c_start();
 i2c_write(0xee);
 i2c_write(0xa2);
 i2c_start();
 i2c_write(0xef);
 c1h=i2c_read(1);
 c1l=i2c_read(0);
 i2c_stop();
 
 delay_ms(1);
 
 
 i2c_start();
 i2c_write(0xee);
 i2c_write(0xa4);
 i2c_start();
 i2c_write(0xef);
 c2h=i2c_read(1);
 c2l=i2c_read(0);
 i2c_stop();
 
  delay_ms(1);
 
 
 i2c_start();
 i2c_write(0xee);
 i2c_write(0xa6);
 i2c_start();
 i2c_write(0xef);
 c3h=i2c_read(1);
 c3l=i2c_read(0);
 i2c_stop();
 
 
  delay_ms(1);
 
 i2c_start();
 i2c_write(0xee);
 i2c_write(0xa8);
 i2c_start();
 i2c_write(0xef);
 c4h=i2c_read(1);
 c4l=i2c_read(0);
 i2c_stop();
 
 
  delay_ms(1);
 
 i2c_start();
 i2c_write(0xee);
 i2c_write(0xaa);
 i2c_start();
 i2c_write(0xef);
 c5h=i2c_read(1);
 c5l=i2c_read(0);
 i2c_stop();
 
 
  delay_ms(1);
 
 
 i2c_start();
 i2c_write(0xee);
 i2c_write(0xac);
 i2c_start();
 i2c_write(0xef);
 c6h=i2c_read(1);
 c6l=i2c_read(0);
 i2c_stop();
  delay_ms(1);
 
 
 c1=make16(c1h,c1l);
 c2=make16(c2h,c2l);
 c3=make16(c3h,c3l);
 c4=make16(c4h,c4l);
 c5=make16(c5h,c5l);
 c6=make16(c6h,c6l);
 }
 
 
 
 void get_d1d2(){
 
 
  i2c_start();
 i2c_write(0xee);
 i2c_write(0x48);
 i2c_stop();
 
 delay_ms(10);
 
  i2c_start();
 i2c_write(0xee);
 i2c_write(0x00);
 i2c_stop();
 
 delay_us(3);

  i2c_start();
 i2c_write(0xef);
p1=i2c_read();
p2=i2c_read();
p3=i2c_read(0);

 i2c_stop();
 
 delay_us(3);
 d1=make32(0,p1,p2,p3);
 
 i2c_start();
 i2c_write(0xee);
 i2c_write(0x58);
 i2c_stop();
 
 delay_ms(10);
 
  i2c_start();
 i2c_write(0xee);
 i2c_write(0x00);
 i2c_stop();
 
 delay_us(3);

 i2c_start();
 i2c_write(0xef);
 t1=i2c_read();
 t2=i2c_read();
 t3=i2c_read(0);
 i2c_stop();
 
 delay_us(3);
 d2=make32(0,t1,t2,t3);
 
 }
 
 
 void get_temp(){
 
  db=c5*256;
 db=d2-((int32)c5*256);
 temp=2000 + db*((float)c6/8388608);
 }
 
 
 void get_pres(){
 
off=((int64)c2*65536) + ((int64)c4*db)/128;
sens=((int64)c1*32768) + ((int64)c3*db)/256;
p=(((d1*sens)/2097152)-off)/32768;
 }


ms5611.c
Code:

#use rs232(xmit=PIN_B0, baud=9600)

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <ms5611prom.c>

void main()
{
ms5611_prom();

delay_ms(50);
char ss[20];

   while(TRUE)
   {
 
get_d1d2();
get_temp();
get_pres();


 itoa(p,10,ss);
 puts(ss);
  }

}




if code does not have problem i put it in code library?

tnx Ttelmah and pcm
m4k



Joined: 27 Mar 2018
Posts: 29

View user's profile Send private message

PostPosted: Tue May 22, 2018 1:04 am     Reply with quote

Ttelmah wrote:
Just to reinforce this, look at the figure 15 you post. Look at the I2C transactions. You will see 'A' for acknowledge on all except the very last one for the data, that has 'N' for not acknowledge.




i try to calculate altitude from the pressure...

What is the pressure-to-height conversion formula?
Ttelmah



Joined: 11 Mar 2010
Posts: 19480

View user's profile Send private message

PostPosted: Tue May 22, 2018 3:09 am     Reply with quote

You have a lot of maths to do first to get the pressure.

You need the six coefficients read from the PROM. Stored as unsigned int16 values C1 to C6. Then:

Code:

signed int32 Dt, TEMP;
signed int64 OFF, SENS, P;

Dt = (signed int32) D2 - ((signed int32)C5 * 256);
TEMP = 2000 + Dt * (signed int32)C6 / 8388608;

OFF = (signed int64)C2 * 65536+(C4 * (signed int64)Dt)/128;
SENS = (signed int64)C1 * 32768+(C3 * (signed int64)Dt)/256;

P = (D1*SENS/2097152 - OFF)/32768;

//This then gives P in 10's of nBar


Then you have to make a decision whether you want to work in standardised altitude or local.

If you look at aircraft, when they want their 'real' altitude at low levels, they work using the local reference pressure. So an aircraft is given the Qnh, which is the local sea level pressure, and can then get their altitude above 'sea level'. When flying into a local airfield and wanting to know their height above this they use Qfe (which is the pressure measured at that airfield). However when working at high altitude they switch to using the 'ICAO standard atmosphere', and work from a base pressure of 1013.25mBar. Now of course if you used this at low altitude on days when the pressure varied significantly you could find yourself many hundreds of feet above or below your 'real' altitude. But at high altitude all the aircraft being a few hundred feet high or low doesn't matter, so long as they are all using the same reference. The altitude at which you switch is the 'transition altitude'.

Now for your pressure to give altitude with good accuracy at a location, you would have to feed it the pressure at a know altitude for the same region. So on GPS's for example with pressure sensors, you can put in a known altitude when you are sitting on an airfield,and it then uses this as the reference. Or in flight you can put in the Qfe or Qnh so you know your reference and height relative to this. The formula for the conversion is the barometric formula. Doing it properly is quite complex. However the simplified form used for aviation is:

Palt = Psurf*(1-22.556922E-6*Alt)^5.2561

Working with pressures in hectoPascals (mBar), and altitude in meters.

However the even simpler formula for low altitude is that the pressure drops by 11.3Pascals per meter.

If you feed an altitude of 100m with a starting pressure of 1013.25mB into the formula above, you get:

Palt = 1001.29

which is a change of 1195 Pascals. The 11.3 Pascal figure (1130 at 100m) would be out by only 5%.


Last edited by Ttelmah on Wed May 23, 2018 1:00 am; edited 1 time in total
m4k



Joined: 27 Mar 2018
Posts: 29

View user's profile Send private message

PostPosted: Tue May 22, 2018 10:04 am     Reply with quote

Ttelmah wrote:
You have a lot of maths to do first to get the pressure.

You need the six coefficients read from the PROM. Stored as unsigned int16 values C1 to C6. Then:

.


i try to export altitude in meter unit and I succeeded..

but I have a strange problem...the datasheet said "High resolution module, 10 cm" According to the output values of pressure its not true...

Please take a look at these values



its not stable


whats wrong?
Ttelmah



Joined: 11 Mar 2010
Posts: 19480

View user's profile Send private message

PostPosted: Tue May 22, 2018 12:04 pm     Reply with quote

Itg wouldn't be. Barometric pressure is changing all the time. The 10cm is the smallest height change it can resolve, not an 'accuracy' that you can achieve. The pressure will even shift as you walk past the sensor.

If you have a phone with a baro sensor, stcnd still and see how it drifts. If I stand in my garden for 10 minutes I'll often find the altitude from the baro drifting by a couple of metres. Day by day, if you have something like a thunderstorm come across, pressure altitude can change by about 300 metres.

If you fly an aircraft for an hour, and land back at the same airport without adjusting the Qfe, it is common to find the 'altitude' has changed by many feet.

Your figure also bears no resemblance to the pressure reading. Typical value should be around ten million. I'd suspect you are only reading the low two bytes. They divide the value by a significant amount for the final pressure figure, which means small changes in the last few bits won't even show...
Ttelmah



Joined: 11 Mar 2010
Posts: 19480

View user's profile Send private message

PostPosted: Tue May 22, 2018 2:07 pm     Reply with quote

OK I see you are actually printing the output. Still a wrong value. Should be about 100000. Look at the maths. For instance:

Code:

 void get_temp(){
 
  db=c5*256; //Er... Why?.
  //Also this is using int16 arithmetic....
  db=d2-((int32)c5*256);
  temp=2000 + db*((float)c6/8388608);
  //Float not wanted here. All the maths is integer
  }


Now compare to my version:
Code:

Dt = (signed int32) D2 - ((signed int32)C5 * 256);
TEMP = 2000 + Dt * (signed int32)C6 / 8388608;


This is smaller and faster, and more accurate.

General comment, stop using 'undefined' numbers like the 0xEE etc.. Use defines and give these names. That way your code becomes much easier to understand and read.

Now why fiddle using itoa. Just print.

Code:

itoa(p,10,ss);
 puts(ss);

//just use
   printf("%ld", p);


itoa is only really ever needed if you are going to a base other than 10, or want to fiddle with the string after generating it. printf handles base 10, and base 16 intrinsically.

Something somewhere is going wildly wrong with the maths, since you should be seeing a result around 100000. 85000 is much too low (unless you were sitting in the eye of a major storm). (actually too low even then - below the lowest ever recorded barometric reading 870hPa).....

Start by printing the numbers you are actually getting from each read. They give typical values for each value in the data sheet, so be really suspicious if any value differs from the expected result by more than perhaps 50%.
Then print the values from each part of the maths. Does it match what it should be (after all you have the earlier values so can check)?.
Long term, is the unit likely to be used at a temperature much below 20C?. If so you have to look at implementing the second order temperature compensation described in the data sheet.
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 1, 2  Next
Page 1 of 2

 
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