Problem in reading data from MPU6050 using I2C protocol

Go To Last Post
30 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi every one I'm new to the forum and this is my first post :

I'm trying to get accelerometer data from MPU6050 module using I2C protocol 
So I've built my own functions using avr-C programming to print data on Serial monitor
but when I'm reading data the read data of the accelerometer Z-axis output oscillates  between 0.9x and 0.xx without I make any movement to the sensor (the sensor is placed on a table without any external forces)
I've attached to this post my code. 

Any help will be so appreciated
 

PS: The problem isn't hardware related because I've tested another code using arduino IDE and it was working fine.    

Attachment(s): 

This topic has a solution.
Last Edited: Tue. Jul 17, 2018 - 11:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is always wise to use proven I2C library code.  e.g. Arduino or Fleury.

Always use return values when available.   This will show where any problems lie.

 

There is nothing wrong with writing your own I2C code.   But if you use the working library first,  you can compare your implementation.

 

I looked at your code and was pleasantly surprised to see that your functions were not void.    But you don't actually return valid values.  So that is worse than void.

 

Oh,  if you want someone to actually build and debug your code,  put an AS7 project into a ZIP and attach the ZIP.

Attaching multiple files is probably better than reams of pasted code.   It is always a judgement as to what is most appropriate.    i.e. what is most likely to "encourage" your readers.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your reply, 
In fact the functions were returning I2C status but I thaught it would be more simple to understand my code if I remove those portions of code and forgot to change some functions type to void
You can find in attach my previous version of code. 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have built an AS7 project.   There are several issues.

 

I am going to the pub.

 

I will address the "issues" and connect it to real hardware tomorrow.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My apologies.   I thought that I had an Ebay MPU6050 module.   I discovered that it was actually ADXL345.    So I can't run on real hardware.

 

Anyway,  these are the "corrections" that I made:

  C:\Users\David Prentice\Documents\Atmel Studio\7.0\User01_MPU6050\User01_MPU6050\USART.c(2):#include <stdio.h>    //.kbv sprintf
  C:\Users\David Prentice\Documents\Atmel Studio\7.0\User01_MPU6050\User01_MPU6050\USART.c(3):#include <stdlib.h>	  //.kbv dtostrf
  C:\Users\David Prentice\Documents\Atmel Studio\7.0\User01_MPU6050\User01_MPU6050\USART.c(15):    UCSR0B = (1 << RXEN0) | (1 << TXEN0) |(0<<RXCIE0);		// .kbv Enable USART Tx+Rx lines
  C:\Users\David Prentice\Documents\Atmel Studio\7.0\User01_MPU6050\User01_MPU6050\USART.c(16):    UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);                // .kbv Define data format to 8 bit data and 1 stop bit

It is VERY important that you include the relevant header files when using library functions like dtostrf()

Your USART init uses |= when = would be more appropriate.

Your USART files enable RXC interrupts but there is no ISR()

 

When dtostrf() has the correct prototype you will probably get accurate values.

Please copy-paste from your Serial Terminal.   This is much easier to read in a message than a PNG file.

 

Oh,   providing return values in your I2C functions is better than void.

I suggest that you have a consistent GOOD or BAD return value.  e.g. 0 is GOOD.   non-zero is BAD (TWI status value)

Of course return values are no good for anything if you don't use them.

 

David.

Last Edited: Tue. Jul 17, 2018 - 07:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
It is VERY important that you include the relevant header files when using library functions like dtostrf()

Indeed.

 

This is basic 'C' stuff - nothing specifically to do with AVR.

 

david.prentice wrote:
much easier to read in a message than a PNG file.

If you are going to post images, then embed them in the post - rather than attaching - so that we can actually see them in context; eg,

 

 

For instructions on how to do that, see Tip #1

 

david.prentice wrote:
copy-paste from your Serial Terminal

For the text to retain its layout as seem on your Serial Terminal, post it as for source code.

 

instructions on how to do that also in Tip #1

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not all Serial Terminals can be cut-n-pasted from.   In which case you are stuck with PNG, JPG, ...

 

