[英]STM32 HAL: How to read I2C memory in truly non-blocking mode?
這是我所擁有的:具有輸入的PCA9555芯片,如果輸入上的信號state發生變化,則發送中斷信號。 然后我可以通過 I2C 讀取芯片以檢查輸入。
我需要什么 - 當引腳更改 state 時,我需要讀取芯片,檢查哪個引腳更改了 state 並通知我的應用程序。
所以我有一個中斷,中斷處理程序絕不能阻塞 MCU。
我明顯的選擇是使用 HAL_I2C_Mem_Read_IT(),對吧?
我制作了整個代碼,並對其進行了測試。 似乎它奏效了……有一段時間了。
直到我添加了每 100 毫秒讀取一次芯片。
代碼仍然有效,但我看到閃爍的東西斷斷續續,停止閃爍超過一秒甚至 2 秒。所以 - 很明顯,HAL_I2C_Mem_Read_IT() 阻止了導致 MCU 凍結的中斷。
我檢查了 HAL 源並發現了這個:
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()
所暗示的那樣 - 它等待。 Yes, it's a while
loop that blocks the executing thread until a flag is set:
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 驅動程序中的錯誤嗎?
我必須實現自己的非阻塞 function 嗎? 這似乎是很多很多小時的編碼,因為 function 非常重要並且與模塊的 rest 緊密耦合。
我的想法是重寫它並用我的非阻塞延遲 function 替換while
循環,它使用定時器中斷在一段時間后繼續工作。 為了讓它更重要,每個回調都必須接收必要的 state 數據才能繼續。 然后 state 機器用我的I2C_RequestMemoryRead_
進程找出我們在哪里。 最后我只調用注冊的回調並完成。 它應該真正無阻塞地工作......
但我有最后期限。 可以做得更快嗎? HAL“_IT”function 怎么可能用一些while
循環阻塞線程? 這是錯誤的。 如果它阻塞,它就破壞了“中斷模式功能”的全部目的。 已經有一個更簡單的阻塞版本。
我通過破解原始 HAL 驅動程序解決了這個問題。
https://gist.github.com/HTD/e36fb68488742f27a737a5d096170623
將文件添加到項目后,需要按照 stm32h7xx_hal_i2c_nb.h 注釋中的描述修改原始 HAL 驅動程序。
為了與 STM32CubeIDE 一起使用,最好將修改后的驅動程序文件移動到不同的位置,以防止 IDE 覆蓋它。
我保留了其他 *IT 功能不變,但很容易對所有剩余功能添加類似的修改。
被黑的驅動程序在我的帶有 PCA9555 16 位 I/O 擴展器的 STM32H747I-DISCO 板上的實際應用中進行了測試。
為了進行測試,我用隨機噪聲信號向輸入發送垃圾郵件,這些信號剛剛使原始驅動程序崩潰。 它在這里工作,不阻塞其他線程,GUI 全速工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.