EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

I2C (slave and master on board)

Started by Jon Trem September 26, 2008
Hello,

I want to test I2C and since I have no I2C device I used I2C0 and I2C1 of a same LPC2148 board.

I2C0 is master transmitter, I2C1 is slave receiver. But I can't make it work.
Using LEDS to debug, I see that :
- I2C0 send a START condition well
- I2C0 send the SLA+W and receive an ACK (0x18 in I2C0STAT)

- I2C1 receive its SLA+W and return an ACK (0x60 in I2C1STAT)

That makes the I2C0 send the byte of data. But then :
- I2C0 neither interrupts with 0x28 (Data transmitted, ACK received) nor 0x30 (Data transmitted, NOT ACK received)
- I2C1 does not interrupt with 0x80 (Data received, ACK returned)
I
put two pull up resistors on SDA and SCL (without them, nothing
happens, I2C0 does not interrupt even for a START condition sent).

I spent all the day on it and I can't find where is the problem.
Thank you for helping!
Here is my code :

// STATUS LEDs
#define LED_1 (1<<16) //Port 1-Pin 16
#define LED_2 (1<<17) //Port 1-Pin 17
#define LED_3 (1<<18) //Port 1-Pin 18

void initialize_leds(void) {

IO1DIR |= LED_1 | LED_2 | LED_3; // Set LED pins as output
IO1SET |= LED_1 | LED_2 | LED_3; // Turn all LEDs off

}

void led_on(unsigned led)
{
IO1CLR |= led;
}

void led_off(unsigned led)
{
IO1SET |= led;
}
//_____________________________________________________________________
#define I2C_AA (1<<2)
#define I2C_SI (1<<3)
#define I2C_STO (1<<4)
#define I2C_STA (1<<5)
#define I2C_I2EN (1<<6)
unsigned I2C_address;
unsigned I2C_data;

void I2CISR(void) __attribute__((interrupt("IRQ")));
void I2CISR(void) {
switch (I2C0STAT) {
case (0x08): // A START condition has been transmitted (Bus was free)
I2C0DAT = I2C_address; // Send the slave address (SLA) and the write bit (0);
I2C0CONCLR = I2C_STA;// Clear the start bit
break;

case (0x20): // SLA+W has been transmitted; NOT ACK has been received
I2C0CONSET = I2C_STA; // repeat START
break;
case (0x10): // A repetead START condition has been transmitted
I2C0DAT = I2C_address; // Send the slave address (SLA) and the write bit (0);
I2C0CONCLR = I2C_STA;// Clear the start bit
break;

case (0x18): // SLA+W has been transmitted; ACK has been received
I2C0DAT = 0x55; // Send first data byte
led_on(LED_1);
break;

case (0x28): // Data byte in I2DAT has been transmitted; ACK has been received
led_on(LED_2);
I2C0CONSET = I2C_STO; // Send STOP condition
break;

case (0x30): // Data byte in I2DAT has been transmitted; NOT ACK has been received
led_on(LED_2);
I2C0CONSET = I2C_STA; // repeat START
break;

case (0xF8):
break;

case (0x00):
break;

}

I2C0CONCLR = I2C_SI; // Clear the interrupt flag
VICVectAddr = 0x00; // Clear interrupt
}

void I2C1ISR(void) __attribute__((interrupt("IRQ")));
void I2C1ISR(void) {
unsigned char st;
st = I2C1STAT;
I2C1CONCLR = 0x2C;

switch (st) {
case (0x60): // Own SLA+W has been received; ACK has been returned
case (0x68): // Own SLA+W has been received; ACK has been returned (Arbitration lost)
case (0x70): // General call address (0x00) has been received; ACK has been returned
led_on(LED_3);
I2C1CONSET = I2C_AA;
break;

case (0x80): // DATA has been received, ACK has been returned
led_on(LED_2);
I2C1CONSET = I2C_AA;
break;

}
VICVectAddr = 0x00; // Clear interrupt
}

