[SOLVED] undefined reference to function I2C library and HMC5883L read function

Go To Last Post
145 posts / 0 new

Pages

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

 

clawson

That code is relying on a bug!

 

You do this:

uint8_t array[2];

That creates a two element array (that's what [2] means) in memory. You are quite right that the elements are 0 based so they are referred to as array[0] and array[1]. There is no such thing as array[2] created in your code. So later when you do:

    array[2] = 27 + 98;

what you are actually doing is randomly writing into the next byte in RAM that just happens to come immediately after the two bytes called array[0] and array[1]. If you wrote:

array[17] = 123;

then that would write to the 18th location after the start address of the array[].

 

C is very "dangerous" in this way. It does not (usually) warn you about this kind of mistake and, indeed, about 75% of all serious software faults in C are probably ultimately traced back to out of bounds array writes or more generally writes to memory through invalid pointer locations (array[17] really means nothing most than *(array + 17) so it's still effectively a write through an invalid pointer).

 

If I build your code in GCC then even if I enable all warnings (-Wall) it still won't tell me that there is a fatal bug in this code. But there is. You cannot make a write to array[2] because no memory has been allocated to hold that element.

OMG I'm sorry, I think I forgot about the real array's indexing rules.

 

I tested a code with sizeof function. And got this result:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

void array_add(void);
uint8_t array[2];

uint8_t i;

int main()
{

    array_add();

    for (i=0;i<sizeof(array);i++)
    {
      printf("array[%d] = %d\n",i,array[i]);
    }

    return 0;
}


void array_add(void)
{
    array[0] = 7 + 8;
    array[1] = 77 + 58;
    array[2] = 27 + 98;
}

And eve I declared the function return type as void with no arguments. And it did same as declaring it as:

uint8_t array_add(uint8_t arr);

At this point I understood that the function modifies any variable if it's global except if it's declared with "const" modifier.

 

So, I really should know when to declared return type for a function and when to pass arguments.

 

 

But, I would:

1. Pass an argument when I want to pass values to a function and modify that variable or affect the process inside the function.

2. Declare a function with return type, when I want to return a value and pass it to another function.

 

I found this eBook which explains some information about return functions:

 

int euclid( int m, int n ) {
if( n>0 ) {
return euclid( n, m%n ) ;
} else {
return m ;
}
}

So, here I know that I can return a value anytime inside the function at a certain point, before proceeding to the rest of the function.

 

 

And this is the result:

array[0] = 15
array[1] = 135

Process returned 0 (0x0)   execution time : 0.035 s
Press any key to continue.

This is the result for the previous function call.

 

 

Similar nonsense exists here:

uint8_t add (uint8_t num1, uint8_t num2);

That tells us of a function called add() that takes two input values in the range 0..255 and it returns a value between 0 and 255. But then you use it as:

   add(msb, lsb);

so again you completely ignore the return value so in:

uint8_t add (uint8_t num1, uint8_t num2)
{
    sum = num1 + num2;

    return sum;
}

the "return sum;" might as well not exist. The only reason the line:

    printf("The add result is 0x%.2x\n\n",sum);

Here I think I don't know when I want to return a value.

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

david.prentice

Go on.   Follow a sensible scheme e.g. start with proven libraries,  and replace small sections with your code.

 

Any educational course will cost money.    Some might be good value.

Likewise,   self-teaching can be effective if you plan it carefully.

 

Show that you are "reading" the replies on this forum.   It might encourage a better response.

 

David.

 Yes :) Thank you for encouraging me. Also thank you for the advice to replace proven library.

 

Well, about educational course, as I mentioned I went to Bengaluru, India, there are reasonable amount of technology institutions. But I didn't have much time and the course wasn't so effective to me.

 

I want to go inside a complex code and I wanted a coach to teach me that code, but I engaged into a normal C classes with beginners. I wanted someone to teach me a complex code I downloaded from the internet about 2.4 TFT display which is about 1000 lines. But they also didn't have the time for that, so I went back home with no big benefit.

 

That's why I'm relying on self teaching, by reading eBooks, testing and investigating easy to intermediate libraries on the web, posting on forums and watching YouTube videos.

 

And I did some OK things; like, getting I2C to work, SPI and interfacing LCD1602 in 4-bit mode with and without the I2C module, Fading RGB module, activating motion sensor which is easy of course :) and other easy stuff.

 

