2024-02-16 06:48 AM - last edited on 2024-07-08 04:54 AM by Peter BENSCH
Hi everyone,
First of all, I use a STWINBX1 board, which include a MCU and several sensors. I try to get the magnetic field by reading the output of the magnetometer (IIS2MDC), but the output value seems false.
Please note that :
- I checked the PIN configuration on STM32 CubeIDE, and the PINs are well configured.
- I use HAL library to configure the chipset (IIS2MDC), and to use I2C protocol.
- I tested 2 differents methods of reading the output using I2C functions from HAL (HAL_I2C_Mem_Read and HAL_I2C_Master_Receive). Both method return me the same output, which is even more confusing for me.
- I have two differents boards of the same models that give me the same errors in the output.
- The slave address (of the Magnetometer) is 0011110b. I have two variable for read and write the slave, which are :
uint16_t IIS2MDCTR_ADDR_VAR_R = 0x3D; // 00111101b
uint16_t IIS2MDCTR_ADDR_VAR_W = 0x3C; // 00111100b
I store them inside a uint16_t as the HAL library need uint16_t address in functions that I use, but these addresses could fit in a single byte.
I am not used to these kinds of datasheet, so I have severals questions.
The datasheet of the magnetometer give an output x, y, z. Each axis are composed of two bytes. Its said that the output is expressed in "two’s complement".
Basically, that mean that the output will be a signed integer (that can be positive or negative) ?
As the output is given on two different bytes, I guess that the sign of the total output (combination of the two bytes) is the biggest bit of the MSB ?
Here is one of the two method I used to read the output of the magnetometer (on one axis, "x", for example) :
I removed errors managements of the code to make it clearer
int16_t getMagneticField(uint8_t LSB_addr){
char buffer_message[100];
uint8_t buf[2];
uint8_t buf_receive[2];
uint16_t slave_addr_read = 0x3D;
uint16_t slave_addr_write = 0x3C;
buf[0] = 0x60; // address of CFG_REG_A (used to configure how we use the magnetometer)
buf[1] = 0x81; // 1000 0001 bit configured to allow single mode
HAL_I2C_Master_Transmit(&hi2c2, slave_addr_write, buf, 2, HAL_MAX_DELAY);
HAL_StatusTypeDef ret = HAL_I2C_Mem_Read(&hi2c2, slave_addr_read, LSB_addr, I2C_MEMADD_SIZE_8BIT, buf_receive, 2, HAL_MAX_DELAY);
int16_t result = (((int16_t)buf_receive[1]) << | buf_receive[0];
return result * sensitivity;
}
For context, here is the configuration of the magnetometer :
void ConfigureMagnetometer()
{
uint8_t buf[2];
buf[0] = 0x60; // addresse du registre CFG_REG_A
buf[1] = 0x81; // 1000 0001 bit configured (enable temperature/single mode read)
HAL_I2C_Master_Transmit(&hi2c2, IIS2MDCTR_ADDR_W, buf, 2, HAL_MAX_DELAY);
buf[0] = 0x61; // addresse du registre CFG_REG_B
buf[1] = 0x12; // 0001 0010 bit configured (enable offset cancellation in single mode read)
HAL_I2C_Master_Transmit(&hi2c2, IIS2MDCTR_ADDR_W, buf, 2, HAL_MAX_DELAY);
buf[0] = 0x62; // addresse du registre CFG_REG_C
buf[1] = 0x10; // 0001 0000 bit configured
HAL_I2C_Master_Transmit(&hi2c2, IIS2MDCTR_ADDR_W, buf, 2, HAL_MAX_DELAY);
HAL_Delay(20);
}
So, my problem is :
When i read the first byte of data (the LSB), the value seem fine. She is updating as I move the board myself.
The other byte of data (the MSB), is always min value (0), or max value (255). He is sometimes equal to 1 or 254, but more rarely, which seems false. And it seem to exist a pattern with these value, with max, min or max -1, or min + 1.
In addition, I intepret the output x, y, z with a simple computing (sqrt of squarred x + squarred y + squarred z), and also this intepretation give me false results, as this result must be constant (when x, y and z change), but its not the case.
I tried to give you the more context I can. If you need any others information to understand my problem, feel free to ask, I'll answer you.
I don't know what I am doing wrong here. Thanks for your help, have a good day.
2024-02-16 07:06 AM
An int16_t value expressed as two unsigned bytes will look like this. The problem is just how you're interpreting it.
value = MSB LSB
...
-2 = 0xFF 0xFE
-1 = 0xFF 0xFF
0 = 0x00 0x00
1 = 0x00 0x01
2 = 0x00 0x02
...
Notice how the MSB goes from 0 to 255 even though the value only changes by 1.
2024-02-16 07:08 AM
Since the registers are in little endian format (LSB first), you should be able to convert it directly to int16 with the following:
int16_t value = 0;
HAL_I2C_Mem_Read(&hi2c2, slave_addr_read, LSB_addr, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&value, 2, HAL_MAX_DELAY);
2024-02-16 08:10 AM - edited 2024-02-16 08:12 AM
Ok,
thanks a lot for your answer, I didnt paid attention to the endianess.
My output (sqrt(squarred(x) + squarred(y) + squarred(z))) is still wrong.
He vary from 2 values even If i dont move the sensor.
Here is a sample of the output if the sensor is stationary
sqrt = 670.387202
sqrt = 899.553778
sqrt = 666.946025
sqrt = 903.058691
sqrt = 652.453830
sqrt = 894.912286
sqrt = 659.749195
sqrt = 910.469110
sqrt = 655.916915
sqrt = 906.294654
sqrt = 662.160857
sqrt = 915.705739
sqrt = 657.499810
sqrt = 907.316924
sqrt = 650.509031
sqrt = 902.203414
sqrt = 654.368398
sqrt = 901.768263
sqrt = 652.144923
sqrt = 909.713691
sqrt = 654.878615
sqrt = 903.834609
sqrt = 662.786542
sqrt = 896.974916
sqrt = 669.574492
sqrt = 906.651532
And if I move the board, the output is varying. I think I miss something else.
2024-02-16 03:03 PM
Perhaps show x, y, and z used in those calculations. Probably aren't getting the int16_t value correct.
2024-02-19 02:03 AM
Here is a sample of my result (sqrt(squarred(x) + squarred(y) + squarred(z))) with x, y and z values (when the magnetometer is stationary):
By the way, I checked some github repositories that use IIS2MDC and they seems to return a int32 (for x, y and z values), as these axis are int16_t multiplied by sensitivity (sensitivity = 1.500). So I think int16_t may overflow if we dont cast axis * sensitivity in int32_t. So I changed , my return statement from
return result * sensitivity; // was returning an int16_t
to
return (int32_t)((float)((float)value * sensitivity)); // now return an int32_t
It seems to still fluctuate around two values when the magnetometer is stationary
sqrt = 175.002857(x:7 y:79 z:156)
sqrt = 538.209067(x:225 y:462 z:160)
sqrt = 440.424795(x:85 y:43 z:430)
sqrt = 548.681146(x:213 y:469 z:189)
sqrt = 423.381625(x:42 y:88 z:412)
sqrt = 690.890006(x:198 y:490 z:445)
sqrt = 433.504325(x:43 y:94 z:421)
sqrt = 689.281510(x:202 y:487 z:444)
sqrt = 429.760398(x:27 y:82 z:421)
sqrt = 687.393628(x:195 y:489 z:442)
sqrt = 425.495006(x:37 y:91 z:414)
sqrt = 695.765765(x:184 y:495 z:453)
sqrt = 423.933957(x:40 y:82 z:414)
sqrt = 693.220744(x:189 y:495 z:447)
sqrt = 437.280231(x:33 y:78 z:429)
sqrt = 689.962318(x:184 y:484 z:456)
sqrt = 434.986207(x:34 y:91 z:424)
sqrt = 696.862253(x:207 y:492 z:448)
sqrt = 437.133847(x:31 y:93 z:426)
sqrt = 694.612122(x:193 y:489 z:454)
sqrt = 426.852434(x:33 y:85 z:417)
sqrt = 688.881702(x:205 y:487 z:442)
sqrt = 438.466646(x:34 y:84 z:429)
sqrt = 686.232468(x:189 y:487 z:445)
sqrt = 431.435974(x:22 y:82 z:423)
sqrt = 695.920973(x:193 y:489 z:456)
sqrt = 429.617272(x:33 y:79 z:421)
sqrt = 699.886419(x:189 y:498 z:454)
sqrt = 431.533313(x:19 y:78 z:424)
I didnt changed configuration's registers from first messages. Still can't find my error.
2024-02-19 05:46 AM
Those values aren't just fluctuating, they are changing every other cycle. Not something that can be explained by misinterpreting the result. This suggests a code error somewhere else in the program. It's like you're getting different values on every other read. Perhaps you are not getting the magnetometer values.
2024-02-19 06:22 AM
If I use the sensor in continuous mode (instead of single mode) I can get more stable sample, like :
(but theses value really change if I move the board, which is not good)
When I was using single mode, as said the doc, I reconfigure to single mode after each read of register (as the sensor return to idle mode after he is read).
2024-02-19 07:08 AM
These values look good. I don't see any problems with them. You should expect some amount of noise in the readings.
> but theses value really change if I move the board, which is not good
Moving the board will affect the readings, no surprise or issues there. Surely it would be a problem if they didn't change, right? Magnetic field will be affected by orientation of the board and proximity to conductive materials.
2024-02-19 08:17 AM
I read that this formula :
should give a constant result (even if we move the board). x, y and z should change, but not the result of this formula.
But maybe I missintepretated the information.
And if I move the board in the space, the output vary a lot, another sample :