発振回路

2026年3月12日 (木)

1Hzパルス発生回路改造

2026年2月 1日:備忘録:1Hzパルス発生回路
ATtiny402を使った1Hzパルス発生回路
これをちょっと手直ししました。
 ・空いている3つのポートを入力にして
  ロータリーDIPスイッチを接続。
 ・「0~7」の3bitで8種類の発生周波数を設定。
 ・オシレータ出力を増幅していた
  74LVC1GU04を74HC1GU04に交換。
    LVCだと電流消費大だった!
てな、手直しを施しました。

8種類の固定周波数しか出せませんが、安定した
60Hz(地元の電源周波数)が欲しかったので、
1Hzだけよりはマシかと、手持ち部品を活用しま
した。
まず回路図。
1hz10

電源は5V。
12.8MHzの発振モジュールは秋月で購入。

小さなプラ箱に入れてます。
1hz12

中の様子。
1hz11_20260312144301

Arduino IDE環境での制御スケッチ。

/**************************/
/* 方形波発生回路 */
/**************************/
// "TINY402_1HZ02.ino"
// 2026-03-12
// 12.8MHz TCXOをクロックに
// DSW(0~7)の設定で方形波を出力
// 0 1Hz
// 1 10Hz
// 2 50Hz
// 3 60Hz (60.000375Hz)
// 4 100Hz
// 5 120Hz (120.00075Hz)
// 6 440Hz (440.01375Hz)
// 7 1kHz
/***** 分周データテーブル *****/
// 周波数発生モードなので12.8MHzを1/2した
// 6.4MHzを原発振周波数と考える
const struct{
const word cmp0; // TCA0 CMP0データ 1/(n-1)
const byte clksel; // プリスケーラ設定値 + ENABLE(b0)
// 1/1,2,4,8,16,64,256,1024
}frq_tbl[] = {
{ 6250 - 1, 0b00001111 }, // 0 1Hz 1/1024 6250Hz
{ 2500 - 1, 0b00001101 }, // 1 10Hz 1/256 25kHz
{ 64000 - 1, 0b00000011 }, // 2 50Hz 1/2 3.2MHz
{ 53333 - 1, 0b00000011 }, // 3 60Hz 1/2 3.2MHz
{ 64000 - 1, 0b00000001 }, // 4 100Hz 1/1 6.4MHz
{ 53333 - 1, 0b00000001 }, // 5 120Hz 1/1 6.4MHz
{ 14545 - 1, 0b00000001 }, // 6 440Hz 1/1 6.4MHz
{ 6400 - 1, 0b00000001 }, // 7 1kHz 1/1 6.4MHz
};
/***** DSW読み込み *****/
// 0~7を返す
// PORTA offで1 onで0
// PA2:DSW-1 PA6:DSW-2 PA7:DSW-4
byte inpdsw(void)
{
byte n;
byte d = 0; // リターンデータ
n = ~PORTA.IN; // ポートA反転して入力
if(n & 0b00000100) d |= 1; // DSW-1
if(n & 0b01000000) d |= 2; // DSW-2
if(n & 0b10000000) d |= 4; // DSW-4
return d;
}
// こんなコードに展開されていた
// 90 91 08 04 lds r25, 0x0408 ;PORTA.IN
// 90 95 com r25
// 92 fb bst r25, 2 ;2
// 88 27 eor r24, r24
// 80 f9 bld r24, 0 ;1
// 96 fd sbrc r25, 6 ;6
// 82 60 ori r24, 0x02 ;2
// 97 fd sbrc r25, 7 ;7
// 84 60 ori r24, 0x04 ;4
// 08 95 ret
// bld,bst命令が珍しい
/***** DSWデータ *****/
byte dsw_now; // 安定した現在値(0~7)
byte f_dswok; // 変化確定フラグ dsw_nowに安定値
/***** DSW変化チェック *****/
// 確定したらf_dswokを1に dsw_nowが確定値
// PITの1024Hz周期で実行
void chkdsw(void)
{
static byte exc; // 実行区分
static byte tm; // 1msタイマ
// PITの1024Hz周期でダウンカウント
static byte chk; // DSW入力安定チェックデータ
byte d;
d = inpdsw(); // DSWデータ入力
if(tm) tm--; // DSWチェックタイマダウンカウント
switch(exc){
case 0: // 変化チェック
if(dsw_now != d){ // DSW変化あり
chk = d; // チェックデータ
tm = 20; // 20ms
exc = 1;
}
break;
case 1:
if(chk != d){ // 変化続く?
chk = d; // チェックデータ再セット
tm = 20; // タイマも再セット 20ms
}
else{ // 安定
if(tm == 0){ // タイムアップ
dsw_now = d; // 新DSW値
f_dswok = 1; // 確定フラグをon
exc = 0; // 次の変化待ちに
}
}
break;
}
}
/***** 周波数設定 *****/
// d:DSW設定値 0~7
// 分周値は-1してある CMP0にセット
void setfrq(byte d)
{
TCA0.SINGLE.CTRLA = 0; // TCA0 タイマー停止
TCA0.SINGLE.CMP0 = frq_tbl[d].cmp0; // 分周値
TCA0.SINGLE.CNT = 0; // カウント 0から
TCA0.SINGLE.CTRLA = frq_tbl[d].clksel; // プリスケーラ+ENABLE
}

