3.3 V ノイズジェネレータ (13)

STM32 の SPI モジュールに内蔵されている CRC 計算回路は、CRC 計算としては 8/16 ビットに限定されますが、CRC 入力データとして「0」(または「1」) の連続として、単なる LFSR として使う場合には 8/16 ビットに限定されずに使えることが分かりました。
これを利用して、STM32F103xx の High density デバイスDAC モジュールに内蔵されている雑音波形出力モードを擬似的に実現してみました。
以前のプログラムで 16 ビット生成多項式を設定している部分を次のリストのように変更するだけです。

// 12-bit generator polynomial for DAC module
//
// g(x) = x^12 + x^6 + x^4 + x + 1
//      = {12, 6, 4, 1}
//      = 0x0053

#define GX12_INIT (0x0053 << 4)

  ... <中略> ...

void SPI_configuration()
{
  ... <中略> ...

  SPI_InitStruct.SPI_CRCPolynomial = GX12_INIT;

  ... <中略> ...
} // void SPI_configuration()

ただし、STM32F103xx の High density デバイスの実際の DAC モジュールとは、以下の点が異なっていると思われます。

  • 12 ビット DAC 回路のノイズ発生回路は Fibonacci 型の LFSR であるが、SPI モジュールの CRC 計算回路は Galois 型なので、m-系列としての周期は 4095 で一致するが、シーケンスの順序自体は一致しない。
  • SPI の 16 ビット CRC 計算回路では、16 ビット分の計算が終了した段階での値が得られるので、毎回の計算結果のシーケンスは、本来のシーケンスを 16 個ごとにサンプリングしたものに相当する。
  • さらに、外付けシリアル DAC に SPI を通じて L ch には 32 ビット CRC 計算回路で生成したシーケンス、 R ch には SPI の受信 CRC 計算回路で生成したシーケンスを送信しているため、受信 CRC 計算結果の半分は捨てていることになる。
    これを考慮すると、本来のシーケンスを 32 個ごとにサンプリングしたシーケンスに相当する。

m-系列としての周期は 212-1 = 4095 で奇数であり、25 = 32 とは「互いに素」なので、32 個ごとにサンプリングされた形になっても、周期自体は 4095 で変わりありません。
結果のホワイトノイズを、いつものように WaveSpectra で観測した結果を下に示します。

赤い線が CRC 計算モジュールを使った場合の 32 ビット m-系列のスペクトラムで、青い線が SPI 内蔵 CRC 計算回路による 12 ビット m-系列のスペクトラムです。
16-ビット・ディジタル・オーディオ用 DAC BU9480F の左右のチャンネルにそれぞれのノイズ系列を同時に出力しています。
高域でレベルが落ちているのは DAC の BU9480F 自体の特性によるものです。
ゲインが少し違っていますが、12 ビット系列の方は、Blackman-Harris ウィンドウをかけてスペクトラムを表示させており、32 ビット系列の方は flat top ウィンドウをかけて観測しているために生じたものです。
いずれもアベレージ機能で 300 回の平均を取ったものを表示しています。
12 ビット系列のレベルが数 100 Hz 以上の部分でデコボコしているのは、クシの歯状のスペクトラムを表示解像度に合わせるための平均化操作によって生じている「見かけ」のものです。
12 ビット系列を周波数軸をリニアスケールで 100 〜 200 Hz まで表示したものを下に示します。

基本波周波数 48 [kHz] / (212-1) = 11.72... [Hz] の整数倍のところに線スペクトルが存在する構造がはっきりと見えます。
「音」としては、約 0.1 秒周期の「ループ感」が耳につき、均質なノイズとは言いがたく、オーディオ用としては、ループ感を感じないような短いエンベロープを掛けて使う以外には、実用にならないと思います。
STM32F103xx の High density デバイスDAC モジュールには、これに加えて、ハードウェア三角波発生機能があります。
これは、内部のアップダウンカウンタにより、0 からカウントアップしていき、カウントが最大値に達すると、カウントダウンに切り換わり、0 までカウントダウンしていく繰り返しで三角波を発生するものです。
カウントアップする最大値は 21-1=1 から 212-1=4095 まで 12 種類選択可能で、発生させた三角波DAC データレジスタに設定した値に加算して最終的な DA 変換のデータとするものです。
ユーザーマニュアルを読む限り、このカウンタの増分は、選択したクロック1発に対して +1、-1 のいずれかに固定されているようで、たとえばクロックの周波数を 48 kHz、三角波の上限値を 4095 とすると、三角波の周波数は
    48 [kHz] / (2 * 4096) = 5.859... [Hz]
となりますから、周波数的には、ビブラートやトレモロなどの「音楽的」な効果のための LFO に適しています。
「効果音」的な目的で 100 Hz 程度の周波数を得ようとすれば、クロック周波数を 800 kHz 程度に選ぶ必要があります。
このクロック源は、ソフトウェア・トリガ、外部クロック、6 本の内蔵タイマのトリガ出力イベントのいずれかを選択することができます。
DAC モジュールでのノイズ発生や、三角波発生はオマケみたいなもので、重要なのは、この内蔵タイマで発生させたクロックで DA 出力更新のタイミングをトリガできることです。
単に出力ポートに DA 変換ネットワークが接続されていて、「素通し」の構成では、CPU が DA 出力ポートにデータを書き込むソフトウェア的なタイミングが、DA 出力のアナログ信号のタイミングにダイレクトに影響する形になります。
ソフトウェアでは、割り込みにしろ、ポーリングによるフラグの監視にしろ、応答のタイミングには不確定さがともない、結果として出力のアナログ信号にジッタが乗る可能性があります。
STM32F103xx の High density デバイスDAC モジュールでは、タイマで発生させたハードウェア・タイミングで DA 出力更新タイミングをコントロールできるので、ジッタが乗らないようにできます。
もちろん、「素通し」の状態の設定もできるようになっています。