2009-02-18 10:00 PM
I2C BUSY flag not set in I2C0_SR1
2011-05-17 12:56 AM
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 Pratt2011-05-17 12:56 AM
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