void initialize_I2C(void) {

PINSEL0 |= (1<<4)|(1<<6);
PINSEL0 |= (1<<22)|(1<<23)|(1<<28)|(1<<29);

VICVectCntl1=0x29;
VICVectAddr1=(unsigned long) I2CISR;
VICIntEnable=0x0200;

VICVectCntl2=0x33;
VICVectAddr2=(unsigned long) I2C1ISR;
VICIntEnable=0x80200;
I2C0SCLH = 0x16;
I2C0SCLL = 0x16;
I2C0CONCLR = 0x6C;

I2C1CONCLR = 0x6C;
I2C1ADR = 0x7F; // 0x3F + 1
I2C1CONSET = 0x44;

}

void I2C_transfer_byte(unsigned addr, unsigned data) {

I2C_address = addr;
I2C_data = data;

I2C0CONCLR = 0x6C;
I2C0CONSET = 0x40; // Enter Master mode = I2C_I2EN;
I2C0CONSET = 0x20; // Send the START condition = I2C_STA
}
//_____________________________________________________________________
int main(void)
{
initialize();
initialize_I2C();
initialize_leds();

I2C_transfer_byte(0x7E,0x30);

}

An Engineer's Guide to the LPC2100 Series

--- In l..., Jon Trem wrote:
>
> Hello,
>
> I want to test I2C and since I have no I2C device I used I2C0 and
I2C1 of a same LPC2148 board.
>
> I2C0 is master transmitter, I2C1 is slave receiver. But I can't make
it work.
> Using LEDS to debug, I see that :
> - I2C0 send a START condition well
> - I2C0 send the SLA+W and receive an ACK (0x18 in I2C0STAT)
>
> - I2C1 receive its SLA+W and return an ACK (0x60 in I2C1STAT)
>
> That makes the I2C0 send the byte of data. But then :
> - I2C0 neither interrupts with 0x28 (Data transmitted, ACK received)
nor 0x30 (Data transmitted, NOT ACK received)
> - I2C1 does not interrupt with 0x80 (Data received, ACK returned)
> I
> put two pull up resistors on SDA and SCL (without them, nothing
> happens, I2C0 does not interrupt even for a START condition sent).
>
> I spent all the day on it and I can't find where is the problem.
> Thank you for helping!
> Here is my code :
>
> // STATUS LEDs
> #define LED_1 (1<<16) //Port 1-Pin 16
> #define LED_2 (1<<17) //Port 1-Pin 17
> #define LED_3 (1<<18) //Port 1-Pin 18
>
> void initialize_leds(void) {
>
> IO1DIR |= LED_1 | LED_2 | LED_3; // Set LED pins as output
> IO1SET |= LED_1 | LED_2 | LED_3; // Turn all LEDs off
>
> }
>
> void led_on(unsigned led)
> {
> IO1CLR |= led;
> }
>
> void led_off(unsigned led)
> {
> IO1SET |= led;
> }
>
//____________________________________________________________________
_
> #define I2C_AA (1<<2)
> #define I2C_SI (1<<3)
> #define I2C_STO (1<<4)
> #define I2C_STA (1<<5)
> #define I2C_I2EN (1<<6)
> unsigned I2C_address;
> unsigned I2C_data;
>
> void I2CISR(void) __attribute__((interrupt("IRQ")));
> void I2CISR(void) {
> switch (I2C0STAT) {
> case (0x08): // A START condition has been transmitted (Bus was
free)
> I2C0DAT = I2C_address; // Send the slave address (SLA) and the
write bit (0);
> I2C0CONCLR = I2C_STA;// Clear the start bit
> break;
>
> case (0x20): // SLA+W has been transmitted; NOT ACK has been
received
> I2C0CONSET = I2C_STA; // repeat START
> break;
> case (0x10): // A repetead START condition has been transmitted
> I2C0DAT = I2C_address; // Send the slave address (SLA) and the
write bit (0);
> I2C0CONCLR = I2C_STA;// Clear the start bit
> break;
>
> case (0x18): // SLA+W has been transmitted; ACK has been
received
> I2C0DAT = 0x55; // Send first data byte
> led_on(LED_1);
> break;
>
> case (0x28): // Data byte in I2DAT has been transmitted; ACK has
been received
> led_on(LED_2);
> I2C0CONSET = I2C_STO; // Send STOP condition
> break;
>
> case (0x30): // Data byte in I2DAT has been transmitted; NOT ACK
has been received
> led_on(LED_2);
> I2C0CONSET = I2C_STA; // repeat START
> break;
>
> case (0xF8):
> break;
>
> case (0x00):
> break;
>
> }
>
> I2C0CONCLR = I2C_SI; // Clear the interrupt flag
> VICVectAddr = 0x00; // Clear interrupt
> }
>
> void I2C1ISR(void) __attribute__((interrupt("IRQ")));
> void I2C1ISR(void) {
> unsigned char st;
> st = I2C1STAT;
> I2C1CONCLR = 0x2C;
>
> switch (st) {
> case (0x60): // Own SLA+W has been received; ACK has been
returned
> case (0x68): // Own SLA+W has been received; ACK has been
returned (Arbitration lost)
> case (0x70): // General call address (0x00) has been received;
ACK has been returned
> led_on(LED_3);
> I2C1CONSET = I2C_AA;
> break;
>
> case (0x80): // DATA has been received, ACK has been returned
> led_on(LED_2);
> I2C1CONSET = I2C_AA;
> break;
>
> }
> VICVectAddr = 0x00; // Clear interrupt
> }
>
> void initialize_I2C(void) {
>
> PINSEL0 |= (1<<4)|(1<<6);
> PINSEL0 |= (1<<22)|(1<<23)|(1<<28)|(1<<29);
>
> VICVectCntl1=0x29;
> VICVectAddr1=(unsigned long) I2CISR;
> VICIntEnable=0x0200;
>
> VICVectCntl2=0x33;
> VICVectAddr2=(unsigned long) I2C1ISR;
> VICIntEnable=0x80200;
> I2C0SCLH = 0x16;
> I2C0SCLL = 0x16;
> I2C0CONCLR = 0x6C;
>
> I2C1CONCLR = 0x6C;
> I2C1ADR = 0x7F; // 0x3F + 1
> I2C1CONSET = 0x44;
>
> }
>
> void I2C_transfer_byte(unsigned addr, unsigned data) {
>
> I2C_address = addr;
> I2C_data = data;
>
> I2C0CONCLR = 0x6C;
> I2C0CONSET = 0x40; // Enter Master mode = I2C_I2EN;
> I2C0CONSET = 0x20; // Send the START condition = I2C_STA
> }
>
//____________________________________________________________________
_
> int main(void)
> {
> initialize();
> initialize_I2C();
> initialize_leds();
>
> I2C_transfer_byte(0x7E,0x30);
>
> }
>