/***** SETUP *****/
void setup() {
cli(); // 割込禁止
// ポート設定
PORTA.DIR = 0b00000010;
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin out WO1 波形出力
// || |+------ PA2 5pin in DSW-1
// || +------- PA3 7pin in 12.8MHzクロック入力
// |+---------- PA6 2pin in DSW-2
// +----------- PA7 3pin in DSW-4
PORTA.PIN2CTRL = 0b00001000; // PA2 5pin DSW-1
PORTA.PIN3CTRL = 0b00001000; // PA3 7pin CLKIN
PORTA.PIN6CTRL = 0b00001000; // PA6 2pin DSW-2
PORTA.PIN7CTRL = 0b00001000; // PA7 3pin DSW-4
// +----- pull up有り
// クロック設定 PA3/CLKINに12.8MHz
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); // プリスケーラなし
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, 3); // 外部からクロック
// タイマーTCA0, 分割モードで初期化されるので16bitモードに
TCA0.SPLIT.CTRLA = 0; // タイマー停止
TCA0.SPLIT.CTRLESET = 0x0F; // 強制リセット
PORTMUX.CTRLC = 0; // TCAポート多重切り替えなしに
// タイマ設定
TCA0.SINGLE.CMP1 = 0; // PA1 4pin WO1
TCA0.SINGLE.CTRLB = 0b00100001;
// ||||+++----- WGM 波形生成FRQ(周波数)
// |||+-------- ALUPD
// ||+--------- CMP0EN
// |+---------- CMP1EN PA1 4pin WO1 出力
// +----------- CMP2EN PA2 5pin
// DSW(0~7)で周波数を設定
dsw_now = inpdsw(); // DSW値(0~7)
setfrq(dsw_now); // 8選択で1Hz~1kHzセット
// RTC,PIT 有効に
while((RTC.STATUS & 0x0F) || // RTC busy ?
(RTC.PITSTATUS & 1)); // PIT busy ?
// PIT分周操作
RTC.PITCTRLA = 0b00100001;
// |||| +-- PITEN PIT有効
// ++++----- PERIOD 1/32 →1024Hz
sei(); // 割込有効
}

/***** LOOP *****/
// DSWの変化をチェック
void loop() {
if(RTC.PITINTFLAGS & 1){ // 1024Hz(約1ms)周期
RTC.PITINTFLAGS = 1;
chkdsw(); // DSW変化チェック
}
if(f_dswok){ // DSW変化あり
f_dswok = 0;
setfrq(dsw_now); // 1Hz~1kHz周波数セット
}
}
#if 0
最大4096バイトのフラッシュメモリのうち、
スケッチが534バイト(13%)を使っています。
最大256バイトのRAMのうち、グローバル変数が
5バイト(1%)を使っていて、ローカル変数で
251バイト使うことができます。
#endif
// end of "TINY402_1HZ02.ino"

