Forums

I2C in LPC2103 doesn't work

Started by Artem March 6, 2010
Hello.
I'm trying to get work I2C0 on Olimex LPC-H2103 board.
I'm using:
Eclipse
Zylin Embedded CDT debug plugin 4.10.1 (for gdb debugging)
YAGARTO GNU ARM toolchain, build 23.12.2009 (Binutils-2.20, Newlib-1.18.0, GCC-4.4.2, GDB-7.0.1)
OpenOCD 0.4.0

I can't even pass start-byte condition ! I initialize I2C0, send start bit and waiting for state change. Because of my such simple wish I even disconnected slave-device providing i2c bus absolutely free ! I2CSTAT must change to 0x08 but it doesn't ! I've read a lot of similar messages on this group and over the internet and taking into account others' mistakes I've checked absolutelly all. Wires are connected, PCONP register set correctly, PINSEL bits also correspond to selected I2C0, errata sheet is ok.. everything is ok ! After power on I'm checking with multimeter levels on pins, they are in high, after i2c init they are also high and after start-bit they are low that means start-bit successfully send and microcontroller waits for what ???

Linker-script and startup-code from: http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/lpc_uart0_20041214.zip (I've modified it for my project)
Compiling:
arm-elf-gcc -I"Z:\Projects\DemoVisionRobot\primary_program\include" -O0 -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -Wall -std=gnu99 -c -fmessage-length=0 -funsigned-char -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mcpu=arm7tdmi-s -g3 -gdwarf-2 -o"$@" "$<"
Linking:
arm-elf-g++ -T"Z:\Projects\DemoVisionRobot\primary_program\lpc2103-ROM.ld" -nostartfiles -Wl,-Map,DemoVisionRobot.map -mcpu=arm7tdmi-s -g3 -gdwarf-2 -o"DemoVisionRobot.elf" $(OBJS) $(USER_OBJS) $(LIBS)

Piece of code:

// setup SCL pin P02
PINSEL0 &= ~(3<<4);
PINSEL0 |= 1<<4;
// setup SDA pin P03
PINSEL0 &= ~(3<<6);
PINSEL0 |= 1<<6;
// disable and reset interface
I2C0CONCLR = 0x6C;
// I'm not dreaming of high speed
I2C0SCLL = 1000;
I2C0SCLH = 1000;
// enable interface and send start bit
I2C0CONSET = 0x60;
//simply waiting for 0x08 state... I'm not ever dreaming of more !
while(I2C0STAT == 0xF8); // loops infinitely

I've tried also to check SI bit in I2CCONSET, different order of setting up registers, to clear SI bit before and after sending start bit, and many other example codes and things - no matters. Interrupts doesnt triggers too. Generated assembly code seems to be also correct.

I've broken my brain ! What's wrong ??? Please, help.

An Engineer's Guide to the LPC2100 Series

Why not start with Google?

Among other things you will find an App Note from NXP:
http://www.nxp.com/documents/application_note/AN10369.pdf

You will notice that NXP implements I2C as an interrupt driven state machine.

Then there is the demo code at www.jcwren.com/arm This is specific to the LPC2148 but i2c-polled may be close enough.

There are at least 3 example I2C projects in the Files folder of this group. None are specific to the LPC2103 but the LPC2106 code should be pretty close.

Richard

Everything I'm doing last days is looping in cycle "googling-trying". Of course I already read this appnote and tried a lot of other code examples. I've tried interrupts but as expected they don't trigger too.
But I guess that reason is incorrect code. Generally speaking, it works more or less well with gcc optimization options -function-sections, -fdata-sections turned on. Assembly code is strange, for example:

while(!(I2C0CONSET & BIT(I2CON_SI)));
524: e3a0320e mov r3, #-536870912 ; 0xe0000000
528: e2833907 add r3, r3, #114688 ; 0x1c000
52c: e5d33000 ldrb r3, [r3]
530: e20330ff and r3, r3, #255 ; 0xff
534: e2033008 and r3, r3, #8
538: e3530000 cmp r3, #0
53c: 0afffff8 beq 524

It's compiled correct but STACK_SIZE is a nonsense ! Why compiler operates with it in flash code ??? I guess stack logic of whole program is broken. But(!) local variables are displayed with correct values. Even more, I think even if something was overflowed, this code doesn't use any variables (even global ones) and must work anyway, doesn't it ?
If I turn off these options then some call of function at runtime fails in " 0xfffffff8" and in assembly code IRQ_STACK_SIZE is present inside of STACK_SIZE.
I've tryed different combinations of toolchains, linker scripts and startup codes but I wasn't able to achieve some WORKING (not i2c, simply running at general) and "debugable" program for various reasons (link-stage errors, or compiling but does'n even starts, or working but outputs garbage in uart and not "debuggable", etc... impressive variety of bugs! Am I looser ?). I returned to latest yagarto and openocd.
One more strange thing. At step debugging time I can look register values such as I2C0CONSET by pointing them with mouse and while executing they changes according to operators. But memory monitor shows zeroes in I2C memory region. Other perepherials such as timer are watchable through memory monitor. There are more strange things...

And what's about processor modes? Every startup code switches main program to author's preffered mode: supervisor, system or user mode. Does it matters ?

Here is my linker script:

ENTRY(_boot)
STACK_SIZE = 0x400;

/* Memory Definitions */
MEMORY
{
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 32K
RAM (rw) : ORIGIN = 0x40000200, LENGTH = 7648
}

/* Section Definitions */
SECTIONS
{
/* first section is .text which is used for code */
.text :
{
*crt0.o (.text) /* Startup code */
*(.text) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
*(.glue_7)
*(.glue_7t)
} > ROM

. = ALIGN(4);
_etext = . ;
PROVIDE (etext = .);

/* .data section which is used for initialized data */
.data : AT (_etext)
{
_data = .;
*(.data)
} > RAM

. = ALIGN(4);
_edata = . ;
PROVIDE (edata = .);

/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
__bss_start = . ;
__bss_start__ = . ;
*(.bss)
*(COMMON)
. = ALIGN(4);
} > RAM

. = ALIGN(4);
__bss_end__ = . ;
PROVIDE (__bss_end = .);

.stack ALIGN(256) :
{
. += STACK_SIZE;
PROVIDE (_stack = .);
} > RAM

_end = . ;
PROVIDE (end = .);

/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}

There are thousand of articles and examples over the internet. It's mysterious that I can't get working at least one of them %(

--- In l..., "rtstofer" wrote:
>
> Why not start with Google?
>
> Among other things you will find an App Note from NXP:
> http://www.nxp.com/documents/application_note/AN10369.pdf
>
> You will notice that NXP implements I2C as an interrupt driven state machine.
>
> Then there is the demo code at www.jcwren.com/arm This is specific to the LPC2148 but i2c-polled may be close enough.
>
> There are at least 3 example I2C projects in the Files folder of this group. None are specific to the LPC2103 but the LPC2106 code should be pretty close.
>
> Richard
>

--- In l..., "Artem" wrote:
>
> Everything I'm doing last days is looping in cycle "googling-trying". Of course I already read this appnote and tried a lot of other code examples. I've tried interrupts but as expected they don't trigger too.
Hi

I don't see the error but I suggest you try the uTasker project. It includes support for the LPC2103 which has been fully proven on both I2C interfaces - including interrupt driven driver (see http://www.utasker.com/docs/uTasker/uTaskerIIC.PDF ).

It also allows you to simulate an LPC2103 (or most LPC devices up to the LPC24XX) so helps checking differences between the simulator and HW target.

As well as being well documented it includes targets for Rowley, GCC standalone, Keil and IAR and any problems are supported in detail on the dedicated forum: http://www.utasker.com/forum/index.php?board=6.0

Regards

Mark

http://www.uTasker.com

P.S. Don't be afraid about the com address - all code and support is completely free for non-commercial use ;-)

uTasker is very complex project. I'll spend much more time learning it's i2c code than trying to test communication between two I2Cs on my microcontroller. I've deeped inside in debugging and found some stupid failures in my configurations. Now my code runing ok, interrupts are working too. But I2C doesn't work anyway.
I guess I misunderstand i2c specification trying to achieve results with disconnected slave device, maybe master in such way checking physically presense of any device on bus while sending start condition and it will not change state to 0x8 although slave doesn't need to respond. If so, my slave device is simply dead :(

--- In l..., "mjbcswitzerland" wrote:
> --- In l..., "Artem" wrote:
> >
> > Everything I'm doing last days is looping in cycle "googling-trying". Of course I already read this appnote and tried a lot of other code examples. I've tried interrupts but as expected they don't trigger too.
> Hi
>
> I don't see the error but I suggest you try the uTasker project. It includes support for the LPC2103 which has been fully proven on both I2C interfaces - including interrupt driven driver (see http://www.utasker.com/docs/uTasker/uTaskerIIC.PDF ).
>
> It also allows you to simulate an LPC2103 (or most LPC devices up to the LPC24XX) so helps checking differences between the simulator and HW target.
>
> As well as being well documented it includes targets for Rowley, GCC standalone, Keil and IAR and any problems are supported in detail on the dedicated forum: http://www.utasker.com/forum/index.php?board=6.0
>
> Regards
>
> Mark
>
> http://www.uTasker.com
>
> P.S. Don't be afraid about the com address - all code and support is completely free for non-commercial use ;-)
>

Hi,
I just finished one project which using i2c communication on lpc2134.

After pins selection, speed,
communication starts:
....
I2C0CONCLR=0xff;
I2C0CONSET=I2EN; //FIRST ENABLE
I2C0CONSET=STA; //START
while(I2C0STAT!=0x08); //WAITING 0x08 condition
....

regards,

--- In l..., "Artem" wrote:
>
> Hello.
> I'm trying to get work I2C0 on Olimex LPC-H2103 board.
> I'm using:
> Eclipse
> Zylin Embedded CDT debug plugin 4.10.1 (for gdb debugging)
> YAGARTO GNU ARM toolchain, build 23.12.2009 (Binutils-2.20, Newlib-1.18.0, GCC-4.4.2, GDB-7.0.1)
> OpenOCD 0.4.0
>
> I can't even pass start-byte condition ! I initialize I2C0, send start bit and waiting for state change. Because of my such simple wish I even disconnected slave-device providing i2c bus absolutely free ! I2CSTAT must change to 0x08 but it doesn't ! I've read a lot of similar messages on this group and over the internet and taking into account others' mistakes I've checked absolutelly all. Wires are connected, PCONP register set correctly, PINSEL bits also correspond to selected I2C0, errata sheet is ok.. everything is ok ! After power on I'm checking with multimeter levels on pins, they are in high, after i2c init they are also high and after start-bit they are low that means start-bit successfully send and microcontroller waits for what ???
>
> Linker-script and startup-code from: http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/lpc_uart0_20041214.zip (I've modified it for my project)
> Compiling:
> arm-elf-gcc -I"Z:\Projects\DemoVisionRobot\primary_program\include" -O0 -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -Wall -std=gnu99 -c -fmessage-length=0 -funsigned-char -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mcpu=arm7tdmi-s -g3 -gdwarf-2 -o"$@" "$<"
> Linking:
> arm-elf-g++ -T"Z:\Projects\DemoVisionRobot\primary_program\lpc2103-ROM.ld" -nostartfiles -Wl,-Map,DemoVisionRobot.map -mcpu=arm7tdmi-s -g3 -gdwarf-2 -o"DemoVisionRobot.elf" $(OBJS) $(USER_OBJS) $(LIBS)
>
> Piece of code:
>
> // setup SCL pin P02
> PINSEL0 &= ~(3<<4);
> PINSEL0 |= 1<<4;
> // setup SDA pin P03
> PINSEL0 &= ~(3<<6);
> PINSEL0 |= 1<<6;
> // disable and reset interface
> I2C0CONCLR = 0x6C;
> // I'm not dreaming of high speed
> I2C0SCLL = 1000;
> I2C0SCLH = 1000;
> // enable interface and send start bit
> I2C0CONSET = 0x60;
> //simply waiting for 0x08 state... I'm not ever dreaming of more !
> while(I2C0STAT == 0xF8); // loops infinitely
>
> I've tried also to check SI bit in I2CCONSET, different order of setting up registers, to clear SI bit before and after sending start bit, and many other example codes and things - no matters. Interrupts doesnt triggers too. Generated assembly code seems to be also correct.
>
> I've broken my brain ! What's wrong ??? Please, help.
>

It doesn't works too

--- In l..., "wox" wrote:
>
> Hi,
> I just finished one project which using i2c communication on lpc2134.
>
> After pins selection, speed,
> communication starts:
> ....
> I2C0CONCLR=0xff;
> I2C0CONSET=I2EN; //FIRST ENABLE
> I2C0CONSET=STA; //START
> while(I2C0STAT!=0x08); //WAITING 0x08 condition
> ....
>
> regards,
>

--- In l..., "Artem" wrote:
>
> It doesn't works too
>
> --- In l..., "wox" wrote:
> >
> >
> >
> > Hi,
> > I just finished one project which using i2c communication on lpc2134.
> >
> > After pins selection, speed,
> > communication starts:
> > ....
> > I2C0CONCLR=0xff;
> > I2C0CONSET=I2EN; //FIRST ENABLE
> > I2C0CONSET=STA; //START
> > while(I2C0STAT!=0x08); //WAITING 0x08 condition
> > ....
> >
> > regards,
>
Do you have ANY project that works on the chip? The ubiquitous blinking LED project proves several things: the startup code (usually crt.s) works, the compiler/assembler works, the linker script is essentially correct, the linker works (produces .hex file) and finally that the device programming methodology (ISP or JTAG) works.

What toolchain are you using? I have simple I2C code for the LPC2106 but it will only work with the GNU toolchain. There's nothing unique about my code, I got it from the NXP example code. I did put a semaphore in it because it was possible for the user to make another call while the interrupt driven process was still busy.

It would be pointless to provide I2C code if the blinking LED isn't working.

It is normal to start up in supervisor mode (SVC) and leave it that way. The usual problem with interrupts is that the startup code leaves them disabled by default and enabling them in C code is an advanced topic. Even if the VIC is set up correctly, if the global interrupt bits are set (which disables interrupts), nothing is going to happen.

So, step 2 of the blinking LED project is to use a timer and an interrupt to cause the blinking. Once this works, you have a chance of getting I2C to work.

I posted a file ARM2106BlinkingLED.zip to the Files folder. It includes a .hex file and I suspect it will work on the LPC2103. But I don't know that...

If you look at the startup code just before 'b main' you will see where the interrupts are turned on (or, rather, not turned off) when the mode is changed to SVC. You will also see VIC code, Timer code, Setup code and, finally, an interrupt driven blinking LED.

The LED pin is defined as P0.7 in the file p0.h

To build the code, you will need GNUARM, WinARM or YAGARTO. You need to change the LOCATION macro in the Makefile. You may need to change all of the tool paths.

Richard

Yes, now I know these tricks and understand linker and startup code perfectly :) I fixed some stupid mistakes. My code and example projects such as BlinkingLED working perfectly :) Interrupts also working ok. Now I'm 99,99% sure that there is only i2c problem

--- In l..., "rtstofer" wrote:
>
> --- In l..., "Artem" wrote:
> >
> > It doesn't works too
> >
> > --- In l..., "wox" wrote:
> > >
> > >
> > >
> > > Hi,
> > > I just finished one project which using i2c communication on lpc2134.
> > >
> > > After pins selection, speed,
> > > communication starts:
> > > ....
> > > I2C0CONCLR=0xff;
> > > I2C0CONSET=I2EN; //FIRST ENABLE
> > > I2C0CONSET=STA; //START
> > > while(I2C0STAT!=0x08); //WAITING 0x08 condition
> > > ....
> > >
> > > regards,
> > >
> > Do you have ANY project that works on the chip? The ubiquitous blinking LED project proves several things: the startup code (usually crt.s) works, the compiler/assembler works, the linker script is essentially correct, the linker works (produces .hex file) and finally that the device programming methodology (ISP or JTAG) works.
>
> What toolchain are you using? I have simple I2C code for the LPC2106 but it will only work with the GNU toolchain. There's nothing unique about my code, I got it from the NXP example code. I did put a semaphore in it because it was possible for the user to make another call while the interrupt driven process was still busy.
>
> It would be pointless to provide I2C code if the blinking LED isn't working.
>
> It is normal to start up in supervisor mode (SVC) and leave it that way. The usual problem with interrupts is that the startup code leaves them disabled by default and enabling them in C code is an advanced topic. Even if the VIC is set up correctly, if the global interrupt bits are set (which disables interrupts), nothing is going to happen.
>
> So, step 2 of the blinking LED project is to use a timer and an interrupt to cause the blinking. Once this works, you have a chance of getting I2C to work.
>
> I posted a file ARM2106BlinkingLED.zip to the Files folder. It includes a .hex file and I suspect it will work on the LPC2103. But I don't know that...
>
> If you look at the startup code just before 'b main' you will see where the interrupts are turned on (or, rather, not turned off) when the mode is changed to SVC. You will also see VIC code, Timer code, Setup code and, finally, an interrupt driven blinking LED.
>
> The LED pin is defined as P0.7 in the file p0.h
>
> To build the code, you will need GNUARM, WinARM or YAGARTO. You need to change the LOCATION macro in the Makefile. You may need to change all of the tool paths.
>
> Richard
>

--- In l..., "Artem" wrote:
>
> Yes, now I know these tricks and understand linker and startup code perfectly :) I fixed some stupid mistakes. My code and example projects such as BlinkingLED working perfectly :) Interrupts also working ok. Now I'm 99,99% sure that there is only i2c problem
Who's board are you using? One thing to check is that there are pull-up resistors on SCL and SDA. Some boards have them and others don't. On the Olimex LPC2148 board these resistors are 2k

The I2C gadget won't send a start if it thinks the bus is busy.

You won't get past the 2d step (sending an address) unless you have a device that responds and provides the ACK bit.

Richard