2015-07-17 06:44 AM
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, SCLGPIO_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; // INTGPIO_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); // SCLGPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);
// SDAI2C_DeInit(I2C1);
I2C_InitTypeDef I2C_InitStruct; I2C_InitStruct.I2C_ClockSpeed = 400000; // 400kHzI2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
// I2C modeI2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
// 50% duty cycle --> standardI2C_InitStruct.I2C_OwnAddress1 = 0x00;
// own address, not relevant in master modeI2C_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 addressesI2C_Init(I2C1, &I2C_InitStruct);
// init I2C1I2C_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)
{ caseI2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
break;
caseI2C_EVENT_SLAVE_BYTE_RECEIVED:
break;
caseI2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
break;
caseI2C_EVENT_SLAVE_STOP_DETECTED:
break;
caseI2C_EVENT_SLAVE_BYTE_TRANSMITTED:
break;
caseI2C_EVENT_SLAVE_ACK_FAILURE:
break;
caseI2C_EVENT_MASTER_MODE_SELECT:
break;
default:
break;
} } After the first time I execute my I2C1_Start() function ,the code stays at the commandwhile
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
... and this interrupt handler is called in a loop, withLastI2Cevent =
I2C_EVENT_MASTER_MODE_SELECT
event. Do you have any idea why? Thanks a lot!2015-07-22 02:36 AM
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 help2015-07-22 05:19 AM
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 Peacock2015-07-23 02:43 AM
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