inpdsw()関数の下にあるコメントに書きましたが、
DSWのビット操作で「bst」と「bld」命令が出て
おりました。
ステータスレジスタの「Tフラグ」の応用、珍しい
のじゃないでしょか。

・Arduino IDEの設定
Ide_set02

書き込みはMPLAB@SNAPで。

※チャタリング対策
ロータリーDIPスイッチ、一般的なスイッチのチャタリング
除去だけじゃなく、回転が安定したことを確かめてから
設定値を更新しなくちゃなりません。
こんな手順です。
 ・約1ms周期でポートからDSWの値を入力。
 ・確定データから変化したかをチェック。
 ・変化があればそれをメモ。
 ・20msタイマをセット。
 ・メモしたのと変化があればタイマを再セット
  してチェック時間を延長。
 ・変化が無ければ(20m間)安定したと判断して
  確定データを更新し、新しくなったことを
  フラグで知らせる。
普通はタイマ割り込み内で処理するのですが、
今回は、他に時間がかかる処理が走っていないの
でメインループで処理しました。
  メインの処理はこれだけなんで。

実際の波形を見てもらいましょう。
I11_20260313105301

上側のch1は方形波出力。
設定7の1kHzと設定6の440Hzが見えています。

下側の波形はスイッチのbit0。
 設定7ならLレベル。
 設定6ならHレベル。
設定の変化から20ms後に周波数が変わっています。

そこにチャタリングを加えます。
 ・「チャタリング除去回路」じゃなくって「チャタリング発生回路」をどうぞ

I12_20260313105501
bit0がバタバタしてる間は周波数は変化しません。
20ms間落ち着いてから周波数を変えています。

| | コメント (0)

2026年2月20日 (金)

ATtiny3224で裸の32bit周波数カウンタ #3

ATtiny3224で裸の32bit周波数カウンタ
ATtiny3224で裸の32bit周波数カウンタ #2
ここでは32.768kHzの時計用水晶発振子
基準クロックにして1秒ゲートを作り、
周波数を計れるようにしました。

これとは違うアプローチで、時計用水晶をやめて
マイコンの主クロックを
 TCXO(Temperature Compensated crystal Oscillator)
にして試してみようと、部品を手配。
共立から ECS-TXO-3225MV-100-TR という
10MHzの1.7V~3.6Vで使える「3225」サイズ
のを買ってみました。

とりあえず発振実験なんですが・・・
  ・・・ピッチ変換基板をどうしよう。

手持ちのをあれこれ探して、これで行こうと
なったのが「SOT-23-6」の変換基板。
この2ピンと5ピンのパターンを削ってハンダ付け。

Tcxo

TCXOを2つ買って、出てきた周波数、
うちの周波数カウンタでの計測値は
 10.000005MHz +0.5PPM
 10.000017MHz +1.7PPM
となりました。
TCXOのスペックでは、
 Frequency Tolerance(@+25℃±2℃) ±1.5 PPM
となってますんで、使ってる周波数カウンタの
精度が「どや?!」っとなってしまいます。

これを使っての周波数カウンタ実験はもうちょい先。

※続き
ATtiny3224で電源周波数測定を試す
ATtiny3224で電源周波数測定を試す #2

| | コメント (1)

2026年2月 1日 (日)

備忘録:1Hzパルス発生回路

トランジスタ技術2025年10月号
特集 今マイコンはArduinoが最強説』からみの備忘録。

p.121 図8 時計用水晶発振子を使った1Hzパルス発生回路
これの亜種を紹介しておきます。

記事では「HC4060」を2段接続して32.768kHzから
1Hzを得ました。
1hz_osc

これと同じ機能を得ます。
まずは、HC40460と「1G80」の組み合わせ。
1h31

次の2つは12.8MHzの高精度発振器を使って1Hzを得ます。
HC4060と10進カウンタHC393の組み合わせ。
1h32
単純に1Hzを得るためですが、ICの数が多くなります。

