SSブログ

pico PIOオシレータ実験 uSDXに使えるか? [pico]

今年初めての投稿です!
おもしろいwebサイトを見つけた。

webサイト.png

picoのPIOで90度の位相差を発信させている。早速私のプログラムに挑戦。サイトでは公式C/C++ SDKとPythonを使っているようですが、私はArduinoIDEで!
私のスケッチでは発信周波数に誤差があります。何度かスケッチを書き換えて誤差が最小になるように変更しましたが、それでも満足な結果にはなりませんでした。
このテストをしてみようとインスピレーションを与えてくれたwebサイトの記事を読んでいると
“To compensate for the coarse frequency resolution in the oscillator, a high-resolution frequency shifter is implemented in the software. (The 32-bit phase accumulator has a theoretical resolution of a little over 0.0001 Hz which should be ample.)”
と説明されていたので、ファームゥエアをダウンロードして周波数の測定をしました。下の表がその結果です。
pico PIC 発信周波数測定.jpg
表の左がそのサイトのファームウエア、右が私のスケッチの結果です。14MHz以下では私のスケッチの精度が良いですが、18MHz以上になるとどちらも同様に精度が悪くなります。分周には限度があって、特に高い周波数では十分な分周ができないようです。
下の写真はwebサイトのファームウェアをダウンロドして使用している写真。画面右のOLEDの表示と周波数カウンターの表示が違う。

FFO00.jpg

VFO01.jpg

下の写真は私のスケッチで発信周波数を表示。
出力波形は90度の位相差を正確に発信できています。

pico_PIO_OSC.jpg

非常に興味のあったテーマでしたが、この結果を見るとAMラジオ放送では問題ないでしょうが、アマチュア無線で使うことは難しいのではないかと思います。
pivcoだけでできると非常にコンパクトにな、SDRの学習用としては面白いですね!

このテストはここまでにして、やはりSi5351などを使用するのが順当だろうという結論に至りました。

本家のサイトへのリンクは“https://github.com/dawsonjon/101Things/tree/master

私のテストプログラムです。

quadrature_wave_pio.h
#ifndef QUADRATURE_WAVE_PIO_H
#define QUADRATURE_WAVE_PIO_H

#include <hardware/pio.h>

// 直交波を生成するPIOプログラムを定義する
#define quadrature_wave_wrap_target 0
#define quadrature_wave_wrap 3

static const uint16_t quadrature_wave_program_instructions[] = {
    0xe001, // 0: set pins, 1 (Set GPIO0 high, GPIO1 low)
    0xe003, // 1: set pins, 3 (Set both GPIO0 and GPIO1 high)
    0xe002, // 2: set pins, 2 (Set GPIO0 low, GPIO1 high)
    0xe000, // 3: set pins, 0 (Set both GPIO0 and GPIO1 low)
};

#if !PICO_NO_HARDWARE
static const struct pio_program quadrature_wave_program = {
    .instructions = quadrature_wave_program_instructions,
    .length = 4,
    .origin = -1,
};

static inline pio_sm_config quadrature_wave_program_get_default_config(uint offset) {
    pio_sm_config c = pio_get_default_sm_config();
    sm_config_set_wrap(&c, offset + quadrature_wave_wrap_target, offset + quadrature_wave_wrap);
    return c;
}
#endif

// void quadrature_wave_program_init(PIO pio, uint sm, uint offset, uint pin);
void quadrature_wave_program_init(PIO pio, uint sm, uint offset, uint pin, float frequency);

#endif // QUADRATURE_WAVE_PIO_H


pico_PIO_VFO_10.ino
/*
pico VFO test JR3XNW
*/
#include 
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include 
#include 

#include "quadrature_wave_pio.h"

#include 
#include 

// U8g2コンストラクタで使用するディスプレイドライバーを指定
// この例ではI2C接続のSSD1306 128x32を使用
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

// Rotaryエンコーダーのピン
const int PIN_A = 21; // GPIO2
const int PIN_B = 20; // GPIO3

Rotary rotary = Rotary(PIN_A, PIN_B);

// 周波数の最小値と最大値
const double FREQ_MIN = 3500000.0; // 3.5MHz
const double FREQ_MAX = 30000000.0; // 30MHz
const double FREQ_STEP = 1000.0; // 10kHz

uint64_t frequency = FREQ_MIN;

