Problem with MAG3110 compass module and Serial Monitor

I am using an Arduino Pro Mini - I'm not sure if that is permissible on this forum?

I created a compass project with an HMC5883L which worked OK, but the readings were a little too variable - I then realised that I had a QMC5883 chip which might be less good?

Anyway, to escape this possibility, I bought a MAG3110 as a replacement, I modified the code and added a voltage driver board to accommodate the 3.3v chip.
The new setup works OK and I like the potential to stabilise the readings by setting Data Rate and Oversampling Ratio – but I haven’t really been able to progress as essentially it only works when attached to the PC.
So, I make changes to the code upload it and run the Serial Monitor – make the moves to calibrate the chip (difficult with a USB connection) and then everything runs fine.

When I disconnect from the PC and run the Arduino from a battery pack it doesn’t function properly i.e. when connected to the PC the readings are repeatable and sweep from +-180 degrees (at the moment), when disconnected the readings are limited to (say) -137 to -127 degrees.

By experimentation I have found that it appears to be an issue with the Serial Monitor, so if I try to run the code attached to the PC without the Serial Monitor open I get the same limited incorrect response.
I can even power up the Compass with its battery, connect to the PC, open the Serial Monitor (which resets the program flow), calibrate the Compass and then disconnect from the PC and run the compass separately reading its LCD display.
Obviously, this is not going to be practical for my real needs.
I have tried removing all references to the Serial Port – so the Serial Monitor shows blank when opened, but it is still required to be opened to allow the compass to work properly.
I have tested the Arduino’s battery (3x18650 Lithium Ion cells with a precision 5 volt regulator board set to 5.00v versus USB + FTDI giving 4.98v).
Connecting or disconnecting the FTDI board does not change things.

I tried a variety of the SparkFun code with different loop delays, Output Data Rates and Oversampling Ratios without any improvement.
NB I didn’t have this problem when using the HMC5883L.
I think an option is to try using interrupts (requires moving a few pins around to release pin 2 or 3) but I suspect this won’t make any difference.
Any thoughts would be gratefully received.

Here is my present code:

#include <Wire.h>
#include <LiquidCrystal.h>

/* Assign a unique ID to this sensor at the same time */
#include <SparkFun_MAG3110.h>

MAG3110 mag = MAG3110(); //Instantiate MAG3110

bool calibrationDone = false;
float x, y, z;
int heading;

//Pins for the 16 x 2 LCD Display
//LiquidCrystal lcd(2, 3, 9, 10, 11, 12); /// REGISTER SELECT PIN,ENABLE PIN,D4 PIN,D5 PIN, D6 PIN, D7 PIN
const int rs = 2, en = 3, d4 = A0, d5 = A1, d6 = A2, d7 = A3;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup(void) 
{
//  Serial.begin(9600);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear();  //make sure screen is clear.
  lcd.setCursor(0,0); //Top left hand corner
  lcd.print("LCD screen on");
  delay(1000);

  mag.initialize();
  if(mag.error) //You can use this to check if there was an error during initialization.
  {
    lcd.print("Can't connect");
    lcd.setCursor(0,1); //Bottom left corner
    lcd.print("to MAG3110");
  }

  Wire.begin(); // Start the i2c communication
    
  //Start calibration
  mag.enterCalMode();  //This sets the output data rate to the highest possible and puts the mag sensor in active mode
}

void loop(void) 
{
  if(mag.isCalibrating()) // Currently calibrating
    {
//      Serial.println("Entering calibration mode");
      mag.calibrate();
      lcd.clear();  //make sure screen is clear.
      lcd.setCursor(0,0); //Top left hand corner
      lcd.print("CALIBRATE! ");
      lcd.setCursor(0,1); //Bottom left corner
      lcd.print("Turn the compass... ");
    }

  if(mag.isCalibrated())
  {

    if(!calibrationDone)   //1st loop since exiting Calibration Mode
      {
//        Serial.println("Exiting calibration mode");
        calibrationDone = true;
//        Serial.println("Calibrated!");
        lcd.clear();  //make sure screen is clear.
        lcd.setCursor(0,0); //Top left hand corner
        lcd.print("CALIBRATED ");
        delay(3000);
        lcd.setCursor(0,0); //Top left hand corner
        lcd.print("Heading: ");
//        Serial.print("setting Data Rate and Oversampling Ratio");
//        mag.setDR_OS(MAG3110_DR_OS_1_25_32);         //Sets Output Data Rate = 1.25Hz, Oversampling Ratio = 32. This means it takes 32 samples and averages the results
        mag.setDR_OS(MAG3110_DR_OS_40_32);
        mag.start();
      }
//     if(mag.dataReady())
//      {
//        heading = (int)mag.readHeading();
//        heading = (int)mag.readHeading()* 180 / M_PI;
//      }
//    if (heading < 0) //If the heading is negative (ranges from -1 to -180)
//      heading *= -1; //Negate the heading
//    else if (heading > 0)
//      heading = 360 - heading;
      
    //Reporting the data to the LCD Screen
    lcd.setCursor(9,0);
    lcd.print(mag.readHeading());
//    Serial.println(mag.readHeading());
  }
delay(1000);
}

I am using an Arduino Pro Mini - I'm not sure if that is permissible on this forum?

Sure it is, but which version are you using? There is a 5V/16MHz version and a 3V3/8MHz version.

Please provide a complete wiring diagram for the battery setup.

For a magnetometer to work as a compass, you must calibrate it in the environment where it will be used. Changing power connections changes the environment, especially when using batteries, which often have a steel case.

At the very least you need to determine an offset and scale factor for each axis, but for best accuracy a more sophisticated procedure is required.

See this extensive tutorial: Tutorial: How to calibrate a compass (and accelerometer) with Arduino | Underwater Arduino Data Loggers