EmbeddedRelated.com
Forums

I2C Master on LPC2129 (also slave)

Started by troqualy February 16, 2007
Hello and thank you in advance for your help.

I have been researching and trying to understand the I2C protocal
for some time now but haven't been able to create a working
program. I have been able to create a start signal (the SDA goes
low, then the SCL goes low), however the clock never creates a
signal and thus my transmition ends.

Ex1: Ex2:
____ _ ____
SDA |____| SDA |____
______ _________
SCL |____ SCL

or sometimes the clock line just seems to stay high (Ex2).

I think that I'm initializing most of the registers, but if someone
could take a look at the code I have below, I would be very thankful.

/*----------------------*/
MAIN.C
/*----------------------*/
#include
#include "hardware.h"

int main(void)
{
CPUinit();
I2Cinit();
__disable_interrupt();
INTERRUPTSinit();
__enable_interrupt();

U8 I2CAddr = 0x20; // These are just random values
int count = 1;
U8 send = 0x99;
U8 *message = &send;

I2CMasterSend(I2CAddr, count, message);

return 0;
}
/*----------------------*/
HARDWARE.H
/*----------------------*/
#include
#include

//Type Definitions -these are tailored to fit given bit sizes
storage requests
// to the actual bit size preference of the target
typedef unsigned int U8; /* 8 bit unsigned
UPGRADE*/
typedef signed int S8; /* 8 bit signed
UPGRADE*/
typedef unsigned int U16; /* 16 bit unsigned */
typedef signed int S16; /* 16 bit signed */
typedef unsigned long int U32; /* 32 bit unsigned */
typedef signed long int S32; /* 32 bit signed */

/*----------------------*/
//Declarations of functions coded in hardware.c
void CPUinit(void);
void I2Cinit(void);
void INTERRUPTSinit(void);
__irq __arm void irq_handler(void);
static void DefDummyInterrupt();

static void I2CISR();
//
void Delay(U32 del);
//
void I2CMasterSend(U8, int, U8*);
void I2CMasterReceive(U8, U8, int, volatile U8*);

/*----------------------*/
//Generic Constants
#define FALSE 0
#define FAIL 0
#define OFF 0
#define DOWN 0
#define LOW 0

#define TRUE 1
#define SUCCESS 1
#define ON 1
#define UP 1
#define HIGH 1

/*----------------------*/
//Generic Macros -BUT IO0CLR_bit.P0_12=1 type bit setting is
preffered
#define BIT_SET(data,bit) (data |= 2^bit)
#define BIT_CLEAR(data,bit) (data &= ~2^bit)
#define BIT_TEST(data,bit) (data & 2^bit)

#define MSB(word) ((U8)((word)>>8)) /* used to
strip MSB and LSB bytes from 16-bit Words */
#define LSB(word) ((U8)(word))

/*----------------------*/
//Hardware Specific Macros -Note the use of structures from IAR
Header files
//Actions (Prefix A_)
#define A_PULL_DOWN IO0CLR_bit.P0_2=1
#define A_PULL_UP IO0SET_bit.P0_2=1
#define A_LED1_ON IO0CLR_bit.P0_12=1
#define A_LED1_OFF IO0SET_bit.P0_12=1
#define A_LED2_ON IO0CLR_bit.P0_13=1
#define A_LED2_OFF IO0SET_bit.P0_13=1
#define A_TD2_LOW IO0CLR_bit.P0_24=1
#define A_TD2_HIGH IO0SET_bit.P0_24=1
//States (Prefix S_)
#define S_DALLAS IO0PIN_bit.P0_17
#define S_FREQ IO0PIN_bit.P0_22
#define S_RD2 IO0PIN_bit.P0_23
#define S_RD1 IO0PIN_bit.P0_25
#define S_ADC IO0PIN_bit.P0_27

#define S_SCL IO0PIN_bit.P0_2
#define S_SDA IO0PIN_bit.P0_3

#define OSCILLATOR_CLOCK_FREQUENCY 14745600 //in MHz
#define PLOCK 0x0400
#define DLS_FREQ_TIME 1000000
#define SET_TIME 100
#define LED_TIME 500000
#define TD2_TIME 1250
/*----------------------*/
HARDWARE.C
/*----------------------*/
#include "hardware.h"

#define FOSC 14745600
#define VALUEOFM 4 //implies PLLCFG_bit.MSEL=3
#define CCLK (FOSC*VALUEOFM) //58.9824 MKz
#define PCLK (CCLK/4) //implies VPBDIV_bit.VPBDIV=0;

//FCCO = 2 * VALUEOFP = 156-302 MHz, so VALUEOFP=2 implies
PLLCFG_bit.PSEL=1;

#define BAUDRATE 9600
#define BAUDRATEDIVISOR (PCLKFREQ/(BAUDRATE*16))
#define VIC_I2C_bit (1 << VIC_I2C)
/*----------------------*/
// GLOBAL Variables
/*----------------------*/
//U8 NoI2CDevice = 1;
volatile U8 lock = 0;
volatile U8 I2CAddress;
volatile U8 I2CCounter;
volatile U8 *I2CData;

