AnsweredAssumed Answered

STM32L i2c bus frozen on occasion

Question asked by PaulLeicester on Dec 9, 2012
Hey again all,

I have a multi master i2c setup, each and every device is also an STM32L.
Each device is configured as below

I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef   GPIO_InitStructure;
NVIC_InitTypeDef   NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOB, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
//RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
//RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = ownid;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
I2C_ITConfig(I2C1, (I2C_IT_ERR), ENABLE);
I2C_ITConfig(I2C1, (I2C_IT_EVT | I2C_IT_BUF), ENABLE);

This is the same across all devices on the bus, the only difference is the address.

1 of the masters can choose which address to send to, all other masters send data back to that master. Forgive me if my understanding of i2c is a little bit vague, how ever I would rather have each device be able to send data immediately back to the main address rather than being polled every few ms as a slave.

The issue I am having how ever is that on a very (annoyingly) rare occasion multiple devices apear to try to grab the bus at the exact same time, they both will not see the bus is busy and generate START at the same time which then freezes the i2c bus as each then thinks that there is another start condition, often with both SCL and SDA low so I cant even clock out the states. What causes the i2c devices to try to work the bus at the same time is out of my control and is a particular part of the application.

I am already trying to resolve the error like so...
NumberOfByteToTransmit = TXBUFFERSIZE;
Tx_Idx = 0x00;
while ((I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))&&(TimeOut != 0x00));
if (!I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
    TimeOut = USER_TIMEOUT;
    I2C_GenerateSTART(I2C1, ENABLE);
    while ((Tx_Idx < TXBUFFERSIZE)&&(TimeOut != 0x00));
    if (TimeOut == 0)
        I2C_GenerateSTOP(I2C1, ENABLE);
    TimeOut = USER_TIMEOUT;
    while ((I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))&&(TimeOut != 0x00));
    Tx_Idx = 0x01;
    I2C_ITConfig(I2C1, (I2C_IT_EVT | I2C_IT_BUF), ENABLE);

But I feel that both devices would then be trying to create the stop condition at the same time also.

Personally I feel that I am not handling multi-master correctly at all or at least the situation I describe. How do other people normaly handle this? There is nothing in the standard libs that I can find that relates to multi master.

Do you think it would be better to just go with a Master > Slave setup and poll each slave (there will be about 6 in the bus) I would be looking at reading each device on the bus 10 times a second minimum to get the type of response I need from this bus.

Can a slave notify the master that it has data to transfer and then the master can make the decision as to which it wants to talk to first?

Many thanks, if there is any more info I can provide, Please let me know.