マイコン工作実験日記

Microcontroller を用いての工作、実験記録

BM20実験基板

2017-08-13 17:51:39 | WT32/BM20
BM20の動作確認のために発注しておいた実験用基板が届きました。今回はElecrowを使って青色基板を指定してみました。5枚で$4.9のコースで、送料込みでも$9.88でしたが、実際には7枚の基板が送られてきました。



基板の回路はBM20の評価ボードであるBM-20-EVBを真似ていますが、まずは必要最低限の動作確認ができればいいので、コネクタや使用部品数を減らして基板サイズも小さくしてあります。
  • 電源の供給とホストとの接続はピンヘッダ経由。
  • ジャックは音声出力用にひとつだけ用意。マイクは基板上に載せてしまうことに。
  • ライン入力は使わないことにして、代わりにブザー用のパターンを用意。
  • NFCタグは使わないことにして、関連部品を省略。
  • DISP SWには秋月で売られていたハーフピッチの4Pを使用。実際には3Pしか使いません。
  • 電源ON/OFFにはMFBだけを使うことにして、スライドSW関連部品を省略。

早速、手持ちの部品を載せてみました。残りがあるつもりだったタクトスイッチがひとつだけしか見つからなかったので、これを電源ON/OFFも兼ねるMFBボタンとして使うことにします。残る5つのスイッチで音量上下や Play/Pause, Fwd/Rev操作ができるのですが、また後で部品箱を漁ってみることにしましょう。ちなみにMFBというのは Multi Function Buttonの略のようです。



続いて、実際に動作を確認するために、電源とスピーカーを接続。 100均のアンプ無しスピーカーなので、音量は出ませんが動作確認にはこれでも十分です。もちろん、イヤホンをつなげれば十分な音量で鳴ります。



電源はFT232ボードを介してUSBからの5VをBM20のADP_INに供給しています。BM20にはLiPo電池の充電機能も備わっており、ヘッダピンには電池をつなぐBAT_IN端子も出してありますが、電池をつながなくても動いてくれるので、オープンのままで動作確認を始めることにします。

BM20

2017-08-11 16:17:24 | WT32/BM20
6年ほど前にWT32で随分と遊びましたが、久しぶりにBluetoothモジュールで遊んでみようと思い、音声対応のClassicのモジュールを探してみました。世の中はIoT流行りなのでBLEのモジュールは色々と出回っていますし、次から次へと新しい製品が出てきます。その反面、HFP, A2DP, SPPに対応した製品はあまり目立たなくなったような気がします。以前は秋月でもRN-52を扱っていたと思うのですが、今は取り扱っていないようです(マルツにはあるようです)。ESP32でもA2DPやAVRCPが使えるようになってきているようですが、こちらは皆さん手を出すでしょうし。他に何か面白そうなものはないかと思って探しいたところ、MicrochipがBM20というモジュールを出しているのを見つけたので、試しにDigikeyから購入してみました。Mouserにも在庫はありましたが、なぜか日本には輸出できないという扱いになっていました。




このBM20はもともは台湾のISSCという会社が製造していたチップを使ったモジュールなのですが、2014年にMicrochipがISSCを買収しています。BM20以外にも、I2S対応したBM23とかBLE対応したBM6xシリーズとかもあるのですが、今回は機能的にはベーシックであり安く買える(1枚1103円)BM20を購入してみました。これらのモジュールですが、Microchipが買収してくれたおかげて、日本向けにもちゃんと技適を取ってくれています。BM20も2年前に取得済みなのですが、上の写真に示すようにモジュールの上面には技適マークの刻印がありません。しかし、裏側を確認すると....




FCC IDも技適番号もこちら側にはシルクで入っています。オイオイ、裏側にシルクがあっても実装したら、見えねぇじゃねーか!

技術基準ではラベルを表示する必要があることが明記されていますが、そのことはMicrochipもちゃんと承知しているので、データシートには「このモジュールを装置に組み込む者がラベルを作成するように」と断り書きがしてあります。

さてこのモジュールですが、もともと台湾メーカの品ということもあって、資料が充実しているとは言い難いところがあります。しかし、とりあえず電源といくつかのスイッチとアンプ、スピーカを繋げるだけでもバカチョンで Bluetoothスピーカが組み立てられるようです。さらに UARTでマイコンとつないで制御することもできるようなのですが、丁寧な解説はほとんど無いので、実際に使ってみながら理解する必要がありそうです。謎解きしながらしばらく楽しめそうです。

モジュールを実装するための実験基板もすでに発注してあり、もうすぐ届く予定です。基板が届き次第、動作実験を開始するつもりです。

DCMIでカメラをつなぐ -- その2

2017-08-07 12:11:51 | Weblog
ハードが用意できたので、続いてソフト編です。OV2640のSCCB制御にはI2C3を割り当てました。カメラに供給するクロックはTIM12を使ってSystemClockを分周して15MHz (90MHz / 6)を作っています。OV2640の初期化ルーチンは以前作ったものを使うつもりでしたが、STM32CubeF4の中のサンプルプロジェクトでカメラを使うものがあり、そこで使用するためにDrivers/BSP/Componets/ov2640というディレクトリがあり、ドライバーが入っていることに気がついたので、今回はこれを流用することにしました。ただし、このドライバではカメラから取り込んだ画像データをそのままLCDに送って表示することを想定しているようで、カメラの出力データ形式がRGB565になっていましたので、これをYUV422に変更して使っています。

