2

我使用STM32F4板作为从接收器,北欧板作为主发射器。我能够发送从机地址为 0x30,这是从机确认的,我将设备寄存器地址发送为 0x10,然后我使用发送一些数据

i2c_write(0x30, 0x10, data, 4);

我能够在我的中断服务程序中获取事件。我收到了“I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED”的 0x00020002。然后我收到 0x00020044 事件并且时钟停止运行。谁能帮我解决这个问题。通过范围界定,我在示波器上看到了从地址、设备寄存器地址和我的第一个带有时钟的数据。但在那之后时钟停止了。

我可以将 STM32F4 用作主发射器并读取一些传感器,但我发现很难将 STM32F4 用作从接收器,将北欧板用作主发射器

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;
            }
    }
}
4

3 回答 3

1

“这些条件似乎已经满足,解释了为什么 STM32F4 I2C 从设备会延长(停止)时钟。看来您需要从数据寄存器中读取以允许它继续 - 实际上,将其作为事件匹配并且去做。”

我完全按照你说的做了,它按预期工作。阅读参考手册有点晚。:)

于 2014-08-20T15:22:55.950 回答
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 位并且接口等待直到通过读取 I2C_DR 寄存器清除 BTF,将 SCL 拉低

这些条件似乎都满足了,这解释了为什么 STM32F4 I2C 从设备会延长(停止)时钟。看起来您需要从数据寄存器中读取以允许它继续 - 实际上,将其作为事件匹配并执行此操作。

我进一步怀疑,当您实际接收到两个字时,您会进入这种情况——一个在接收缓冲区中由 RXNE 表示,另一个在接收器本身中由 BTF 表示。在这一点上,它被卡住了,不能再接受了——你可以考虑通过添加一个中断使能来自己捕获 RXNE,可能通过在第二个单词完成接收之前提前声明第一个单词来提高效率。

如果您设法让它完全工作,请随意编写自己的确切答案并接受。

于 2014-08-19T21:28:58.523 回答
0

Make sure you are handling all possible error conditions and interrupt causes:

  1. I2C_IT_SMBALERT: SMBus Alert flag
  2. I2C_IT_TIMEOUT: Timeout or Tlow error flag
  3. I2C_IT_PECERR: PEC error in reception flag
  4. I2C_IT_OVR: Overrun/Underrun flag (Slave mode)
  5. I2C_IT_AF: Acknowledge failure flag
  6. I2C_IT_ARLO: Arbitration lost flag (Master mode)
  7. I2C_IT_BERR: Bus error flag
  8. I2C_IT_TXE: Data register empty flag (Transmitter)
  9. I2C_IT_RXNE: Data register not empty (Receiver)
  10. I2C_IT_STOPF: Stop detection flag (Slave mode)
  11. I2C_IT_ADD10: 10-bit header sent flag (Master mode)
  12. I2C_IT_BTF: Byte transfer finished flag
  13. I2C_IT_ADDR: Address sent flag (Master mode) "ADSL"

Some of these are cleared by a write to the bit in SR1. Some are cleared by a DR read, some by a DR read OR write. Some require a read of SR1 then a read of SR2. Some require a read of SR1 then a write to CR1. The I2C section of the reference manual has all the information, you just have to wade through it. It takes some time but it is worth it. Start with section 18.6.6 I2C Status register 1 (I2C_SR1) in the reference manual RM0368. Google "RM0268 stm32f4". Several of the interrupt causes (STOPF, ADDR, TXE, RXNE) have a weird way of being cleared. Some are standard and can be cleared by a write to the but in SR1.

于 2015-02-05T20:15:50.317 回答