element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Sensors
  • Technologies
  • More
Sensors
Blog ROHM Magnetometer Sensor BM1422AGMV
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Sensors to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 23 Nov 2018 2:34 PM Date Created
  • Views 6571 views
  • Likes 8 likes
  • Comments 27 comments
  • RoadTest
  • rohm
  • road_test
Related
Recommended

ROHM Magnetometer Sensor BM1422AGMV

Jan Cumps
Jan Cumps
23 Nov 2018

I'm Road Testing the Rohm SensorShield-EVK-003 (Arduino Compatible) and the sensors that come with it.

In this post, the Geo Magnetic Sensor BM1422AGMVBM1422AGMV.

image

 

The Sensor Shield ecosystemSensor Shield ecosystem is ROHM's test bed for their sensors. It's an Arduino form shield with a number of slots.

The small evaluation boards for their sensors plug into that board.

For each of the sensors, there's an example sketch available.

For this blog post, I'm testing the Magnetometer sensor that comes with the kit.

 

Evaluation Board

 

This tiny PCB contains the sensor, required bypass capacitors, optional footprints for i2c pull-ups and a jumper to change the address of the sensor.

imageimage

 

The sensor comes in a QFN  package.

imageimage

 

The datasheet does not explain the physical constructions.

But it's safe to assume that there are 3 sensors on board. Each physically mounted in one of the 3 axis.

 

The quote below - from (deprecated) android documentation - shows how the axis are interpreted in a smartphone.

  • Azimuth (degrees of rotation about the -z axis). This is the angle between the device's current compass direction and magnetic north. If the top edge of the device faces magnetic north, the azimuth is 0 degrees; if the top edge faces south, the azimuth is 180 degrees. Similarly, if the top edge faces east, the azimuth is 90 degrees, and if the top edge faces west, the azimuth is 270 degrees.
  • Pitch (degrees of rotation about the x axis). This is the angle between a plane parallel to the device's screen and a plane parallel to the ground. If you hold the device parallel to the ground with the bottom edge closest to you and tilt the top edge of the device toward the ground, the pitch angle becomes positive. Tilting in the opposite direction— moving the top edge of the device away from the ground—causes the pitch angle to become negative. The range of values is -180 degrees to 180 degrees.
  • Roll (degrees of rotation about the y axis). This is the angle between a plane perpendicular to the device's screen and a plane perpendicular to the ground. If you hold the device parallel to the ground with the bottom edge closest to you and tilt the left edge of the device toward the ground, the roll angle becomes positive. Tilting in the opposite direction—moving the right edge of the device toward the ground— causes the roll angle to become negative. The range of values is -90 degrees to 90 degrees.

source: developer.android.com

 

Firmware

 

What surprised me is that the example available from the ROHM website is better than what's on github.

The downloadable one supports a trigger when data is available from the magnetometer.

That's a useful demo for this device and it is interesting for Arduino education.

The Software registers the trigger, and based on the mode of the device attaches that trigger on the falling or rising edge.

image

image source: BM1422AGMV datasheet

 

I'm quoting from both sketch and library.

Copyright (c) 2017 ROHM Co.,Ltd.

Please check the - very liberal - copyright notice in the source files.

 

Here's the trigger handler. It's defined in the sketch.

void bm1422agmv_isr(void)
{
  bm1422agmv.set_drdy_flg();
}

 

The trigger is attached in the Setup() method in the sketch.

BM1422AGMV bm1422agmv(BM1422AGMV_DEVICE_ADDRESS_0E);
// ...
void setup() {
// ...
  Wire.begin();
  rc = bm1422agmv.init();
// ...

  bm1422agmv.isr_func(0, bm1422agmv_isr);
}

 

We see the constructor and three methods used from the ROHM library BM1422AGMV.

You can check out the C++ code in the zip file you downloaded from ROHM website.

I'll show some extracts from them, with focus on the steps happening:

 

Constructor

#define BM1422AGMV_DEVICE_ADDRESS_0E   (0x0E)    // 7bit Addrss

BM1422AGMV::BM1422AGMV(int slave_address)
{
  _device_address = slave_address ;
}

 