Make sure you clear the I2C1 interrupt flag (like you do for I2C0).

TC

--- In l..., "tcirobot" wrote:
>
> --- In l..., Jon Trem wrote:
> >
> > Hello,
> >
> > I want to test I2C and since I have no I2C device I used I2C0 and
> I2C1 of a same LPC2148 board.
> >
> > I2C0 is master transmitter, I2C1 is slave receiver. But I can't make
> it work.
> > Using LEDS to debug, I see that :
> > - I2C0 send a START condition well
> > - I2C0 send the SLA+W and receive an ACK (0x18 in I2C0STAT)
> >
> > - I2C1 receive its SLA+W and return an ACK (0x60 in I2C1STAT)
> >
> > That makes the I2C0 send the byte of data. But then :
> > - I2C0 neither interrupts with 0x28 (Data transmitted, ACK received)
> nor 0x30 (Data transmitted, NOT ACK received)
> > - I2C1 does not interrupt with 0x80 (Data received, ACK returned)
> >
> >
> > I
> > put two pull up resistors on SDA and SCL (without them, nothing
> > happens, I2C0 does not interrupt even for a START condition sent).
> >
> >
> >
> > I spent all the day on it and I can't find where is the problem.
> >
> >
> > Thank you for helping!
> >
> >
> > Here is my code :
> >
> > // STATUS LEDs
> > #define LED_1 (1<<16) //Port 1-Pin 16
> > #define LED_2 (1<<17) //Port 1-Pin 17
> > #define LED_3 (1<<18) //Port 1-Pin 18
> >
> > void initialize_leds(void) {
> >
> > IO1DIR |= LED_1 | LED_2 | LED_3; // Set LED pins as output
> > IO1SET |= LED_1 | LED_2 | LED_3; // Turn all LEDs off
> >
> > }
> >
> > void led_on(unsigned led)
> > {
> > IO1CLR |= led;
> > }
> >
> > void led_off(unsigned led)
> > {
> > IO1SET |= led;
> > }
> >
> //____________________________________________________________________
> _
> >
> >
> > #define I2C_AA (1<<2)
> > #define I2C_SI (1<<3)
> > #define I2C_STO (1<<4)
> > #define I2C_STA (1<<5)
> > #define I2C_I2EN (1<<6)
> >
> >
> > unsigned I2C_address;
> > unsigned I2C_data;
> >
> > void I2CISR(void) __attribute__((interrupt("IRQ")));
> > void I2CISR(void) {
> >
> >
> > switch (I2C0STAT) {
> > case (0x08): // A START condition has been transmitted (Bus was
> free)
> > I2C0DAT = I2C_address; // Send the slave address (SLA) and the
> write bit (0);
> > I2C0CONCLR = I2C_STA;// Clear the start bit
> > break;
> >
> > case (0x20): // SLA+W has been transmitted; NOT ACK has been
> received
> > I2C0CONSET = I2C_STA; // repeat START
> > break;
> > case (0x10): // A repetead START condition has been transmitted
> > I2C0DAT = I2C_address; // Send the slave address (SLA) and the
> write bit (0);
> > I2C0CONCLR = I2C_STA;// Clear the start bit
> > break;
> >
> > case (0x18): // SLA+W has been transmitted; ACK has been
> received
> > I2C0DAT = 0x55; // Send first data byte
> > led_on(LED_1);
> > break;
> >
> > case (0x28): // Data byte in I2DAT has been transmitted; ACK has
> been received
> > led_on(LED_2);
> > I2C0CONSET = I2C_STO; // Send STOP condition
> > break;
> >
> > case (0x30): // Data byte in I2DAT has been transmitted; NOT ACK
> has been received
> > led_on(LED_2);
> > I2C0CONSET = I2C_STA; // repeat START
> > break;
> >
> > case (0xF8):
> > break;
> >
> > case (0x00):
> > break;
> >
> > }
> >
> > I2C0CONCLR = I2C_SI; // Clear the interrupt flag
> > VICVectAddr = 0x00; // Clear interrupt
> > }
> >
> > void I2C1ISR(void) __attribute__((interrupt("IRQ")));
> > void I2C1ISR(void) {
> > unsigned char st;
> > st = I2C1STAT;
> > I2C1CONCLR = 0x2C;
> >
> > switch (st) {
> > case (0x60): // Own SLA+W has been received; ACK has been
> returned
> > case (0x68): // Own SLA+W has been received; ACK has been
> returned (Arbitration lost)
> > case (0x70): // General call address (0x00) has been received;
> ACK has been returned
> > led_on(LED_3);
> > I2C1CONSET = I2C_AA;
> > break;
> >
> > case (0x80): // DATA has been received, ACK has been returned
> > led_on(LED_2);
> > I2C1CONSET = I2C_AA;
> > break;
> >
> > }
> >
> >
> > VICVectAddr = 0x00; // Clear interrupt
> > }
> >
> > void initialize_I2C(void) {
> >
> > PINSEL0 |= (1<<4)|(1<<6);
> > PINSEL0 |= (1<<22)|(1<<23)|(1<<28)|(1<<29);
> >
> > VICVectCntl1=0x29;
> > VICVectAddr1=(unsigned long) I2CISR;
> > VICIntEnable=0x0200;
> >
> > VICVectCntl2=0x33;
> > VICVectAddr2=(unsigned long) I2C1ISR;
> > VICIntEnable=0x80200;
> >
> >
> > I2C0SCLH = 0x16;
> > I2C0SCLL = 0x16;
> > I2C0CONCLR = 0x6C;
> >
> > I2C1CONCLR = 0x6C;
> > I2C1ADR = 0x7F; // 0x3F + 1
> > I2C1CONSET = 0x44;
> >
> > }
> >
> > void I2C_transfer_byte(unsigned addr, unsigned data) {
> >
> > I2C_address = addr;
> > I2C_data = data;
> >
> > I2C0CONCLR = 0x6C;
> > I2C0CONSET = 0x40; // Enter Master mode = I2C_I2EN;
> > I2C0CONSET = 0x20; // Send the START condition = I2C_STA
> >
> >
> > }
> >
> >
> >
> //____________________________________________________________________
> _
> >
> >
> > int main(void)
> > {
> > initialize();
> > initialize_I2C();
> > initialize_leds();
> >
> > I2C_transfer_byte(0x7E,0x30);
> >
> > }
> > Make sure you clear the I2C1 interrupt flag (like you do for I2C0).
>
> TC
>