That's why I'm moving to HMC5883L which is more complex than the easy things I did before.

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

 

I was working on this code and trying to do some debugging.

 

I developed a function to read the value in the MODE register which has to be 0x00.

 

Where I get in the first reading on the serial monitor 1 and then right after continuous 3, 3, 3, ...?!

 

Where 1 means the device is configured as single measurement, 3 means the device is in the idle mode.

 

But in init function I literally wrote 0x00 to the register.

 

I commented init function and thought it's not working at all, but the first reading of the reading MODE register is 3. So my writing to registers in init function is working.

 

But why the MODE register is not accepting to be in continuous measurement?

 

This is the code:

#include <I2C.h>

#define HMC5883L_read   0x3D
#define HMC5883L_write  0x3C

#define Configuration_Register_A    0x00  //Read/Write
#define Configuration_Register_B    0x01  //Read/Write
#define Mode_Register               0x02  //Read/Write
#define Data_Output_X_MSB_Register  0x03  //Read
#define Data_Output_X_LSB_Register  0x04  //Read
#define Data_Output_Z_MSB_Register  0x05  //Read
#define Data_Output_Z_LSB_Register  0x06  //Read
#define Data_Output_Y_MSB_Register  0x07  //Read
#define Data_Output_Y_LSB_Register  0x08  //Read
#define Status_Register             0x09  //Read
#define Identification_Register_A   0x10  //Read
#define Identification_Register_B   0x11  //Read
#define Identification_Register_C   0x12  //Read
#define declination_angle 3.46

void HMC5883L_init (void);
int16_t data_read (int16_t *results);
void HMC5883L_read_reg (uint8_t reg);

int16_t results[3];
float m_scale = 1.0;

void setup() {
  // put your setup code here, to run once:
  I2C_init();
  Serial.begin(9600);
  HMC5883L_init();
  Serial.print("mode register ");
  HMC5883L_read_reg(Mode_Register);
  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:
  data_read(results);
  Serial.print("x-axis = ");
  Serial.println(results[0]);
  Serial.print("z-axis = ");
  Serial.println(results[1]);
  Serial.print("y-axis = ");
  Serial.println(results[2]);
  Serial.println();
  Serial.print("mode register ");
  HMC5883L_read_reg(Mode_Register);
  Serial.println();
_delay_ms(500);
}

void HMC5883L_init (void)
{
  I2C_start(HMC5883L_write);
  I2C_tx(Configuration_Register_A);
  I2C_tx(0x07);
  I2C_tx(Configuration_Register_B);
  I2C_tx(0x01);
  I2C_tx(Mode_Register);
  I2C_tx(0x00);
  I2C_stop(); 
}

int16_t data_read (int16_t *results)
{
  uint16_t lsb,msb;
  int16_t status_of_process = 0;
  I2C_start(HMC5883L_write);
  I2C_tx(Data_Output_X_MSB_Register);
  I2C_start(HMC5883L_read);
 
  msb = I2C_rx();
  lsb = I2C_rx();
  results[0] = msb << 8 | lsb;  

  msb = I2C_rx();
  lsb = I2C_rx();
  results[1] = msb << 8 | lsb;

  msb = I2C_rx();
  lsb = I2C_rx();
  results[2] = msb << 8 | lsb;
  
  I2C_stop();

  return status_of_process;
}

void HMC5883L_read_reg (uint8_t reg)
{
  uint8_t reg_dat;
  I2C_start(HMC5883L_write);
  I2C_tx(reg);
  I2C_start(HMC5883L_read);
  reg_dat = I2C_rx();
  Serial.println(reg_dat);
}

 

Last Edited: Sat. Jun 10, 2017 - 04:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

 

