I2C, PIC18F452 and Devantech CMPS03

General discussion on mikroPascal.
Post Reply
Author
Message
padu
Posts: 186
Joined: 01 Oct 2004 07:10
Location: California

I2C, PIC18F452 and Devantech CMPS03

#1 Post by padu » 01 Sep 2005 18:06

Disclaimer: This is a newbie thread about I2C :D

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!

User avatar
zristic
mikroElektronika team
Posts: 6608
Joined: 03 Aug 2004 12:59
Contact:

Re: I2C, PIC18F452 and Devantech CMPS03

#2 Post by zristic » 02 Sep 2005 08:30

We will have to check this. You'll be notified when we have some answers.

padu
Posts: 186
Joined: 01 Oct 2004 07:10
Location: California

Re: I2C, PIC18F452 and Devantech CMPS03

#3 Post by padu » 02 Sep 2005 17:29

zristic wrote:We will have to check this. You'll be notified when we have some answers.
Do you smell a bug here? I was hoping that somehow I was making something stupid and you would tell me to change one line of code and voila... everything solved... :(

Diogenes
Posts: 47
Joined: 04 Apr 2005 20:39
Location: Belgium
Contact:

#4 Post by Diogenes » 02 Sep 2005 20:52

Hi Padu,

i had some problems trying to use the standard I2C for my project, i dont have time right now but i'll look into my and your program and hopefully find something usefull

diogenes
still looking for the man...

User avatar
zristic
mikroElektronika team
Posts: 6608
Joined: 03 Aug 2004 12:59
Contact:

#5 Post by zristic » 04 Sep 2005 17:37

I checked the ASM your code produces and there in nothing wrong with it. I assume you are having problems with protocol that the sensors require. I2C has been proven to be working in many cases (if you doubt the library)...

padu
Posts: 186
Joined: 01 Oct 2004 07:10
Location: California

#6 Post by padu » 05 Sep 2005 04:49

zristic wrote:I checked the ASM your code produces and there in nothing wrong with it. I assume you are having problems with protocol that the sensors require. I2C has been proven to be working in many cases (if you doubt the library)...
Hey, thanks for checking that.

I've tried reading the compass using the PWM signal that it generates by using timers, but at 4MHz, I cannot get a timing precise enough.

I will try I2C again, this time with the right resistor values.

padu
Posts: 186
Joined: 01 Oct 2004 07:10
Location: California

#7 Post by padu » 07 Sep 2005 23:42

padu wrote: I've tried reading the compass using the PWM signal that it generates by using timers, but at 4MHz, I cannot get a timing precise enough.

I will try I2C again, this time with the right resistor values.
I've set the pullups with the suggested resistance values (1.8k), now it seems to work a little bit better, but it still gives me trouble. Every other sampling sequence, I get an error (I2C_Wr <> 0) in one of the writes (sometimes in the first one, sometimes the second one). Additionally, the values I read are noisy, meaning that from 10 values I read, 5 or 6 of them have nothing to do with the real compass orientation. All the time I'm also monitoring the PWM output using an oscope, that's how I know what value is inside the CMPS03 module.

My guess is that the baud rate is mismatched.


*** now, this could be a problem with the library, or with my brain...
*** the second alternative is the most probable

I was reading the 18F452 datasheet for the 10th time (section 15.4.7 - Baud rate generator) and either I read that completely wrong, mP is not setting the I2C frequency correctly to SPADD.

Let's say the target frequency is 100kHz (10uS). The datasheet says that the lower 7 bits of SPADD shall be initialized with such a value that when counted every other clock pulse (Q2 and Q4), it should take exactly the 10uS.

I'm using a 4MHz xtal, which means each clock pulse takes 1/4E6=250nS
If SPADD is decremented on Q2 and Q4, then the interval between decrements is two pulses, 500nS right?
So, how many SPADD decrements do I need in order to take exactly 10uS to zero? Unless I'm completely crazy, it is 10uS/500nS = 20 (0x14h).

Both mikroPascal and the PIC datasheet insist in saying that the correct value for SPADD @ 4MHz is 10 (0x0A). Why is that?

Clearly I'm loosing something here.


Also, after reading a couple of other posts involving problems using I2C, I've just made a note to myself to check the following:

1-check if all pins on portc are pulled up (they are not, the only ones I have pulled up were SCL and SDA with 1.8KOHM)
2-check if i2c idle before writing or reading (I2C_Is_Idle)
3-check resistor pack of portc, someone said that pin 1 to 4 was left unsoldered on easypic2

Any other hint?

Thanks

Padu

LGR
Posts: 3204
Joined: 23 Sep 2004 20:07

#8 Post by LGR » 09 Sep 2005 14:55

padu wrote:My guess is that the baud rate is mismatched.
I2C is syncronous. You don't need to match baud rates. You just need to make sure both devices can handle the baudrate, which is always set by the master.
If you know what you're doing, you're not learning anything.

padu
Posts: 186
Joined: 01 Oct 2004 07:10
Location: California

#9 Post by padu » 09 Sep 2005 18:03

LGR wrote:
padu wrote:My guess is that the baud rate is mismatched.
I2C is syncronous. You don't need to match baud rates. You just need to make sure both devices can handle the baudrate, which is always set by the master.
I got that yesterday... I was measuring the signal duration on the oscope and it was giving me a frequency of 50KHz... I said what the heck? Then I looked at my code and it was really 50KHz (from a test I did the other day).

Now this is what's happening:

After every attempt to write on the I2C bus, I check the function result and if it returns anything different than 0, I turn some leds on to tell me which I2C_Wr is failing. Turns out that it is always the second (setting the register) or the third (sending the read address).
Some times it doesn't give any errors and I can get an ok read of the compass, but for every 10 samplings, 7 will generate error (I2C_Wr returning <> 0).

Yesterday I tried inserting the following piece of code just before any write:

Code: Select all

repeat
  nop;
until (I2C_Is_Idle)

But it hangs, the SCL is never released and it keeps waiting forever. I don't know who is holding the clock line low, the master or the compass.

Another basic question: in my mind, I had to initialize the bus (I2C_Init) only once, but if I do that, my code won't work at all. I had to leave the I2C_Init call inside my sampling routine. Is that the normal thing to do?

As you can see, I'm pretty newbie on I2C.... I thought it would take me one or two days to set up the compass, but it's taking more than two weeks already.... frustration...

Thanks for the help!

LGR
Posts: 3204
Joined: 23 Sep 2004 20:07

#10 Post by LGR » 09 Sep 2005 18:12

I2C can be very frustrating. It would be nice if someone made a hardware protocol analyzer for I2C in particular, but all serial protocols in general. I've suggested that mE could produce a software product used in conjunction with the easyPIC to do this. This would be a nontrivial task to create the product, but I'm convinved there's a definate market, because this ends up being so time-consuming.
If you know what you're doing, you're not learning anything.

Bob Lawrence
Posts: 300
Joined: 18 Aug 2004 11:55
Location: Lwr Sackville, Nova Scotia, Canada

Beagle I2C/SPI Protocol Analyzer

#11 Post by Bob Lawrence » 09 Sep 2005 21:14

The versatile Beagle I2C/SPI Protocol Analyzer is the ideal tool for the embedded engineer who is developing an I2C and/or an SPI based product. The Beagle analzyer provides a high performance monitoring solution in a small, portable package. Perfect for engineers in the field and in the lab.


http://www.totalphase.com/products/beagle/i2cspi/

There are others out there as well. Seems like mE have their hands full at the moment so don't hold your breath :wink:

padu
Posts: 186
Joined: 01 Oct 2004 07:10
Location: California

Re: Beagle I2C/SPI Protocol Analyzer

#12 Post by padu » 09 Sep 2005 21:37

One thing that is still unanswered for me and I think it's piece of cake for you I2C guru guys.

Do I have to initialize the bus (I2C_Init(frequency)) every time I'm going to sample the slave? I tried initializing only once and sampling many times, but that didn't work.
When I added the i2c_init line within my sampling procedure, it worked (with only one leg, as stated in my previous post)

Bob Lawrence
Posts: 300
Joined: 18 Aug 2004 11:55
Location: Lwr Sackville, Nova Scotia, Canada

Follow the Assembler example here:

#13 Post by Bob Lawrence » 09 Sep 2005 21:58

You should be able to follow this and convert it over to MP.

http://www.picbook.com/downloads/sasm/CH17.asm

MHI
Posts: 56
Joined: 13 Mar 2010 20:52

Re: I2C, PIC18F452 and Devantech CMPS03

#14 Post by MHI » 21 Apr 2010 19:34

hello padu and everyone

is your problem solved ?? does anyone able to write and read over the compass without blocking the program ??

Regards

harryweston
Posts: 1
Joined: 10 Jul 2011 13:40

Re: I2C, PIC18F452 and Devantech CMPS03

#15 Post by harryweston » 10 Jul 2011 14:11

Hello MHI

I have successfully used a PIC18F2420 to display the bearing from a Devantech CMPS03 compass on a Devantech LCD03 display using MPASM assembler. I did it to get experience and understanding of I2C protocol and I will be happy to share this with anyone who is interested. There is too much material to include it all here, but I can send it as email attachments, (.text notes file, .asm file of nearly 1000 lines, config include file, .jpeg image of a diagram of I2C signals)

Harry

Post Reply

Return to “mikroPascal General”