Is I2C1CONCLR = 0x2C; not doing it?
--- In l..., "jon.trem" wrote:
>
> --- In l..., "tcirobot" wrote:
> > ....
> > Make sure you clear the I2C1 interrupt flag (like you do for
I2C0).
> >
> > TC
> > Is I2C1CONCLR = 0x2C; not doing it?
>

You need to do it in the I2C1 ISR (like you do in the I2C0 ISR).

TC
--- In l..., "tcirobot" wrote:
>
> --- In l..., "jon.trem" wrote:
> >
> > --- In l..., "tcirobot" wrote:
> > > ....
> > > Make sure you clear the I2C1 interrupt flag (like you do for
> I2C0).
> > >
> > > TC
> > >
> >
> > Is I2C1CONCLR = 0x2C; not doing it?
> > You need to do it in the I2C1 ISR (like you do in the I2C0 ISR).
>
> TC
>

Thank you for your help

But I2C1CONCLR = 0x2C; is in the I2C1 ISR and clear the interrupt flag.
--- In l..., "jon.trem" wrote:
>
> --- In l..., "tcirobot" wrote:
> >
> > --- In l..., "jon.trem" wrote:
> > >
> > > --- In l..., "tcirobot" wrote:
> > > > ....
> > > > Make sure you clear the I2C1 interrupt flag (like you do for
> > I2C0).
> > > >
> > > > TC
> > > >
> > >
> > > Is I2C1CONCLR = 0x2C; not doing it?
> > >
> >
> > You need to do it in the I2C1 ISR (like you do in the I2C0 ISR).
> >
> > TC
> > Thank you for your help
>
> But I2C1CONCLR = 0x2C; is in the I2C1 ISR and clear the interrupt
flag.
>