I did one update to the code I learned from stack exchange and it worked well for the mode register but I still get constant readings!

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

Look at known good code and see how it does it.

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

Yes of course, I think I'm close to solution. I know I should look into other codes but I open libraries on GitHub and it's written in C++ and apply other header libraries. And also there are other functions for calibration and setting the gain but I don't know what is gain and calibration are for?

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

Regardless of the actual language - look for how they initialise the device and how they read the information. How do you handle the ACK bit in i2c? That might be a clue.
As for the cal functions - read the device datasheet like everyone else would do.

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

I don't know what is gain and calibration are for?

 

Well, each magnetometer raw value , say E[i 1=1,3] is linked to the "real" avlue M[i] in the approximate way:

E[i] = Ai*M[i] + Bi + noise + things I forget to make things simple...

 

Ai is i-th magnetometer gain. Bi is a bias

Suppose A1 == 1 (a perfect reading) and A2 == 0.5 and each B is zero and your magnetometer is horizontal.

With a 45 degree heading, axis 1 will read ... 1 and axis 2 will read 0.5 -> a 63 degree estimated error, almaost 20 degree error

 

sh-4.1$ python
Python 2.7.3 (default, Dec 18 2012, 13:50:09) 
[GCC 4.5.3] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from math import *
>>> atan2(1,1)
0.7853981633974483
>>> atan2(1,0.5)
1.1071487177940904
>>> atan2(1,0.5)*45/atan2(1,1)
63.43494882292201
>>> quit()

I gave the way python computed it ...

 

Bias is important, too , if one is near a magnet (the magnufacturer cannot compensate it and arduini can drive DC motors). If there was a 100% bias on one axis, your magneteometer will always estimate a  North -ish (say : values are easy to figure out with Python, Excel, a brain... ) direction. It can be compensated, in a very crude way, by rotating slowly the magnetometer and keeping it horizontal: "smart" phones compute it from half the sum of the maximum and minimum values (disacrding other values : if a non shaking hand finds out correctly the max and the min, this gives good corrections)...

 

Bias and offset estimations should not be neglected (at least for boats -even in the 1980s, compasses were very carefully compensated, after I do not know-, prayers)

 

Noise can be estimated on an Arduino by the sum of the absolute difference between two consecutive values (for white gaussian noise, it is proportional to the standard deviation, and easier to compute) ... or sending -via a serial link- each value to a PC/RPi/nanoPi with some statistical software....

 

Things I forget to be kept simple  can be found by google search, if one really needs to make complicated things.

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

To say "I can't afford it!"  shuts down the mind, instead focus on "How can I afford it!" to open your mind to the possibilities. 

If you want it bad enough, you will find a way!

 

Jim

 

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

Kartman

Regardless of the actual language - look for how they initialise the device and how they read the information. How do you handle the ACK bit in i2c? That might be a clue.
As for the cal functions - read the device datasheet like everyone else would do.

 

I have this function which tells me about ACK:

 

void I2C_TWSR_Check(void)
{
  uint8_t Status;
  Status = TWSR & 0xF8;
  switch(Status)
  {
    /////////////// MASTER TRANSMITTER //////////////
    case 0x08: 
    Serial.println("Start is OK");
     break; 
    case 0x10:
    Serial.println("Re start");    
     break;    
    case 0x18:    
    Serial.println("SLA+W OK ACK");    
     break;    
    case 0x20:  
    Serial.println("SLA+W no ACK");    
     break;      
    case 0x28:  
    Serial.println("data TX OK ACK");    
     break;    
    case 0x30:       
    Serial.println("data TX OK no ACK");   
     break;       
    case 0x38:        // arbitration lost in SLA+W or data TX
    Serial.println("arbitration lost in SLA+W or data TX");    
     break;

    /////////////// MASTER RECEIVER //////////////  
    case 0x40:
    Serial.println("SLA+R OK ACK");    
     break;    
    case 0x48:    
    Serial.println("SLA+R OK NO ACK");   
     break;       
    case 0x50:  
    Serial.println("data RX OK ACK");   
     break;  
    case 0x58: 
    Serial.println("data RX OK NO ACK");   
     break;  

     default:
     Serial.println("Error");
    break;
  }
}

 

 

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

