View Full Version : I2C and multiple interrupts
RageKage
01-27-07, 10:06 PM
In my ongoing adventure in programming for the 2138, I've come across a roadblock. I have combined the sample code from the website with the I2C code provided by Philips and have what I believe should be a functional I2C interface with the ability to notify me where it is at in the process. All wrapped up in a program that has 2 interrupts only one of which I believe should be running. Here's my code thus far:
#include "LPC213X.H"
void Initialize(void);
/* I2C ISR */
__attribute__((interrupt)) void I2C_ISR(void);
/* Master Transmitter states */
void ISR_8(void);
void ISR_18(void);
void ISR_28(void);
const int masterbuffer[1] = {0x9};
const int mastercounter = 1;
int main(void)
{
Initialize();
I2C0CONSET = 0x20;
}
/*************** System Initialization ***************/
void Initialize()
{
/* Remap interrupt vectors to SRAM */
MEMMAP=0x2;
/* Initialize GPIO ports to be used as indicators */
IODIR0=0xF0;
IOSET0=0xF0;
/* Initialize Pin Connect Block */
PINSEL0=0x50;
/* Initialize I2C */
I2C0CONCLR=0x6c; /* clearing all flags */
I2C0CONSET=0x40; /* enabling I2C */
I2C0SCLH=0xC8; /* 375 KHz */
I2C0SCLL=0xC8;
/* Initialize VIC for I2C use */
VICIntSelect=0x0; /* selecting IRQ */
VICIntEnable= 0x200; /* enabling I2C */
VICVectCntl0= 0x29; /* highest priority and enabled */
VICVectAddr0=(unsigned long) I2C_ISR;
/* ISR address written to the respective address register*/
}
/********************** I2C ISR **************************/
__attribute__((interrupt)) void I2C_ISR()
{
int temp=0;
temp=I2C0STAT;
switch(temp)
{
case 8:
ISR_8();
break;
case 24:
ISR_18();
break;
case 40:
ISR_28();
break;
default :
break;
}
VICVectAddr=0xFF;
}
/* I2C states*/
/* Start condition transmitted */
void ISR_8()
{
/* Port Indicator */
IOCLR0=0x10;
/* Slave address + write */
I2C0DAT=0xBA;
/* Clear SI and Start flag */
I2C0CONCLR=0x28;
/* Port Indicator */
IOSET0=0x10;
}
/* Acknowledgement received from slave for slave address */
void ISR_18()
{
/* Port Indicator */
IOCLR0=0x20;
/* Data to be transmitted */
I2C0DAT=0x03;
/* clear SI */
I2C0CONCLR=0x8;
/* Port Indicator */
IOSET0=0x20;
}
/* Acknowledgement received from slave for byte transmitted from master. Stop
condition is transmitted in this state signaling the end of transmission */
void ISR_28()
{
static int counter = 0;
/* Port Indicator */
IOCLR0=0x80;
if(counter < mastercounter)
{
I2C0DAT=masterbuffer[counter];
counter++;
}
else
{ /* Transmit stop condition */
I2C0CONSET=0x10;
}
/* clear SI */
I2C0CONCLR=0x8;
/* Port Indicator */
IOSET0=0x80;
}
Those familiar with the original code will know that while running the user should have full control over the leds on the board. This works just fine. However the I2C doesn't seem to do anything at all. Not even the default case which should just output to the screen. As I am programming with Eclipse and need to use ivt startup makefile etc I'm using the one's provided by this Newmicros.
LDR PC, [PC, #-0xFF0] @ load irq vector from vic
that line is found in the ivt.s
I am running out of patience with I2C unfortunately I need to work with it for the project I am working on.
mckenney
01-28-07, 11:18 AM
I'm not familiar with Eclipse, but some things at first glance:
1) You really should have an infinite ("while(1);") loop in main() somewhere, so
it doesn't return. Some compilers will provide this if you return from main(),
but some don't (one I know of restarts your program instead).
2) What board are you using? If I'm reading the Tini2138/Pluga2138 schematics
correctly, the LEDs are connected to P1.21-23, but you seem to be using
P0.4-7.
3) I don't see much in the way of MCU setup code (notably: PLL setup). Does
the Eclipse runtime library do this for you? Asked another way: Are you
certain that your program is running at all?
RageKage
01-29-07, 04:19 PM
It looks like I uploaded the wrong code. Here should be the most up to date code that I have.
[CODE]
/* code originally from phillips appnote 10254 */
/* *********************************************************
Function declarations
********************************************************* */
/* I2C ISR */
void I2C_ISR(void);
/* Master Transmitter states */
void ISR_8(void);
void ISR_18(void);
void ISR_28(void);
/* Timer 1 */
void IRQHandler(void);
void feed(void);
void Initialize(void);
/**********************************************************
Header files
**********************************************************/
#include "LPC213x.h"
#define UART0_LSR U0LSR
#define UART0_THR U0THR
#define UART0_RBR U0RBR
#define IODIR IODIR1
#define IOSET IOSET1
#define IOCLR IOCLR1
#define TIMER1_TCR T1TCR
#define TIMER1_TC T1TC
#define TIMER1_PR T1PR
#define TIMER1_PC T1PC
#define TIMER1_MR0 T1MR0
#define TIMER1_MCR T1MCR
#define UART0_FCR U0FCR
#define UART0_LCR U0LCR
#define UART0_DLL U0DLL
#define UART0_DLM U0DLM
#define UART0_LCR U0LCR
#define TIMER1_IR T1IR
#include <string.h>
// serial port
#define RDR 0x01
#define THRE 0x20
const int masterbuffer[1] = {0x9};
const int mastercounter = 1;
char rx_query(void)
{
return UART0_LSR & RDR;
}
char tx_query(void)
{
return UART0_LSR & THRE;
}
void tx(char c)
{
UART0_THR = c;
switch (c) {
case '1':
IOSET = 0x00800000; // green led on
break;
case '2':
IOCLR = 0x00800000; // green led off
break;
case '3':
IOSET = 0x00400000; // yellow led on
break;
case '4':
IOCLR = 0x00400000; // yellow led off
break;
case '5':
IOSET = 0x00200000; // red led on
break;
case '6':
IOCLR = 0x00200000; // red led off
break;
}
}
char rx(void)
{
return UART0_RBR;
}
void tx_str(char *s) // send a string
{
while(*s)
if (tx_query())
tx(*s++);
}
/**********************************************************
MAIN
**********************************************************/
void __main (void)
{
char *x = (char *)0, *y = (char *)0x1000;
/* Initialize the system */
Initialize();
/* Start timer */
// Interrupts not working yet so this code is commented out for now
// TIMER1_TCR=0x1;
// For testing library inclusion
// memcpy(x,y,100);
// test banner
tx_str("\n\rNow Running\n\r");
I20CONSET = 0x20; //Send Start Condition
// echo for main loop
while(1)
if (rx_query() && tx_query()) // received and ready to send
tx(rx()); // get and send
}
/**********************************************************
Initialize
**********************************************************/
extern const char _text_start, _text_end;
extern char _data_start, _data_end;
#define PLOCK 0x400
void Initialize(void)
{
// memcpy(&_data_start, &_text_end, &_data_end - &_data_start);
// set io pins for leds red off, yellow off, green on
IODIR |= 0x00E00000; // 21-23 are outputs
IOSET = 0x00800000; // green led on
IOCLR = 0x00600000; // red and yellow off
/*
* Initialize PLL (Configured for a 10MHz crystal) to
* boost processor clock to 60MHz
*/
/* Setting Multiplier and divider values */
PLLCFG=0x25;
feed();
/* Enabling the PLL */
PLLCON=0x1;
feed();
/* Wait for the PLL to lock to set frequency */
while(!(PLLSTAT & PLOCK)){}
/* Connect the PLL as the clock source */
PLLCON=0x3;
feed();
/*
* Enabling MAM and setting number of clocks used for
* Flash memory fetch
*/
MAMCR=0x2;
MAMTIM=0x4;
/*
* Setting peripheral Clock (pclk) to System
* Clock (cclk)
*/
VPBDIV=0x1;
/* Initialize GPIO */
// IODIR=0xFFFF;
// IOSET=0xFFFF;
/* Remap interrupt vectors to SRAM */
MEMMAP=0x2;
/* Initialize GPIO ports to be used as indicators */
IODIR0=0xF0;
IOSET0=0xF0;
/* Initialize Pin Connect Block */
PINSEL0=0x50;
/* Initialize I2C */
I20CONCLR=0x6c; /* clearing all flags */
I20CONSET=0x40; /* enabling I2C */
I20SCLH=0x50; /* 375 KHz */
I20SCLL=0x50;
/* Initialize Timer 1 */
TIMER1_TCR=0x0;
TIMER1_TC=0x0;
TIMER1_PR=0x0;
TIMER1_PC=0x0;
/* End user has to fill in the match value */
TIMER1_MR0=0x123456;
/* Reset and interrupt on match */
TIMER1_MCR=0x3;
/* Initialize VIC */
VICIntSelect = 0x0; /* Timer 1 selected as IRQ */
VICIntEnable |= 0x220; /* Timer 1 and I2C interrupt enabled */
VICVectCntl0 = 0x29;
VICVectCntl1 = 0x25;
/* Address of the ISR */
VICVectAddr0 = (unsigned long)I2C_ISR; //highest priority
VICVectAddr1 = (unsigned long)IRQHandler;
/* initialize serial port */
// initialize UART
PINSEL0 = 5; // enable UART0 in/out
UART0_FCR = 0x7; // enable and reset fifos
UART0_LCR = 0x83; // 8 bits; enable divisor latches
UART0_DLL = 0x87; // LSB divider for 60mhz to be 9600x16
UART0_DLM = 0x01; // MSB
UART0_LCR = 0x3; // disable divisor latches
}
/**********************************************************
Timer 1 ISR
**********************************************************/
void __attribute__((interrupt)) IRQHandler(void)
{
/*
* The Interrupt Service Routine code will come here. The
* interrupt needs to be cleared in Timer1 and a write must
* be performed on the VIC Vector Address Register to
* update the VIC priority hardware. Here the user could
* blink a few LEDÕs or toggle some port pins as an
* indication of being in the ISR
*/
IOSET = 0x04000000; // yellow led on
TIMER1_IR=0x1;
VICVectAddr=0xff;
}
void feed(void)
{
PLLFEED=0xAA;
PLLFEED=0x55;
}
/********************** I2C ISR **************************/
void __attribute__((interrupt)) I2C_ISR(void)
{
int temp=0;
temp=I20STAT;
switch(temp)
{
case 0x08:
ISR_8();
break;
case 0x18:
ISR_18();
break;
case 0x28:
ISR_28();
break;
default :
tx_str("\n\rWhere Am I\n\r");
break;
}
VICVectAddr=0xFF;
}
/* I2C states*/
/* Start condition transmitted */
void ISR_8()
{
tx_str("\n\rStart Condition Transmitted\n\r");
/* Slave address + write */
I20DAT=0xBA;
/* Clear SI and Start flag */
I20CONCLR=0x28;
}
/* Acknowledgement received from slave for slave address */
void ISR_18()
{
tx_str("\n\rAcknoledgement received from slave for slave address\n\r");
/* Data to be transmitted */
I20DAT=0x03;
/* clear SI */
I20CONCLR=0x8;
}
/* Acknowledgement received from slave for byte transmitted from master. Stop
condition is transmitted in this state signaling the end of transmission */
void ISR_28()
{
static int counter = 0;
tx_str("\n\rAcknoledge Received sending Stop Bit in 2\n\r");
if(counter < mastercounter)
{
I20DAT=masterbuffer[counter];
counter++;
}
else
{ /* Transmit stop condition */
I20CONSET=0x10;
}
/* clear SI */
I20CONCLR=0x8;
}
[\CODE
Just so you know this is an extension of my previous thread. Only I made what I think to be progress only the other thread wasn't posted at the time.
mckenney
01-29-07, 10:18 PM
Is the LED from the timer interrupt switching on? I'm just wondering if you're
getting any interrupts at all.
RageKage
01-30-07, 04:47 PM
currently the timer code isn't enabled, simply because it does nothing. I did enable it to test and the light comes on.
I also noticed that I set the value of PINSEL0 twice. ON the second time wiping out the value I set it to in the first place so I changed that bit of code to PINSEL0=0x55 so both the uarts and i2c pins know what they are doing. When I do this however the code freezes up the moment i2c is started, meaning after "Now Running" is displayed and I20CONSET = 0x20 gets set.
mckenney
01-30-07, 07:46 PM
PINSEL0=0x50;
...
PINSEL0 = 5; // enable UART0 in/out
The second assignment is overriding the first, so SDA0/SCL0 aren't assigned to
the pins. This is presumably why your I2C isn't working. The second assignment --
both of them, really -- should be done with "|=".
IOSET = 0x04000000; // yellow led on
By my count this is setting P1.26, not P1.22 (where the yellow LED is). Try:
IOSET = 0x00400000; // yellow led on
At one time there were defines of the form LED_{Y,G,R} in the code on the
Web site, which can help avoid this kind of thing.
Also, you don't seem to be setting the low (Enable) bit of TIMER1_TCR, so the
timer presumably isn't running (so you won't be getting a timer interrupt
anyway).
mckenney
01-31-07, 08:00 PM
First thought is that there's something wrong with your stack. Maybe it's
large enough for the (fairly simple) timer ISR but not the (larger) I2C ISR.
What does your start.s look like?
RageKage
02-11-07, 03:40 PM
I have changed the 2 PINSEL0 lines to:
PINSEL0 |= 0x5;
PINSEL0 |= 0x50;
Still nothing. The Program is freezing up as soon as the I2C start condition is sent. My start.s file is as follows.
@// code originally from phillips appnote 10254
@ ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ
@ Assembler Directives
@ ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ
.section asm_code,"ax" @ New Code section
@ CODE32 @ ARM code
.extern __main @ main not defined
@ in this section
.global _start @ global symbol
@ referenced in
@ ivt.s
@ ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ
_start:
@ Set SP for Supervisor mode. Depending upon
@ the stack the application needs this value
@ needs to be set.
@ stack is already set by bootloader
@ but if this point is entered by any
@ other means than reset, the stack pointer
@ needs to be set explicity
@ LDR SP,=0x40001000
@ Setting up SP for IRQ and FIQ mode.
@ Change mode before setting each one
@ move back again to Supervisor mode
@ Each interrupt has its own link
@ register, stack pointer and program
@ counter The stack pointers must be
@ initialized for interrupts to be
@ used later.
@ setup for fiq and irq interrupt stacks to run
@ below current stack by 1000.
mov r0, sp @ copy current stack pointer
sub r0, r0, #1000 @ make irq stack pointer
sub r1, r0, #1000 @ make fiq stack pointer
msr cpsr_c, #0x12 @ switch to irq mode
mov sp, r0 @ set irq stack pointer
msr cpsr_c, #0x11 @ fiq mode
mov sp, r1 @ set fiq stack pointer
msr cpsr_c, #0x13 @ supervisor mode F,I enabled
@ Jump to C code
LDR lr, =__main
MOV pc, lr
Is there anyway to change the stack size in the start.s file?
mckenney
02-11-07, 08:29 PM
@ LDR SP,=0x40001000
On the umpteenth reading I realized that this is a comment. The assumption
seems to be that the Flash Loader's stack is at least 2000 bytes, but it
might not be.
Try un-commenting this line (remove the '@') and see what it does. It isn't
a long-term solution since eventually your .data/.bss will grow into the stack,
but that won't happen soon. Long term, see if your C compiler has a "tuned"
startup module (in WinARM, e.g., look for a file named "crt0.S").
vBulletin v3.0.7, Copyright ©2000-2012, Jelsoft Enterprises Ltd.