2024年4月14日日曜日

BlackpillというSTM32 board(5)(ADC 2ch運用&高速化 20kHzサンプル)

中華STM32基板のBlackpillを味見しています.

前回は、ADCを2ch運用しましたが、サンプル周波数は500Hzと遅かったです.
今回は、サンプル周波数を20kHzまで上げます.

無理矢理で40kHzまで行けるかな?って感触ですが、20kで止めておきました.律速は割り込みroutineでbuffer copyとかする部分ですので高速化の余地はありそうですが、さりとて100kHzまで上げられる気はしません.

なお、CPU STM32F401のADC性能では1MHz近いサンプルが可能のようです.

ーーーー
やったことのリスト

・サンプリング周波数は20kHz
・連続する1000ptsをメモリにストア
・同1000ptsをCDC(USB COM)でPCへ送信する
・サンプリング周期はTIM3の出力する50uSecで決める (つまりhardware自走)
・ADC入力はIN1とIN9の2本 (2ch scan)
・ADCは1トリガで2サンプル (2ch scan)
・DMAを使う
・DMAはIN1サンプル→DMA→IN9サンプル→DMAという動作をする
・すなわち、TIM3→ADC(IN1)→DMA→ADC(IN9)→DMAがhardwareで自走する
・ADC完了をIRQで知る
・同IRQで1000pts x 2ch分のbufferに積む
・同IRQでbuffer fullになったらUSB送信を起動
・USB転送終了をIRQで知る
・USB busyの最中はADC IRQでbufferに積まない (buffer衝突防止)
・ADCは12bitなので、1サンプルあたりASCIIの3bytesをbufferに積む
・ゆえに1USB送信あたり1000x2x3=6000bytes
・USB FULL SPEED(12Mbps)で6000bytes送信するのにover head込みで50mSecぐらいかかっている(実測)

ーーーー
前回も触れましたが、いろんな疑問点について

Q:STM32CubeIDEとArduinoIDEのどちらを使う?
A:STM32CubeIDE
ArduinoIDEだとUSB関連のexampleが見当たらず使いませんでした.
STMCubeIDEのCDC exampleを雛形にして改造しました.

Q:TIM3+ADC+DMAを起動するやりかた
A:HAL_Delay(3000);
  HAL_TIM_Base_Start_IT(&htim3);
  HAL_ADC_Start_DMA(&hadc1, &buffer[0], 2);
main()の最初の方の各種Initの後で1回だけこれをやると、あとはhardwareが自走してくれます.詳細は前回を参照.
HAL_Delay(3000)は必須です.USB接続の直後は不安定なので3秒待ちます.

Q:ADC終了割り込みはどれを使えばいいんだ?
A:HAL_ADC_ConvCpltCallback()
事情は前回を参照.

Q:USB終了割り込みはどれを使えばいいんだ?
A:CDC_TransmitCplt_FS()
USB COMのUSBの転送終了を知るにはこれが良いようです.
USB転送終了までbufferへのADC dataの上書きを禁止するためにこの割り込みを使います.

Q:DMAのdata widthは8/16/32bitのどれにしようか?
A:32bitにした
事情は前回を参照.

Q:USB転送終了calbackでやること
A:busy flugを下げる
USB転送が終わると自動的にこの関数がcallされます.
CDC_TransmitCplt_FS(){
  uint8_t result = USBD_OK;
  UNUSED(Buf);
  UNUSED(Len);
  UNUSED(epnum);
  usb_busy = 0;   ←これを追加
  return result;
}

Q:HAL_ADC_ConvCpltCallback()で何をやる?
A:改造の中心部がここ、main()の上の辺りにでも追加、weak宣言されてる
#define PTS 1000   連続サンプル数1000
#define CH 2   ADC 2ch scan
#define BUFSIZE (3*PTS*CH)  USB bufferサイズ6000bytes
int usb_busy = 0;  USB busyフラグ
static uint32_t buffer[4];  ADC dataを都度格納する場所
static uint8_t usbbuf[BUFSIZE+100];   USB buffer確保
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
  static int N = 0;
  if(usb_busy==0){
    char c[15];
    sprintf(c,"%03X",buffer[0]);  IN1 ASCII変換
    usbbuf[N++] = c[0]; strcat()は遅いので使うのやめた
    usbbuf[N++] = c[1];
    usbbuf[N++] = c[2];
    sprintf(c,"%03X",buffer[1]);  IN9 ASCII変換
    usbbuf[N++] = c[0];
    usbbuf[N++] = c[1];
    usbbuf[N++] = c[2];
  }
  if(N>=BUFSIZE){ 6000bytes積んだらUSB起動
    usbbuf[BUFSIZE] = '\n';
    N=0;
    usb_busy=1; USB転送はmain()で起動する
  }
}