ki0bk

To say "I can't afford it!"  shuts down the mind, instead focus on "How can I afford it!" to open your mind to the possibilities. 

If you want it bad enough, you will find a way!

 

Jim

Yeah, but that's too much money to throw on a course which lasts for only 5 days! How would I learn a lot in embedded systems in only 5 days?!

 

If the course << to my personal economical balancing of my budget, would cost 100 pounds for 5 days, then I would say go for it. You have the chance to test your abilities of how much knowledge you can get in 5 days.

 

And how much content you can receive in 5 days, what are the topics? Are the topics what I want to learn?

 

I can pay 100 pounds and then evaluate the results and the value you get after the course in comparison with the money you paid, I won't regret it even if the course didn't give me what I need.

 

But if I have to pay; like, 900 pounds, now I would really consider the money more that I'm getting in an embedded systems course, I would think about the money all the time, because that's out of my budget.

And, taking into account my thinking during the course, about the money I paid and what I'm getting right now! All these calculations are not comfortable during the course.

 

Not mentioning that I have to pay 2500 pounds!!? Are you serious :) That's too much money!

 

If the course is 6 months, I would say. OK, you can learn a lot in 6 months and the money worth the course. 5 days! No way I would finish only learning how to do USART and CAN for AVR, not mentioning working with ESP32, ARM or raspberry pi platforms and how each one would consume time to learn and do advanced applications and projects.

 

 

It's not about "I can't afford it!" or "How can I afford it!", it's about reasonable money in this world. I mean in USA universities which is the king of technology, you pay less than this money for one semester. Of course you have to pay this much every semester until you get the bachelor degree.

 

But my point of view comparing a specialized center for training to one semester in a fine university in USA, big difference I guess.

 

But of course there would be no aspects for comparing a complete course in embedded systems, which I don't think it's complete in 5 days! To a complete semester with different courses in a university. That's how I calculate it for this course.

Last Edited: Thu. Jun 15, 2017 - 02:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You clearly have not read the Philips/NXP spec on i2c.
Pretty well the functions boil down to :
Start
Write
Read with ack
Read with nak
Stop

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

I have every sympathy for wolfrose. Foreign educational courses are very expensive for private individuals.
They are designed for company employees.
.
Yes, you can pick up lots of advice from forums like this. But you have to read it carefully.
I would guide you through any sensible strategy. e.g. start with proven libraries.
I would even help you to "fix" your void I2C_xxxx() functions.
.
Meanwhile, this thread has stagnated for days.
We could get you solved within hours --------------- if you followed advice.
.
David.

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

The reality is that there is a wealth of learning material on the interwebs. I wouldnt be able to half of what i do if it werent for St Google. Granted that courses give you structure and a certificate.

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

Kartman

You clearly have not read the .
Pretty well the functions boil down to :
Start
Write
Read with ack
Read with nak
Stop

Why I would read the "Philips/NXP spec on i2c"? My configuration is AVR microcontroller and Honeywell HMC5883L 3-Axis Megnetoresistive Sensor module.

 

I did the I2C status checking with the AVR's datasheet, so with the receiving part, it obviously would be with the same datasheet, and thank you for advising me of the receiving part. I should add that now to my I2C library :)

 

But I think I don't need "Read with nak" because with I2C all you need for successful transmission is Read/Write with ack to know if your I2C process is going well. I think "nak" is not for debugging.

 

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

david.prentice

I have every sympathy for wolfrose. Foreign educational courses are very expensive for private individuals.
They are designed for company employees.

Thank you very much for your concern, I think they're most expensive in UK and Europe, maybe USA I don't have an experience searching US training centers' websites for embedded systems courses but I think they would be nearly as UK and Europe.

 

If they are designed for companies, then what is there for individuals? Also, what is the relationship that the courses are expensive because they're designed for companies? Is it because companies can afford this money and it's on business with high profit for training centers. So individuals really can't get into these courses?

 