If you can copy-paste the text from a Serial Terminal it means that the reader can capture it too.    And use regular text manipulation tools like grep and diff.    Or simply use the Browser "ctrl-F"

In your case the text is pretty trivial but often the Serial Terminal is used for important debug logging.

 

Yes,  it is handy if the PNG is embedded into your message but you still can't extract the text.

 

David.

Last Edited: Tue. Jul 17, 2018 - 08:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

EDIT - TRY AGAIN

 

david.prentice wrote:
Not all Serial Terminals can be cut-n-pasted from. 

I'd venture to suggest that any Serial Terminal which can't be cut-n-pasted from/to should be replaced ASAP with one which can!

 

surprise

 

Most Serial Terminals can also log to a file.

 

TeraTerm, for one, has the advantage that it can timestamp that log - which can be invaluable.

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Tue. Jul 17, 2018 - 10:03 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi again,
I've made the changes you told me David on my code but the problem is still unsolved.
I also included some debug outputs to my code.

 

Serial Debug Output :

 

Serial Output Without Debug :

 

Please also find in attach a new version of the code where I made the changes you told me and added The debug code.
Thank you for all the advices.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

User01 wrote:
Z-axis output oscillates  between 0.9x and 0.xx 

So which axis are you calling 'Z' ?

 

If it's the vertical axis, could this be a problem with your cancellation of gravity - especially as the numbers seem to be varying between +0.9x and -0.xx ... ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Indeed Z_axis is the vertical axis 
But I don't think there is a cancellation  of gravity because I just kept the sensor on a table without touching it nor applying external forces to it so if it osscillates it should be oscillating around a value close to "1" but there it goes too much far away when it indicates a value of 0.xx
Also I've tested an Arduino sketch and the values was something like 0.9x (always) so if it was a cancellation of gravity there also I should have got values oscillating between 0.9x and 0.xx which is not the case.

Last Edited: Tue. Jul 17, 2018 - 02:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

User01 wrote:
Also I've tested an Arduino sketch and the values was something like 0.9x (always) 

So you have a known-working reference point, then.

 

Compare & contrast your code with that sketch to see where your code is going wrong ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

User01 wrote:
Indeed Z_axis is the vertical axis 

So what happens if you change the orientation:

  1. So that what is currently the 'X' axis becomes 'Z' ?
  2. So that what is currently the 'Y' axis becomes 'Z' ?

 

Does the "oscillation" stay with whichever axis happens to be vertical at the time ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is no mythical "gravity cancellation" in MPU6050 datsheet....

The Z axis is slightly more noisier (but each and every axis can measure gravity, else one could not tilt sensor)

