I'm trying to make a devantech cmps03 (a compass daughterboard based on philips KMZ51 magnetic sensors and a PIC uC) to interface with my 18F452. I'm using an EasyPIC2 and the latest release of mP.
This board has two outputs: PWM and I2C.
First test was to plug power and GND to the chip, pull up the SDA and SCL lines as suggested by the manufacturer and see how the PWM behaves. It turns out that it works fine, and there is almost no need to recalibrate the unit.
Second test was to write code to interface with the unit via I2C. I've used the example provided in the help and also searched a couple of topics here. It doesn't work. I think it must be something very simple and I will feel very dumb when I find out, but I couldn't figure out by myself.
For this second test, the manufacturer suggests pulling sda and scl lines using a 1.8K resistor (instead of the 10K of embedded pullup on easypic2). I didn't have a 1.8K, so I tested with 1.2K and 2.4K (two 1.2K in series), both didn't work.
Here's my code (sorry the lenght, it is mainly due to debug leds)
Code: Select all
program compass1;
var i, reg_adr, k : byte;
label getout;
begin
TRISD := 0; // PORTD is output
PORTD := $FF; // Initialize PORTD
Delay_ms(2000);
PORTD := 0;
Delay_ms(500);
I2C_Init(100000); // Initialize full master mode
PORTD := $FF;
Delay_ms(500);
PORTD := 0;
Delay_ms(500);
i := I2C_Start; // Issue I2C start signal
if i=0 then
begin
PORTD := $0F;
Delay_ms(1000);
PORTD := 0;
Delay_ms(500);
end
else begin
PORTD := $AA;
delay_ms(50);
PORTD := 1;
goto getout;
end;
i := I2C_Wr($C0); // Send byte via I2C(command to cmps03)
if (i=0) then
begin
PORTD := $F0;
Delay_ms(1000);
PORTD := 0;
Delay_ms(500);
end
else begin
PORTD := $AA;
delay_ms(50);
PORTD := 3;
goto getout;
end;
reg_adr := 1;
i := I2C_Wr(reg_adr); // Send byte(register 1 - 0-255 angles)
if i<>0 then
begin
PORTD := $AA;
delay_ms(50);
PORTD := 7;
goto getout;
end;
I2C_Repeated_Start; // Issue I2C signal repeated start
I2C_Wr($C1);
if i<>0 then
begin
PORTD := $AA;
delay_ms(50);
PORTD := $F;
goto getout;
end;
k := I2C_Rd(1); // Read the data
I2C_Stop; // Issue I2C stop signal
PORTD := k; // Show data on PORTD
delay_ms(100);
PORTD := $AA;
PORTD := k; // Show data on PORTD
delay_ms(100);
PORTD := $AA;
PORTD := k; // Show data on PORTD
delay_ms(100);
PORTD := $AA;
PORTD := k; // Show data on PORTD
getout:
// Endless loop
while true do
begin
PORTD := $80;
Delay_ms(20);
PORTD := $40;
Delay_ms(20);
PORTD := $20;
Delay_ms(20);
PORTD := $10;
Delay_ms(20);
PORTD := $08;
Delay_ms(20);
PORTD := $04;
Delay_ms(20);
PORTD := $02;
Delay_ms(20);
PORTD := $01;
Delay_ms(20);
end;
end.
So here's what happens:
By looking at the leds on portd, I can see that it executes the I2C_Init(100000) (they suggest using 100kHz).
It also executes I2C_Start without errors, but when I try to execute I2C_Wr($C0), nothing happens. leds on PORTD go low and stay low.
If you take a better look at my code, you will see that PORTD should display $F0 if success or $AA if no success...
Is there a possibility that my program is getting stuck somewhere inside the I2C_Wr?
Looking at the scl line with an oscope, there is no activity, it is always high (a tad below 3V). Shouldn't it oscillate after the I2C_Init?
Do you think the problem is the non-matching resistor value? I'd think that in this case, the clock line would oscilate at a different frequency, instead of not oscillating at all.
Thanks for you help!