简体   繁体   English

STM32 I2C中断方法需要阻塞while循环?

[英]STM32 I2C interrupt method requires a blocking while loop?

I have a Nucleo-F446RE, and I'm trying to get the I2C working with an IMU I have (LSM6DS33).我有一个 Nucleo-F446RE,我正在尝试让 I2C 与我拥有的 IMU (LSM6DS33) 一起工作。 I am using STM32CubeMX and checked out all the example code for my board which is related to I2C.我正在使用 STM32CubeMX 并检查了与 I2C 相关的我的板的所有示例代码。 Specifically I'll be talking about their 'I2C_TwoBoards_ComIT' example, but all their examples which use the interrupt method have this same quirk.具体来说,我将讨论他们的“I2C_TwoBoards_ComIT”示例,但他们所有使用中断方法的示例都有同样的怪癖。 Here is a snipped of their code from main.c:这是他们从 main.c 中截取的代码:

  /* The board sends the message and expects to receive it back */
  do
  {
    /*##-2- Start the transmission process #####################################*/  
    /* While the I2C in reception process, user can transmit data through 
    "aTxBuffer" buffer */
    if(HAL_I2C_Master_Transmit_IT(&I2cHandle, (uint16_t)I2C_ADDRESS, (uint8_t*)aTxBuffer, TXBUFFERSIZE)!= HAL_OK)
    {
      /* Error_Handler() function is called in case of error. */
      Error_Handler();
    }

    /*##-3- Wait for the end of the transfer ###################################*/  
    /*  Before starting a new communication transfer, you need to check the current   
    state of the peripheral; if it’s busy you need to wait for the end of current
    transfer before starting a new one.
    For simplicity reasons, this example is just waiting till the end of the 
    transfer, but application may perform other tasks while transfer operation
    is ongoing. */ 
    while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
    {
    }

    /* When Acknowledge failure occurs (Slave don't acknowledge its address)
    Master restarts communication */
  }
  while(HAL_I2C_GetError(&I2cHandle) == HAL_I2C_ERROR_AF); 

Under comment ##-3- they explain that unless we wait for the I2C state to be ready again, after sending a command, the next command will overwrite the previous one, so they use a while loop which waits for the I2C state to be 'ready' before continuing.在评论 ##-3- 他们解释说,除非我们等待 I2C 状态再次准备好,否则在发送命令后,下一个命令将覆盖前一个命令,因此他们使用等待 I2C 状态的 while 循环在继续之前“准备好”。

Isn't this a very inefficient way to use an interrupt, and no different from using the standard polling method?这不是使用中断的一种非常低效的方式,与使用标准轮询方法没有区别吗? Both block the main code, so what's the purpose of the interrupt?两者都阻塞了主代码,那么中断的目的是什么?

In my personal example, I want to collect the accelerometer/gyroscope data at the 1.66 kHz rate which the IMU is capable of.在我个人的示例中,我想以 IMU 能够达到的 1.66 kHz 速率收集加速度计/陀螺仪数据。 I use a 2kHz timer to send an I2C command to read the acc/gyr data-ready register, and if the data is ready for either sensor I read their 6 bytes to get the x/y/z plane information.我使用 2kHz 定时器发送 I2C 命令以读取 acc/gyr 数据就绪寄存器,如果数据已为任一传感器准备好,我读取它们的 6 个字节以获取 x/y/z 平面信息。 Using the polling method is too slow as blocking the code at a rate of 2kHz is not inefficient, but the interrupt method doesn't seem to be any faster as I still need to hang the system during the aforementioned while loop to check if I2C is ready for another command.使用轮询方法太慢了,因为以 2kHz 的速率阻塞代码并不是低效的,但是中断方法似乎并没有更快,因为我仍然需要在上述 while 循环期间挂起系统以检查 I2C 是否准备好接受另一个命令。 What am I missing here?我在这里想念什么?

Is this (the example you provided) an efficient way of doing things?这(您提供的示例)是一种有效的做事方式吗? No. Can blocking part be avoided?不,可以避免阻塞部分吗? Yes.是的。 It's only a small example, a proof of concept, so there is some blocking in there.这只是一个小例子,一个概念证明,所以那里有一些障碍。 You should look deeper at why it is there and how can you implement what it does without blocking.您应该更深入地了解它存在的原因以及如何在不阻塞的情况下实现它的功能。

The point of that blocking part is to not start an I2C communication while another I2C communication is in progress.该阻塞部分的要点是在另一个 I2C 通信正在进行时不启动 I2C 通信。 The problem is that while your line of code to send something over I2C has already been executed, the data is still being physically sent over the line, just because your MCU is much faster than I2C.问题是,虽然您通过 I2C 发送内容的代码行已经执行,但数据仍在物理上通过线路发送,只是因为您的 MCU 比 I2C 快得多。 You need to wait until I2C line is idle and available for transmission.您需要等到 I2C 线路空闲且可用于传输。

How to achieve that with interrupts and not waste cycles and processing time?如何通过中断而不浪费周期和处理时间来实现这一点? Given in your case you can easily estimate the amount of data per each transmission, there is no probem to estimate how much time every transmission will take given your I2C speed.在您的情况下,您可以轻松估计每次传输的数据量,没有问题可以估计在您的 I2C 速度下每次传输将花费多少时间。 Since you're smartly and correctly using timer to schedule regular transmissions, you should be able to set the timer in such a way that by the next timer interrupt, which will send data, your previous communication has already ended.由于您巧妙且正确地使用计时器来安排定期传输,因此您应该能够设置计时器,以便在下一个将发送数据的计时器中断时,您之前的通信已经结束。

For example, if you set the timer to 1Hz to start transmission, you can obviously be sure that by the next interrupt all the communication has happened.例如,如果您将定时器设置为 1Hz 开始传输,您显然可以确定到下一次中断时所有通信都已发生。 You don't need to poll anything at all.你根本不需要投票。

I don't see much point in I2C-polling the IC at 2kHz if it produces data at 1.6kHz.如果它以 1.6kHz 产生数据,我认为以 2kHz 的频率对 IC 进行 I2C 轮询没有多大意义。 You will have uneven time periods between samples, some data will be very fresh, while some data will come with little delay, plus there will be communication without data ready.样本之间的时间段会不均匀,一些数据会非常新鲜,而一些数据会延迟很少,另外还会有没有准备好数据的通信。 It would be better to poll it at something like 1.5-1.6kHz and just expect data to always be there.最好以 1.5-1.6kHz 的频率对其进行轮询,并期望数据始终存在。 Of course, given the communication fits into 1.5kHz period, which requires some napkin math.当然,鉴于通信适合 1.5kHz 周期,这需要一些餐巾数学。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM