Skip to main content
Visitor II
February 19, 2009
Question

I2C BUSY flag not set in I2C0_SR1

  • February 19, 2009
  • 2 replies
  • 851 views
Posted on February 19, 2009 at 07:00

I2C BUSY flag not set in I2C0_SR1

    This topic has been closed for replies.

    2 replies

    jonathan2Author
    Visitor II
    May 17, 2011
    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

    Visitor II
    May 17, 2011
    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