死鎖的復(fù)現(xiàn)方式
- 在I2C恢復(fù)函數(shù)下個(gè)斷點(diǎn)(檢測(cè)到I2C多次超時(shí)之后,應(yīng)該能跳轉(zhuǎn)到I2C恢復(fù)函數(shù))
- 使用鑷子,將SCL與SDA短接,很快就能看到程序停到恢復(fù)函數(shù)的斷點(diǎn)上,此時(shí)再執(zhí)行恢復(fù)函數(shù),看能否正常走出(可在回復(fù)函數(shù)中寫個(gè)死循環(huán),只有I2C正常才跳出,檢測(cè)I2C正常的辦法,可以讀從設(shè)備的ID)
-
void HAL_I2C_MspInit(I2C_HandleTypeDef *i2cHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if (i2cHandle->Instance == I2C1) { /* USER CODE BEGIN I2C1_MspInit 0 */ /* USER CODE END I2C1_MspInit 0 */ __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); for (int i = 0; i < 10; ++i) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET); HAL_Delay(1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); HAL_Delay(1); } HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET); HAL_Delay(1); i2cHandle->Instance->CR1 |= I2C_CR1_SWRST; //復(fù)位I2C控制器 HAL_Delay(1); i2cHandle->Instance->CR1 = 0; //解除復(fù)位(不會(huì)自動(dòng)清除) /**I2C1 GPIO Configuration PB6 ------> I2C1_SCL PB7 ------> I2C1_SDA */ GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* I2C1 clock enable */ __HAL_RCC_I2C1_CLK_ENABLE(); /* USER CODE BEGIN I2C1_MspInit 1 */ /* USER CODE END I2C1_MspInit 1 */ } } /* USER CODE BEGIN 1 */ void I2C_Reset() { HAL_I2C_MspDeInit(&hi2c1); hi2c1.State = HAL_I2C_STATE_RESET; MX_I2C1_Init(); // 硬件i2c會(huì)出現(xiàn)死鎖,當(dāng)超時(shí)次數(shù)達(dá)到一定數(shù)量,即很有可能是發(fā)生了死鎖 // 所謂死鎖是指主機(jī)與從機(jī)互相等待,主機(jī)以為總線在從機(jī)手上控制,從機(jī)以為總線在主機(jī)手上控制,一直再等待對(duì)方釋放總線 }
死鎖的解決方法
- 釋放IO口為GPIO,復(fù)位句柄狀態(tài)標(biāo)志,改為IO方式
- 將SDA改為高電平?
- 將SCK發(fā)送9個(gè)時(shí)鐘? 為高電平時(shí),測(cè)試SDA是否為低電平完成死鎖。
通過(guò)模擬幾種情形來(lái)實(shí)際體會(huì)一下(從機(jī)對(duì)SDA的操作紅色表示):
如果在地址字節(jié)第9個(gè)CLK拉高后主機(jī)復(fù)位。在模擬的第一個(gè)時(shí)鐘低電平期間就可以看到SDA的釋放,隨后主機(jī)先拉低SDA,再模擬一個(gè)STOP結(jié)束條件。
在數(shù)據(jù)字節(jié)第2個(gè)CLK拉高后主機(jī)復(fù)位,在第二個(gè)模擬的時(shí)鐘低電平期間才看到SDA釋放
在數(shù)據(jù)字節(jié)第6個(gè)CLK拉高后主機(jī)復(fù)位,在第三個(gè)模擬的時(shí)鐘低電平期間才看到SDA釋放
通過(guò)以上三種情況的分析,想必你已經(jīng)非常清楚改如何處理了,最后附上一個(gè)程序處理流程圖:
SCL掛死
I2C從機(jī)主動(dòng)拉低SCL線在規(guī)范中是一個(gè)合法的行為,稱之為Clock Stretching(時(shí)鐘擴(kuò)展,我一般叫他時(shí)鐘同步)。通常是主機(jī)請(qǐng)求數(shù)據(jù)( 收或者發(fā))后從機(jī)需要一些時(shí)間處理,且沒有多余Buffer可以接收接或者提供接下來(lái)的數(shù)據(jù)的時(shí)候從機(jī)則會(huì)拉低SCL一段時(shí)間直到有新的數(shù)據(jù)準(zhǔn)備好。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-745815.html
SCL掛死(也就是前面所說(shuō)一直拉低SCL)這種情況在標(biāo)準(zhǔn)I2C從器件上基本不會(huì)出現(xiàn),因?yàn)橹灰酒€在正常工作buffer總算有準(zhǔn)備好的時(shí)候,自然就就釋放SCL了。往往是使用用戶使用MCU作為I2C從機(jī)時(shí),程序設(shè)計(jì)上的問題導(dǎo)致MCU無(wú)法讀取&填充buffer而導(dǎo)致,重點(diǎn)分析MCU I2C中斷服務(wù)程序。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-745815.html
- I2C中斷服務(wù)程序被意外屏蔽
- 中斷服務(wù)程序中陷入了一些標(biāo)志位查詢的
while(flag != xxx)
死循環(huán) - I2C功能系統(tǒng)被意外禁止
到了這里,關(guān)于GD32 單片機(jī) 硬件I2C死鎖解決方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!