I haven't studied your code carefully but in the I2C1 ISR...

- switch on the I2C1 status first (before you clear the interrupt
state)
- you want to clear the I2C1 interrupt state at the end of the ISR

If you look at the differences between your I2C0 and I2C1 ISRs I think
you will see the difference I am talking about.

TC
--- In l..., "tcirobot" wrote:
>
> --- In l..., "jon.trem" wrote:
> >
> > --- In l..., "tcirobot" wrote:
> > >
> > > --- In l..., "jon.trem" wrote:
> > > >
> > > > --- In l..., "tcirobot" wrote:
> > > > > ....
> > > > > Make sure you clear the I2C1 interrupt flag (like you do for
> > > I2C0).
> > > > >
> > > > > TC
> > > > >
> > > >
> > > > Is I2C1CONCLR = 0x2C; not doing it?
> > > >
> > >
> > > You need to do it in the I2C1 ISR (like you do in the I2C0 ISR).
> > >
> > > TC
> > >
> >
> > Thank you for your help
> >
> > But I2C1CONCLR = 0x2C; is in the I2C1 ISR and clear the interrupt
> flag.
> > I haven't studied your code carefully but in the I2C1 ISR...
>
> - switch on the I2C1 status first (before you clear the interrupt
> state)
> - you want to clear the I2C1 interrupt state at the end of the ISR
>
> If you look at the differences between your I2C0 and I2C1 ISRs I think
> you will see the difference I am talking about.
>
> TC
>

Okay I changed it, but it didn't solve the problem.
--- In l..., "jon.trem" wrote:
>...
>
> Okay I changed it, but it didn't solve the problem.
>

Post your latest code and I'll look at it again. It is a bit tricky to
get the LPC21xx I2C controller to function at first. I found the
documentation to be inadequate.

Do you have an oscilloscope? It helps a great deal to be able to view
the I2C signals when debugging the code.

TC
Thank you very much for your help. Unfortunately, I don't have any
oscilloscope.

Here is my latest code (without the LED functions that are OK) :
#define I2C_AA (1<<2)
#define I2C_SI (1<<3)
#define I2C_STO (1<<4)
#define I2C_STA (1<<5)
#define I2C_I2EN (1<<6)
unsigned I2C_address;
unsigned I2C_data;

