cancel
Showing results for 
Search instead for 
Did you mean: 

I2C BUSY flag not set in I2C0_SR1

jonathan2
Associate II
Posted on February 19, 2009 at 07:00

I2C BUSY flag not set in I2C0_SR1

2 REPLIES 2
jonathan2
Associate II
Posted on May 17, 2011 at 09:56

Hi.

I am trying to write two bytes to a I2C0 peripheral as master at 400kHz using interrupts [haven't tried it with polling]. When I send a start bit I get an interrupt but the I2C0_SR1 register does not have the BUSY flag set, so the state machine goes to pieces.

More detail:

STR911FAW42 (G silicon) on custom board

ST libraries turfed

Non-nested IRQ handling with irq vector set to:

0018: ldr pc, [pc, #-0x0FF0]

[Interrupts working OK for UART0 driver]

I2C device = AD5243 (dual digital potentiometer)

I2C clock = 400kHz

PCLK = 48MHz (cpu running @ 96MHz)

No other I2C devices

Only want to transmit (ie don't need to read)

No other interrupts are occuring when the i2c transfer is started

The I2C initialisation is:

===============================================

SCU_PRR1 &= 0xFFFFFFBF;

SCU_PRR1 |= 0x00000040;

I2C0_CR = 0x00;

I2C0_ECCR = 0x00;

I2C0_CCR = 0xA5;

I2C0_OAR1 = 0x01;

I2C0_OAR2 = 0x80;

I2C0_CR = I2Cbit_PE;

iic_progress = IICstate_BUSY;

I2C0_CR = I2Cbit_PE | I2Cbit_START | I2Cbit_ITE;

===============================================

NOTES:

I2C0 peripheral is reset each time I try to send because of another forum message which mentioned bus bouncing but it has made no difference

I2C0_OAR1 set to the ignored slave address (0x01)

iic_progress is a local variable to indicate whether i2c transaction is complete

If I don't set I2C_CR twice (once without the start bit, then with the start bit) no start bit is sent...

The interrupt service routine is:

===============================================

void iic_isr (void) __attribute__((interrupt));

void iic_isr (void) {

unsigned long state;

static unsigned char iic_iteration;

state = ((I2C0_SR2 << 0x08) | I2C0_SR1) & 0x3FFF;

switch (state) {

case I2Cstate_EVENT5:

/* send slave address */

I2C0_DR = (ADnum_SLAVE_ADDRESS << 0x01) | IICact_WRITE;

break;

case I2Cstate_EVENT6:

/* clear event 6 */

I2C0_CR |= I2Cbit_PE;

/* becomes event 8 - send first data byte */

I2C0_DR = iic_data[0x00];

iic_iteration = 0x00;

break;

case I2Cstate_EVENT8:

/* first time send second byte of data, second time generate

* stop condition

*/

if (iic_iteration == 0x00) {

I2C0_DR = iic_data[0x01];

} else {

I2C0_CR |= I2Cbit_STOP;

iic_progress = IICstate_COMPLETE;

}

iic_iteration++;

break;

default:

/* some error */

iic_progress = IICstate_ERROR;

I2C0_CR = 0x00; /* kill the error */

}

VIC0_VAR = 0x00000000;

VIC1_VAR = 0x00000000;

}

===============================================

NOTES:

This isr does _everything_ (as far as I can tell) that the ST library functions do in the i2c example without the obfusction of a plethora of function calls and worrying about whether we're transmitting or receiving.

VICx_VAR is written because of the non-nested interrupts

No handling of event 7 since we are transmit only

When the isr is called (after sending a start bit) the value of I2C0_SR1 is always 0x83 (EVT, MSL & SB flags set, but BUSY flag is not). This causes the default case to be called and no transfer occurs. On the I2C bus I get a start bit and then nothing else.

If I ignore the fact that the busy flag is not set (and write the slave address to the I2C0_DR register) I get a 3.5us delay followed by a 400kHz clock which never ends with the data line SCL held low [and no more interrupts]

If I ignore the fact that the busy flag is not set (and just exit the isr waiting for busy flag to become set) I get infinite interrupts so the application effectively hangs and the clock line is held low after the start condition.

Does anyone know what I might have done incorrectly, or from where this problem has arisen?

Thanks

Jonathan Pratt

davidfussell9
Associate II
Posted on May 17, 2011 at 09:56

Hi Jonathan,

I guess from the age of your post you've resolved this issue, but since I've been a victim of the same problem I thought I'd post details of what I had to do to get things working (which relates to the GPIO port setup):

I'm using P0.0 and 0.1 as I2C0 SCL/SDA, so my port config is:

Code:

GPIO_StructInit (&vl_GPIOInit);

// Pins 0, 1 as I2C0

vl_GPIOInit.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 ;

vl_GPIOInit.GPIO_Direction = GPIO_PinInput;

vl_GPIOInit.GPIO_Type = GPIO_Type_OpenCollector;

vl_GPIOInit.GPIO_IPInputConnected = GPIO_IPInputConnected_Enable;

vl_GPIOInit.GPIO_Alternate = GPIO_OutputAlt2;

// Write config to port

GPIO_Init(GPIO0, &vl_GPIOInit);

Which is fine, until I configured P2.0 and P2.1 as CTS/DTR for Uart0:

Code:

// Apply defaults to IO structure

GPIO_StructInit (&vl_GPIOInit);

// Pins 0 and 1 as UART0 CTS & DSR (inputs)

vl_GPIOInit.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

vl_GPIOInit.GPIO_Direction = GPIO_PinInput;

vl_GPIOInit.GPIO_Type = GPIO_Type_PushPull;

// vl_GPIOInit.GPIO_IPInputConnected = GPIO_IPInputConnected_Enable; // WRONG!!

vl_GPIOInit.GPIO_IPInputConnected = GPIO_IPInputConnected_Disable; // RIGHT !!

// Write config to port

GPIO_Init(GPIO2, &vl_GPIOInit);

My mistake was to enable the 'alternative' input function of these pins, since that creates a second pair of SCL/SDA lines to the I2C0 device.

Disabling the alternative input (as shown) ensures the busy bit gets set following generation of the start bit.

Hope this helps someone-

Dave