STM32 I2C中断方法需要循环时阻止?

发布于 2025-01-23 09:57:39 字数 1723 浏览 4 评论 0原文

我有一个Nucleo-f446re,我正在尝试使I2C与IMU一起工作(LSM6DS33)。我正在使用STM32Cubemx,并检查了与I2C相关的所有董事会示例代码。具体来说,我将讨论他们的“ I2C_TWOBOARDS_COMIT”示例,但是他们使用中断方法的所有示例都具有相同的怪癖。 的剪切。

  /* 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); 

这是从main.c的剪切中 使用一段时间循环,等待I2C状态在继续之前“准备就绪”。

这不是一种使用中断的非常低效的方法,并且与使用标准轮询方法没有什么不同?两者都阻止了主代码,那么中断的目的是什么?

在我的个人示例中,我想以IMU能够的1.66 kHz速率收集加速度计/陀螺仪数据。我使用2kHz计时器发送I2C命令来读取ACC/GYR数据就绪的寄存器,如果数据已准备就绪,我读了他们的6个字节以获取X/Y/Z平面信息。使用轮询方法太慢了,因为以2kHz的速率阻止代码效率并非效率低下,但是中断方法似乎并不快,因为在循环时,我仍然需要在上述过程中悬挂系统以检查I2C是否是准备另一个命令。我在这里想念什么?

I have a Nucleo-F446RE, and I'm trying to get the I2C working with an IMU I have (LSM6DS33). I am using STM32CubeMX and checked out all the example code for my board which is related to 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. Here is a snipped of their code from 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.

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. 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. 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. What am I missing here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

神经大条 2025-01-30 09:57:39

这(您提供的示例)是一种有效的做事方式吗?否。可以避免阻塞零件吗?是的。这只是一个小例子,是一个概念证明,因此其中有一些阻塞。您应该更深入地了解为什么它在那里,以及 you 如何在不阻止的情况下实现它的作用。

该阻止部分的目的是不启动I2C通信,而另一个I2C通信正在进行中。问题在于,尽管您要通过I2C发送的代码线已经执行,但数据仍在实际发送,只是因为您的MCU比I2C快得多。您需要等到I2C线闲置并用于传输。

如何通过中断而不是浪费周期和处理时间来实现这一目标?在您的情况下,您可以轻松估计每次每个变速箱的数据量,没有任何可能估计给定i2c速度的每次传输将花费多少时间。由于您巧妙,正确地使用计时器安排常规传输,因此您应该能够以下一个会发送数据的计时器中断的方式设置计时器,该计时器将发送数据,您以前的通信已经结束。

例如,如果将计时器设置为1Hz以开始传输,则显然可以确保在下一个中断时,所有通信都发生了。您根本不需要进行任何调查。

如果I2C以1.6kHz的形式产生的数据,我认为I2C填充IC的点不多。您将在样本之间存在不平衡的时间段,一些数据将非常新鲜,而某些数据将很少延迟,而且还没有准备好数据的通信。最好以1.5-1.6khz的速度进行轮询,并希望数据始终存在。当然,鉴于沟通适合1.5kHz时期,这需要一些餐巾数学。

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. 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. You need to wait until I2C line is idle and available for transmission.

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. 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. 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. 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. Of course, given the communication fits into 1.5kHz period, which requires some napkin math.

荒路情人 2025-01-30 09:57:39

该阻止是用于快速循环或多线程应用程序,因此它不会中断出去的I2C事务并在最后一个完成之前启动另一个转移。

如果单个螺纹应用程序(或Bare-Metal's(1))正在执行不够快的请求,则该条件将永远不会被击中。但是,如果一个多线程应用程序试图从多个线程访问I2C资源,那么这种情况肯定是有道理的。因此,避免此循环的一个不错的解决方案将是互斥克保护您的资源(I2C)。

对于裸金属循环,最好根据I2C通道的波特率使用足够的延迟(阻塞或非阻滞)(如果您希望最大化带宽利用率)

The blocking is for fast loops or multi-threaded applications, so it doesn't interrupt an out going I2C transaction and initiate another transfer before the last one completes.

If a single threaded application( or bare-metal's while(1) ) is doing a request that isn't fast enough, this condition will never be hit. However, if a multi-threaded app is trying to access the I2C resource from more than one thread, then this condition will definitely make sense. So, a decent solution to avoid this loop would be to mutex protect your resource(I2C) .

For while loops of bare metal, better to use a sufficient delay(blocking or non-blocking) based on the baud rate of the I2C channel (if you wish to maximise the bandwidth utilisation)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文