STM32F4 I2C从设备接收器

时间:2014-08-19 20:39:34

标签: embedded i2c stm32 master-slave stm32f4discovery

我使用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;
            }
    }
}

3 个答案:

答案 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)

确保您正在处理所有可能的错误情况和中断原因:

  1. I2C_IT_SMBALERT:SMBus警告标志
  2. I2C_IT_TIMEOUT:超时或Tlow错误标志
  3. I2C_IT_PECERR:接收标志中的PEC错误
  4. I2C_IT_OVR:溢出/欠载标志(从模式)
  5. I2C_IT_AF:确认失败标志
  6. I2C_IT_ARLO:仲裁丢失标志(主模式)
  7. I2C_IT_BERR:总线错误标志
  8. I2C_IT_TXE:数据寄存器空标志(发送器)
  9. I2C_IT_RXNE:数据寄存器不为空(接收器)
  10. I2C_IT_STOPF:停止检测标志(从模式)
  11. I2C_IT_ADD10:10位标头发送标志(主模式)
  12. I2C_IT_BTF:字节传输完成标志
  13. I2C_IT_ADDR:地址发送标志(主模式)&#34; ADSL&#34;
  14. 通过写入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中清除。