硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3290|回复: 12
收起左侧

[I2C] 任务切换导致I2C出错

[复制链接]

13

主题

192

回帖

231

积分

高级会员

积分
231
发表于 2021-6-26 11:23:00 | 显示全部楼层 |阅读模式
目前使用的是H743,上的FreeRTOS,驱动用的HAL库,但是发现一个问题,在一个任务执行读取I2C数据时,如果另一个任务抢占了优先级,会导致I2C总线出现错误,只能复位I2C才能恢复。目前的解决方案是,在使用HAL_I2C_MEM_READ和HAL_I2C_MEM_WRITE的时候停止了任务切换,但是这种太浪费了,在这里用锁,锁不住切换到其他任务。所以请问大家有没有什么好办法
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106840
QQ
发表于 2021-6-26 12:12:27 | 显示全部楼层
如果你用的硬件I2C还有这种问题,那个这种硬件I2C的驱动设计不太好。

得查下是哪里的问题,HAL库还是基于HAL的驱动问题。
回复

使用道具 举报

13

主题

192

回帖

231

积分

高级会员

积分
231
 楼主| 发表于 2021-6-26 16:03:24 | 显示全部楼层
eric2013 发表于 2021-6-26 12:12
如果你用的硬件I2C还有这种问题,那个这种硬件I2C的驱动设计不太好。

得查下是哪里的问题,HAL库还是基 ...

也不能说是HAL库的问题,HAL_I2C_MEM_READ和HAL_I2C_MEM_WRITE这两个操作不是原子操作,我们目前只能在使用这两个函数的时候禁止任务切换操作
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106840
QQ
发表于 2021-6-26 16:44:14 | 显示全部楼层
zhang0352505 发表于 2021-6-26 16:03
也不能说是HAL库的问题,HAL_I2C_MEM_READ和HAL_I2C_MEM_WRITE这两个操作不是原子操作,我们目前只能在使 ...

得想办法解决下,我看下这个函数,代码量太大了,本身I2C就很慢,这么搞确实有问题
  1. /**
  2.   * @brief  Read an amount of data in blocking mode from a specific memory address
  3.   * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
  4.   *                the configuration information for the specified I2C.
  5.   * @param  DevAddress Target device address: The device 7 bits address value
  6.   *         in datasheet must be shifted to the left before calling the interface
  7.   * @param  MemAddress Internal memory address
  8.   * @param  MemAddSize Size of internal memory address
  9.   * @param  pData Pointer to data buffer
  10.   * @param  Size Amount of data to be sent
  11.   * @param  Timeout Timeout duration
  12.   * @retval HAL status
  13.   */
  14. HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress,
  15.                                    uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
  16. {
  17.   uint32_t tickstart;

  18.   /* Check the parameters */
  19.   assert_param(IS_I2C_MEMADD_SIZE(MemAddSize));

  20.   if (hi2c->State == HAL_I2C_STATE_READY)
  21.   {
  22.     if ((pData == NULL) || (Size == 0U))
  23.     {
  24.       hi2c->ErrorCode = HAL_I2C_ERROR_INVALID_PARAM;
  25.       return  HAL_ERROR;
  26.     }

  27.     /* Process Locked */
  28.     __HAL_LOCK(hi2c);

  29.     /* Init tickstart for timeout management*/
  30.     tickstart = HAL_GetTick();

  31.     if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK)
  32.     {
  33.       return HAL_ERROR;
  34.     }

  35.     hi2c->State     = HAL_I2C_STATE_BUSY_RX;
  36.     hi2c->Mode      = HAL_I2C_MODE_MEM;
  37.     hi2c->ErrorCode = HAL_I2C_ERROR_NONE;

  38.     /* Prepare transfer parameters */
  39.     hi2c->pBuffPtr  = pData;
  40.     hi2c->XferCount = Size;
  41.     hi2c->XferISR   = NULL;

  42.     /* Send Slave Address and Memory Address */
  43.     if (I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK)
  44.     {
  45.       /* Process Unlocked */
  46.       __HAL_UNLOCK(hi2c);
  47.       return HAL_ERROR;
  48.     }

  49.     /* Send Slave Address */
  50.     /* Set NBYTES to write and reload if hi2c->XferCount > MAX_NBYTE_SIZE and generate RESTART */
  51.     if (hi2c->XferCount > MAX_NBYTE_SIZE)
  52.     {
  53.       hi2c->XferSize = MAX_NBYTE_SIZE;
  54.       I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
  55.     }
  56.     else
  57.     {
  58.       hi2c->XferSize = hi2c->XferCount;
  59.       I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
  60.     }

  61.     do
  62.     {
  63.       /* Wait until RXNE flag is set */
  64.       if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_RXNE, RESET, Timeout, tickstart) != HAL_OK)
  65.       {
  66.         return HAL_ERROR;
  67.       }

  68.       /* Read data from RXDR */
  69.       *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->RXDR;

  70.       /* Increment Buffer pointer */
  71.       hi2c->pBuffPtr++;

  72.       hi2c->XferSize--;
  73.       hi2c->XferCount--;

  74.       if ((hi2c->XferCount != 0U) && (hi2c->XferSize == 0U))
  75.       {
  76.         /* Wait until TCR flag is set */
  77.         if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK)
  78.         {
  79.           return HAL_ERROR;
  80.         }

  81.         if (hi2c->XferCount > MAX_NBYTE_SIZE)
  82.         {
  83.           hi2c->XferSize = MAX_NBYTE_SIZE;
  84.           I2C_TransferConfig(hi2c, DevAddress, (uint8_t) hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
  85.         }
  86.         else
  87.         {
  88.           hi2c->XferSize = hi2c->XferCount;
  89.           I2C_TransferConfig(hi2c, DevAddress, (uint8_t)hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
  90.         }
  91.       }
  92.     } while (hi2c->XferCount > 0U);

  93.     /* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */
  94.     /* Wait until STOPF flag is reset */
  95.     if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
  96.     {
  97.       return HAL_ERROR;
  98.     }

  99.     /* Clear STOP Flag */
  100.     __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);

  101.     /* Clear Configuration Register 2 */
  102.     I2C_RESET_CR2(hi2c);

  103.     hi2c->State = HAL_I2C_STATE_READY;
  104.     hi2c->Mode  = HAL_I2C_MODE_NONE;

  105.     /* Process Unlocked */
  106.     __HAL_UNLOCK(hi2c);

  107.     return HAL_OK;
  108.   }
  109.   else
  110.   {
  111.     return HAL_BUSY;
  112.   }
  113. }