init()

byte BM1422AGMV::init(void)
{
// ...

  _drdy_flg = 0;

  rc = read(BM1422AGMV_WIA, &reg, sizeof(reg));
// ...

  if (reg != BM1422AGMV_WIA_VAL) {
// ...
  }

  // Step1
  reg = BM1422AGMV_CNTL1_VAL;
  rc = write(BM1422AGMV_CNTL1, &reg, sizeof(reg));
// ...

  // Check 12bit or 14bit
  buf[0] = (BM1422AGMV_CNTL1_VAL & BM1422AGMV_CNTL1_OUT_BIT);
  if (buf[0] == BM1422AGMV_CNTL1_OUT_BIT) {
    _sens = BM1422AGMV_14BIT_SENS;
  } else {
    _sens = BM1422AGMV_12BIT_SENS;
  }
  delay(1);
// ...

  buf[0] = (BM1422AGMV_CNTL4_VAL >> 8) & 0xFF;
  buf[1] = (BM1422AGMV_CNTL4_VAL & 0xFF);
  rc = write(BM1422AGMV_CNTL4, buf, sizeof(buf));
// ...
  // Step2
  reg = BM1422AGMV_CNTL2_VAL;
  rc = write(BM1422AGMV_CNTL2, &reg, sizeof(reg));
// ...

  // Step3

  // Option
  reg = BM1422AGMV_AVE_A_VAL;
  rc = write(BM1422AGMV_AVE_A, &reg, sizeof(reg));
// ...

  return (rc);
}

 

 

isr_func()

void BM1422AGMV::isr_func(int int_num, void func(void))
{
  if (BM1422AGMV_CNTL2_VAL & BM1422AGMV_CNTL2_DRP) {
    attachInterrupt(int_num, func, RISING);
  } else {
    attachInterrupt(int_num, func, FALLING);
  }
}

 

In the loop() method, the sketch gets data from the sensor.

void loop() {
  byte rc;
  float mag[3];

  rc = bm1422agmv.get_val(mag);
  if (rc == 0) {
    Serial.print(F("BM1422AGMV XDATA="));
    Serial.print(mag[0], 3);
    Serial.println("[uT]");
    Serial.print(F("BM1422AGMV YDATA="));
    Serial.print(mag[1], 3);
    Serial.println("[uT]");
    Serial.print(F("BM1422AGMV ZDATA="));
    Serial.print(mag[2], 3);
    Serial.println("[uT]");
    Serial.println();
  }
  delay(500);
}

 

Here are the library functions used:

 

get_val()

byte BM1422AGMV::get_val(float *data)
{
  byte rc;
  unsigned char val[6];
  signed short mag[3];
  rc = get_rawval(val);
  if (rc != 0) {
    return (rc);
  }
  mag[0] = ((signed short)val[1] << 8) | (val[0]);
  mag[1] = ((signed short)val[3] << 8) | (val[2]);
  mag[2] = ((signed short)val[5] << 8) | (val[4]);
  convert_uT(mag, data);
  return (rc);  
}

 

get_rawval()

byte BM1422AGMV::get_rawval(unsigned char *data)
{
// ...
  // Step4
  reg = BM1422AGMV_CNTL3_VAL;
  rc = write(BM1422AGMV_CNTL3, &reg, sizeof(reg));

  while(_drdy_flg == 0) {
    delayMicroseconds(100);
  };
  _drdy_flg = 0;

  rc = read(BM1422AGMV_DATAX, data, 6);
// ...
  return (rc);
}

 

convert_uT

void BM1422AGMV::convert_uT(signed short *rawdata, float *data)
{
  // LSB to uT
  data[0] = (float)rawdata[0] / _sens;
  data[1] = (float)rawdata[1] / _sens;
  data[2] = (float)rawdata[2] / _sens;
}

 

Here you see how the read from the sensor works in collaboration with the data ready flag and the interrupt.

 

Measurements

 

A few measurements, first flat on the table, with the text on the sensor PCB facing:

North:

BM1422AGMV XDATA=1.208[uT]
BM1422AGMV YDATA=-0.375[uT]
BM1422AGMV ZDATA=-76.875[uT]