Yes, you can pick up lots of advice from forums like this. But you have to read it carefully.

That's what I'm doing, I solved all my issues by the web and forums, but to be precise, I won't say I read carefully at first but I work on the advices and the help I get until I solve the problem and edit the topic title as [SOLVED].

 

I would guide you through any sensible strategy. e.g. start with proven libraries.

I did that, that's the reason I speak with you with confident that my issues are with the coding, because I tested my configuration with a library from e.g. GitHub.

 

I would even help you to "fix" your void I2C_xxxx() functions.

That'd be awesome :)

 

Meanwhile, this thread has stagnated for days.

Absolutely, I would start another post.

 

  We could get you solved within hours --------------- if you followed advice.

 I'm sorry, I try my best I don't want to hang you a lot, I really want to solve it from the first reply.

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

Kartman

Granted that courses give you structure and a certificate.

But I think for my level in programming, they won't be so helpful. Because I need to learn a lot in programming basics.

 

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

I actually now have a new compiling error :)

 

Arduino: 1.8.0 (Windows 10), Board: "Arduino Nano, ATmega328"

libraries\HMC5883L_my\HMC5883L_my.cpp.o (symbol from plugin): In function `HMC5883L_init()':

(.text+0x0): multiple definition of `axis_results'

sketch\HMC5883L.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\HMC5883L_my\HMC5883L_my.cpp.o (symbol from plugin): In function `HMC5883L_init()':

(.text+0x0): multiple definition of `measurement_scale'

sketch\HMC5883L.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here

collect2.exe: error: ld returned 1 exit status

exit status 1
Error compiling for board Arduino Nano.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

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

The error is quite clear - multiple definitions - axis_results and measurement_scale

You've defined these variables twice (or more). Identify where in the code you have these references and check your usage with the C/C++ rules.

My compiler has been complaining at me all day - I do try to keep it happy :(

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

I revised the code, but I didn't find it defined twice!

 

What new I did today, is that I moved HMC5883L definitions and functions to a separate .h and .cpp files. So that my HMC5883L.ino looks more compact and easier to deal with.

 

So that's how I got the error, and because I included:

 

#include "I2C.h"

Inside HMC5883L.cpp file. I think that what caused the problem, but I don't know how to solve it, at least right now.

 

I attached the libraries.

 

And this is my new easier to look code :)

 

#include "HMC5883L_my.h"
#include "I2C.h"

void setup() {
  // put your setup code here, to run once:
  I2C_init();
  Serial.begin(9600);
  HMC5883L_init();
  Serial.print("mode register ");
  HMC5883L_read_reg(Mode_Register);
  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:
  data_read(results);
  Serial.print("x-axis = ");
  Serial.println(results[0]);
  Serial.print("z-axis = ");
  Serial.println(results[1]);
  Serial.print("y-axis = ");
  Serial.println(results[2]);
  Serial.println();
  Serial.print("mode register ");
  HMC5883L_read_reg(Mode_Register);
  I2C_TWSR_Check();
  Serial.println();
_delay_ms(500);
}

 

I started to get more developed than before, e.g. I develop libraries by my self and include 2 libraries to my .ino file!! I consider that as I learned something the past weeks :) So, when I solve this error, it would be easier for me to develop libraries and get along with C/C++ coding for microcontroller projects.

 

Attachment(s): 

Last Edited: Fri. Jun 16, 2017 - 03:37 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Why I would read the "Philips/NXP spec on i2c"?

Because they invented I2C (TWI for Atmel) and wrote the standard to which every company must follow.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

wolfrose wrote:
Why I would read the "Philips/NXP spec on i2c"?
Because I2C was invented by Philips and their document is the "standard". In fact the very reason Atmel call it "TWI" rather than "I2C" is that the latter is a trademark of Philips and they cannot infringe it.

 

So, yeah, if you want to understand I2C/TWI then the very first thing everyone should read is the original spec from Philips.

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

