cancel
Showing results for 
Search instead for 
Did you mean: 

After the I2C start, the interrupt handler is called in a loop with I2C_EVENT_MASTER_MODE_SELECT event

benoit2
Associate II
Posted on July 17, 2015 at 15:44

Hello everybody,

First I have to say that I never implemented I2C with interruptions. I searched on this forum and on the ST libraries a functional and simple send/receive I2C code working with interruptions and I don't find something interesting, maybe I'm wrong. If you have a good example, do not hesitate 🙂

I have already a working code for I2C communications (including

I2C1_Start,I2C1_Repeated_Start,I2C1_Stop,I2C1_Wr,I2C1_Read_Ack,I2C1_Read) but without interruptions: my code is not real-time. For the moment I just coded an interruption handler to check if thisIRQHandleris called each time an I2C message is received by the STM32:

void

I2C_Config(

void

)

{

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

///////////////////////

/// INIT GPIO I2C ///

///////////////////////

// SDA and SCL Pins declaration

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_6;

// SDA, SCL

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

GPIO_Init(GPIOB, &GPIO_InitStructure);

// READY pin

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

// INT

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(GPIOB, &GPIO_InitStructure);

// Connect I2C1 pins to AF

GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);

// SCL

GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);

// SDA

I2C_DeInit(I2C1);

I2C_InitTypeDef I2C_InitStruct;

I2C_InitStruct.I2C_ClockSpeed = 400000;

// 400kHz

I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;

// I2C mode

I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;

// 50% duty cycle --> standard

I2C_InitStruct.I2C_OwnAddress1 = 0x00;

// own address, not relevant in master mode

I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;

// enable acknowledge when reading (can be changed later on)

I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

// set address length to 7 bit addresses

I2C_Init(I2C1, &I2C_InitStruct);

// init I2C1

I2C_Cmd(I2C1, ENABLE);

// I2C NVIC

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PREAMPTION_PRIORITY_LOW;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;

NVIC_Init(&NVIC_InitStructure);

I2C_ITConfig(I2C1,I2C_IT_EVT,ENABLE);

// enable event IRQ

}

void

I2C1_EV_IRQHandler(

void

)

{

uint32_t LastI2Cevent = I2C_GetLastEvent(I2C1);

switch

(LastI2Cevent)

{

case

I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:

break

;

case

I2C_EVENT_SLAVE_BYTE_RECEIVED:

break

;

case

I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:

break

;

case

I2C_EVENT_SLAVE_STOP_DETECTED:

break

;

case

I2C_EVENT_SLAVE_BYTE_TRANSMITTED:

break

;

case

I2C_EVENT_SLAVE_ACK_FAILURE:

break

;

case

I2C_EVENT_MASTER_MODE_SELECT:

break

;

default

:

break

;

}

}

After the first time I execute my

I2C1_Start() function

,the code stays at the command

while