If there was a mythical "cancellation of gravity", one could not rotate the sensor (ex : one rotates it round Y axis: X should measure gravity (with a sign depending on luck and skill).

That -90 ° rotation around X or Y axis, swapping Y -resp X- and Z -  would be a way of knowing whether this failure is Z axis specific, or affects every axis (if every axis is affected, seems a software issue).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dbrion0606 wrote:
There is no mythical "gravity cancellation" in MPU6050 datsheet....

I was thinking of processing in the OP's code - not by the MPU6050 itself.

 

Quote:
if every axis is affected, seems a software issue

Exactly.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dbrion0606 wrote:

 

That -90 ° rotation around X or Y axis, swapping Y -resp X- and Z -  would be a way of knowing whether this failure is Z axis specific, or affects every axis (if every axis is affected, seems a software issue).

 

I've tested your proposition and found that indeed the issue was affecting every axis

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so it is a fault in your software, then!

 

Try printing out the raw bytes as they come from the bus - instead of doing any processing within the AVR.

 

Again, look at how the Arduino handles the raw bytes.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

So you have a known-working reference point, then.

 

Compare & contrast your code with that sketch to see where your code is going wrong ...

 

Indeed I have a reference point (which you can find in attach of this post) but it uses <Wire.h> library so all the implementation that I can compare to is within this library but when I searched for the library on the net I found many different implementation and they all used an interrupt based method instead of a polling method like mine. 
 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

Try printing out the raw bytes as they come from the bus - instead of doing any processing within the AVR.

 

The problem remains even after printing just raw bytes :

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

"

dbrion0606 wrote:

There is no mythical "gravity cancellation" in MPU6050 datsheet....

aweill wrote:

 

"I was thinking of processing in the OP's code - not by the MPU6050 itself."

 

Well, I bet you read OP code, did not you...

and you noticed that, nowhere, "gravity cancellation" occured (main read rawdata, scales them by dividing (float)  by 2**13, prints them as they are; and that 's all)

 

So, this "gravity cancellation" remains  a myth. (it may occur later in SW, if one has a reliable information of rotation, but OP very wisely deals ... with rawdata ... the very name of his project)

 

main countains (among other things)

  Read_Accel_Values();

                        // Divide raw values by sensitivity scale factor
                        Xa = Acc_x/16384.0;
                        Ya = Acc_y/16384.0;
                        Za = Acc_z/16384.0;
                        
                        //Print Data
                        print( " Ax = %s g\t",Xa, 3, 2);
                        print(" Ay = %s g\t",Ya, 3, 2);
                        print(" Az = %s g\n\n",Za, 3, 2);

(Xa ... Za are floats:  print -I would have called it myPrint... but it doesnot solve anything -  is defined (from usart.c)  as

void print(char msg[30],double data,char intpart,char floatpart){
        dtostrf( data, intpart, floatpart, float_ );
        sprintf(buffer,msg,float_);
        USART_SendString(buffer); // buffer exists, is [20] in usart.h
}
 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
        dtostrf( data, intpart, floatpart, float_ );
        sprintf(buffer,msg,float_);

If I live to be a million I don't think I'll ever understand that. Why the separate call to dtostrf() if sprintf() is to be used? Why not just %f directly in the sprintf() format string? Is this about someone who hasn't come across libprintf_flt.a by any chance?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

        dtostrf( data, intpart, floatpart, float_ );
        sprintf(buffer,msg,float_);

If I live to be a million I don't think I'll ever understand that. Why the separate call to dtostrf() if sprintf() is to be used? Why not just %f directly in the sprintf() format string? Is this about someone who hasn't come across libprintf_flt.a by any chance?

with dtostrf I format my variables to set how many digits should be printed in their integer part and their decimal part before changing them to a string 

sprintf is to put the formated variable into a message

 

Last Edited: Tue. Jul 17, 2018 - 05:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had a look at https://www.microchip.com/webdoc...

 

And it seery interesting (as, unlike sprintf -which is standard, width and decimal position can vary %f or %7.2f do not control these parameters)

 

 

Function dtostrf()

char * dtostrf(
	double __val,
	signed char __width,
	unsigned char __prec,
	char * __s)

The dtostrf() function converts the double value passed in val into an ASCII representationthat will be stored under s. The caller is responsible for providing sufficient storage in s.

 

(here _float (OP's "_s") is given 10 chars in usart.h) . This removes something I  suspected .

But, at least for debugging, integer value of what is received should be printed (i.e Acc_x, Acc_y, Acc_z).

 

Is this about someone who hasn't come across libprintf_flt.a by any chance?

sh-4.1$ less USART.c  
sh-4.1$ less USART.h
sh-4.1$ less  ReadingMPURawData/ReadingMPURawData/main.c  
sh-4.1$ grep --recursive printf_flt ReadingMPURawData
sh-4.1$ 

OP sent a whole project... Nowhere is the  printf_flt invoked .... (sending integers as they are received would not hurt, before float/any conversion)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would rewrite :


void Read_Accel_Values()
{
        MPU_Start_Loc_Accel();          // Define the start address from where to read data (ACCEL_XOUT_H)
        Acc_x = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        Acc_y = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        Acc_z = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Nack());
        I2C_Stop();
}

as


void Read_Accel_Values()
{
    int x1, x2, y1, y2, z1, z2;
    
        MPU_Start_Loc_Accel();          // Define the start address from where
        to read data (ACCEL_XOUT_H)
         x1 = (int)I2C_Read_Ack();
         x2 = (int)I2C_Read_Ack();
         Acc_x = (x1 << 8) | x2; // 
        // Acc_x = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        if (debug){ 
                sprintf(buffer, "%d %d %d \n",x1, x2, Acc_x ); /*
        this is overkill but I do not miss anyhing; there is room enaugh in buffer -glob.var. like debug*/
               USART_SendString(buffer);
}
        Same conversions for y....
        Acc_y = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        Acc_z = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Nack());
        I2C_Stop();
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dbrion0606 wrote:
I would rewrite :


void Read_Accel_Values()
{
        MPU_Start_Loc_Accel();          // Define the start address from where to read data (ACCEL_XOUT_H)
        Acc_x = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        Acc_y = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        Acc_z = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Nack());
        I2C_Stop();
}

Indeed.

 

The MPU gives a 16-bit 2's complement value; the I2C_Read_... functions return 'char' - check that the sign information is being properly propagated.

 

Again, print out the raw received bytes - and, as dbrion0606 shows, your intermediate values...

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
Acc_x = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());

The compiler doesn't guarantee that the two I2C_Read_Ack()s will be called in any particular order. Either the first or the second might be called first. You need to call them explicitly in order like this:

Acc_x = (int)I2C_Read_Ack()<<8;

Acc_x |= I2C_Read_Ack();

or this, depending on the byte order:

Acc_x = I2C_Read_Ack();

Acc_x |= (int)I2C_Read_Ack()<<8;

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dbrion0606 wrote:

I would rewrite :


void Read_Accel_Values()
{
        MPU_Start_Loc_Accel();          // Define the start address from where to read data (ACCEL_XOUT_H)
        Acc_x = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        Acc_y = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        Acc_z = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Nack());
        I2C_Stop();
}

