在驅動程式開發中,時鐘信號對硬體設備的重要性,猶如心臟對人體供血般不可或缺。無論設備擁有內建時鐘,還是依賴外部系統時鐘,時鐘源的正確性都是設備正常運作的基石。然而,在實際開發中,我們常面臨無法直接用示波器探測時鐘腳位的困境——或是封裝過於緊密,或是現場缺乏儀器。本文分享一套純軟體實現的時鐘頻率檢測方案,助您在無硬體儀器輔助下,精準驗證時鐘是否正常工作。
在開發多通道控制器(MCC)驅動時,我們遇到一個棘手問題:無論如何配置 MCC 參數與觸發條件,設備始終毫無反應,彷彿「僵死」一般。經排查,發現 MCC 所依賴的時鐘源 MT9045 未正確配置。該時鐘源需同時提供傳輸時鐘、接收時鐘與同步時鐘,配置極為複雜,且當時資料不足,導致長時間無法調通。急需一種方法快速驗證端口時鐘頻率是否正確輸出。
利用系統高精度計時器(Tick)作為基準時間窗,在單位時間內對目標暫存器的特定位元進行高頻採樣,統計電平翻轉次數,即可推算出該信號的近似頻率。CPU 頻率越高、系統 Tick 精度越高,測量結果越準確。
static int frequency_count(volatile unsigned long addr, unsigned int mask)
{
int t, nt, et; // 時間變數
int v, lv, cnt = 0; // 當前值、上一次值、翻轉計數
// 等待下一個 Tick 邊緣,對齊時間基準
t = Gettick();
while (1) {
nt = Gettick();
if (nt != t) break;
}
// 設定採樣結束時間:當前 Tick + 1 秒(系統 Tick 頻率)
et = nt + GetsysClkRate();
lv = v = (*(int*)addr) & mask; // 讀取初始值
// 在一秒內持續採樣
while (1) {
nt = Gettick();
if (nt >= et) break; // 時間到,結束採樣
v = (*(int*)addr) & mask; // 讀取暫存器並套用遮罩
if (v != lv) { // 偵測到電平變化
lv = v;
cnt++; // 計數器加一
}
}
return cnt / 2; // 每個週期有兩次邊緣(上升/下降),除以 2 得頻率
}
上述程式碼依賴兩個平台相關函數,需根據目標作業系統實現:
static int Gettick() {
return (int)jiffies; // 內核全域 Tick 計數器
}
static int GetsysClkRate() {
return (int)HZ; // 系統 Tick 頻率(每秒 Tick 數)
}
static int Gettick() {
return tickGet(); // 獲取系統 Tick 計數
}
static int GetsysClkRate() {
return sysClkRateGet(); // 獲取系統時鐘頻率
}
欲檢測某時鐘輸出腳位(對應記憶體映射位址的特定 Bit)頻率,呼叫 frequency_count(位址, 遮罩)。
範例:檢測位址 0xFDF90D50 的 Bit 0,呼叫 frequency_count(0xFDF90D50, 0x00000001),回傳值即為該腳位輸出時鐘的近似頻率(Hz)。
addr 必須是已映射至核心虛擬位址空間的實體位址。這套「軟體示波器」技巧,以極低成本解決了驅動開發初期時鐘驗證的燃眉之急。它不替代專業儀器,卻能在缺乏硬體條件時,快速定位時鐘源配置錯誤、信號斷路等常見問題,是嵌入式驅動工程師工具箱中極具實戰價值的一把「瑞士刀」。