プリント基板
57x29mm もっと小さく作りたかったけど.....
A面 パターンカットあり
B面 ジャンパーあり
3Dプリンタで作るケース
2枚貝型ケース.62x34x15mm
ネジ穴は設けてないので接着で対応する前提.わたしはホットメルトが好きです.
周波数変更方法
push SWを押す毎にcyclicに周波数を変更します.周波数は飛び飛びの値です.
下記tableに14種類の{ ①sin波周波数、②I2S Fs、③sin tableのbit数 }が記載されています.③に応じてsin tableを再計算し、②をI2Sに設定し、③をDMAの長さに設定します.
uint32_t h_freqTable[]={
18, I2S_AUDIOFREQ_16K, 16*1800,
36, I2S_AUDIOFREQ_32K, 16*1800,
53, I2S_AUDIOFREQ_48K, 16*1800,
107, I2S_AUDIOFREQ_96K, 16*1800,
213, I2S_AUDIOFREQ_192K, 16*1800,
333, I2S_AUDIOFREQ_192K, 16*1152,
500, I2S_AUDIOFREQ_192K, 16*768,
1000, I2S_AUDIOFREQ_192K, 16*384,
2000, I2S_AUDIOFREQ_192K, 16*192,
3310, I2S_AUDIOFREQ_192K, 16*116,
5052, I2S_AUDIOFREQ_192K, 16*76,
10105, I2S_AUDIOFREQ_192K, 16*38,
19200, I2S_AUDIOFREQ_192K, 16*20,
24000, I2S_AUDIOFREQ_192K, 16*16 };
周波数精度
sin波周波数はピッタリ理論値にはならず、数%誤差ります.原因は2つ.
1)RC発振器誤差
部品点数削減のためXtalを省いています.STM32の内蔵RC発振器を使って源発振clk (48MHz)を得ています.RC発振器は数%ズレています.
2)I2S Fs誤差
192kHz,96kHz,48kHz,32kHz,16kHzを作るためにSTM32内蔵PLLで源発振clkを掛けたり割ったりします.整数の掛け算割り算では必ずしもFsとピッタリにならず、数%ズレます.
source code
STM32CubeMXが生成したsource codeを変更します.
変更したfileはmain.cとstm32c0xx_it.cです.
新規追加fileはh_1bit_dac.cとh_1bit_dac.hです.
STM32CubeIDEは1.15.0を使っています.
STM32C011の出荷時設定のままだとI2Sが動きません.reset pin=I2Sと衝突しているからです.回避するためにoption byteの変更が必要です.→
こちらを参照
main.c
初期化の後に追記.
h_freq_init(); sine tableを計算
HAL_I2S_Transmit_DMA(......); I2SをDMA modeで起動
stm32c0xx_it.c
外部pin割り込みハンドラに追記します.
push SWが押されたら割り込みがかかるので周波数を変更します.
void EXTI4_15_IRQHandler(void) {
HAL_I2S_DeInit(&hi2s1); I2Sを停める
h_freq_init(); sine table再計算
HAL_I2S_Init(&hi2s1); I2Sを再設定
HAL_I2S_Transmit_DMA(......); I2SをDMAモードで再起動
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
h_1bit_dac.c、h_1bit_dac.h
sine tableを計算する関数h_freq_init()が記載されています.
sin→PWM変換と周波数tableを実装してあります.
push SWチャタリング防止回路
netで見つけた回路で良さそうに動いてます.
要は0.1u+100Ωで平滑化してるってことで.
sin波形
ミニマム構成ゆえに問題はあります.
↓18kHz (I2S Fs=192kHz) 滑らか
↓500Hz (I2S Fs=192kHz)
滑らか↓200Hz (I2S Fs=192kHz) 滑らか
↓100Hz (I2S Fs=96kHz) 少しバサつき
↓54Hz (I2S Fs=48kHz) バサつき
↓36Hz (I2S Fs=32kHz) バサつき
↓17Hz (I2S Fs=16kHz) バサバサ
問題点は、Fsが低くなるにつれて波形がバサバサになってゆくところです.
この原因は、LPFをFs=192kHzに最適化したためです.Fs=16kHzにもなるとPWMの不要帯域をカットしきれなくてバサバサになってしまいます.本当はLPFもFsに応じて切り替えなくちゃいけないのだけど、CPUのpinが余ってないので無理です.
CPU内部RAMが64kBぐらいあれば、sine tableを長大にできるのでFs=192kHzでsin波=20Hzぐらいまで下げられるんですがね.
ミニマムシステムゆえに許してくれ.
基板改修
OPAMP電源を3.3V→5Vに変えています.
OPAMPには3.3V rail to railが必要です.
秋月で売られているNJU77552なら3.3V電源のままで動きます.
しかし秋月で売られているNJM2746Mだと5V電源にしないと動きません.
NJM2746Mは入力についてはrail to railでないので、電源を5Vにして逃げます.