as


void Read_Accel_Values()
{
    int x1, x2, y1, y2, z1, z2;

        MPU_Start_Loc_Accel();          // Define the start address from where
        to read data (ACCEL_XOUT_H)
         x1 = (int)I2C_Read_Ack();
         x2 = (int)I2C_Read_Ack();
         Acc_x = (x1 << 8) | x2; //
        // Acc_x = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        if (debug){
                sprintf(buffer, "%d %d %d \n",x1, x2, Acc_x ); /*
        this is overkill but I do not miss anyhing; there is room enaugh in buffer -glob.var. like debug*/
               USART_SendString(buffer);
}
        Same conversions for y....
        Acc_y = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
        Acc_z = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Nack());
        I2C_Stop();
}

 

 

Sorry for the delay I was busy with something else 
You can find below the Serial output after the change you asked me to make :

Last Edited: Tue. Jul 17, 2018 - 10:48 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah, I see there's an issue with signed values. Take the last sample:

z1=58 z2=-120 Acc_z=-120

It looks like I2C_Read_Ack() returns data as a signed 8-bit value and not an unsigned 8-bit value. Change this:

         x1 = (int)I2C_Read_Ack();
         x2 = (int)I2C_Read_Ack();

to this:

         x1 = (uint8_t)I2C_Read_Ack();
         x2 = (uint8_t)I2C_Read_Ack();

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

christop wrote:

Ah, I see there's an issue with signed values. Take the last sample:

z1=58 z2=-120 Acc_z=-120

It looks like I2C_Read_Ack() returns data as a signed 8-bit value and not an unsigned 8-bit value. Change this:

         x1 = (int)I2C_Read_Ack();
         x2 = (int)I2C_Read_Ack();

to this:

         x1 = (uint8_t)I2C_Read_Ack();
         x2 = (uint8_t)I2C_Read_Ack();

 

 

Yeah, it is working fine now thank you 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It looks as if your problems were due to your "unusual" API for the I2C functions.

 

Look at Fleury or other proven libraries.   Peripheral primitives always return uint8_t.   You extend values to uint16_t or uint32_t.

 

If the particular data is signed,   you do the casting on the extended uint16_t or whatever.

 

Seriously,   it is worth starting with a simple Arduino sketch.   Then writing your equivalent version in C.   

There is nothing special about the Wire.h library.   You write a sequence.   Then request a fixed number of bytes to read.

It is easy enough to implement this with polled functions e.g. Fleury.

 

I am pleased that you have got it working now.

 

David.