/*----------------------*/
// HARDWARE Initializations
/*----------------------*/
void CPUinit(void)
{
PLLCFG_bit.MSEL=3; //See PLL calculations in #define section at
// top of this file
PLLCFG_bit.PSEL=1; //See PLL calculations in #define section at
// top of this file
PLLFEED=0xAA;
PLLFEED=0x55;
PLLCON_bit.PLLE=1; // Enable the PLL
PLLFEED=0xAA;
PLLFEED=0x55;
while(!(PLLSTAT & PLOCK)); // Wait for PLL to lock

//Init MAM & Flash memory fetch
MAMCR_bit.MODECTRL=2;
MAMTIM_bit.CYCLES=4;
VPBDIV_bit.VPBDIV=0; // See PLL calculations in #define section
// at top of this file

//GPIO init
//A_LED1_OFF;
//A_LED2_OFF;
//PINSEL0=0; //P0 lower 16 bits all GPIO
//PINSEL1=0; //P0 upper 16 bits all GPIO

// IODIR in binary 0000 0000 0000 0000 0000 0000 0000 0000
// ...SCL(P0.2), SDA(P0.3)
//IO0DIR=0x00000000;
}

void I2Cinit(void)
{
//if ((IO0PIN & 0x0C) == 0x0C) // SCL & SDA should be high, they
// will be pulled
//{ // down with jumpers when there is no I2C device
//NoI2CDevice = FALSE;
PINSEL0 |= 0x50; // switch GPIO to I2C pins
I2CONCLR = 0x6C; // clear all I2C settings
I2CONSET = 0x40; // enable I2C interface
I2SCLH = 300; // set bit rate to 58.9824 MHz / 100000
I2SCLL = 300; // or about 600 -- 300 counts high, 300 low
//}
//else
//NoI2CDevice = TRUE;
}

/*----------------------*/
//INTERRUPT initialisation and handling functions
/*----------------------*/
void INTERRUPTSinit(void)
{
#ifdef SRAM_VIA_JLINK
MEMMAP = 2;
#endif
// Setup interrupt controller.
VICProtection = 0;

// Disable ALL interrupts
VICIntEnClear = 0xffffffff;
VICDefVectAddr = (U32)&DefDummyInterrupt;
VICDefVectAddr = (U32)&I2CISR;
VICIntSelect &= ~VIC_I2C_bit;
VICVectAddr1 = (U32)&I2CISR; // pass the address of the ISR
VICVectCntl1 = 0x20 | VIC_I2C; // select a priority spot for a
// given interrupt
VICIntEnable = VIC_I2C_bit; // enable interrupt
}

/*----------------------*/
#pragma vector=0x18
__irq __arm void irq_handler(void)
{
void (*interrupt_function)();
U16 vector;

vector = VICVectAddr; // GET VECTOR ADDRESS
// FROM VIC CONTROLLER
interrupt_function = (void(*)())vector;

(*interrupt_function)(); // Call vectored
// interrupt function.

VICVectAddr = 0;
//A_LED1_OFF; // Clear interrupt in VIC.
}

/*----------------------*/
static void DefDummyInterrupt()
{
}

//Default interrupt handler, called as default in irqHandler()
/*----------------------*/
void I2CISR (void)
{
switch (I2STAT)
{
case (0x00): // bus error
I2CONSET = 0x14;
lock = 0;
break;
case (0x08): // start bit sent
case (0x10): // repeated start sent
I2CONCLR = 0x20; // clear start bit
I2DAT = I2CAddress; // send address and W
break;
case (0x18): // slave addr+W, ACK
case (0x28): // data transmitted ACK
if (I2CCounter > 0) // any data left?
{
I2DAT = *I2CData; // send data
I2CData++;
I2CCounter--;
}
else
{
I2CONSET = 0x10; // send stop bit
lock = 0;
}
break;
case (0x20): // slave addr NOT ACK
case (0x30): // data sent NOT ACK
I2CONSET = 0x14; // send stop bit
lock = 0;
break;
case (0x38): // arbitration lost,restart
I2CONSET = 0x24; // set STA and AA bits
break;
case (0x40): // slave addr + R, ACK
I2CONSET = 0x04; // enable ACK for byte
break;
case (0x48): // slave addr + R, NOT ACK
I2CONSET = 0x14; // set STO and AA bits
lock = 0;
break;
case (0x50): // data received ACK
*I2CData = I2DAT;
I2CData++;
if (--I2CCounter > 1)
{
I2CONSET = 0x04;
}
else // next byte is last byte
{
I2CONCLR = 0x04; // set AA condition
}
break;
case (0x58): // data received NOT ACK
*I2CData = I2DAT; // last byte
I2CONSET = 0x14; // set STO and AA bits
lock = 0;
break;
default:
break;
}
I2CONCLR = 0x08; // clear I2C int flag
VICVectAddr = 0xFF; // clear interrupt in VIC
}

/*----------------------*/
void I2CMasterSend(U8 I2CAddr, int count, U8 *message)
{
//if (NoI2CDevice)
//return;

while (lock == 1); // wait for interrupt to signal end of I2C
// activity
lock = 1; // set I2C bus as active
I2CAddress = I2CAddr;
if (count > 0)
{
I2CData = message; // NOT SURE ABOUT * IN *message
}
I2CCounter = count;
I2CONSET = 0x60; // send start condition;

while (lock == 1);
}

void I2CMasterReceive(U8 I2CAddr, U8 Address, int count, volatile U8
*message)
{
// U8 packet[1];

//if (NoI2CDevice)
//return;

while (lock == 1); // wait for interrupt to signal end of I2C
// activity
// from any previous operation
lock = 1;
I2CAddress = I2CAddr | 0x01; // set read bit
I2CCounter = count;
I2CData = message;
I2CONSET = 0x20; // set start condition

while (lock == 1); // wait for interrupt to signal end of I2C
// activity
// before returning to caller
}
/*----------------------*/
These are the three main files that I have been using and
modifying. A lot of the code I have taken off this site (from
rtstofer, thank you) and tried to modify to meet my needs.

Again thank you for any help that you can provide and have a good
day.

Matt
m...@gonzaga.edu

An Engineer's Guide to the LPC2100 Series