using I2C in dspic30f

Thread Starter

turo2003

Joined Oct 14, 2011
12
hi,
i'm trying to use the I2C bus between 2 same dspic30f4011 controllers.
i'm using 1.8 Kohms pull-up resistors, one resistor on SDA and one resistor on SCL.
i'm supplying both dspic's with external power (5v).
here is the code for both master and slave, there is only 1 line different..

#include "p30f4011.h"
#include "libpic30.h"
#include "i2c.h"

#define BUT PORTBbits.RB8
#define LED PORTBbits.RB0

int main(void)
{
ADPCFG = 0xFFFF;
unsigned int I2CConfig, I2C_BRG;

TRISFbits.TRISF2 = 1; // SDA
TRISFbits.TRISF3 = 1; // SCL
TRISBbits.TRISB0 = 0; //Output for led
TRISBbits.TRISB8 = 1; //but

//Configure the I2C Bus//
I2CConfig = I2C_ON & //Enable the I2C Bus
I2C_IDLE_CON & I2C_CLK_HLD & I2C_IPMI_DIS &
I2C_7BIT_ADD & //Use a 7 Bit Slave Address
I2C_SLW_DIS & //Slew Rate disabled (enbled only for "fast mode" 400kHz)
I2C_SM_DIS & I2C_GCALL_DIS & I2C_STR_DIS &
I2C_NACK & //Send NACK during acknowledge
I2C_ACK_DIS & I2C_RCV_DIS & I2C_STOP_DIS & I2C_RESTART_DIS & I2C_START_DIS; //All seq. disabled

I2C_BRG = 0xB5; //0xB5 = 181 => Fscl=100kHz=Boud Rate, PGD=250ns, Fcy=20MHz/ 0x1F = 31 =>Fscl=400kHz

/*SLAVE ONLY*/// I2CADD = 0x08; // the slave address is 0x08, with r/w bit=0, we get 0x10

OpenI2C(I2CConfig , I2C_BRG); //Open the I2C Bus

LED=0;

IdleI2C();
StartI2C();
while(I2CCONbits.SEN); // Wait till Start sequence is completed
if (MasterWriteI2C(0x10) == 0) // the slave address is 0x08, with r/w bit=0, we get 0x10
{
LED=1;
__delay32(2500000); // =0.5 sec
LED=0;
__delay32(2500000); // =0.5 sec
LED=1;
__delay32(2500000); // =0.5 sec
LED=0;
}
StopI2C();
}


what happens is that the leds start blinking all the time, not only twise like it should.

where is my problem ?
 

ErnieM

Joined Apr 24, 2011
8,377
I don't see a problem, you're telling the LEDs to continuously blink as you have no STOP structure. Thus the code exits main() and the device restarts over and over.
 

Thread Starter

turo2003

Joined Oct 14, 2011
12
hi,
of course you were right, I have forgotten to add while(1) at the end.
that problem is fixed, thanks :)

now, I'm trying to activate the led which is on port B0, the address of the PORTB register is 0x02c8, I'm using this code on the muster:


IdleI2C();
StartI2C();
while(I2CCONbits.SEN); // Wait till Start sequence is completed
if (MasterWriteI2C(0x10) == 0) // the slave address is 0x08, with r/w bit=0, we get 0x10
{
LED=1;
__delay32(2500000); // =0.5 sec
LED=0;
__delay32(2500000); // =0.5 sec
LED=1;
__delay32(2500000); // =0.5 sec
LED=0;
}
MasterWriteI2C(0x02); // lower bits of PORTB
MasterWriteI2C(0xc8); // higher bits of PORTB
MasterWriteI2C(0x01); // send "1" to portBbits.rb0 - activate led
StopI2C();


unfortunatelly, this is not working..
where am I wrong ?
 

ErnieM

Joined Apr 24, 2011
8,377
Ummm, well... it could be a lot of things...

