Help w/ Interrupts
2004-10-19 by peterburdine
I seem to be having this continuous problem with interrupts. I can
seem to get time interrupts to work just fine, but I'm trying to get
the UART Tx interrupt and the I2C interrupt to work. All it seems
that I ever get it to do is reset itself (as seen by the something
that is sent out repeated over and over again). The strange thing is
that if I try and debug it with a JTAG interface, it does not reboot.
In this code, the uart0 does not use the tx interrupt to send, it
just waits untill all data has been put in U0THR.
The reset appears to occur as soon as I enable the start bit in
I2CONSET [in i2c_txData()]. Code is written and compiled using Keil's
tools v3.05.
Here is my I2C code, is there something obvious? I'd appreciate any
help on this.
Assembly for enabling/disabling ARM IRQs
IRQ_MASK EQU 0x80
FIQ_MASK EQU 0x40
AREA ArmIRQs, CODE, READONLY
PUBLIC disableArmIRQ?A
disableArmIRQ?A PROC CODE32
MRS R0, CPSR
ORR R0, R0, #IRQ_MASK
MSR CPSR_cxfs, R0
MOV PC, LR
ENDP
PUBLIC enableArmIRQ?A
enableArmIRQ?A PROC CODE32
MRS R0, CPSR
BIC R0, R0, #IRQ_MASK
MSR CPSR_cxfs, R0
MOV PC, LR
ENDP
i2c.h
#ifndef _I2C_H
#define _I2C_H
/***** INCLUDES
**************************************************************/
#include "LPC2294.h"
#include "chipParams.h"
#include "types.h"
#ifdef ENABLE_I2C
/***** DEFINES
**************************************************************/
/* I2C Interface */
#define I2CONSET (*((volatile unsigned char *) 0xE001C000))
#define I2STAT (*((volatile unsigned char *) 0xE001C004))
#define I2DAT (*((volatile unsigned char *) 0xE001C008))
#define I2ADR (*((volatile unsigned char *) 0xE001C00C))
#define I2SCLH (*((volatile unsigned short*) 0xE001C010))
#define I2SCLL (*((volatile unsigned short*) 0xE001C014))
#define I2CONCLR (*((volatile unsigned char *) 0xE001C018))
#define ENABLE_I2C_PINS ( PINSEL0 = ((PINSEL0&0xFFFFFF0F) |
PINSEL0_02_SCL | PINSEL0_03_SDA ) )
#define ENABLE_I2C_IRQ ( VICIntEnable = (0x1 << I2C_IRQ) )
#define DISABLE_I2C_IRQ ( VICIntEnClr = (0x1 << I2C_IRQ) )
#define ENABLE_I2C_AA ( I2CONSET |= (0x1 << 2))
#define DISABLE_I2C_AA ( I2CONCLR = (0x1 << 2))
#define I2C_BIT_RATE(rate) (I2SCLH = I2SCLL =
((Uint16)(PERIPH_FREQ/2/rate)+10))
#define I2C_SEND_START (I2CONSET |= (0x1 << 5))
#define I2C_SEND_STOP (I2CONCLR = (0x1 << 4))
#define I2C_BUFFER_LENGTH 32
#define I2C_RX_BUFFER_LENGTH 32
enum I2C_MODE { MASTER_TX,
MASTER_RX,
SLAVE_TX,
SLAVE_RX };
extern enum I2C_MODE i2cMode;
extern Uint16 i2c_bytesRemaining;
extern Uint8 i2c_address;
extern Uint8 i2c_RdnWr;
extern Uint8 i2c_buffer[];
extern Uint8 i2c_sendStop;
extern Uint16 i2c_pos;
extern Uint8 i2c_rxComplete;
extern Uint16 i2c_rxWrPos;
extern Uint8 i2c_rxBuffer[];
extern Uint8 i2c_rxBytesRemaining;
/***** FUNCTION PROTOTYPES
****************************************************/
void i2c_config(Uint32 bitRate);
void i2c_isr (void);
void i2c_txData(Uint8 address, Uint8 * buffer, Uint16 length, Uint8
sendStop);
void i2c_rxData(Uint8 * buffer, Uint16 length);
#endif // ENABLE_I2C
#endif // _I2C_H
i2c.c
#include "i2c.h"
#include "uart.h"
extern disableArmIRQ(void);
extern enableArmIRQ(void);
enum I2C_MODE i2cMode;
Uint16 i2c_bytesRemaining = 0;
Uint8 i2c_address;
Uint8 i2c_RdnWr;
Uint8 i2c_buffer[I2C_BUFFER_LENGTH];
Uint8 i2c_sendStop;
Uint16 i2c_pos;
Uint8 i2c_rxComplete;
Uint16 i2c_rxWrPos;
Uint8 i2c_rxBuffer[I2C_RX_BUFFER_LENGTH];
Uint8 i2c_rxBytesRemaining;
void i2c_config(Uint32 bitRate) {
ENABLE_I2C_PINS;
//I2C_BIT_RATE(bitRate);
I2SCLH = I2SCLL = 160;
// Reset Everything
I2CONCLR = 0x6C;
disableArmIRQ();
VICIntSelect &= ~(0x1 << 9); // Select as IRQ
VICVectAddr9 = (unsigned long) i2c_isr;
VICVectCntl9 = 0x20 | 9;
VICIntEnable |= (0x1 << 9);
enableArmIRQ();
i2cMode = SLAVE_RX;
I2CONSET |= (0x1 << 6); // Enable I2C
}
void i2c_txData(Uint8 address, Uint8 * buffer, Uint16 length, Uint8
sendStop) {
Uint16 i;
i2c_bytesRemaining = length;
DISABLE_I2C_AA;
for(i = 0; i < length; i++)
i2c_buffer[i] = *(buffer++);
i2c_sendStop = sendStop;
i2c_RdnWr = 0;
i2c_address = address;
i2c_rxBytesRemaining = I2C_RX_BUFFER_LENGTH;
i2c_rxWrPos = 0;
i2c_rxComplete = 0;
i2cMode = MASTER_TX;
uart0_sendString("i2c about to send\n\r");
I2C_SEND_START; /******* RESET OCCURS HERE ***********/
uart0_sendString("i2c send done\n\r");
}
void i2c_rxData(Uint8 * buffer, Uint16 length) {
Uint16 i;
i2c_rxBytesRemaining = length;
while(!i2c_rxComplete);
for(i = 0; i < length; i++)
i2c_buffer[i] = *(buffer++);
}
i2c_isr.c
#include "i2c.h"
#include "uart.h"
void i2c_isr (void) __irq {
Uint8 code;
uart0_sendString("i2c_isr");
code = I2STAT;
switch(i2cMode) {
case MASTER_TX:
switch(code) {
case 0x08: // First Start Transmitted
case 0x10: // Repeated Start
// Write address and tell if it is read or write
I2DAT = (i2c_address << 1) | i2c_RdnWr;
I2CONCLR = (0x1 << 3); // Clear SI
break;
case 0x18: // Start + Wr sent, ACK received
case 0x20: // Start + Wr sent, Not ACK received
case 0x28: // Data byte sent, ACK recieved
case 0x30: // Data byte sent, Not Ack received
if(i2c_bytesRemaining > 0) {
I2DAT = i2c_buffer[i2c_pos++];
i2c_bytesRemaining--;
}
else if(i2c_sendStop) {
I2C_SEND_STOP; // Send Stop
}
else { // Change from master_tx to master_rx
i2cMode = MASTER_RX;
i2c_RdnWr = (~i2c_RdnWr)&0x1;
i2c_sendStop = 1;
i2c_pos = 0;
i2c_rxComplete = 0;
I2C_SEND_START;
}
I2CONCLR = (0x1 << 3); // Clear SI
break;
}
break;
case MASTER_RX:
switch(code) {
case 0x08: // Start Has been sent
case 0x10: // RStart has been sent
I2DAT = (i2c_address << 1) | i2c_RdnWr;
I2CONCLR = (0x1 << 3); // Clear SI
break;
case 0x40: // Waiting for data byte
if(i2c_rxBytesRemaining > 1)
ENABLE_I2C_AA; // Ack data when it comes in
else
DISABLE_I2C_AA; // Don't Ack data
I2CONCLR = (0x1 << 3); // Clear SI
break;
case 0x50: // Data received, Ack sent
i2c_rxBuffer[i2c_rxWrPos] = I2DAT;
i2c_rxWrPos++;
i2c_rxBytesRemaining--;
if(i2c_rxBytesRemaining > 1)
ENABLE_I2C_AA;
else
DISABLE_I2C_AA;
I2CONCLR = (0x1 << 3); // Clear SI
break;
case 0x58: // Data received, NOT Ack sent
i2c_rxComplete = 1; // Done receiving all requested data
I2C_SEND_STOP;
I2CONCLR = (0x1 << 3); // Clear SI
break;
}
break;
case SLAVE_TX:
switch(code) {
}
break;
case SLAVE_RX:
switch(code) {
}
break;
}
VICVectAddr = 0x00000000;
}