(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

... and this interrupt handler is called in a loop, with

LastI2Cevent =

I2C_EVENT_MASTER_MODE_SELECT

event.

Do you have any idea why?

Thanks a lot!

3 REPLIES 3
benoit2
Associate II
Posted on July 22, 2015 at 11:36

Do I have to clear a flag or IT related to

I2C_EVENT_MASTER_MODE_SELECT ?

I try to clear everything in the handler:

void
I2C1_EV_IRQHandler(
void
)
{
I2C_ClearITPendingBit(I2C1,I2C_IT_SMBALERT);
I2C_ClearITPendingBit(I2C1,I2C_IT_TIMEOUT);
I2C_ClearITPendingBit(I2C1,I2C_IT_PECERR);
I2C_ClearITPendingBit(I2C1,I2C_IT_OVR);
I2C_ClearITPendingBit(I2C1,I2C_IT_AF);
I2C_ClearITPendingBit(I2C1,I2C_IT_ARLO);
I2C_ClearITPendingBit(I2C1,I2C_IT_BERR);
I2C_ClearITPendingBit(I2C1,I2C_IT_TXE);
I2C_ClearITPendingBit(I2C1,I2C_IT_RXNE);
I2C_ClearITPendingBit(I2C1,I2C_IT_STOPF);
I2C_ClearITPendingBit(I2C1,I2C_IT_ADD10);
I2C_ClearITPendingBit(I2C1,I2C_IT_BTF);
I2C_ClearITPendingBit(I2C1,I2C_IT_ADDR);
I2C_ClearITPendingBit(I2C1,I2C_IT_SB);
I2C_ClearFlag(I2C1,I2C_FLAG_SMBALERT);
I2C_ClearFlag(I2C1,I2C_FLAG_TIMEOUT);
I2C_ClearFlag(I2C1,I2C_FLAG_PECERR);
I2C_ClearFlag(I2C1,I2C_FLAG_OVR);
I2C_ClearFlag(I2C1,I2C_FLAG_AF);
I2C_ClearFlag(I2C1,I2C_FLAG_ARLO);
I2C_ClearFlag(I2C1,I2C_FLAG_BERR);
I2C_ClearFlag(I2C1,I2C_FLAG_TXE);
I2C_ClearFlag(I2C1,I2C_FLAG_RXNE);
I2C_ClearFlag(I2C1,I2C_FLAG_STOPF);
I2C_ClearFlag(I2C1,I2C_FLAG_ADD10);
I2C_ClearFlag(I2C1,I2C_FLAG_BTF);
I2C_ClearFlag(I2C1,I2C_FLAG_ADDR);
I2C_ClearFlag(I2C1,I2C_FLAG_SB);

 I2C_ClearFlag(I2C1,I2C_FLAG_DUALF);
 I2C_ClearFlag(I2C1,I2C_FLAG_SMBHOST);
 I2C_ClearFlag(I2C1,I2C_FLAG_SMBDEFAULT);
 I2C_ClearFlag(I2C1,I2C_FLAG_GENCALL);
 I2C_ClearFlag(I2C1,I2C_FLAG_TRA);
 I2C_ClearFlag(I2C1,I2C_FLAG_BUSY);
 I2C_ClearFlag(I2C1,I2C_FLAG_MSL);
}

But it does not change anything. My problem is still the same: right after the instruction

I2C_GenerateSTART(I2C1, ENABLE);

The interrupt handler

I2C1_EV_IRQHandler()
{
 ...
}

is called in a loop with

I2C_GetLastEvent(I2C1) ==I2C_EVENT_MASTER_MODE_SELECT

Thanks for your help
jpeacock
Associate II
Posted on July 22, 2015 at 14:19

You don't need to clear all those flags in the interrupt.  In the MASTER_MODE_SELECT state (EV5) you send out the address and R/W bit. using I2C_Send7BitAddress().  If you are using DMA transfers the buffer interrupt (I2C_IT_BUF) is disabled at this point since EV7 and EV8 are handled by the DMA controller; otherwise buffer interrupt is enabled for data transfers at the next (EV6 and EV7/8) state.  That's all that's needed.

Why are you polling the state?  It isn't necessary or useful if you are using interrupts and the I2C state machine events.

Also, be aware that on the EV7 and EV8 states you need to allow for the BTF flag when checking the event code. As is the I2C library definitions for states don't handle this when decoding the event in the switch statement.

  Jack Peacock

benoit2
Associate II
Posted on July 23, 2015 at 11:43

Hello Jack, thanks for your answer!

I know I don't need to clear all those flags but it was a test, to understand why the handler is called is called in a loop with always the same interrupt id. Even if I clear all flags each time, this handler is still called in a loop.

If I understand, I need to send out the address and R/W bit to pass the I2C_EVENT_MASTER_MODE_SELECT interrupt, instead of clearing its flags?

I need to code the whole I2C state machine. Is there any existing examples of I2C communications? I think it would be easier if I start with a full example of send/receive datas.

Note: I don't use DMA in my code.

Thanks!

Best