wolfrose wrote:
I think that what caused the problem, but I don't know how to solve it, at least right now.
Learn the difference between "definition" and "declaration". That will solve your problem.

Stefan Ernst

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

The datasheet for the hm5883 mentions i2c on the first page. I gather you've not read that document either.
If you just want to throw something together, use Arduino. If you want to learn the finer details, then read, read and read some more. This knowlege is not going to fall into your lap like a manna from heaven.

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

well , if OP thinks Phillips/NXP seminal note is unuseful -or too detailed for a beginner-,  he might have a look at wikipedia ("I google search "wikipdia i2c") unless he stays in Turkey. Advantages:

a) the link to the reference note is given 

b) each and every notion which might be complicated is given a IT link

c) it may improve, and it is a natural way -except in Turkey- to begin : pupils ask internet cafe for a button to wikipedia....

 

The only drawback I see for the wikipedia I2C page is :

1/1 ) they   the English (Potugues, Spanish, French and German do not)  version shows a code for bit banging (and the definition of this -rare, with modern MCU- method is linked to), adding unnecessary complexity -though interesting and arousing curiousity..-

 

OTOH : I do not see the point of trying to write other I2C libraries for a complex circuit. I would begin with a simple one (Arduino examples, in the "Wire" section,  shows how to program an Arduino as a slave : this lead to a problem where -part of- solution is known , and one can concentrate on the master part, the hardware issues.... getting time to read the Holy Manuals). A compass needs some processing (how to have a nice display/ filter out noise -current spikes in the vicinity; magnets/unluck) and finding out the processing one thinks is perfect, though one uses well proven libraries -at least to begin- ,might  be more interesting....

Last Edited: Fri. Jun 16, 2017 - 12:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js

Because they invented I2C (TWI for Atmel) and wrote the standard to which every company must follow.

clawson

Because I2C was invented by Philips and their document is the "standard". In fact the very reason Atmel call it "TWI" rather than "I2C" is that the latter is a trademark of Philips and they cannot infringe it.

 

 

So, yeah, if you want to understand I2C/TWI then the very first thing everyone should read is the original spec from Philips.

I learned before that Philips is the inventor of I2C communication protocol.

 

But I mean that reading Atmel 328p datasheet is enough. Because it contains Status codes for the different transmission/receiving modes. Are the Status codes in the 328p datasheet for AVR microcontrollers or it's in the Philips datasheet too?

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

sternst

 Learn the difference between "definition" and "declaration". That will solve your problem.

 

Declaration is function or variable first introduction to the compiler.

Definition is the implementation, description and initialization of that function or variable.

 

So, I wont say I'm %100 sure of my files, but I think I arranged them in the proper way.

 

Declaration in the header file and definition in the .c/.cpp file.

 

 

I'm trying to figure out what I'm missing here, the problem is around the array which is:

int16_t results[3];

So what is the problem about this array? I didn't initialize it.

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

Wolfy - why cut corners? We've suggested you read the i2c spec, but then you question this? Read the spec and answer your question.

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

wolfrose wrote:
So what is the problem about this array?
It is a definition. And it is in a header file and you include that into multiple source files, therefore you get "multiple definition" errors. Change it into a declaration and add the definition to one source file instead.

Stefan Ernst

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

Seriously.

 

You can "learn" I2C for AVR in an hour or two.

You can "learn" SPI for AVR in an hour.

You can "learn" ADC for AVR in an hour.

You can "learn" USART for AVR in an hour or two.

 

Yes,  you can do it faster with Arduino Libraries.   Or with Codevision C libraries.

 

With GCC,  it might take some time to "find" appropriate code.

 

Having learned how to read docs and call libraries,   you can study the library code.

Yes,  if you want to be able to write "your own versions" in exam conditions,   you probably need to do lots of practice exercises.    Just like studying for a Maths exam in school.

 

Personally,   I see little point in "re-inventing wheels" but I must confess that I have done "my own versions" as an academic exercise.

A student's time is better spent in learning how to find and read datasheets and Application Notes.

 

