戰(zhàn):從CubeMX配置到動(dòng)態(tài)地址分配完整指南)
1. 從I2C到I3C這次升級(jí)到底強(qiáng)在哪做嵌入式這些年I2C應(yīng)該沒人不熟。兩根線、多設(shè)備掛載、從機(jī)尋址從傳感器到EEPROM功勞不小。但真到了產(chǎn)品落地吐槽點(diǎn)也一堆速度上不去、地址沖突要跳線、沒有中斷上報(bào)主從結(jié)構(gòu)死板、時(shí)序還容易被拉死。I3C就是來收拾這個(gè)爛攤子的。MIPI聯(lián)盟推出的I3C官網(wǎng)說法是可以兼容I2C設(shè)備但真正的價(jià)值在于速率提升到12.5MHzSDR模式甚至更高、支持動(dòng)態(tài)地址分配、帶帶內(nèi)中斷IBI、支持熱加入還能在一條總線上同時(shí)掛I2C和I3C設(shè)備。聽起來很香但上手配置并不是打開CubeMX點(diǎn)兩下就行。這篇文章我用手頭的STM32U5系列開發(fā)板帶I3C外設(shè)的型號(hào)走一遍完整流程。從CubeMX圖形化配置到底層寄存器理解再到動(dòng)態(tài)地址分配的完整實(shí)現(xiàn)每一步都給出實(shí)際驗(yàn)證過的操作和代碼。如果你正準(zhǔn)備在新項(xiàng)目里評(píng)估I3C或者單純想把I3C跑通這篇文章可以直接當(dāng)操作手冊(cè)用。要注意的是并非所有STM32型號(hào)都帶I3C外設(shè)。目前主要集中在新出的U5系列、H5系列和部分L5型號(hào)。老款F1/F4/G4系列沒有I3C別在CubeMX里找半天沒有就是沒有。2. I3C總線的核心概念不要拿I2C的思維套2.1 動(dòng)態(tài)地址分配I3C最值錢的功能I2C的從機(jī)地址是硬件固化一個(gè)總線上如果兩個(gè)設(shè)備地址相同那是真的災(zāi)難只能改板子或者換芯片。I3C通過動(dòng)態(tài)地址分配Dynamic Address Assignment徹底解決了這個(gè)問題。每個(gè)I3C從設(shè)備在出廠時(shí)都有一個(gè)48位的靜態(tài)IDStatic ID包含廠商ID、器件類型和實(shí)例ID。總線初始化時(shí)主控制器會(huì)向所有設(shè)備廣播一個(gè)ENTDAAEnter Dynamic Address Assignment命令然后像比武招親一樣從靜態(tài)ID的最高位開始逐位進(jìn)行地址仲裁。贏的那個(gè)設(shè)備獲得一個(gè)由主機(jī)分配的7位動(dòng)態(tài)地址然后退出仲裁剩下的設(shè)備繼續(xù)直到所有設(shè)備都拿到動(dòng)態(tài)地址。這個(gè)過程把從機(jī)的地址從“出廠寫死”變成了“運(yùn)行時(shí)分配”對(duì)同一型號(hào)的多傳感器模組、可熱插拔的擴(kuò)展板來說省掉的跳線和設(shè)計(jì)限制非??捎^。2.2 三種速率模式SDR、HDR和DDNI3C在速率上分了幾個(gè)檔位。最基礎(chǔ)的是SDRSingle Data Rate模式最大12.5MHz這是I3C的基本工作模式幾乎所有I3C設(shè)備都支持。往上還有HDRHigh Data Rate模式包括HDR-DDR、HDR-TSP和HDR-TSL速率能跑到25MHz以上。另外還有DDNDDR模式用于特定的雙數(shù)據(jù)率傳輸。實(shí)際項(xiàng)目里99%的情況用SDR就夠了傳感器的數(shù)據(jù)量沒那么大SDR模式兼容性最好、代碼最簡單。HDR模式需要主從雙方都支持而且時(shí)序要求嚴(yán)苛PCB布線不好的話反而容易翻車。2.3 帶內(nèi)中斷和熱加入為現(xiàn)代傳感器而生傳統(tǒng)I2C里傳感器要主動(dòng)通知主機(jī)數(shù)據(jù)準(zhǔn)備好了通常得額外拉一根INT腳。I3C引入了IBIIn-Band Interrupt設(shè)備可以在總線上直接發(fā)起中斷請(qǐng)求不用多余引腳。這對(duì)引腳緊張的方案是個(gè)大利好。熱加入Hot-Join功能允許設(shè)備在總線運(yùn)行過程中隨時(shí)申請(qǐng)加入比如一個(gè)擴(kuò)展板在工作時(shí)插入主機(jī)同意后會(huì)給它分配動(dòng)態(tài)地址實(shí)現(xiàn)“即插即用”。這兩個(gè)功能在老掉牙的I2C協(xié)議里想都不敢想。2.4 糾錯(cuò)機(jī)制和CRC可靠性的大幅提升I3C的幀結(jié)構(gòu)里帶了奇偶校驗(yàn)位P在HDR模式下還有CRC校驗(yàn)以及主設(shè)備超時(shí)檢測機(jī)制。如果總線某個(gè)設(shè)備出問題導(dǎo)致時(shí)鐘拉低超時(shí)主設(shè)備可以執(zhí)行總線復(fù)位恢復(fù)這比I2C掛死只能斷電重啟強(qiáng)太多了。3. CubeMX環(huán)境準(zhǔn)備型號(hào)選擇和工程初始化3.1 選擇合適的MCU型號(hào)I3C是較新的外設(shè)并不是所有STM32都支持。確認(rèn)你的型號(hào)是否帶I3C最簡單的辦法就是在CubeMX的外設(shè)列表里找I3C找到就有找不到就沒戲。我測試用的是STM32U575ZIT6QNUCLEO-U575ZI-Q開發(fā)板搭配一個(gè)I3C從機(jī)傳感器LIS2DUX12ST的加速度計(jì)支持I3C接口。這套組合比較典型主控和傳感器都是ST自家產(chǎn)品CubeMX里集成度最高調(diào)試起來最省心。3.2 安裝CubeMX和固件包STM32CubeMX版本建議6.9.0以上老版本對(duì)I3C支持不完整。固件包方面在CubeMX的固件包管理器里下載STM32CubeU5固件包版本1.3.0以上。需要提醒的一點(diǎn)是CubeMX生成代碼時(shí)會(huì)在.ioc文件里保留所有圖形化配置信息所以工程文件、源碼、CubeMX配置要一起放版本庫后面改配置重新生成代碼時(shí)對(duì)照著方便。3.3 基本工程創(chuàng)建打開CubeMX選擇MCU型號(hào)我這里輸入STM32U575ZIT6Q雙擊創(chuàng)建工程。工程創(chuàng)建后第一件事是配置時(shí)鐘在Clock Configuration頁面里把系統(tǒng)時(shí)鐘拉滿到160MHzI3C外設(shè)的時(shí)鐘源選擇PCLK。I3C的時(shí)序完全由外設(shè)時(shí)鐘分頻而來時(shí)鐘樹配置錯(cuò)誤直接導(dǎo)致I3C通信失敗這一點(diǎn)很坑。配置完后在Project Manager頁面設(shè)置工程名和存儲(chǔ)路徑Toolchain選擇STM32CubeIDE或者M(jìn)DK-ARM都行我這邊用STM32CubeIDE調(diào)試方便。生成代碼后先編譯一次驗(yàn)證工具鏈沒問題。4. I3C控制器配置CubeMX圖形化操作全流程4.1 I3C引腳分配在Pinout Configuration頁面找到I3C外設(shè)有兩種選擇I3C1和I3C2。STM32U5系列通常有兩個(gè)I3C控制器。我用了I3C1默認(rèn)會(huì)分配SCL和SDA兩個(gè)引腳。關(guān)鍵點(diǎn)來了I3C引腳的復(fù)用功能選擇和GPIO模式設(shè)置。I3C的SDA是開漏輸出和I2C一樣SCL也是開漏但更特殊一點(diǎn)因?yàn)镮3C允許主設(shè)備通過推挽驅(qū)動(dòng)SCL來提高速率。CubeMX里分配好引腳后需要手動(dòng)確認(rèn)GPIO配置為Alternate Function模式Open DrainSpeed設(shè)為Very High。這一步容易出錯(cuò)的原因是I3C復(fù)用功能在芯片引腳上經(jīng)常和I2C、SPI等其他功能復(fù)用選錯(cuò)了AF編號(hào)就完全不通。4.2 I3C Mode配置參數(shù)詳解在I3C1的Mode配置頁面把I3C外設(shè)設(shè)為I3C Controller模式即Primary Controller。這時(shí)會(huì)出現(xiàn)詳細(xì)的參數(shù)配置表我先逐個(gè)解釋關(guān)鍵參數(shù)再給推薦值I2C Timing ConfigurationI3C控制器兼容I2C協(xié)議的時(shí)序參數(shù)。這個(gè)參數(shù)實(shí)際是一個(gè)分頻系數(shù)決定了SCL時(shí)鐘頻率。CubeMX里通過這個(gè)值間接設(shè)置速率內(nèi)部邏輯是SCL頻率 I3C內(nèi)核時(shí)鐘 / (I2C Timing配置值 × 2)。Bus Free Time總線空閑時(shí)間即連續(xù)兩次傳輸之間總線必須保持空閑的最小時(shí)間。I3C協(xié)議規(guī)定這個(gè)值要大于1個(gè)時(shí)鐘周期CubeMX里可以設(shè)置具體數(shù)值太短會(huì)導(dǎo)致時(shí)序違規(guī)。Rise Time / Fall Time總線上升沿和下降沿時(shí)間這個(gè)和PCB布線、上拉電阻值直接相關(guān)。估不準(zhǔn)的話按手冊(cè)里默認(rèn)值填但如果你的PCB走線特別長或者上拉電阻特別大這里要調(diào)整。Address Arbitration Enable動(dòng)態(tài)地址仲裁使能做動(dòng)態(tài)地址分配必須打開。Timeout Enable超時(shí)檢測使能建議打開。萬一從機(jī)掛死主機(jī)能通過超時(shí)檢測恢復(fù)總線不打開的話排查問題只能靠復(fù)位。我的推薦配置是速率先選1MHz SDRI3C支持的最高SDR速率是12.5MHz但初次調(diào)試不建議直接拉滿1MHz跑穩(wěn)再說、Bus Free Time設(shè)100ns、Rise Time 100ns、Fall Time 30ns、打開地址仲裁、打開超時(shí)檢測。4.3 NVIC中斷配置I3C外設(shè)強(qiáng)烈建議使用中斷方式工作。在NVIC Settings頁面打開I3C1全局中斷。I3C的事件類型比較多DAA完成、IBI請(qǐng)求、錯(cuò)誤事件等中斷里要能區(qū)分處理。優(yōu)先級(jí)的設(shè)置也注意一下I3C這種時(shí)序敏感的通信協(xié)議中斷優(yōu)先級(jí)建議偏高。我設(shè)置為優(yōu)先級(jí)1數(shù)字越小優(yōu)先級(jí)越高避免被其他外設(shè)中斷長期打斷導(dǎo)致時(shí)序超時(shí)。5. 動(dòng)態(tài)地址分配實(shí)戰(zhàn)從理論到代碼逐行實(shí)現(xiàn)5.1 ENTDAA和地址仲裁的工作流程動(dòng)態(tài)地址分配最核心的一段。整個(gè)流程可以拆解成下面幾步主機(jī)發(fā)出START信號(hào)和廣播地址0x7E緊跟著ENTDAA命令??偩€上所有未分配動(dòng)態(tài)地址的I3C設(shè)備都響應(yīng)這個(gè)命令。然后進(jìn)入地址仲裁階段。每個(gè)設(shè)備把48位靜態(tài)ID一位一位地放到SDA上所有設(shè)備同時(shí)發(fā)送。位是“線與”邏輯誰發(fā)送0誰就把SDA拉低如果某個(gè)設(shè)備發(fā)送1但檢測到SDA被拉低說明有另一個(gè)更高優(yōu)先級(jí)的設(shè)備也在仲裁中這個(gè)設(shè)備立即退出仲裁。重復(fù)48輪后最后勝出的設(shè)備它的靜態(tài)ID在整個(gè)總線上是唯一的。主機(jī)確認(rèn)這個(gè)獲勝設(shè)備后把一個(gè)7位的動(dòng)態(tài)地址發(fā)給它收到地址的設(shè)備回應(yīng)一個(gè)確認(rèn)位然后退出。主機(jī)再次發(fā)送ENTDAA命令剩下未分配的設(shè)備繼續(xù)仲裁如此循環(huán)直到總線上所有I3C設(shè)備都分配了動(dòng)態(tài)地址。靜態(tài)ID的高位決定了仲裁優(yōu)先級(jí)ID值最大的設(shè)備最先獲得動(dòng)態(tài)地址。理解了這一點(diǎn)你就知道ST傳感器動(dòng)態(tài)地址分配的先后順序其實(shí)是由硬件ID決定的軟件層面無法控制順序。5.2 用CubeMX HAL庫實(shí)現(xiàn)DAACubeMX生成的HAL庫代碼里已經(jīng)封裝了完整的DAA操作我們主要需要做的是初始化配置和事件處理。看幾個(gè)關(guān)鍵代碼段。首先是I3C控制器初始化CubeMX自動(dòng)生成但可以對(duì)照理解hi3c1.Instance I3C1; hi3c1.Init.BusMode I3C_BUS_MODE_I3C; hi3c1.Init.Prescaler 4; hi3c1.Init.DCALimit 0; hi3c1.Init.SclLow 2; hi3c1.Init.SclHigh 2; hi3c1.Init.WakeUp I3C_WAKEUP_ENABLE; hi3c1.Init.Timeout I3C_TIMEOUT_DISABLE; hi3c1.Init.BusFreeTime 0x3; hi3c1.Init.RiseTime 0x3; hi3c1.Init.FallTime 0x2; hi3c1.Init.ClockStretch I3C_CLOCK_STRETCH_ENABLE;接著是動(dòng)態(tài)地址分配的一次完整調(diào)用流程。HAL庫把整個(gè)過程分成了“準(zhǔn)備-啟動(dòng)-處理事件-完成”幾個(gè)階段/* 觸發(fā)一次動(dòng)態(tài)地址分配過程 */ HAL_I3C_DAA_Init(hi3c1); HAL_I3C_GenerateDAA(hi3c1); /* 在中斷回調(diào)中處理地址分配的各個(gè)階段 */ void HAL_I3C_NotifyCallback(I3C_HandleTypeDef *hi3c, uint32_t EventCode, uint32_t Arg) { switch (EventCode) { case HAL_I3C_EVENT_DAA_PREPARE: /* 硬件已發(fā)出ENTDAA命令等待設(shè)備參與仲裁 */ break; case HAL_I3C_EVENT_DAA_PROCESS: { uint8_t staticId[6]; HAL_I3C_DAA_GetStaticID(hi3c1, staticId); /* 向勝出的設(shè)備分配動(dòng)態(tài)地址例如0x1A */ HAL_I3C_DAA_SetDynamicAddress(hi3c1, 0x1A); break; } case HAL_I3C_EVENT_DAA_END: /* 所有設(shè)備已完成動(dòng)態(tài)地址分配 */ uint8_t daaCount HAL_I3C_DAA_GetDeviceCount(hi3c1); break; case HAL_I3C_EVENT_DAA_ERROR: HAL_I3C_DAA_ResetState(hi3c1); break; default: break; } }這個(gè)回調(diào)的執(zhí)行邏輯就像流水線HAL_I3C_GenerateDAA觸發(fā)一次ENTDAA然后硬件自動(dòng)完成48位仲裁仲裁出結(jié)果后觸發(fā)HAL_I3C_EVENT_DAA_PROCESS事件你在回調(diào)里調(diào)用HAL_I3C_DAA_GetStaticID讀取獲勝設(shè)備的靜態(tài)ID然后調(diào)用HAL_I3C_DAA_SetDynamicAddress給它分配地址。這個(gè)設(shè)備退出后硬件繼續(xù)發(fā)起下一輪ENTDAA直到所有設(shè)備分配完畢最后觸發(fā)HAL_I3C_EVENT_DAA_END事件。值得注意的一點(diǎn)是在DAA_PROCESS回調(diào)里調(diào)用HAL_I3C_DAA_SetDynamicAddress時(shí)主機(jī)需要等待從機(jī)完成地址鎖定這個(gè)等待過程在HAL庫里已經(jīng)封裝了超時(shí)機(jī)制但如果你的從機(jī)響應(yīng)特別慢建議在應(yīng)用層把I3C_TIMEOUT值調(diào)大一些。5.3 從機(jī)側(cè)LIS2DUX12的地址分配驗(yàn)證LIS2DUX12傳感器掛載在I3C總線上時(shí)如果主機(jī)執(zhí)行DAA流程傳感器會(huì)以IRQ事件響應(yīng)。我實(shí)際測試打印出來的DAA日志如下通過串口打印I3C: DAA started I3C: Device 0 staticIDE0 02 12 01 01 0A, assigned addr0x1A I3C: DAA completed, 1 device(s) on bus通過這個(gè)日志可以確認(rèn)傳感器成功參與了仲裁并獲得了0x1A動(dòng)態(tài)地址。之后訪問這個(gè)傳感器就統(tǒng)一用0x1A和它出廠默認(rèn)地址無關(guān)了。6. I3C普通數(shù)據(jù)收發(fā)配置完成后如何讀寫傳感器6.1 標(biāo)準(zhǔn)的I3C讀寫時(shí)序結(jié)構(gòu)動(dòng)態(tài)地址分配完成后總線進(jìn)入正常通信階段。I3C的讀寫時(shí)序和I2C相似但不完全一樣I3C的START條件是在SCL高電平時(shí)SDA拉低這個(gè)和I2C相同但I(xiàn)3C還支持一種更快的“無 STOP 的重復(fù)起始”模式連續(xù)訪問多個(gè)寄存器時(shí)效率更高。I3C地址頭的最后一位是R/W位和I2C一樣0表示寫1表示讀。不同的是I3C還引入了一種“廣播地址”模式可以對(duì)總線上所有設(shè)備同時(shí)發(fā)送數(shù)據(jù)這在對(duì)多個(gè)傳感器同時(shí)下配置時(shí)能省不少時(shí)間。6.2 HAL庫收發(fā)函數(shù)的正確用法CubeMX HAL庫提供的I3C讀寫函數(shù)已經(jīng)封裝好了地址頭和數(shù)據(jù)發(fā)送邏輯直接調(diào)用即可uint8_t regAddr 0x0F; /* 寄存器地址 */ uint8_t txData[2]; uint8_t rxData[6]; /* 寫操作先發(fā)寄存器地址再發(fā)要寫入的數(shù)據(jù) */ txData[0] regAddr; txData[1] 0x01; /* 示例使能傳感器 */ HAL_I3C_Write(hi3c1, 0x1A, 0, txData, 2, 100); /* 讀操作發(fā)送寄存器地址后產(chǎn)生重復(fù)起始然后讀數(shù)據(jù) */ HAL_I3C_Write(hi3c1, 0x1A, 0, regAddr, 1, 100); HAL_I3C_Read(hi3c1, 0x1A, 0, rxData, 6, 100);這里0x1A是前面動(dòng)態(tài)分配好的地址0是子地址模式Sub-Address Mode很多I3C設(shè)備支持這種模式來減少通信開銷。如果你的設(shè)備不支持子地址模式這個(gè)參數(shù)就用I3C_NO_SUBADDRESS代替。串口打印讀取到的傳感器數(shù)據(jù)時(shí)注意字節(jié)序。加速度計(jì)輸出的X、Y、Z軸數(shù)據(jù)一般是小端模式直接拼接int16_t時(shí)要小心int16_t xAxis (int16_t)(rxData[0] | (rxData[1] 8));6.3 IBI中斷處理讓傳感器主動(dòng)通知你I3C真正比I2C體驗(yàn)好得多的地方就是IBI。LIS2DUX12配置為數(shù)據(jù)就緒時(shí)通過IBI通知MCUMCU這邊不需要輪詢傳感器有新數(shù)據(jù)時(shí)它自己往總線上發(fā)起中斷請(qǐng)求。IBI的處理在中斷回調(diào)里和DAA事件區(qū)分開void HAL_I3C_NotifyCallback(I3C_HandleTypeDef *hi3c, uint32_t EventCode, uint32_t Arg) { switch (EventCode) { case HAL_I3C_EVENT_IBI_INTERRUPT: /* 傳感器有數(shù)據(jù)準(zhǔn)備好在這里讀取數(shù)據(jù) */ HAL_I3C_Read(hi3c1, 0x1A, 0, rxData, 6, 100); processSensorData(rxData); break; } }注意IBI是中斷上下文中處理的不要在回調(diào)里做耗時(shí)的數(shù)據(jù)處理比如浮點(diǎn)運(yùn)算、打印日志。正確做法是把數(shù)據(jù)從rxData拷貝到全局緩沖區(qū)置一個(gè)標(biāo)志位然后回到主循環(huán)里處理。7. 常見問題與排查技巧實(shí)錄7.1 SCL時(shí)鐘頻率不對(duì)示波器量出來差一半我剛開始配的時(shí)候發(fā)現(xiàn)設(shè)置的1MHz速率實(shí)際量出來只有500kHz甚至更低。后來查了參考手冊(cè)才明白I3C的SDR模式SCL頻率計(jì)算公式不是直接分頻還包含SCL高電平和低電平各自的保持周期。CubeMX里配置的Prescaler、SclLow、SclHigh三個(gè)值共同決定最終時(shí)鐘。手動(dòng)計(jì)算方式是SCL頻率 I3C內(nèi)核時(shí)鐘 /Prescaler × (SclLow SclHigh)。CubeMX不會(huì)自動(dòng)幫你算最終SCL頻率它只負(fù)責(zé)生成寄存器配置值。解決方式很簡單確認(rèn)I3C內(nèi)核時(shí)鐘配置正確然后用示波器實(shí)測。如果頻率不對(duì)主要調(diào)Prescaler。7.2 動(dòng)態(tài)地址分配卡死在PREPARE階段DAA流程觸發(fā)后回調(diào)一直停在不出來反復(fù)死在這里。排查下來發(fā)現(xiàn)是從機(jī)沒響應(yīng)ENTDAA命令。原因可能有兩個(gè)一是從機(jī)沒上電或者SDA接觸不良二是因?yàn)殚_啟了超時(shí)檢測但這個(gè)值設(shè)置過小設(shè)備仲裁還沒完成就觸發(fā)了超時(shí)。排查方法先用示波器看SDA上有沒有正常的仲裁波形。如果連波形都沒有先檢查引腳配置和從機(jī)電源。如果波形正常但總是超時(shí)把超時(shí)檢測關(guān)掉或者把Timeout值調(diào)大重新跑一次看看。7.3 IBI中斷頻繁觸發(fā)導(dǎo)致系統(tǒng)卡頓傳感器配置成數(shù)據(jù)就緒中斷后數(shù)據(jù)速率如果很高IBI會(huì)非常頻繁。如果主循環(huán)里處理數(shù)據(jù)的速度跟不上中斷回調(diào)不斷進(jìn)來系統(tǒng)看起來就像卡死了。解決思路有兩個(gè)方向一是降低傳感器輸出數(shù)據(jù)速率配置ODR寄存器二是把IBI的“數(shù)據(jù)已讀”機(jī)制利用好。I3C的IBI本質(zhì)上是一種中斷請(qǐng)求你清除中斷的方式就是讀取對(duì)應(yīng)狀態(tài)寄存器。如果讀完后傳感器立刻又產(chǎn)生新的中斷那確實(shí)是數(shù)據(jù)速率太高了。實(shí)測中LIS2DUX12以100Hz輸出時(shí)IBI處理完全沒問題到400Hz以上時(shí)主循環(huán)開始忙不過來這時(shí)建議通過DMA方式讀取或者降低ODR。7.4 總線上同時(shí)掛I2C和I3C設(shè)備時(shí)的坑I3C的官方宣傳說兼容I2C設(shè)備實(shí)際使用要注意I2C設(shè)備永遠(yuǎn)不會(huì)響應(yīng)ENTDAA命令但它們可能會(huì)干擾地址仲裁過程尤其是在SDA線上的行為不可預(yù)測。廠商的做法一般是把I2C設(shè)備放在I3C總線的末端并且在時(shí)序上做隔離處理。在STM32上進(jìn)行混合掛載測試時(shí)我發(fā)現(xiàn)I2C設(shè)備如果是開漏輸出、高阻態(tài)特性良好的通常沒問題。但有些老款I(lǐng)2C設(shè)備的SDA驅(qū)動(dòng)能力太強(qiáng)會(huì)導(dǎo)致I3C仲裁誤判。遇到這種情況最穩(wěn)妥的方案是I3C總線上只掛I3C設(shè)備I2C設(shè)備走獨(dú)立的I2C總線。7.5 從機(jī)動(dòng)態(tài)地址丟失熱重啟后通信失敗DAA分配的動(dòng)態(tài)地址是易失性的掉電就沒了。如果系統(tǒng)設(shè)計(jì)成傳感器不斷電、但主控重啟了那主機(jī)側(cè)的地址表就失效了。這種情況下必須在主機(jī)初始化階段重新執(zhí)行一次完整的DAA流程重新獲取所有設(shè)備的動(dòng)態(tài)地址。但在某些場景下傳感器不希望每次主機(jī)重啟都被重新分配地址比如它內(nèi)部正在跑某些需要保持狀態(tài)的算法。I3C協(xié)議里提供了Set Dynamic Address命令和Store Dynamic Address命令后者可以把動(dòng)態(tài)地址寫到設(shè)備非易失性存儲(chǔ)中。但要注意不是所有設(shè)備都支持Store功能使用前查閱數(shù)據(jù)手冊(cè)確認(rèn)。8. 實(shí)操心得從項(xiàng)目角度給三條建議I3C這套流程跑通之后回過頭來看配置本身難度不大真正折騰人的都是細(xì)節(jié)。我最后總結(jié)了三條在實(shí)際項(xiàng)目中比較有價(jià)值的經(jīng)驗(yàn)。第一條時(shí)鐘配置要從后往前推。很多人配置I3C是先隨便選個(gè)Prescaler等發(fā)現(xiàn)速率不對(duì)再去改。正確做法是先確定目標(biāo)SCL頻率再根據(jù)I3C內(nèi)核時(shí)鐘逆推Prescaler和SclLow/SclHigh的組合值。也就是先算數(shù)、再填框不要填了再看示波器。第二條動(dòng)態(tài)地址分配流程一定要做成可重入的。在真實(shí)產(chǎn)品里可能會(huì)有熱插入的設(shè)備在運(yùn)行過程中請(qǐng)求加入總線你的控制器必須能在不停機(jī)的情況下處理一次新的DAA流程。剛開始跑通一次DAA之后建議把整個(gè)流程封裝成單獨(dú)的函數(shù)把設(shè)備狀態(tài)表維護(hù)好后面加設(shè)備就不慌了。第三條I3C的調(diào)試要善用邏輯分析儀。雖然示波器能看到波形但I(xiàn)3C的協(xié)議幀比較復(fù)雜邏輯分析儀配協(xié)議解析功能比如Saleae的I3C協(xié)議解析能直接把幀結(jié)構(gòu)解析出來定位問題是哪一幀卡住效率高很多。硬件調(diào)試工具的這一筆投資絕對(duì)值得。另外如果產(chǎn)品對(duì)功耗有要求I3C也提供了低速模式和喚醒機(jī)制傳感器在待機(jī)時(shí)總線可以進(jìn)入低功耗狀態(tài)通過Wake-Up命令喚醒設(shè)備這部分配置在CubeMX里也有對(duì)應(yīng)選項(xiàng)項(xiàng)目上有功耗指標(biāo)的話建議一并研究下。