画像データの取り込みにはDCMIを使い、そのデータはDMAでメモリに転送します。STM32CubeMXでの設定は次のようにしました。VsyncとHsyncの極性指定は、映像データの出力信号が無効な期間の極性を指定することに注意。

OV2640にはJPEGで画像データを取り込む機能がありますが、今回はその機能は使わずに無圧縮でデータを取り出し、UVCでホストに送信することにします。


STM32CubeF4が提供するHALのAPIとしては、HAL_DCMI_Start_DMA()が用意されています。引数のDCMI_MODEとしてDCMI_MODE_CONTINUOUSを指定してやると画像データを連続してDMA受信してくれます。DCMIの使い方を示すサンプルプロジェクトを見ると、1フレーム分のバッファを用意しておいてフレーム単位で受信する使い方をしているのですが、そのためにはSDRAMのような外部メモリが必要となってしまいます。今回の実験であるUVCカメラでは、受信したデータはすぐUSBから送信してしまえば良いので、フレーム分のバッファは不要です。そこで、2ラスタ分のバッファを用意しておき、これをダブルバッファリングで使うことにしました。つまり、1ラスタの受信が終わったら、そのデータをすぐにUSBから送信し、その間にもう一つのバッファにカメラからのデータを受信しておきます。

ラスタ単位での受信完了はDCMIのIT_LINE割り込みで検出することができ、HALのAPIではHAL_DCMI_LIneEventCallback()が呼ばれますので、この時点で受信できているデータをUSB UVCで送ってやります。 またUSB UVCではフレームの区切りをパケットのヘッダー情報として示してやる必要がありますが、この区切りはIT_VSYNCとHAL_DCMI_VsyncEventCallback()で検出してやります。

このようにしてなんとかOV640からのVGA画像をMac上のQuick Cameraアプリで表示できるようになりました。






室内で実験していますが、XPCLK=15MHzにておよそ9fpsとなりました。XPCK=22.5MHzにすると13.7fpsくらい出るのですが、PCに画像が表示できません。そこでカメラが出力している信号を確認してみると...





Hsyncの間隔が短い箇所では111.4usecしかありません。受信した1ラスタ分の画像信号を1マイクロフレームに入れて送っていたのですが、USB High speedのマイクロフレームの間隔は125usecですので、画像の取り込み速度に間に合っていません。Hsync信号自体は、1msに最大8回しか出ていないので、USBに出力するパケットデータをキューに溜めてから出力するようにしたところ13.7fpsの画像も表示できるようになったのですが、時折画像が乱れます。

画像が乱れる原因としては次のような事項が挙げられます。
  1. DCMIで受信した画像データを一旦USB送信用のバッファーにコピーしているため、その処理に時間がかかっている。DCMIとUSB送信処理でバッファを共有してコピー不要にすれば、改善できるはず。
  2. USB送信用バッファからSTM32F446のPDCの送信FIFOにデータを送る際にソフトでコピー処理を行っているために時間がかかっている。DMAを使えば改善できる。

無駄なデータコピーが2度も行われており、そのためにCPUサイクルが消費されてしまっているのが原因です。DMAを使うだけでも13.7fpsでの画像が安定することはわかっているのですが、 そうするとどういうわけか UVC のインターフェース切り替えを行なった際にUSBのスタックの動作がおかしくなってしまいます。USBスタックのDMA動作に問題が残っているようです。

今回の実装では、1ラスタ分のデータを1マイクロフレームに入れて送信しています。1ラスタ分のUVCデータ量は、YUVデータ(640*2) + ヘッダ(12) = 1292バイトになりますが、アイソクロナス転送での1トランザクションの最大データ量は1024バイトなので、1マイクロフレームの期間に2トランザクションを使ってデータを送っています。カメラが出力するHsync信号が1msあたり8回ですので、このような簡単な処理でも表示ができています。画像データサイズが大きくなったり、取得できる秒間フレーム数が増えた場合には、できるだけ多くのデータを1マイクロフレームで運ぶ必要が生じます。そのためには、2トランザクション分の容量2048バイトに画像データを詰め込んで送信したり、それでも足りない場合には1マイクロフレームあたり、3トランザクションを送るようにする必要があります。本当はそのあたりも挑戦してみたかったのですが、DMAで安定して1トランザクションで3パケットが送れるようにならないと無理ですね。DMAについてはSTM32 Forumでもバグ報告されているので、今後のリリースに反映されることを期待したいです。

DCMIでカメラをつなぐ

2017-08-03 13:18:22 | CMOSカメラ

気をとりなおして改めてUVCカメラに挑戦することにします。 USB部分はそれなりに動くようになったので、今度はカメラをつなげました。用意してあったコネクタをSTM32F446のDCMIを使ってつなげてやっただけです。



現在のピン割り当ては次のようになっています。USBのHigh speed PHYと DCMIを使ってOV2640をつないだだけで 64ピンのうちの30ピンほどを使ってしまいます。電源とJTAG関係を除くと、使える端子は多くありません。


OV2640に供給するクロックは、TIM12 CH2を使ってシステムクロックを分周して供給することにしました。