dbrion's suggestion to read Wikipedia is the best advice.    The articles are generally "better written" than the original spec.    Easier to understand.

I suspect it even appears in your own language.

 

Your current attitude will just ensure that you spend weeks getting absolutely nowhere.

 

David.

Last Edited: Fri. Jun 16, 2017 - 10:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK I found the answer in Stack Exchange, on this link:

https://stackoverflow.com/questions/6762655/array-declaration-in-the-h-file-is-it-a-good-idea

 

I just have to add extern in .h file and declare it again but without extern in .c/.cpp file.

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

I did a debugging to my "read_data" function, and this is the result I get on the serial monitor.

 

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

OK friends I solved the read_data problem, I referred back to an answer provided to me in http://arduino.stackexchange.com.

 

It was a problem in the configuration values, but I followed the values in the datasheet! How I missed that :)

 

Anyway it's working now in continuous mode, but now I need to learn about gain and the other stuff.

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

Had you followed the advice you were given, you would've solved the problem yourself. You had a number of sources for reference.

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

Kartman

Had you followed the advice you were given, you would've solved the problem yourself. You had a number of sources for reference.

 

I didn't know how to follow the advice, I needed more explanation.

 

But now I have a new problem :)

 

The module stops reading the values when I move it around the x-axis! 

Last Edited: Sat. Jun 17, 2017 - 02:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One of the suggestions was to look at the Arduino example. Surely you don't need more explanation than that!

As for the module stopping - what is the most obvious cause? What evidence have you collected?

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

On the serial monitor, when I move the module to the x-axis, at the end of x-axis reading range, I guess the module is ... wait.

 

 

Well, I included the I2C checking function to know the state of the receiving after each read process, and ... the surprise!

 

 

 

 

The readings look that they were working well, but actually the I2C state is "ERROR"!

Last Edited: Sun. Jun 18, 2017 - 04:04 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That might suggest a hardware problem.

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

I have downloaded this library and tested my hardware, but there's no problem with the hardware.

 

I know it's in my code! I'm just kicking off HMC5883L coding, I even don't know what is "degress, heading, gain ... etc", I just wanted to get it working in the continuous mode. So, I'm in the learning process I haven't mastered the HMC5883L.

 

And my code is of course a beginner code, I should get these errors :)

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

Then maybe your I2C_TWSR check is suspect. It seems weird that you would check for errors that way. How would you know where the error occurred? And why would you put twsr in the function name? You want to abstract your code away from the hardware, not mimic it.

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

What I discovered now, is that the function I2C_TWSR_Check(); works only right after each I2C operation, I can't apply it after a complete processing function; like, read_data();.

 

That's why it gives errors, because I guess there's no value in TWST after I2C_stop();

 

I tested the check function inside my functions and it worked.

 

Now, I should go back to my HMC5883L code and include the check function inside the read_data function and see why it stops.

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

How can you even think about when you can't even trust the I2C code? Embed software should be written in modular layers, you can't move to layer 2 until you are convinced that every last function of layer 1 is fully tried and tested. That's the very reason you should have unit tests.

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

Alright, I know, I thought that there's a problem in my I2C library, but after a small test, it turns out that I can't apply the TWSR checking function after any other function after I2C_stop function.

 

So, I have to embed it inside the function I want to check its I2C operations.

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

We've been trying to tell you that from the beginning. If you toik the time to read and understand how i2c works, you'd realise that it is worthless continuing the transaction if the start sequence fails.

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

OK, I got an evidence :)

 

As soon as x gets to the positive values, the program crashes and stops reading values.

 

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

You've just begun. You'll need a bit more evidence than that.

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

Have you tried this?

 

https://www.sparkfun.com/tutorials/301

 

 

Their code:

/*
An Arduino code example for interfacing with the HMC5883

by: Jordan McConnell
 SparkFun Electronics
 created on: 6/30/11
 license: OSHW 1.0, http://freedomdefined.org/OSHW

Analog input 4 I2C SDA
Analog input 5 I2C SCL
*/

