|
|
View previous topic :: View next topic |
Author |
Message |
DireSpume
Joined: 07 Jan 2013 Posts: 31
|
Cannot change speed of I2C |
Posted: Tue Apr 09, 2013 3:38 pm |
|
|
Hi all, I have a problem I hope I can get some advice on. I am using a PIC18F67K22 with compiler version 4.140. I am using I2C in master mode to communicate with a power supply. The communication is working fine. My problem is that I can't get the clock rate to change. No matter what I try, it is stuck at roughly 20 kHz. My PIC is running at 20 MHz.
This is the relevant #use i2c line:
Code: | #use i2c(Master,Fast=400000,sda=PIN_D5,scl=PIN_D6,FORCE_HW,stream=I2C_POWER) |
I have tried Fast=100000 also, as well as slow, and none of the options seem to make a difference; clock speed remains at ~20kHz.
The only explanation I can come up with is that it is running in software mode despite the FORCE_HW option. Although even then it is mighty slow.
Any ideas? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 09, 2013 4:46 pm |
|
|
Comment out the #nolist statement at the top of the 18F67K22.h file
and re-compile. Look at the .LST file and look at the code for an
i2c_write() statement. If it calls a routine, look at the routine.
Make sure the compiler .LST file format is set for Symbolic mode.
You should easily be able to to determine if the ASM code is referencing
hardware registers, or if it's doing bit-banging. Then you will know if
it's doing hardware or software i2c. |
|
|
DireSpume
Joined: 07 Jan 2013 Posts: 31
|
|
Posted: Tue Apr 09, 2013 7:23 pm |
|
|
Okay, so it looks like it's using the hardware. This is what i2c_write() calls:
Code: |
!#use i2c(Master,Fast=400000,sda=PIN_D5,scl=PIN_D6,FORCE_HW,stream=I2C_POWER)
0x403C: BCF SSP2CON1, 7, ACCESS
0x403E: BCF PIR2, 5, ACCESS
0x4040: MOVFF _invar3, SSP2BUF
0x4044: MOVLW 0x2
0x4046: BTFSC SSP2CON1, 7, ACCESS
0x4048: BRA 0x4054
0x404A: BTFSS PIR2, 5, ACCESS
0x404C: BRA 0x404A
0x404E: MOVLW 0x0
0x4050: BTFSC SSP2CON2, 6, ACCESS
0x4052: MOVLW 0x1
0x4054: MOVWF _invar21, ACCESS
0x4056: RETURN 0
|
So now I really have no clue what is going on. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 09, 2013 11:48 pm |
|
|
Quote: |
My problem is that I can't get the clock rate to change. No matter what I
try, it is stuck at roughly 20 kHz. |
How are you testing the i2c clock speed ? You should do an i2c_write()
continuously in a loop, and look at the SCL2 pin with an oscilloscope.
Example:
Code: |
while(1)
{
i2c_write(I2C_POWER, 0x01);
delay_us(50);
}
|
|
|
|
DireSpume
Joined: 07 Jan 2013 Posts: 31
|
|
Posted: Tue Apr 09, 2013 11:58 pm |
|
|
I am using an oscilloscope to measure clock rate on SCL2. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Wed Apr 10, 2013 12:43 am |
|
|
Have you something else in use on the chip that relies on 'time'. UART etc.?.
The first thing I'd suspect is that your master oscillator fuse configurations are wrong, or the crystal itself is not working as you think, and the chip is 'dropping back' to the internal oscillator at 1MHz. Hence the I2C is running at 1/20th the rate you are asking for.....
Start with a simple 'toggle a pin' test, and see if this gives the frequency as being for a 20MHz clock or not. If not then you need to tell us how your crystal is wired, what frequency it is (are you using PLL), and your fuses.
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Apr 10, 2013 1:14 am |
|
|
Try changing the i2c speed in main(), using the macro shown in the
example below:
Code: |
#include <18F67K22.h>
#fuses HSH, NOWDT, PUT, BROWNOUT
#use delay(clock=20M)
#use i2c(Master,Fast=400000,sda=PIN_D5,scl=PIN_D6,FORCE_HW,stream=I2C_POWER)
// This macro sets the hardware i2c baudrate for SSP2.
#byte SSP2ADD = getenv("SFR:SSP2ADD")
#byte SSP2CON1 = getenv("SFR:SSP2CON1")
#define set_i2c_speed2(baud) \
SSP2CON1 = 0x28; \
SSP2ADD = (((getenv("CLOCK") + (baud *2))/ (baud * 4)) -1)
//==========================================
void main()
{
// Examples of how to call it.
set_i2c_speed2(100000);
set_i2c_speed2(400000);
while(1);
} |
This macro first puts the MSSP in a mode such that SSP2ADD is treated
as the baudrate register. Then it calculates the baudrate value, and
rounds off the result, and then it writes it to the baudrate register.
Why not use i2c_speed() ? Because I'm not sure CCS is doing it correctly. |
|
|
DireSpume
Joined: 07 Jan 2013 Posts: 31
|
|
Posted: Wed Apr 10, 2013 12:13 pm |
|
|
Even though I was 99.9% sure my oscillator was working as expected, I did double check it as you suggested, Ttelmah. Using FAST_IO, I was able to get 1.25 MHz on an output pin. The assembly code consists is 3 instructions, taking 4 cycles to complete = 20MHz/(4*4) = 1.25 MHz. So now I'm 100% sure the oscillator is working as expected, so that's good. (Incidentally, I did initially have problems with the fuses at first, as you suspected, and it defaulted to the internal oscillator (which is 8 MHz on the 18F67K22)).
PCM Programmer, your method worked! Any idea why the back-door method works but the normal method (i.e. Fast=100000) doesn't? Also, I tried the built-in i2c_speed() function, but that caused it to crash on i2c_start() for some reason. I'm both delighted to have a workaround and annoyed that I don't understand why it's necessary.
Also, when I use your macro at 100000, the actual frequency is around 92 kHz, and at 400000, the actual frequency is 285 kHz. I know the clock frequency has only certain discrete settings, but does this sound about right? Thanks for your help guys! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Apr 10, 2013 12:38 pm |
|
|
Post your test program which you use to measure the SCL clock frequency. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|