South:

BM1422AGMV XDATA=-26.333[uT]
BM1422AGMV YDATA=-24.333[uT]
BM1422AGMV ZDATA=-79.417[uT]

East:

BM1422AGMV XDATA=-28.917[uT]
BM1422AGMV YDATA=-4.042[uT]
BM1422AGMV ZDATA=-80.917[uT]

West:

BM1422AGMV XDATA=1.333[uT]
BM1422AGMV YDATA=-26.708[uT]
BM1422AGMV ZDATA=-78.083[uT]

 

And here pointing the board up and down:

Up West:

BM1422AGMV XDATA=-49.875[uT]
BM1422AGMV YDATA=-41.667[uT]
BM1422AGMV ZDATA=-25.625[uT]

Down West:

BM1422AGMV XDATA=32.375[uT]
BM1422AGMV YDATA=-29.333[uT]
BM1422AGMV ZDATA=-20.542[uT]

 

i2c Traffic

 

I've captured the traffic of a measurement sequence. Here you can see the effects of the following lines of code:

  rc = read(BM1422AGMV_DATAX, data, 6);

It generates an address write, then 6 blocks of char size data returning.

You may recognise this address on line 3:

#define BM1422AGMV_DATAX              (0x10)

image

 

I've also measured the impact of moving the sensor in increments of 22°. I'll post them if there's interest.

 

Related blog
ROHM Temperature Sensor BD1020HFV
ROHM Magnetometer Sensor BM1422AGMV
ROHM Hall Sensor BD7411G
ROHM Colour Sensor BH1749NUC
ROHM Colour Sensor BH1749NUC - part 2: Other Firmware Libraries
ROHM Ambient Light and Proximity Sensor RPR-0521RS
  • Sign in to reply

