Help converting HM55B Compass reader from Arduino code

I have the HM55B compass module connected to the Baby Orangutan 328P. I am using the Orangutan programmer and AVR Studio 4/GCC compiler. I found Arduino code at http://www.arduino.cc/playground/Main/HM55B by kiilo to get the angle value, but don’t understand how to convert some of the code. I have searched the AVR/Orangutan libraries, but haven’t been able to find the answer. My version runs, but always gives output of 0 for the angle so I am doing something wrong. A key section of the code is below with differences marked. Any help would be appreciated, Thanks. :neutral_face:
:

int ShiftIn(int BitsCount) { int ShiftIn_result; ShiftIn_result = 0; his=>pinMode(DIO_pin, INPUT); mine=>set_digital_input(IO_B2, PULL_UP_ENABLED); //connected to Dout+Din for(int i = BitsCount; i >= 0; i--) { his=> digitalWrite(CLK_pin, HIGH); mine=>set_digital_output(IO_B0, HIGH); //connected to CLK delayMicroseconds(1); his=> if (digitalRead(DIO_pin) == HIGH) { mine=>if (is_digital_input_high(IO_B2)) { ShiftIn_result = (ShiftIn_result << 1) + 1; //Serial.print("x"); } else { ShiftIn_result = (ShiftIn_result << 1) + 0; //Serial.print("_"); } his=> digitalWrite(CLK_pin, LOW); mine=>set_digital_output(IO_B0, LOW); delayMicroseconds(1); }
:

The Arduino code you linked to contains a lot more than just the ShiftIn function, for example:

HM55B_StartMeasurementCommand(); // necessary!!

Did you port all of the example Arduino code to use the Pololu AVR Library? If so, then you should post it here. If not, you have more work to do.

Also, when posting code you should post your complete program. Since you only pasted a snippet of code, I can’t check critical things like what you’re doing with the return value or how you defined BitsCount. But you should also simplify your program until it is the smallest possible thing that should work.

-David

Also, I don’t see any errors in the code that you did post. --David

Thanks for the quick response, David.
You asked:
Did you port all of the example Arduino code to use the Pololu AVR Library? – Yes. I have included the complete program below. My confusion is mainly with what to substitute for the pinMode() and digitalWrite() functions.

[code]#define F_CPU 20000000UL // Baby Orangutan frequency (20MHz)

#include <math.h>
#include <avr/io.h>
#include <util/delay.h> // uses F_CPU to achieve us and ms delays
#include <pololu/orangutan.h>
#include <stdlib.h>

void delayms( uint16_t millis ) {

while ( millis ) {
	_delay_ms( 1 );
	millis--;
}

}

/ BABY O PINS <==> HM55B PINS
//
// PB0:IO_B0 <==> #4:CLK
// PB1:IO_B1 <==> #5/Enable
// PB2:IO_B2 <==> #1:Dout,#2:Din

int X_Data = 0;
int Y_Data = 0;
int angle;
unsigned char return_value_of_pin;

//// FUNCTIONS

void ShiftOut(int Value, int BitsCount) {
for(int i = BitsCount; i >= 0; i–)
{
set_digital_output(IO_B0, LOW);
if ((Value & 1 << i) == ( 1 << i))
{
set_digital_output(IO_B2, HIGH);
//Serial.print(“1”);
}
else
{
set_digital_output(IO_B2, LOW);
//Serial.print(“0”);
}
set_digital_output(IO_B0, HIGH);
delayMicroseconds(1);
}
}

int ShiftIn(int BitsCount) {
int ShiftIn_result;
ShiftIn_result = 0;
set_digital_input(IO_B2, PULL_UP_ENABLED);
for(int i = BitsCount; i >= 0; i–) {
set_digital_output(IO_B0, HIGH);
delayMicroseconds(1);
if (is_digital_input_high(IO_B2)) {
ShiftIn_result = (ShiftIn_result << 1) + 1;
//Serial.print(“x”);
}
else {
ShiftIn_result = (ShiftIn_result << 1) + 0;
//Serial.print("_");
}
set_digital_output(IO_B0, LOW);
delayMicroseconds(1);
}
if ((ShiftIn_result & 1 << 11) == 1 << 11) {
ShiftIn_result = (0B11111000 << 8) | ShiftIn_result;
}
return ShiftIn_result;
}

void HM55B_Reset() {
set_digital_output(IO_B1, LOW);
ShiftOut(0B0000, 3);
set_digital_output(IO_B1, HIGH);
}

void HM55B_StartMeasurementCommand() {
set_digital_output(IO_B1, LOW);
ShiftOut(0B1000, 3);
set_digital_output(IO_B1, HIGH);
}

int HM55B_ReadCommand() {
int result = 0;
set_digital_output(IO_B1, LOW);
ShiftOut(0B1100, 3);
result = ShiftIn(3);
return result;
}

void Read_Compass() {
int HM55B_result;
HM55B_StartMeasurementCommand(); // necessary!!
delayms(40); // the data is 40ms later ready
HM55B_result = HM55B_ReadCommand(); // read data and save Status
X_Data = ShiftIn(11); // Field strength in X
Y_Data = ShiftIn(11); // and Y direction
set_digital_output(IO_B1, HIGH); // ok deselect chip
angle = 180 * (atan2(-1 * Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
}

void blink_and_pause(int x)
{
// flash led for each digit in angle
int counter, y;

y = x;
if(x==0) y = 10;

for(counter=1;counter<=y;counter++)
{
DDRD |= 1 << PD1; // set LED pin PD1 to output
PORTD |= 1 << PD1; // LED on
delayms(200);
PORTD &= ~( 1 << PD1 ); //LED off
delayms(200);
}
delayms(3000); // end of digit
}

void flash_angle()
{
// LED flashes indicate integer value
// 1 flash -> 1
// 2 flashes -> 2
// :
// 9 flashes -> 9
// 10 flashes -> 0 (special case)
//
// ex. angle = 037 degrees -> 10 flashes + pause + 3 flashes + pause + 7 flashes
int y, ones, tens, hundreds;
y = abs(angle); // ignore sign
hundreds = (int)(y/100);
tens = (int)((y - hundreds100)/10);
ones = y - tens
10 - hundreds*100;
blink_and_pause(hundreds);
blink_and_pause(tens);
blink_and_pause(ones);
}

int main()
{
HM55B_Reset();
Read_Compass();
flash_angle();
while(1);
return 0;
}
[/code]

I have it working now, thanks. I was able to substitute set_digital_output() for Arduino’s pinMode() and digitalWrite() functions. I can post the completed program if you wish after I have the calibration part done.

SF

Great! What was wrong with the code you posted? I couldn’t find anything that should cause a problem; I noticed that in a few places you didn’t translate the “pinMode” command but didn’t think it would matter because “set_digital_output” sets the pin mode anyway.

–David

All the HIGH and LOW parameters were reversed in ShiftOut()
In HM55B_ReadCommand() I needed to pulse PB1/\Enable with a HIGH followed by a LOW
In HM55B_StartMeasurementCommand() I removed the last statement: set_digital_output(IO_B1, HIGH); – \Enable should have been left LOW
I added a while() loop to poll for ready status in Read_Compass()
and added an initial setup() module which initialized \Enable LOW and Clk HIGH
I think that is all.
SF