我使用STM32F4板作为从接收器和北欧板作为主发送器。我能够将从机地址发送为0x30,由从机确认,我将设备寄存器地址发送为0x10然后我使用
发送一些数据i2c_write(0x30, 0x10, data, 4);
我能够在中断服务程序中获取事件。我收到了“I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED”的0x00020002。然后我收到0x00020044事件,时钟停止运行。任何人都可以帮我这个。通过范围确定,我在示波器上看到了Slave地址,设备寄存器地址和我的第一个带时钟的数据。但在那个时钟停止之后。
我能够使用STM32F4作为主发射器并读取一些传感器,但我发现很难将STM32F4用作带有北欧板作为主发射器的Slave接收器
void i2c_init2()
{
GPIO_InitTypeDef gpio_init;
I2C_InitTypeDef i2c_init;
NVIC_InitTypeDef NVIC_InitStructure, NVIC_InitStructure2;
I2C_DeInit(I2C2 ); //Deinit and reset the I2C to avoid it locking up
I2C_SoftwareResetCmd(I2C2, ENABLE);
I2C_SoftwareResetCmd(I2C2, DISABLE);
/*!< I2C Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
/* setup SCL and SDA pins
* SCL on PB10 and SDA on PB11
*/
gpio_init.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; // we are going to use PB10 and PB11
gpio_init.GPIO_Mode = GPIO_Mode_AF; // set pins to alternate function
gpio_init.GPIO_Speed = GPIO_Speed_50MHz; // set GPIO speed
gpio_init.GPIO_PuPd = GPIO_PuPd_UP; //Pull up resistor
gpio_init.GPIO_OType = GPIO_OType_OD; //Open Drain
GPIO_Init(GPIOB, &gpio_init);
// Connect I2C2 pins to AF
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2 ); // SCL
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2 ); // SDA
/* Configure the Priority Group to 1 bit */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure2.NVIC_IRQChannel = I2C2_ER_IRQn;
NVIC_InitStructure2.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure2.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure2.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure2);
I2C_ITConfig(I2C2, I2C_IT_EVT, ENABLE);
I2C_ITConfig(I2C2, I2C_IT_ERR, ENABLE);
I2C_ITConfig(I2C2, I2C_IT_BUF, ENABLE);
i2c_init.I2C_ClockSpeed = 100000;
i2c_init.I2C_Mode = I2C_Mode_I2C;
i2c_init.I2C_DutyCycle = I2C_DutyCycle_2;
i2c_init.I2C_OwnAddress1 = 0x30;
i2c_init.I2C_Ack = I2C_Ack_Enable;
i2c_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C2, &i2c_init);
I2C_StretchClockCmd(I2C2, ENABLE);
I2C_Cmd(I2C2, ENABLE);
}
void I2C2_ER_IRQHandler(void)
{
/* Read SR1 register to get I2C error */
if ((I2C_ReadRegister(I2C2, I2C_Register_SR1 ) & 0xFF00) != 0x00)
{
STM_EVAL_LEDOn(LED6);
/* Clears error flags */
I2C2 ->SR1 &= 0x00FF;
}
}
void I2C2_EV_IRQHandler(void)
{
uint8_t dataRX;
Event = I2C_GetLastEvent(I2C2 );
printf("Event: 0x%x\n", Event);
switch (Event)
{
case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED :
{
printf("Slave Address Matched\n");
STM_EVAL_LEDOn(LED4);
I2C2 ->SR1;
I2C2 ->SR2;
break;
}
case I2C_EVENT_SLAVE_BYTE_RECEIVED :
{
printf("Slave Byte Received\n");
dataRX = I2C_ReceiveData(I2C2 );
break;
}
case I2C_EVENT_SLAVE_ACK_FAILURE :
{
STM_EVAL_LEDOn(LED3);
I2C2 ->SR1 &= 0x00FF;
break;
}
case I2C_EVENT_SLAVE_STOP_DETECTED :
{
I2C2 ->SR1;
I2C2 ->CR1 |= 0x1;
break;
}
}
}
答案 0 :(得分:1)
然后我收到了0x00020044事件,时钟停止运行。
术语“事件”的使用有点松散。 ST的头文件所做的是将事件定义为标志的某些组合。你有一个稍微不同的组合。将其分解,设置以下位:
#define I2C_FLAG_BUSY ((uint32_t)0x00020000)
#define I2C_FLAG_RXNE ((uint32_t)0x10000040)
#define I2C_FLAG_BTF ((uint32_t)0x10000004)
(在不同的寄存器中实际上有两组 - 通过已知事件的定义,看起来后一组中的前导“1”在组合时会被丢弃,但我不是100%肯定的)
查看参考手册,有以下内容:
如果设置了RxNE,则在下一个数据结束之前未读取DR寄存器中的数据 接收,BTF位置位,接口等待直到通过读取清除BTF I2C_DR寄存器,将SCL拉低
似乎满足了这些条件,解释了为什么STM32F4 I2C从器件正在拉伸(停止)时钟。看起来您需要从数据寄存器中读取以允许它继续 - 实际上,将其作为事件匹配并执行此操作。
当你实际收到两个单词时,我进一步怀疑你处于这种状态 - 接收缓冲区中的一个由RXNE表示,另一个在接收器本身由BTF表示。此时它被卡住了,不能再接受了 - 您可以考虑通过为此添加一个中断启用来捕获RXNE,可能通过在第二个字完成接收之前声明第一个字来提高效率。
如果你设法让它完全发挥作用,请随意写下你自己的答案并接受它。
答案 1 :(得分:1)
“似乎满足了这些条件,解释了为什么STM32F4 I2C从器件正在拉伸(停止)时钟。看起来您需要从数据寄存器读取以允许它继续 - 实际上,将其匹配为一个事件并做到这一点。“
我完全按照你说的做了,它按预期工作。稍后阅读参考手册。 :)
答案 2 :(得分:0)
确保您正在处理所有可能的错误情况和中断原因:
通过写入SR1中的位来清除其中一些。一些通过DR读取清除,一些通过DR读取或写入清除。有些需要读取SR1然后读取SR2。有些需要读取SR1然后写入CR1。参考手册的I2C部分包含所有信息,您只需要浏览它。这需要一些时间但值得。从参考手册RM0368中的第18.6.6节I2C状态寄存器1(I2C_SR1)开始。 Google&#34; RM0268 stm32f4&#34;。一些中断原因(STOPF,ADDR,TXE,RXNE)有一种奇怪的清除方式。有些是标准的,可以通过写入但在SR1中清除。