Top Comments

  • Jan Cumps
    Jan Cumps over 6 years ago in reply to genebren +3
    I don't know yet how to write the full review. There's so many diverse things here that reporting on all of them isn't straightforward in a single post. My current idea is to continue writing a post per…
  • kulky64
    kulky64 over 6 years ago +3
    Have you tried to calibrate out hard and soft iron interference? Because from your data it seems there is some present. If you are in Belgium you should be getting total magnetic field of around 49 uT…
  • Jan Cumps
    Jan Cumps over 6 years ago in reply to kulky64 +3
    There is an iron molecule in my neighbourhood
  • Jan Cumps
    Jan Cumps over 6 years ago in reply to DAB

    DAB  wrote:

     

    Nice post Jan.

     

    Have you done any sensitivity testing to see how accurate the device is to tell direction?

     

    DAB

    DAB , in the comment above I tried to dial in to the magnetic north, following kulky64 's instructions - keep the sensor horizontal and try to get the Y be 0.

    This after non-optimal but good-enough-for-this-exercise calibration.

    It's very sensitive. I could not dial in to Y==0.000 by manipulating the Arduino. It only worked by using the USB cable as a long tail. That allowed me to very slightly pivot the Arduino until Y == 0.000.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 6 years ago in reply to kulky64

    kulky64  wrote:

     

    ... In x-axis you should see horizontal component of Earth's magnetic field ("Horizontal Intensity") of 19.7542 uT, y should be zero as mentioned and in z axis you should see vertical component of Earth's magnetic field ("Vertical Comp") of 44.5747 uT ...

    BM1422AGMV XDATA=20.750[uT]
    BM1422AGMV YDATA=-0.000[uT]
    BM1422AGMV ZDATA=-37.979[uT]
    BM1422AGMV VECTOR=43.278

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • kulky64
    kulky64 over 6 years ago in reply to Jan Cumps

    Now that you have your sensor (semi)calibrated place it horizontal as accurately as you can get (so that x-y plane of your sensor is perfectly horizontal) and rotate it so that one of the axis (for example x-axis) points exactly at magnetic north pole (reading in the other y-axis should be zero in that case). Now compare your results with the calculations from the NOAA website. In x-axis you should see horizontal component of Earth's magnetic field ("Horizontal Intensity") of 19.7542 uT, y should be zero as mentioned and in z axis you should see vertical component of Earth's magnetic field ("Vertical Comp") of 44.5747 uT (you will get negative number here because z-axis of your sensor is pointing up, in NOAA results downward facing field is considered positive as indicated by "(+ D | - U)"). You can calculate inclination angle as arctan(Vertical_Comp / Horizontal_Intensity) = arctan(44.5747 uT / 19.7542 uT) = 66 deg 5 min 55 sec and "Total Field" is calculated from the Pythagorean theorem as sqrt(Vertical_Comp ^ 2 + Horizontal_Intensity ^ 2) = 48.7558 uT.

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 6 years ago in reply to kulky64

    Quick update of the example code, taking in account the average from previous test:

    #define X_MIN (-61.125)
    #define X_MAX (32.375)
    #define Y_MIN (-61.500)
    #define Y_MAX (29.667)
    #define Z_MIN (-91.667)
    #define Z_MAX (11.542)
    
    #define X_OFFSET ((X_MIN + X_MAX)/2)
    #define Y_OFFSET ((Y_MIN + Y_MAX)/2)
    #define Z_OFFSET ((Z_MIN + Z_MAX)/2)
    
    // ...
    
    void loop() {
      byte rc;
      float mag[3];
    
      rc = bm1422agmv.get_val(mag);
    
      if (rc == 0) {
        mag[0] -= X_OFFSET;
        mag[1] -= Y_OFFSET;
        mag[2] -= Z_OFFSET;
        Serial.print(F("BM1422AGMV XDATA="));
        Serial.print(mag[0], 3);
        Serial.println("[uT]");
        Serial.print(F("BM1422AGMV YDATA="));
        Serial.print(mag[1], 3);
        Serial.println("[uT]");
        Serial.print(F("BM1422AGMV ZDATA="));
        Serial.print(mag[2], 3);
        Serial.println("[uT]");
        Serial.print(F("BM1422AGMV VECTOR="));
        Serial.print(sqrt(pow(mag[0], 2.0) + pow(mag[1], 2.0) + pow(mag[2], 2.0)), 3);  
        Serial.println();
      }
    
      delay(500);
    }

     

    Some samples:

     

     

    BM1422AGMV XDATA=6.625[uT]
    BM1422AGMV YDATA=-16.667[uT]
    BM1422AGMV ZDATA=-39.771[uT]
    BM1422AGMV VECTOR=43.628
    
    BM1422AGMV XDATA=-10.000[uT]
    BM1422AGMV YDATA=8.500[uT]
    BM1422AGMV ZDATA=-41.146[uT]
    BM1422AGMV VECTOR=43.188
    
    BM1422AGMV XDATA=-13.333[uT]
    BM1422AGMV YDATA=6.625[uT]
    BM1422AGMV ZDATA=-39.146[uT]
    BM1422AGMV VECTOR=41.882

     

     

    Approx. 6 off, but stable ...

     

    When pointing north:

    BM1422AGMV XDATA=0.458[uT]
    BM1422AGMV YDATA=6.542[uT]
    BM1422AGMV ZDATA=-47.812[uT]
    BM1422AGMV VECTOR=48.260

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • shabaz
    shabaz over 6 years ago in reply to Jan Cumps

    Hi Jan!

     

    That's correct, the board will need to be rotated in every direction in all planes, like a sphere. From the values you have, I think you've done a good amount of rotation, because the min and max difference is about 90uT.

    So for X, you have 32.375+61.125 = 93.5, and this difference seems correct, it just means there is an offset.

    The offset is the average, i.e. (-61.125+32.375)/2 = -14.375. The calibration is therefore just to add 14.375 to whatever the X value reported by the sensor is.

    From your values, it looks like all the three axes have a negative offset so to compensate a positive value is to be added to them. The Z-axis min-max difference is about 103uT which is higher than X and Y, but it could be it is a different sensor for the Z axis (presumably due to the way the sensors are created on the silicon). So there maybe should be some slight scaling done to the Z axis, but I guess the error is low and not relevant if the system will mainly be used in the plane where X and Y see the majority of the components of the magnetic field.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube