DDS IC「AD9833」の周波数レジスタ書き込みで
Arduino UNO R4 minimaの1MHz波ビート音実験で
急ぎでっちあげたアナデバのDDS IC「AD9833」。
Arduino UNOで制御する時にちょいと気になる
ことがありました。
・・・たいしたことじゃないけど
AD9833の周波数レジスタは28bitで、LSBとMSBに
分けて2回、14bitで書き込みを行います。
こんな感じ。
AD9833ctrl(0x2000); // B28 on コントロール
spi16(0x4000 | (d & 0x3FFF)); // ch0 LSB 14bit
spi16(0x4000 | ((d >> 14) & 0x3FFF)); // MSB 14bit
「d」が32bit(つまり4バイト)の書き込みデータで、
最初に「これから2回のデータを書くで」っという
制御コード(B28 on)を送ってから、LSB、MSBの順に
14bitのデータをSPIで書き込みます。
このタイミングをオシロで見たら、SPIの間隔がずいぶん
空いていたのです。
16bitのSPI転送は5μsほどなのに、
LSBとMSBのあいだが9μsほどに
広がっていました。
32bit値を右に14bitシフトする「(d >> 14)」に、
いがいと時間がかかります。
このようにコードが展開されてました。
bae: ldi r17, 0x0E ;14
bb0: lsr r7
bb2: ror r6
bb4: ror r5
bb6: ror r4
bb8: dec r17
bba: brne .-12 ;0xbb0
bbc: ldi r24, 0x3F ;上位3Fでマスク
bbe: and r5, r24
bc0: movw r24, r4 ;R5,R4をR25,R24に
;コピーしてspi16()へ
ここで時間がかかっているのが
32bitデータを保持しているR7,R6,R5,R4レジスタの
14回のシフト。
シフト命令もDEC命令も1クロック。
loop中のBRNEが2クロック。
7クロックが14回で98クロックを要します。
そこで、ちょっとでもスピードアップということで、
14bitのシフト方法を変えてみました。
uint16_t a; // 2バイトの一時レジスタ
AD98ctrl(0x2000); // B28 on コントロール
spi16(0x4000 | (d & 0x3FFF)); // ch0 LSB 14bit
d = d << 2; // d >> 14のかわり
a = d >> 16; // シフト2回とレジスタ交換に
spi16(0x4000 | (a & 0x3FFF)); // MSB 14bit
これだと、このように展開されて、シフト回数が2に
なり、ちょいとだけ高速化できます。
bae: ldi r17, 0x02 ; 2
bb0: add r4, r4
bb2: adc r5, r5
bb4: adc r6, r6
bb6: adc r7, r7
bb8: dec r17
bba: brne .-12 ; 0xbb0
bbc: movw r24, r6
bbe: andi r25, 0x3F
さらに「d = d << 2;」という2bitのシフトを、
「d <<= 1; d <<= 1;」と2つに分割してたら
ldi r17,1
dec r17
brne .-12 が無くなるかと
期待したのですが、同じコードに展開されました。
brneを使う方が1命令少なくなります。
オシロで見るとこんな波形。
上段の(d >>14 )のところ、なぜか広いので
「これはなんだろか?」っと思いませんか?
気になってコードを見たら、14回のループに
時間がかかっていたというお話しでした。
※関連
・2025年5月21日:Arduino UNO R4 minima 電源供給方法でクロックが変わる#4
| 固定リンク
「Arduino」カテゴリの記事
- UNO R4はanalogWrite(n,128)でデュティー50%の方形波が出るぞ(2025.06.03)
- DDS IC「AD9833」の出力にバッファアンプを(2025.05.27)
- DDS IC「AD9833」をArduino UNO R3で制御(2025.05.25)
- DDS IC「AD9833」の周波数レジスタ書き込みで(2025.05.23)
- Arduino UNO R3で周波数を計る(2025.05.16)
コメント