// 周波数設定を含む quadrature_wave_program_init 関数の定義
void quadrature_wave_program_init(PIO pio, uint sm, uint offset, uint pin, double initial_frequency) {
  pio_sm_config c = quadrature_wave_program_get_default_config(offset);

  sm_config_set_set_pins(&c, pin, 2);
  pio_gpio_init(pio, pin);
  pio_gpio_init(pio, pin + 1);
  pio_sm_set_consecutive_pindirs(pio, sm, pin, 2, true);

  const double base_clock = 125000000.0;
  double clkdiv = base_clock / (4 * initial_frequency);  // クロック分周値の計算

  // クロック分周値を設定
  sm_config_set_clkdiv(&c, clkdiv);

  pio_sm_init(pio, sm, offset, &c);
  pio_sm_set_enabled(pio, sm, true);
}

// 関数:所望の周波数に対して分周値を設定
void set_frequency(PIO pio, uint sm, uint64_t frequency) {
  const double base_clock = 125000000.0; // Picoの基準クロック周波数(125MHz)

  double clkdiv = base_clock / (frequency * 4.0); // 4は波形のステップ数
  // 分周値を計算し、PIOのクロック分周器に設定
  pio_sm_set_clkdiv(pio, sm, clkdiv);

  // デバッグのための分周値の表示
  printf("Frequency: %f Hz, Clock divider: %f\n", frequency, clkdiv);
}

// Rotaryエンコーダーからの入力を処理する関数
void checkRotaryEncoder() {
  unsigned char result = rotary.process();
  if (result) {
    if (result == DIR_CW && frequency < FREQ_MAX) {
      frequency += FREQ_STEP;
    } else if (result == DIR_CCW && frequency > FREQ_MIN) {
      frequency -= FREQ_STEP;
    }

    Serial.print("Frequency: ");
    Serial.print(frequency);
    Serial.println(" Hz");

    // ここで周波数を設定する関数を呼び出す
    set_frequency(pio0, 0, frequency);
  }
}

void isr() {
  checkRotaryEncoder();
}

void setup() {
  rotary.begin();
  u8g2.begin();
  // 割り込みの設定
  attachInterrupt(digitalPinToInterrupt(PIN_A), isr, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_B), isr, CHANGE);

  // 初期周波数を3.5MHzに設定
  quadrature_wave_program_init(
    pio0,
    0,
    pio_add_program(pio0, &quadrature_wave_program),
    0,
    3500000.0  // 初期周波数
  );
}

void loop() {
  checkRotaryEncoder();
  u8g2.clearBuffer();         
  u8g2.setFont(u8g2_font_8x13B_tr); // フォントを選択
  u8g2.setCursor(0, 15); // カーソル位置を設定
  u8g2.print("Freq: ");  // テキストを描画
  u8g2.print(frequency); // 変数frequencyの値を描画
  u8g2.print(" Hz");
  u8g2.sendBuffer();      // ディスプレイに内容を送信
}

ヘッダファイルを同じフォルダに入れてコンパイルしてください。テストしているArduino IDEのバージョンは2.21です。 2024/1/25 スケッチを修正しました。

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

pico版SDR受信機 [pico]

pico版SDR受信機、位相制御のVFO、バンドスコープ、ウォータフォール、SSB復調のプログラムが一応できたので、uSDXのミキサー部分を使って受信テスト中です。
まだ感度の不足、AGCの問題などいくつか修正を必要とする所はあるが、一応受信できている。テストをして改善していこうと思っています。ある程度納得ができたらGitHubにアップしたいと思います。


nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

pico バンドスコープとVFOとSメーター [pico]

picoバンドスコープに位相制御のVFOとSメーターを追加しました。しかし、VFOがうまくいきません。ここ数日悩んでいます。
バンドスコープを持ったpico版uSDXを目指しているのですが先はまだまだ見えません。

VFO_S.jpg

uSDXも少しLPFを作り変えたり、オペアンプのLPFのCRを変更したり細かい実験を続けています。
もう少し形になれば公開したいと思っています。
nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

pico FFT [pico]

仕事に追われて、久しぶりでpicoをいじっています。
また寄り道を始めました。0.96インチのOLEDでバンドスコープをテスト。画面上の周波数表示等はダミーです。
ArduinoFFTライブラリーを使っていますが、FFTのプログラムは初めてなので難しいですね。勉強しながら進めていきます。




タグ:pico FFT
nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。