追記:sprintf()も遅いので自作のitoa()に変えたら50kHzサンプルで動きました.

Q:main()でUSB転送を起動するには?
A:while()でCDC_Transmit_FS()をcallする
while (1)  {
  if(usb_busy==1) CDC_Transmit_FS(&usbbuf[0],BUFSIZE+1);
}

ーーーー
STM32CubeMXの設定について.

ADCの設定
DMAの設定
TIM3の設定
clk=84MHzなので、84M÷84÷50=20kHz

BlackPillを味見するのはここまでにしとうございます.

簡易オシロを作ろうかな.ESP32のほうがいろいろと高速かもしれない.

4へ    6へ

かしこ

37 件のコメント:

  1. その昔、サンプリング周波数は、帯域幅の二倍と聞いたことある
    なんで二倍かわすれました
    Mp3のエンコードで128khz
    とかあったから256kHzでサンプリングするのかしら?

    返信削除
    返信
    1. MP3はサンプル48kHzが多くて、128kとかいうのはたいていビットレートかと思われます.

      削除
    2. >サンプリング周波数は、帯域幅の二倍
      「帯域幅」っていうか、サンプリング対象の「最大周波数」ですね。
      ※「標本化定理」で、ググって下さい。あと、基本事項なので、デジタル信号処理の教科書には必ず載ってますよ。

      >Mp3のエンコードで128khz
      mp3 とかの、「xxKHz」とかは、これとはまた別の話です(無関係では無いが)
      (このコメント欄に記すには余白が狭すぎるので、以下略。)

      削除
    3. そうでした、なるほど すこし思いだしました

      削除
  2. >ESP32のほうがいろいろと高速かもしれない
    私もそんな気がします。
    ※でもそれは「ネイティブ開発環境(ESPIDE)」を使った時の話で、
    Arduino にしちゃうと、あんまり早く無いカモです。あと、USBは(RISC-V版を除いて)使えません。

    返信削除
    返信
    1. 「esp32 oscilloscope」は、検索すると、海外含めていっぱい出てきますね。
      github にも、たくさん落ちてますね。

      削除
    2. wifiはsocketってやつでdata受けるんでしょうか.socketって使ったことないんです.

      削除
    3. >socketって使ったことない
      ESP32とかは、
      ・そういう細かいところを知らなくても使えるのがウリ
      のハズなので、繋がってしまえば、単に、
      ・とあるプロセスに「STDIN」「STDOUT」があるだけ(シリアル In/Out と言ってもイイ)
      です。
      ※大体、殆どの通信系(TCP/IP、 USBとかも)は、つまるところ、
      ・RS-232C 上位互換
      と、言っても過言では無いです。
      ※open、close、read、write があるだけ。これですべて事足ります。
      (細かいことを言わなければ。速度とかパフォーマンスを追求し出すと、イロイロ知らないといけなくなりますが。)

      削除
    4. そもそも、Socket = RS232Cの(物理的な)コネクタ みたいなイメージです
      コネクト/ディスコネクト=コネクタを差し込む/抜く と思っていいです

      ※WebPageをブラウザに表示、とかは、また「別のレイヤー」なので、別の話です。http(s)プロトコルの知識が必要になる。

      削除
    5. Unixの開発者は、
      ・すべてを、「STDIN」「STDOUT」で、記述したい
      と思って、みーんな、「共通API 」(open close read write)だけて、
      「いろんなプログラムを、使いまわしできる」ように設計しました。
      ※なので、「ファイル」「シリアル」「TCPIPネットワーク」「USB」は、ぜーんぶ、この基本APIだけは共通です。
      (勿論「固有API」は、個別に必要になりますが、たいがい、決まった「おまじない」を唱えれば済む。)

      削除
    6. リダイレクト大好きです

      削除
    7. リダイヤル使ってます

      削除
    8. Unix開発者えらい バークレー?

      削除
    9. 「カリフォルニア大学バークレー校」は、「ソケットAPI」を、開発したところですね。
      「STDIN」「STDOUT」は、それよりもっと前からあるハズ。
      https://ja.wikipedia.org/wiki/%E3%83%91%E3%82%A4%E3%83%97_(%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF)
      ※Windows も、この辺にかなり影響を受けてるので、同様のAPIは持ってます。

      削除
    10. 復活の呪文はリブート

      削除
  3. ※なんか、こういうのを「サクッと作れる」
    ・Mixed Signal FPGA
    とか、あればいいのに。と、時々思います。
    ・A/D ブロックと、CPUブロックと、ちょっとした Glue-logic が記述できればいい
    だけでしょ? 現時点でも「Verilog とかで、記述だけ」なら出来ますね。
    どこかで作ってくれないかな・・・

    返信削除
    返信
    1. ADのADAU1401がもっと融通の利く仕様だったらいいのに、PCにdata送信とかできなくてなんだかなぁでした

      削除
    2. CPUブロックでなくて再販した電子ブロックはだいぶひかれましたが買いませんでした

      削除
    3. 電子ブロック100が昭和50年頃に¥6800ぐらいしていてなかなか高価な玩具でした.買いました.

      削除
    4. >昭和50年頃に¥6800ぐらい
      今だと、
      ・1万4千円くらいの価値(消費者物価指数から計算)
      みたいですが。
      ※Nintendo Switch のほうが高いな。(37980円[税込])
      意外と安い感じがする。

      削除
    5. 実は、私の家(実家)にも、これ
      https://www.denshiblock.co.jp/siryoindex.html
      電子ブロック ST-100
      が、ありました。
      ※復刻版がある「EX-150」とは、シリーズが違う。こっちのが、古いようです。
      定価¥4,950 だった模様。

      削除
    6. わたしもST100でした.
      初代は1965年からあったようですね.ゲルマニウムか.

      削除
    7. 「ST-100」の、「ST」とは、
      ・Silicon Transistor
      の意味のようです。
      ※ちなみに、私が持っていた ST-100 に使われてたのは、
      ・2SC372(ツバ付きのやつ。新しい奴はツバが付いて無い。)
      だった記憶があります。

      削除
    8. でもなぜか、ネットで出てくる回路図で使われてるのは、
      ・2SC945
      なんだよなー。あと、「2SC372」ジャナクテ「2SC373」だったかも知れない。

      削除
    9. 372であってるとおもいます

      削除
    10. いや、現物が、
      ・2SC373
      だった記憶があります。
      ※多分「大人の事情」(単に、入手できなかったので代用したロット)
      だったのだと思いますが・・・・
      というか、これで当時、
      2SC373≒2SC372 (細かいこと言わなきゃ、代用可能)
      ということを知りました。

      削除
    11. CQ出版のトランジスタ互換表を思い出しました

      削除
  4. 2SC372 2SC945 2SC1185 の流れ?

    返信削除
    返信
    1. さらに2458とかだったか

      削除
    2. だんだん小さくなる

      削除
    3. ハンダづけの手間を考えるにSOT23ぐらいまでにしとうございます

      削除
    4. スキャナーの基板をみて 部品どりしてリサイクルとおもいましたが 0.3ミリピッチで 人間技ではありません
      秋葉原で買った実体顕微鏡がこんなこともあろうかと用意してましたが使う気力がなく てが震えて使えないなとおもいました 手は震えてはいないのですが何となく絶望感

      削除
  5. Seeed XIAO RP2040をなにかにつかえないかと800円くらいで買いました
    端子はusb と ピン端子のみ
    Lan用端子はなし
    使い道ありそうでしょうか
    たしか 1.4インチ液晶でspi接続でもしようかと買った気がします
    気圧表示くらいかなあ

    返信削除
  6. フラットヘッドスキャナーを部品どりして 3Dプリンタでも作ろうと妄想してます 薄型スキャナーはダメなことがわかったです 使える部品がないです
    太いガイド用の丸い鉄棒もなかった

    返信削除