void I2CISR(void) __attribute__((interrupt("IRQ")));
void I2CISR(void) {
switch (I2C0STAT) {
case (0x08): // A START condition has been transmitted (Bus was free)
I2C0DAT = I2C_address; // Send the slave address (SLA) and the
write bit (0);
I2C0CONCLR = I2C_STA;// Clear the start bit
break;

case (0x20): // SLA+W has been transmitted; NOT ACK has been received
I2C0CONSET = I2C_STA; // repeat START
break;
case (0x10): // A repetead START condition has been transmitted
I2C0DAT = I2C_address; // Send the slave address (SLA) and the
write bit (0);
I2C0CONCLR = I2C_STA;// Clear the start bit
break;

case (0x18): // SLA+W has been transmitted; ACK has been received
I2C0DAT = 0x55; // Send first data byte
led_on(LED_1);
break;

case (0x28): // Data byte in I2DAT has been transmitted; ACK has
been received
led_on(LED_2);
I2C0CONSET = I2C_STO; // Send STOP condition
break;

case (0x30): // Data byte in I2DAT has been transmitted; NOT ACK
has been received
led_on(LED_2);
I2C0CONSET = I2C_STA; // repeat START
break;

case (0xF8):
break;

case (0x00):
break;

}

I2C0CONCLR = I2C_SI; // Clear the interrupt flag
VICVectAddr = 0x00; // Clear interrupt
}

void I2C1ISR(void) __attribute__((interrupt("IRQ")));
void I2C1ISR(void) {

switch (I2C1STAT) {
case (0x60): // Own SLA+W has been received; ACK has been returned
case (0x68): // Own SLA+W has been received; ACK has been returned
(Arbitration lost)
case (0x70): // General call address (0x00) has been received; ACK
has been returned
led_on(LED_3);
I2C1CONSET = I2C_AA;
break;

case (0x80): // DATA has been received, ACK has been returned
led_on(LED_2);
I2C1CONSET = I2C_AA;
break;

}
I2C1CONCLR = I2C_SI; // Clear the interrupt flag
VICVectAddr = 0x00; // Clear interrupt
}

void initialize_I2C(void) {

PINSEL0 |= (1<<4)|(1<<6);
PINSEL0 |= (1<<22)|(1<<23)|(1<<28)|(1<<29);

VICVectCntl1=0x29;
VICVectAddr1=(unsigned long) I2CISR;
VICIntEnable=0x0200;

VICVectCntl2=0x33;
VICVectAddr2=(unsigned long) I2C1ISR;
VICIntEnable=0x80200;

I2C0SCLH = 0x16;
I2C0SCLL = 0x16;
I2C0CONCLR = 0x6C;

I2C1CONCLR = 0x6C;
I2C1ADR = 0x7F; // 0x3F + 1
I2C1CONSET = 0x44;

}

void I2C_transfer_byte(unsigned addr, unsigned data) {

I2C_address = addr;
I2C_data = data;

I2C0CONCLR = 0x6C;
I2C0CONSET = 0x40; // Enter Master mode
I2C0CONSET = I2C_STA; // Send the START condition
}
//_____________________________________________________________________
int main(void)
{
initialize();
initialize_I2C();
initialize_leds();

I2C_transfer_byte(0x7E,0x30);

}

--- In l..., "tcirobot" wrote:
>
> --- In l..., "jon.trem" wrote:
> >...
> >
> > Okay I changed it, but it didn't solve the problem.
> > Post your latest code and I'll look at it again. It is a bit tricky to
> get the LPC21xx I2C controller to function at first. I found the
> documentation to be inadequate.
>
> Do you have an oscilloscope? It helps a great deal to be able to view
> the I2C signals when debugging the code.
>
> TC
>

--- In l..., "jon.trem" wrote:
> ...
> void initialize_I2C(void) {
>
> PINSEL0 |= (1<<4)|(1<<6);
> PINSEL0 |= (1<<22)|(1<<23)|(1<<28)|(1<<29);

I'm not sure what you intended the second write to PINSEL0 above to do,
but it does not configure the I2C1 pins. I didn't see in your code
where you configured the I2C1 SCL and SDA pins. I was looking for the
something like the following (using your coding style)...

PINSEL1 |= (1<<2)|(1<<4);

I still haven't had a chance to walk through the rest of the code
carefully.

TC

The 2024 Embedded Online Conference