#include <Wire.h> //I2C Arduino Library

#define address 0x1E //0011110b, I2C 7bit address of HMC5883

void setup(){
  //Initialize Serial and I2C communications
  Serial.begin(9600);
  Wire.begin();
  
  //Put the HMC5883 IC into the correct operating mode
  Wire.beginTransmission(address); //open communication with HMC5883
  Wire.send(0x02); //select mode register
  Wire.send(0x00); //continuous measurement mode
  Wire.endTransmission();
}

void loop(){
  
  int x,y,z; //triple axis data

  //Tell the HMC5883 where to begin reading data
  Wire.beginTransmission(address);
  Wire.send(0x03); //select register 3, X MSB register
  Wire.endTransmission();
  
 
 //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 6);
  if(6<=Wire.available()){
    x = Wire.receive()<<8; //X msb
    x |= Wire.receive(); //X lsb
    z = Wire.receive()<<8; //Z msb
    z |= Wire.receive(); //Z lsb
    y = Wire.receive()<<8; //Y msb
    y |= Wire.receive(); //Y lsb
  }
  
  //Print out values of each axis
  Serial.print("x: ");
  Serial.print(x);
  Serial.print("  y: ");
  Serial.print(y);
  Serial.print("  z: ");
  Serial.println(z);
  
  delay(250);
}

 

Looks simple ...

 

 

Their result:

 

 

 

 

MG

I don't know why I'm still doing this hobby

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

Kartman

You've just begun. You'll need a bit more evidence than that.

 I know I just entered the world of debugging your code :) But seriously, now I don't know why it crashes when x gets positive?!

 

I changed the configuration bit for positive and negative bias, as I even don't know what does changing bias bits do? Anyway, I tried to change Configuration_Register_A bits, but the same problem.

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

Thank you very much for the code, this one doesn't crash.

 

It seems similar to my code, so what's the problem with my code??!

 

The functions of Wire.h are changed, send with write & receive with read.

 

This is the code after the changes:

 

#include <Wire.h>

/*
An Arduino code example for interfacing with the HMC5883

by: Jordan McConnell
 SparkFun Electronics
 created on: 6/30/11
 license: OSHW 1.0, http://freedomdefined.org/OSHW

Analog input 4 I2C SDA
Analog input 5 I2C SCL
*/

#include <Wire.h> //I2C Arduino Library

#define address 0x1E //0011110b, I2C 7bit address of HMC5883

void setup(){
  //Initialize Serial and I2C communications
  Serial.begin(9600);
  Wire.begin();
  
  //Put the HMC5883 IC into the correct operating mode
  Wire.beginTransmission(address); //open communication with HMC5883
  Wire.write(0x02); //select mode register
  Wire.write(0x00); //continuous measurement mode
  Wire.endTransmission();
}

void loop(){
  
  int x,y,z; //triple axis data

  //Tell the HMC5883 where to begin reading data
  Wire.beginTransmission(address);
  Wire.write(0x03); //select register 3, X MSB register
  Wire.endTransmission();
  
 
 //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 6);
  if(6<=Wire.available()){
    x = Wire.read()<<8; //X msb
    x |= Wire.read(); //X lsb
    z = Wire.read()<<8; //Z msb
    z |= Wire.read(); //Z lsb
    y = Wire.read()<<8; //Y msb
    y |= Wire.read(); //Y lsb
  }
  
  //Print out values of each axis
  Serial.print("x: ");
  Serial.print(x);
  Serial.print("  y: ");
  Serial.print(y);
  Serial.print("  z: ");
  Serial.println(z);
  
  delay(250);
}

 

 

But I'm still thinking what could be the problem!

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

You included wire.h twice ?

 

I'm not Arduino guy so clearly I dare not give you direct advice.

 

If you tested it and it works fine then track it one by one compare to yours. 

 

Let's say is your write / read function give the same result with send / receive ? If not then there's differences in how your functions works with those functions.

 

Patience is the key.

 

 

 

MG

 

 

 

 

 

I don't know why I'm still doing this hobby

Pages