最後がマイコン。
1h33
水晶発振モジュールから出てくるのは、アナログ波形
なんで、マイコンのクロックとして使うには信号レベルを
大きくしなければなりません。
「1GU04」で増幅しています。

// ATtiny402で1Hzを作る(Microchip Studio)
#include <avr/io.h>
int main(void) {
PORTA.DIR = 0b11000110; // ポートの入出力
// || |||+---- PA0 6pin in UPDI
// || ||+----- PA1 4pin out 1Hz出力 (CMP1)
// || |+------ PA2 5pin out 1Hz出力 (CMP2)
// || +------- PA3 7pin in CLKin 12.8MHz発振器入力
// |+---------- PA6 2pin out (-)
// +----------- PA7 3pin out (-)
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); // プリスケーラなし
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, 3); // 外部からクロック
TCA0.SINGLE.CMP0 = 6250 - 1; // CMP0出力 1Hz
TCA0.SINGLE.CMP1 = 0; // PA1 4pin
TCA0.SINGLE.CMP2 = 3125; // PA2 5pin (1/4位相差)
TCA0.SINGLE.CTRLB = 0b01100001;
// ||||+++----- WGM 波形生成FRQ(周波数)
// |||+-------- ALUPD
// ||+--------- CMP0EN
// |+---------- CMP1EN PA1 4pin 出力
// +----------- CMP2EN PA2 5pin 出力
TCA0.SINGLE.CTRLA = 0b00001111;
// |||+----- ENABLE 動作開始
// +++------ CLKSEL プリスケーラ1/1024
while(1){ } // PA1,PA2に1Hzを出力し続ける
}

 

1hz11

配線して組み立てる工数からはマイコンを使うのが
いちばん簡単。
でも「チップにプログラムを書き込む」という壁が
存在します。

| | コメント (0)

2025年7月 3日 (木)

DDS IC「AD9833」をArduino UNO R3で制御:箱入れ #2

DDS IC「AD9833」をArduino UNO R3で制御:箱に入れる
ここからちょっと手直し。
 ・高い周波数で方形波を出力するとちゃんとした
  波形が出てこない。原因はアンプの飽和。
 ・AD9833の出力、正弦波と三角波だとおよそ
  0.6V(p-p)なのが、方形波だと電源電圧フルスイング
  になってしまう。
 ・このため、前の回路では前段のアンプ(4V(p-p)まで増幅)
  が飽和。
 ・そこで、方形波の時にレベルを下げるような細工
  を入れ込む。
 ・使ったのは2入力のアナログマルチプレクサ。
    74LVC2G53 8pinのIC
      「2G」なんで2ゲートかと思いきや
      機能ブロック的には一つだけ。
      なんかへんな感じ。
 ・方形波を出力する時は、出力レベルを1/9した側に
  切り替える。
 ・飽和しないしLPFを通らないので、まっとうな
  方形波(今度はアンプでの帯域制限)が出るように。

ということで、こんな回路になりました。
  ※回路変更あり(一連のコメントを参照)
Ad9833
・BSch3Vのデータ
   ・ダウンロード - ad9833_04.ce3

・切り替え機能を追加したスケッチ。
   ・ダウンロード - ad9833_03.zip

・HEXファイル
   ・ダウンロード - ad9833_03_hex.zip
 AD9833_03.ino.hex
 AD9833_03.ino.with_bootloader.hex
この2つ。

AD9833を使う時の参考にどうぞ。

周波数を高くするときにいるのは、やっぱ、フィルタです。
これ以上の高速アンプは電気食いだし、電池運用はちょい
としんどいか。

※回路図をちょっと訂正
LVC2G53の手前の2段CRフィルタ。
マルチプレクサの入力容量がけっこうあるようなので
(データシートでオン時約20PF)フィルタ部を変更しました。
9833a
  入力部の抵抗を200Ω→1Kに。
  コンデンサをなしに。
1MHzあたりからレベルが落ち始めます。
4MHzになると出力電圧はほぼ半分に。

※追記
AD9833の出力を
  ・出力レベルを可変したい
  ・出力ののDCオフセット電圧を可変したい
ときの方法、面倒でもこんな構成かと。
Pm4
方形波の時はLPFを通さずできるだけ「生」信号
を使えるよう、MPXで分けます。
正弦波、三角波の時だけLPFを通します。
12dB/octので描きましたが、2段にして24dB/octや
LCフィルタでも良いわけです。
方形波出力のとき、後段アンプを飽和させないように
します。
  飽和させると電源ラインが汚くなります。
周波数が高くなると、高抵抗が使えなくなるので
ボリュームの入力部が面倒になります。

現スケッチのままで動くように
 マルチプレクサのプルアップ抵抗をプルダウンに。

04a


| | コメント (31)

2025年6月30日 (月)

DDS IC「AD9833」をArduino UNO R3で制御:箱に入れる

DDS IC「AD9833」をArduino UNO R3で制御
DDS IC「AD9833」の出力にバッファアンプを
DDS IC「AD9833」の出力にバッファアンプを #2

この時は、むき出しのユニバーサル基板でした。
便利に使おうとすると、
 ・箱に入ってて欲しい
 ・電池運用したい
となってしまいます。

百均屋で買ってきた透明樹脂の「箱」に入れました。
  回路は、元のとほぼ同じ。
  出力アンプはOPA2863で。
  1MHzちょいが安定して出ればOK。
  ほんとは出力レベルを可変したかったけど、
  DCオフセットの調整だけ。

Sw11
手組みした基板の様子。
Ss12_20250630150301
回路図。 (クリックで拡大↓)
Ad9833_dds03
スケッチ
  ・ダウンロード - ad9833_02.zip

AD9833のクロックをATmega328Pから出してますんで
ヒューズを書き換えて、16MHzクロックを出すようにし
なくちゃなりません。
  テストするだけならPB1に出してる8MHzも
  使えます。

役に立つかどうかは不明ですが、周波数スイープ機能を
入れてます。
  ラジオのIFトランスの調整あたりに
  使えないかなぁ。
ジャンクボックス内で拾った455kHzのセラミック・フィルタ
とTrラジオのIFTで試してみました。
Sw13

Sw14
フィルタの中心、455kHzが見えています。

スイープ速度を速くすると、周波数計算を行っている
サイクルが見えてきます。
Sw15
計算はもっと早くできるんですが液晶表示が遅い。
液晶表示は0.1秒に1回。

もうひとつ。
AD9833をはじめ、さまざまなDDS IC、無線家の皆さんが
VFOとして使われることが多いようで「スプリアス」を
気にされています。
しかし・・・原理的に、クロック周波数に近い、高い周波数
を出そうとすると、DDS処理に絡むジッタの割合が大きく
なり、きれいな波形が得られません。

これ、正弦波じゃなく方形波(DACデータのMSB)で見ると、
「なんじゃこりゃ」が見えてきます。
今回の回路では16MHzが基準クロック。
割り切れる8MHzや4MHz、2MHz、1.6MHz、1MHzは
きれいな波が出てきます。

4MHzだとまっとうな方形波。
Aa001_20250630170201
16クロックで1μsになり、そこに4発の方形波
が並びます。
1発あたり4クロック。

ところが5MHzになると・・・
  発生周波数を自由にできるのが
  DDSの取り柄なんですけれど。
Aa000_20250630170401
1μs間に5発のパルスが続くんで間違いなく5MHz。
でもそのパルスの間隔、周期は1クロック幅で右に
行ったり左に行ったり。

例えば、1秒ゲートの周波数カウンタで計ったら
こんな波形でもほんとにジャスト5MHzになります。
  それがDDSの原理。

オシロで単発波形を採るんじゃなくちょいと
流してみるとこんな波形になります。
Aa002
「なんじゃこりゃ」のデジタルデータを使って正弦波の
データが入ったROMをアクセスしてD/A変換。
周波数が高いほど、影響が大きく出てきます。
この波形が元になるんで、
  「スプリアス、そりゃ出まっせ」
かと。
クロック周波数に近い、高い周波数が欲しいときは、
出す周波数ギリギリのフィルタで高調波を落と
すしかないでしょ。

※追記
もう一つ、スイープ波形。
制限波出力で1kHz→4MHzを4秒かけてスイープ。
 上段がスイープトリガ用出力。
 中段がAD9833の出力。
 下段だOPA2863を2段通った出力。
  リニアでのスイープなんでこういった周波数特性
  を見る時はLOGスイープが欲しくなります。

Wv12
4MHzになるとレベルが約半分に。
OPA2863の性能が見えてます。
  オペアンプ前段に入れた220Ω+100PF2段の
  LPFのせいです。
  OPA2863はもっと優秀。

※MAX038発振器では ・・・
昔に組んだMAX038発振器では出力オペアンプとして
「AD811」を使ってました。
  帯域幅    140MHz
  スルーレート 2500V/μs
DigiKeyでの現在価格2200円。

※続き
DDS IC「AD9833」をArduino UNO R3で制御:箱入れ #2


| | コメント (0)

2025年6月26日 (木)

DDS IC「AD9833」の出力にバッファアンプを #2

2025年5月27日:DDS IC「AD9833」の出力にバッファアンプを
この記事でチラリと書いた、高速オペアンプ。

この時は手持ちの「AD823」を使いました。
その後、OPA2863(バイポーラのdual op-amp)と
OPA810(SOT23のsingle FET入力OP-AMP)とを手
に入れて比較してみました。

AD823
 FET-input
 Output swings rail-to-rail
 -3dB bandwidth of 16MHz, G = +1
 Slew rate of 22V/μs
 maximum input bias current: 25pA

OPA2863
 rail-to-rail input and output,
 Unity-gain bandwidth: 110MHz
 Gain-bandwidth product: 50MHz
 Slew rate: 105V/μs
 Input bias current: 300nA

OPA810
 FET-input
 Rail-to-rail input and output
 Small-signal bandwidth: 140MHz
 Gain-bandwidth product: 70MH
 Slew rate: 200V/μs
 Input bias current: 2pA

AD9833 DDS ICが出す出力波形は、
  正弦波、三角波、方形波が
選べます。
正弦波と三角波は、L電圧が0.038V、H電圧が0.65Vで
P-P値で0.6Vほど。
方形波にすると、0V~5Vのフルスイング波が出てきちゃう
のです。
こんな回路でバッファしたので、方形波を出すとAMP1が
飽和してしまいます。
Cc05
3種のアンプで、出力波形がどうなるか、方形波を
出力して比較してみました。
Cc02
それぞれの波形、
  上からDDS出力につながるAMP1の+入力。
  真ん中がAMP1の出力。
  下が出力波形。 (AMP2は反転増幅)
AD823は1MHzになるとまともな波形が出てきません。
  ※正弦波だとレベルは下がるけどちゃんと
   見えます。
他の二つはさすがに高速アンプ。
飽和した方形波でも頑張って出してくれました。

DigiKey調べだと
 AD823  1400円  昔はもっと安かった
 OPA2863 360円
 OPA2810 730円
  (実験で使ったのはsingleのOPA810を二つ)

OPA2863がリーズナブルでしょか。
ただし、バイポーラなんで入力バイアス電流が300nAと
だいぶと大きいです。
汎用のLM358の入力バイアス電流が20nAですんで、
15倍の差があります。
  LM1458は200nA。
帰還抵抗をあまり大きくできません。
バイアス電流の小さなFET入力のだと、自由に決められるんで
便利です。

| | コメント (0)

2025年5月27日 (火)

DDS IC「AD9833」の出力にバッファアンプを

2025年5月25日:DDS IC「AD9833」をArduino UNO R3で制御 
この続き。
便利そうなツールになりそうなのでケース(百均の)に
入れるつもりですが、作業はまだ。

AD9833の出力レベルが小さいので、もうちょい大きくして
みました。

定格だと、Vout(max)が0.65V。
正弦波や三角波だとGNDからちょっと上がったところ
から波形が始まり、ピークが約0.6Vちょい。
P-P値で0.6Vほど。
RF用途では、このままで良いかもしれませんが、
正確で安定した周波数を出せるんで、低周波発振器としても
役立ちそうです。

そこで、現状の
・0.6V(P-P)を6倍ちょいして0~4Vの振幅に。
・マイナス電源を用意して
  0~+4V、-2V~+2V、-4V~0V
 くらいの範囲で出力電圧をオフセットできるように。
   0Vを中心に4V(P-P)の波形を上下。
・オフセット電圧の調整はボリュームで。
・1MHzを越える周波数はちょっと置いておいて。
・低周波用に直流結合で。

こんな回路を付加してみました。
Ad98_01
手持ちの Rail to Rail In/Outのオペアンプで
使えそうなのが(帯域が欲しいゾ)AD823あたり。
  とりあえず、様子見で
出力波形を切り替えて方形波にしても、ドカンと大レベル
のが出ちゃうということがなくなります。
  正弦波や三角波だと0.6Vですが、方形波にすると
  電源電圧いっぱいの信号になります。
  4V(p-p)になるようにしてるのが、5Vで頭が
  制限されるので、信号が大きくなってびっくり
  することがありません。

帯域があって使いやすそうで安価なアンプ、
このあたりかな。
・OPA810 FET入力 70MHz 1コ入り
・OPA863 バイポーラ入力 110MHz 1コ入り
     OPA2863が2コ入り
     入力バイアス電流が大(0.3uA)
何かのついでに買ってみます。

OPA2863、OPA810での実験

| | コメント (0)

2025年5月25日 (日)

DDS IC「AD9833」をArduino UNO R3で制御

備忘録としてアップしておきます。
2025年5月21日:Arduino UNO R4 minima 電源供給方法でクロックが変わる#4 
この実験で使った「1MHz近傍周波数発振回路」です。

Arduino UNO R4 minima、あるいはRA4M1コアボードから
出力させた1MHzを、このDDS回路で出力した1MHzをmix
してビート音を出しました。
Ad9833_01
DDS IC AD9833は、モジュールじゃなく単体の石を
買ってありました。
25MHzの水晶もあったのですが、あえてATmega328P
から16MHzのクロックを出すようにして横取りしました。
  全体の消費電流は25mAくらい

出力はフィルタやアンプを入れずにそのままです。
  高速オペアンプを買ってあれこれ試して
  みたいところです。
最低周波数が1Hz。 最小桁が0.1Hz。
最高周波数は5MHzあたり。

周波数をスイープする機能を入れてありますんで、
何かの実験で役立つかもしれません。

・制御スケッチ
  ・ダウンロード - ad9833_01.zip

※スケッチ追加修正してます
・sweep時のトリガ用(オシロでの観察)として
 Rise時、PD4をHにしています。
 Hの↑エッジで周波数 A->Bのスイープが
 始まります。
 ↓エッジがWait-Hのタイミングになります。

ABCラジオ(AM 1008kHz)にビートをかけて
遊んでいるところ。 (ラジオを横に置いて)
Aa11_20250525180601

液晶アクセスの「TWI」、AD9833アクセスの「SPI」。
ともにライブラリは使わずATmega328PのI/Oレジスタを
直接操作しています。

ATmega328Pの「SPI」なんて、ほんとに簡単。
  (出力制御の場合)
I/Oポートを操作してる感覚で制御できますんで、
ライブラリなんて要りません。
要るのはATmega328Pのハードウェアマニュアル。


※関連
2024年10月6日:おっと。map関数の計算桁に注意

| | コメント (0)

2025年5月23日 (金)

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命令少なくなります。

オシロで見るとこんな波形。
A01_20250523114301
上段の(d >>14 )のところ、なぜか広いので
「これはなんだろか?」っと思いませんか?

気になってコードを見たら、14回のループに
時間がかかっていたというお話しでした。



※関連
2025年5月21日:Arduino UNO R4 minima 電源供給方法でクロックが変わる#4

| | コメント (0)

2025年5月15日 (木)

Arduino UNO R4 minima 電源供給方法でクロックが変わる#3

2025年5月9日:Arduino UNO R4 minima 電源供給方法でクロックが変わる#2 
この続き。

UNO R4の内蔵クロック、とりあえず判明していることは
 ・USBでPCとつないだときはクロック精度が上がる。
    水晶発振並みに
 ・USBを外して外部電源にした時はクロック精度が落ちて
  しまう。
 ・外部電源のときは「HOCOUTCR」トリミングレジスタで
  周波数を調整できる。
 ・でも、USBにつないだ状態でHOCOUTCRを触ったら、
  なんかおかしい。
この他、ジッタ(周波数の微少変動)の問題もあります。

気になるのは、USB接続時のHOCOUTCR操作。
これがどんなものか、テストプログラムを書いてみました。

 ・D4ポートに内蔵クロックを分周して作った1MHzの方形波を出力。
  この周波数をチェックして内蔵クロックの変化を見る。

 ・D3ポートは32ビットのGPT1タイマーのクロック入力に。
  ここにD4ポートが出す1MHzパルスを入れる。

 ・D2ポートをGPT1タイマーのキャプチャ入力に。
  外部から(正確な)1Hzのパルスを入力。
  その↓エッジでカウント値をラッチ。
  1秒周期なのでHz単位でカウント値が読める。

 ・D8ポートはキャプチャのチェックに使える1Hzパルス。
  でもHOCOUTCRを操作して周波数を変えると、この
  パルスの周波数も変わってしまう。
  1MHzパルスと同じ比で変化するので、D8→D2とつな
  ぐと、HOCOUTCRが変わってもいつも1000000Hzジャスト
  のカウント値が得られる。

UNO R4 minimaとの接続はこんな具合。
H11_20250515151201
USBコネクタを外しても通信できるよう、D0ポートの
TXDでデータを出力しています。
  SrealではなくSerial1で。

・制御スケッチ(ファイルタイプをtxtにしています)
   ・ダウンロード - hoco_02.txt

HOCOUTCRを-10~+10まで変化させた時の1MHz周波数を
順次シリアルデータとして出力します。

・外付け電源のときのデータ。
   ・ダウンロード - aux01.txt

・USB接続でのデータ。
   ・ダウンロード - usb01.txt

それをグラフにすると

・外付け電源のとき
Cap004_20250515151601

まっとうに変化しました。
それが、USB接続ではもうはちゃめちゃに。
Cap006_20250515151701
ほぼ1MHzなんですが、ところどころで、タイミングか
なにかは不明ですが、とんでもない周波数が出ています。

これを見ての評価。
  USB接続のときにHOCOUTCRを触ると、クロック周波数が
  とんでもない値になることがある。

内蔵クロックを分周して作った1MHz、USB接続では
1MHzになるよう合わせ込みをしているようです。
しかし、HOCOUTCRをユーザーが変更すると、競合して
しまうようです。

HOCOUTCRの値は、書いたものがそのまま読み出されま
したので、USBでの周波数合わせではこれは触っていない
ようです。

ということで、
 ・HOCOUTCRを触ってメインクロック周波数を
  変えてはダメ。
 ・クロック周波数の精度がいるのなら水晶発振子を
  使うように。

が結論でしょうか。


ちなみに、1Hz信号発生回路はこんなの。
1hz_osc

「ダイソーのミニケース」 に組んでます。
Osc1hz

8ピンの小マイコンを使うとか、リアルタイムクロックICを
使うとか、あれこれ考えられますが、プログラムを組まなくて
も1Hzが得られる4060Bを使いました。
これの欠点。4060Bひとつだと出てくるのは2Hz。
もう1/2したいわけですが、それに何を使うか。

フリップフロップ4013や4027で1/2するのも手ですが、
ワンゲートロジックに「74LVC1G80」という5本足の
「D type FF」があるんで、これで1/2が作れます。
  電源とGND。
  クロック入力(立ち上がり)とD入力。
  そして/Q(反転)出力。
反転出力というのが面白い。
何かのついでに買っておきますわ。

| | コメント (0)