5

Supermicro X7DWA マザーボードのWinbond W83793 チップからOpenHardwareMonitorに温度データを読み取らせようとしています。問題は、私には低レベルのプログラミング経験がなく、オンラインで入手可能なドキュメントが温度へのアクセス方法を説明するのに十分ではないように思われることです。

しかし、この問題に取り組んできた 1 か月間、問題を解決する鍵となる可能性のある値と低レベルのメソッドをいくつか発見しました。必要なものを得るためにそれらを使用する方法を理解する必要があります。私とは異なり、あなたはこの情報が何を意味し、どのように適用するかを理解しているかもしれないので、私はあなたに頼ります. 私はすでにかなりの部分を突っついてきましたが、その結果、多くのブルースクリーンとコンピューターの再起動が発生しました。十分に推測して、これらの手がかりをつなぎ合わせる必要があります。これが私がこれまでに知っていることです:

  1. チップから読み取るには、どうにかして SMBus にアクセスする必要があります。これは、CPUID HWMonitor などの監視プログラムが情報を取得する方法だからです。私の知る限り、OpenHardwareMonitor には SMBus にアクセスするためのコードが含まれていないため、チップから読み取れない可能性があります。ただし、OpenHardwareMonitor には、他のチップからの情報にアクセスするために使用するRing0 クラスに含まれる次のメソッドがあります。これらの方法を有利に使用できる場合があります。

    void Ring0.WriteIOPort(uint port, byte value);
    byte Ring0.ReadIOPort(uint port);
    
  2. レポートを保存すると、HWMonitor は Winbond W83793 チップに関する次の情報をレポートします。

    レジスタ空間: SMBus、ベースアドレス = 0x01100

    SMBus リクエスト: チャネル 0x0、アドレス 0x2F

    これらは重要な値のように見えますが、それらが何を意味するのか、上記の Ring0 メソッドと組み合わせてどのように使用できるのか正確にはわかりません。うーん...非常に多くの手がかり。HWMonitor が表示する他の値は、実際の電圧、温度、ファン速度、およびチップ上のどこかからのデータを表す 16 進数値の配列です。見たい場合はここで再現します。

  3. 最後に、W83793 データ シートの 53 ページ (ドキュメントを開いている場合) に、私が読みたい温度の 16 進数のアドレスがあります (私は信じています)。

    TD1 読み出し - バンク 0 アドレス 1C

    TD2 読み出し - バンク 0 アドレス 1D

    TD3 読み出し - バンク 0 アドレス 1E

    TD4 読み出し - バンク 0 アドレス 1F

    下位ビットの読み出し - バンク 0 アドレス 22

    TR1 読み出し - バンク 0 アドレス 20

    TR2 読み出し - バンク 0 アドレス 21

これまでのところ、私が知っているのはそれだけです。OpenHardwareMonitor、W83793 チップ、および Ring0 コードは、上記のリンクから入手できます。先ほど言ったように、私は 1 か月間取り組んできましたが、まだこの謎を解くことができていません。あなたが私を助けてくれることを願っています。これらの情報はすべて少し難解に思えるかもしれませんが、低レベルのプログラミング経験がある人にとっては理解できると確信しています。

私の質問を要約すると、上記の手がかりを使用して、OpenHardwareMonitor に W83793 チップから温度を読み取らせる方法を見つけてください。OpenHardwareMonitor でのチップの作成に関する詳細は必要ありません。すでにクラスの準備ができています。それが必要な場合は、Ring0コマンドを書き込むためのシーケンスとフォーマットが必要です。

編集:さらに情報が見つかりました。HWMonitor から SMBus デバイス レポートを出力したところ、0x2F と表示されているため、ここに含まれている次の行が得られました。

SMB デバイス: I/O = 0x1100、アドレス 0x2F、チャネル = 0

これは、I/O のアドレスをチップのアドレス (0x2F と思われる) と組み合わせる必要があることを意味しているに違いありません。それらを合計してみましたが、すべての温度測定値が 255 になったので、それは正しい推測ではありませんでした。

4

2 に答える 2

4