复制代码


回复

使用道具 举报

12

主题

178

回帖

214

积分

高级会员

积分
214
发表于 2021-7-3 09:54:32 来自手机 | 显示全部楼层
用mutex呢?是不是好点?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106840
QQ
发表于 2021-7-3 11:55:37 | 显示全部楼层
gallop020142 发表于 2021-7-3 09:54
用mutex呢?是不是好点?

得优化驱动,否则这个驱动跟用模拟I2C没什么区别了。
回复

使用道具 举报

13

主题

192

回帖

231

积分

高级会员

积分
231
 楼主| 发表于 2021-7-3 14:21:27 | 显示全部楼层
gallop020142 发表于 2021-7-3 09:54
用mutex呢?是不是好点?

跟mutex没关系,因为现在的FreeRTOS是抢占式和时间片同时存在,高优先级任务会打断驱动的执行,导致I2C时序出现问题
回复

使用道具 举报

12

主题

178

回帖

214

积分

高级会员

积分
214
发表于 2021-7-3 22:11:01 来自手机 | 显示全部楼层
eric2013 发表于 2021-7-3 11:55
得优化驱动,否则这个驱动跟用模拟I2C没什么区别了。

也就是说如果用模拟方式,可以用mutex互斥,对吧?
有的例程里printf也是用mutex互斥的
回复

使用道具 举报

9

主题

23

回帖

50

积分

初级会员

积分
50
发表于 2021-10-30 09:18:21 | 显示全部楼层
最后怎么解决的呢?
回复

使用道具 举报

5

主题

25

回帖

40

积分

新手上路

积分
40
发表于 2021-10-30 15:06:29 | 显示全部楼层
我用的硬件I2C DMA 没有出现你说的这种问题。
回复

使用道具 举报

5

主题

25

回帖

40

积分

新手上路

积分
40
发表于 2021-10-30 15:07:02 | 显示全部楼层
C:\Users\Administrator\Desktop
回复

使用道具 举报

0

主题

19

回帖

19

积分

新手上路

积分
19
发表于 2021-11-3 09:40:07 | 显示全部楼层
可以参考cmsis里面的I2C驱动可以用,很不错,推荐DMA
回复

使用道具 举报

0

主题

4

回帖

4

积分

新手上路

积分
4
发表于 2022-4-21 10:56:52 | 显示全部楼层
a13421364618 发表于 2021-11-3 09:40
可以参考cmsis里面的I2C驱动可以用,很不错,推荐DMA

cmsis和HAL驱动不一样么?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-7 02:23 , Processed in 0.187594 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表