運行環境: stm32h743iit6; 主頻480MHz; APB1; 240MHz; TIM5 240MHz; 預分頻系數為1; 定時器計數頻率240MHz;
應用需求:實現軟件模擬IIC,延遲精度2個微秒;
量變引起質變,當延遲粒度太小時,需要考慮延遲的實現策略是否適合。
目前的延遲策略:
-
傳統的基于定時器中斷策略;
-
polling輪詢等待策略;
對于強迫癥和完美主義的人來講,可能首選考慮的是中斷策略。但是當下形勢變化了,由于延遲時間過于短(2個微秒)所以對延遲精度要求較高。
根據當前判斷,采取的是執行polling輪詢等待策略實現。
實現正確延遲的前提是,必須保證各個節點的時鐘頻率是計算正確的符合實際的!
polling輪詢等待策略的實現
-
根據外部為 timer 提供的時鐘源速率、內部預分頻系數等計算得到定時器的計數器的運行時頻率,也就得到了1秒內計數器累加多少次的節拍; 當然可以計算獲得1微秒需要走多少個節拍,這個可能更加實用。
-
程序內延遲開始時,直接摘取定時器計數器的當前值,作為開始的測量點;延遲結束后,再次直接讀取定時器的計數器的當前值作為結束的測量點; 由此得到,延遲過程中定時器的計數器走過多少個節拍,也就是累加的增量是多少個。
-
根據前兩步得到的,延遲總節拍數除以1微秒的節拍數就可以知道此過程延遲了多少個微秒。
注意:延遲過程內的代碼應該盡量簡潔,就是不要執行過多的不處于測量范圍內的CPU指令,否則這部分也會被算進去導致測量有誤差。
測量時代碼實現上:
-
計算延遲 n 微秒需要的總步長,n*STEP,也就是計數器應該累加的增量值N;
-
將當前定時器的計數器的數值設置為零,從零開始計數;
-
polling輪詢 計數器的值 與 N 作比較,使其在不少于N的范圍內繼續等待,否則延遲時間達到,跳出延遲代碼;
-
可以將受保護的代碼使?禁?中斷保護起來,運?結束再開啟中斷;
void delay_us (uint32_t us)
{//可以禁用中斷,保證不可打斷volatile uint32_t ticks = us * STEP_OF_TIM5_CNT;TIM5->CNT = 0;while (TIM5->CNT < ticks);//可以禁用中斷,保證不可打斷,且需要覆蓋下面延遲的目的代碼:比如IIC的電平轉換,以保證效果。}
如何測量延遲是否準確
測量延遲節拍數是否符合預期
原理前面講了,可以通過調試軟件觀察得到節拍數,進行驗證。
使用keil仿真調試
可以使用keil仿真觀察直接顯示的時間結果數據。在此之前,需要正確設置好keil,且確保MCU內有ARM debug IP core 的DWT(debug watch point)IP core支持,因為keil就是通過 jlink、stlink 間接獲取DWT的計時數據。那么如何設置好keil呢?這里參考了魚鷹的微博寫的很好,做簡明描述:
實際測試數據
案例2
案例3
案例4
這次延遲5000個微秒,誤差只有1.30個微秒,屬于正常剛好跟上?的誤差延遲對應。說明?較準確了。可能上次有進出中斷導致誤差太?了!。