With the stock amplifier gain, when exposed to even modest magnetic fields, the chip undergoes some sort of automatic adjustment which can result in lockup and/or wildly incorrect output. Cycling the power does not help. The solution is to send the "reset S/R bridge offset" command, the effect of which is not explained in the datasheet. The S/R reset does not affect the results of the built-in "user calibration procedure", which is also poorly documented.
So, I looked closer, examining the raw magnetometer data and the result of the user calibration command. The raw magnetometer data are positive integers, i.e. the ADC results, and the result of the user calibration procedure is just to calculate and subtract an average offset in the X and Y measurements. In my HMC6352, the gains of the X and Y amplifiers are significantly different, which seems to be true for all inexpensive magnetometers and this leads to magnetic bearings that are far less accurate than the data sheet claims.
Inspired by various efforts to extract the best possible data out of 3D magnetometer/accelerometers, I wrote a 2D version of the procedure described in http://sailboatinstruments.blogspot.com ... ation.html for the HMC6352. As is usual I fit an ellipse to the data and rotate/rescale the ellipse to a circle. This makes a big difference, up to 5 degrees, in the accuracy of the reported angle of the magnetic field vector.
The output of the code posted below, on data collected from the HMC6352 in the Earth's magnetic field (after using the built-in user calibration procedure) was the following matrix and offset vector. As you can see, the correction is about 9% in magnitude for the X axis with a significant rotational component.
scaled rotation matrix and vector to apply: Q*(XY-XY0)The figure below shows the raw data for two complete revolutions of the compass, while held level (blue circles) and the rescaled data points (green circles). The fitted ellipse is the solid line. The figure below shows the difference in magnetic bearings in degrees, obtained from the data before and after calibration by using the atan2 function. The current code is written for MATLAB. If there is sufficient interest, I could write a version in C.
(1.0886 0.0407)*(X - ( -1.4))
(0.0407 1.0187)*(Y - ( -8.0))
Caveat: this code has not been thoroughly tested and will probably fail in pathological cases!
% % File: magcal_2d.m % This MATLAB program calculates the calibration parameters for a 2D magnetometer. % As is customary, data for one or two complete revolutions of the magnetometer % should be collected while held level, points closely spaced if possible. % % uses published Matlab function EllipseDirectFit.m % http://www.mathworks.com/matlabcentral/fileexchange/22684-ellipse-fit-direct-method % % First step: collect data and produce a CSV file (comma separated values) of % magnetometer X and Y values (can be raw). % % Second step: from Matlab File Menu, import CSV file of (max, magy) % measurements into array magxy. % % Third step: execute magcal_2d.m % % This work was inspired by the 3D procedure described in: % http://sailboatinstruments.blogspot.com/2011/08/improved-magnetometer-calibration.html % A = EllipseDirectFit(magxy); % modified coefficients of equation for ellipse % from http://mathworld.wolfram.com/Ellipse.html a = A(1); b = A(2)/2; c = A(3); d = A(4)/2; f = A(5)/2; g = A(6); % X0, Y0 offset (centroid of ellipse) x0 = (c*d - b*f)/(b^2 - a*c); y0 = (a*f - b*d)/(b^2 - a*c); % semimajor and semiminor axes numer = 2*(a*f*f+c*d*d+g*b*b-2*b*d*f-a*c*g); denom1 = (b*b-a*c)*( sqrt((a-c)^2 + 4*b*b) - (a+c)); denom2 = (b*b-a*c)*(-sqrt((a-c)^2 + 4*b*b) - (a+c)); a_axis = sqrt(numer/denom1); b_axis = sqrt(numer/denom2); % angle of ellipse semimajor axis wrt X-axis if (a < c) theta = 0.5*acotd((a-c)/(2*b)); else theta = 90.0 + 0.5*acotd((a-c)/(2*b)); end s=sprintf('x0 = %5.2f y0 = %5.2f a = %5.2f, b= %5.2f, theta(d) = %4.1f', ... x0,y0,a_axis,b_axis, theta); disp(s); % rotation matrix to align semimajor axis to X-axis ct=cosd(theta); st=sind(theta); R = [ct st; -st ct]; xy0 = [x0 y0]; %rescale vector, correct for difference in magnetometer X & Y gains scale = [b_axis/a_axis,1]; % final result: matrix to align ellipse axes wrt coordinates system, normalize X and Y gains and rotate back. Q = R^-1*([scale(1) 0; 0, scale(2)]*R); % correct the input data for i = 1 : length(magxy) xy(i,:) = ( Q*(magxy(i,:)-xy0)' )'; end % replot scaled data. Set "hold on" in EllipseDirectFit.m scatter(xy(:,1),xy(:,2)); % residual plot figure; p1 = (180./3.14159).*atan2(magxy(:,2),magxy(:,1)); p2 = (180./3.14159).*atan2(xy(:,2),xy(:,1)); xp = 1:length(magxy); hold on title('Residual bearings in degrees after rescaling'); plot(xp,p1-p2,'-g'); disp(' '); disp('scaled rotation matrix and vector to apply: Q*(XY-XY0)'); s = sprintf('(%6.4f %6.4f)*(X - (%5.1f))',Q(1,1),Q(1,2),x0); disp(s); s = sprintf('(%6.4f %6.4f)*(Y - (%5.1f))',Q(2,1),Q(2,2),y0); disp(s);