IO メソッドが必要です。x86 ハードウェアには、実際には 1 つではなく 2 つのアドレス プールがあります。1つはメモリ用で、命令を読み取るときにチップによって参照され、何千もの便利で便利なアクセス方法があります。もう 1 つは、外部チップのアドレス指定を目的としており、読み取りおよび書き込み操作のセットが非常に限られており、比較的低速です。識別した方法により、2 番目の領域にアクセスできます。

読み取りたいレジスタはバンク 0 にあるため、最初に 12 ページに従って、チップのバンク 0 を選択する必要があります。セクション 8.1.2.1 の図に従って、アドレス 00 に 0x80 を書き込む必要があります。チップのベース アドレスは 0x01100 です。これは、 WriteIOPort.

ReadIOPortその後、0x01100+0x1c、0x01100+0x1d などから必要な値を読み取ることができるはずです。

リンク先のドキュメントを完全に理解する時間はありませんでしたが、それは妥当な推測です。一部のチップには、値を書き込んでから結果を確認する必要がある、少し複雑な手順がありますが、ドキュメントにはそのようなものはありません。また、マルチタスクにも注意する必要があります。バンク 0 の設定と関連するレジスタの読み取りの間にコードが中断された場合、その間の何らかのプロセスが他のバンクを設定し、読み取った値が任意の他の値になる可能性があります。OpenHardwareMonitor にはそれに対処するための何らかのメカニズムがあると思いますが、純粋にユーザー空間の実装をすばやく試して、時々奇妙な結果が得られる場合は、覚えておく価値があります。

于 2011-08-22T19:04:50.067 に答える
2

最後に、OpenHardwareMonitor の作成者に親切に助けてもらい、チップから温度を読み取ることができるようになりました。この問題の全体的な解決策はもう少し複雑で、まだ私には理解できませんが、興味のある方のために、Ring0 クラスを使用した基本的な読み取りと書き込みを次に示します。これは私のマシンとチップに固有のものであることに注意してください。ベース アドレスとスレーブ アドレスは異なる場合がありますが、レポートを印刷することで、CPUID HWMonitor を使用して見つけることができます。

まず、使用された定数は次のとおりです。

private const int   BASE_ADDRESS    = 0x1100;
private const uint  SLAVE_ADDRESS   = 0X2F; // as we figured out already
private const byte  HOST_STAT_REG   = 0;    // host status register
private const byte  HOST_BUSY       = 1;    
private const byte  HOST_CTRL_REG   = 2;    // host control register
private const byte  HOST_CMD_REG    = 3;    // host command register
private const byte  T_SLAVE_ADR_REG = 4;    // transmit slave address register
private const byte  HOST_DATA_0_REG = 5;  
private const byte  BYTE_DATA_COMM  = 0x08; // byte data command
private const byte  START_COMM      = 0x40; // start command
private const byte  READ            = 1;
private const byte  WRITE           = 0;

次に、チップ上のレジスタから特定のバイトを読み取るための基本的なコードを次に示します。

// first wait until ready
byte status;
do
{
  status = Ring0.ReadIoPort(BASE_ADDRESS + HOST_STAT_REG);
} while ((status & HOST_BUSY) > 0);
if ((status & 0x1E) != 0)
{
  Ring0.WriteIoPort(BASE_ADDRESS + HOST_STAT_REG, status);
}

// now get the value
Ring0.WriteIoPort(BASE_ADDRESS + HOST_DATA_0_REG, 0);
Ring0.WriteIoPort(BASE_ADDRESS + HOST_COMM_REG, theRegister)
Ring0.WriteIoPort(BASE_ADDRESS + T_SLAVE_ADR_REG, 
            (byte)((SLAVE_ADDRESS << 1) | READ));
Ring0.WriteIoPort(BASE_ADDRESS + HOST_CTRL_REG,
            START_COMM | BYTE_DATA_COMM);
Ring0.ReadIoPort(BASE_ADDRESS + HOST_DATA_0_REGISTER); // this returns the value

// now wait for it to end
while ((Ring0.ReadIoPort(BASE_ADDRESS + HOST_STAT_REG) & HOST_BUSY) > 0) {}

私はそれをよく理解していませんが、これは、同様の問題を抱えている私よりも低レベルの経験を持つ人への大まかなガイドとして役立つ可能性があります.

于 2011-08-25T18:53:41.723 に答える