首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >STM32 HAL:如何在真正的非阻塞模式下读取I2C内存?

STM32 HAL:如何在真正的非阻塞模式下读取I2C内存?
EN

Stack Overflow用户
提问于 2022-07-02 15:06:47
回答 1查看 655关注 0票数 0

这就是我所拥有的:具有输入的PCA9555芯片,如果输入上的信号状态发生变化,中断信号就会被发送。然后我可以通过I2C读取芯片来检查输入。

我需要什么-当一个引脚改变状态时,我需要读取芯片,检查哪个引脚改变了状态并通知我的应用程序。

所以我有一个中断,中断处理程序不能阻止MCU。

我明显的选择是使用HAL_I2C_Mem_Read_IT(),对吗?

我做了完整的代码,测试了它。好像成功了..。一段时间。

直到我增加了每100毫秒读一次芯片。

代码仍然工作,但我看到闪烁的东西结结巴巴,停止闪烁超过一秒,甚至2。因此,很明显,HAL_I2C_Mem_Read_IT()阻止我的中断,使单片机冻结。

我查了一下HAL的资料,发现如下:

代码语言:javascript
运行
复制
static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
                                               uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout,
                                               uint32_t Tickstart)
{
  I2C_TransferConfig(hi2c, DevAddress, (uint8_t)MemAddSize, I2C_SOFTEND_MODE, I2C_GENERATE_START_WRITE);

  /* Wait until TXIS flag is set */
  if (I2C_WaitOnTXISFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK)
  {
    return HAL_ERROR;
  }

  /* If Memory address size is 8Bit */
  if (MemAddSize == I2C_MEMADD_SIZE_8BIT)
  {
    /* Send Memory Address */
    hi2c->Instance->TXDR = I2C_MEM_ADD_LSB(MemAddress);
  }
  /* If Memory address size is 16Bit */
  else
  {
    /* Send MSB of Memory Address */
    hi2c->Instance->TXDR = I2C_MEM_ADD_MSB(MemAddress);

    /* Wait until TXIS flag is set */
    if (I2C_WaitOnTXISFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK)
    {
      return HAL_ERROR;
    }

    /* Send LSB of Memory Address */
    hi2c->Instance->TXDR = I2C_MEM_ADD_LSB(MemAddress);
  }

  /* Wait until TC flag is set */
  if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TC, RESET, Timeout, Tickstart) != HAL_OK)
  {
    return HAL_ERROR;
  }

  return HAL_OK;
}

正如I2C_WaitOnTXISFlagUntilTimeout()这个名字所暗示的,它等待着。是的,它是一个while循环,它阻止正在执行的线程,直到设置了标志:

代码语言:javascript
运行
复制
static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status,
                                                    uint32_t Timeout, uint32_t Tickstart)
{
  while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status)
  {
    /* Check for the Timeout */
    if (Timeout != HAL_MAX_DELAY)
    {
      if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U))
      {
        hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
        hi2c->State = HAL_I2C_STATE_READY;
        hi2c->Mode = HAL_I2C_MODE_NONE;

        /* Process Unlocked */
        __HAL_UNLOCK(hi2c);
        return HAL_ERROR;
      }
    }
  }
  return HAL_OK;
}

这些滞后函数有3个。

对于我的应用程序,这是一个节目停止。它只是不起作用,因为它依赖于实时处理事件。此外,它还有一个GUI,当中断处理程序阻塞时,它会冻结。

有什么快速的解决办法吗?是HAL司机的窃听器吗?

我必须实现自己的非阻塞功能吗?这看起来像是很多很多小时的编码,因为这个函数并不简单,并且与模块的其余部分紧密耦合。

我的想法是重写它,用我的非阻塞延迟函数替换while循环,该函数使用计时器中断在一段时间后继续工作。为了使其变得更重要,每个回调都必须接收必要的状态数据才能继续。然后是状态机,以确定我们在I2C_RequestMemoryRead_进程中的位置。最后,我只需拨打注册电话就可以了。它应该能正常工作.

但我还有最后期限。能做得更快吗?HAL "_IT“函数怎么可能用while循环阻塞线程呢?这是错的!它违背了“中断模式函数”的全部目的。如果它阻塞,那么已经有了一个更简单的阻塞版本。

EN

回答 1

Stack Overflow用户

发布于 2022-07-03 14:20:59

我解决了黑客攻击原HAL司机的问题。

https://gist.github.com/HTD/e36fb68488742f27a737a5d096170623

在将文件添加到项目之后,需要像stm32h7xx_hal_i2c_nb.h注释中所描述的那样修改原始HAL驱动程序。

为了与STM32CubeIDE一起使用,最好将修改后的驱动程序文件移动到不同的位置,以防止IDE覆盖它。

我将其他*IT函数保持不变,但很容易将类似的修改添加到其余的所有函数中。

在我的STM32H747I-Diso板上用PCA9555 16位I/O扩展器测试了被黑客攻击的驱动程序。

对于测试,我垃圾输入随机噪声信号,刚刚崩溃了原来的驱动器。在这里,它可以工作,不会阻塞其他线程,GUI可以全速工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72840119

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档