I just spent nearly a week tweaking the library I2C functions for the PIC32 (and I was just using it as a master), seems I2C is so simple from the hardware end but really involved on the software side.

I'm assuming you don't have a scope, that's what your LED is for. Ouch, this is pretty hard even with a scope. But perhaps not impossible.

Is MasterWrite() a blocking call? Meaning will it not return until it is complete? If not, you could be causing write collisions inside the master. You don't check that the slave ACKed (acknowledged) any of the information it was sent: so check ACK and light your LEDs if you do get ACKed.

The 4 bytes you send make sense only if your slave is properly coded to accept that data, and it is very dangerous to let a foreign device have total and complete control of your special function registers. It's OK to get something up and working but not production ready if you catch my drift. Better to send a symbol (say 'A' or 'B' or 'C' as a port name), and only read or write from registers you've defined a symbol for.

Anyway, I'll assume your slave gets the 3 bytes, and does a write to the register address it makes from the first 2 bytes using the 3rd byte. That can work. A few years back I did an I2C slave in a PIC18 device and it was a ton of work using both a scope and an in-circuit debugger (PICkit 2).

Back to ACK: if your Master is not seeing an ACK then the Slave isn't "seeing" the data stream. That points you to the slave code. So your first task is not to light a LED on slave port B.0 but to get the master to see an ACK.
 

Thread Starter

turo2003

Joined Oct 14, 2011
12
"I'm assuming you don't have a scope, that's what your LED is for. Ouch, this is pretty hard even with a scope. But perhaps not impossible."

I do have a scope but it does not display I2C, I mean I know there are scopes that can display digital bits of information, but I don't have one.

basically I am using the led to notify me when the ack is accepted (sent from the slave to the master).

"Is MasterWrite() a blocking call? Meaning will it not return until it is complete? If not, you could be causing write collisions inside the master. You don't check that the slave ACKed (acknowledged) any of the information it was sent"

the MasterWrite() function returns 0 when ack is accepted,If write collision occurs,return -1 , if there is NO ack, returns -2.

" so check ACK and light your LEDs if you do get ACKed."

I did exactly that.

"The 4 bytes you send make sense only if your slave is properly coded to accept that data, and it is very dangerous to let a foreign device have total and complete control of your special function registers. It's OK to get something up and working but not production ready if you catch my drift. Better to send a symbol (say 'A' or 'B' or 'C' as a port name), and only read or write from registers you've defined a symbol for."

yes, I agree, but at the end, I don't really want to communicate with 2 dspics, I want a system contains a dspic and an open-servo, talking in I2C protocol. I have tried letters also, that din't work.

"Back to ACK: if your Master is not seeing an ACK then the Slave isn't "seeing" the data stream. That points you to the slave code. So your first task is not to light a LED on slave port B.0 but to get the master to see an ACK."

ok, I have tried that also, this was my main goal. like I said, I want to establish communication between a dspic and an open-servo and according to the datasheet of that open-servo, it's address is 0x20, I send 0x40 because I'm using 7-bit address and 0x20 with r/w bit set to 0 gives 0x40, however, when I want the led to light up when ack is received from the open-servo,it does not. I have written a small loop sending addresses from 0x04 to 0xFE and checks for ack, with increments of 0x01, I see the led blinking twice, that means that an ack was received from ONE of the addresses once when the 8th bit (r/w) was 0 and once when it was 1, when I try to find that address, I fail.

I have narrowed it down to an address between 0x15 to 0x30, there the led blinks once, but when I checked each address separately it never blink :( I'm puzzled, any ideas ?

p.s.
thank you very much for your help.
 

ErnieM

Joined Apr 24, 2011
8,377
OK, so MasterWrite is a blocking call, but you are not checking it's return value so you don't know if it is being ACKed.

I'm not sure what you mean by "narrowed it down to an address between 0x15 to 0x30..."

If you are talking about this OpenServo project then you need not worry how to make a I2C slave (which is a pretty hard task), you just have to get the Master side to work, which is much easier.
 
Top