2021年05月01日

STM32マイコンUART拡張機能

STM32F7、L4、H7シリーズではUART通信をする際に非常に便利な拡張機能があります。今回はUART拡張機能について紹介します。例えばUARTを利用する際に基板のTXとRXを間違えて逆転させてしまったり(回路上でTXとRXをクロスさせることを忘れていた)、フォトカプラを接続するので論理を逆転させたい(通常は論理反転のバッファICやトランジスタ等で追加ハードウェアで論理反転させる)、DMA受信時のエラー処理を無効にしたい(デフォルトではSTM32のUART受信でフレームエラー等が発生するとクリアするまで受信できない)といったことが多々あると思います。そのような場合にUART拡張機能を利用することでハードウェア追加や修正なしにソフトウェア側の設定変更のみで切り替えることが可能です。

UART拡張機能は下記の通りです。

名称機能
UART_ADVFEATURE_TXINVERTTX論理反転
UART_ADVFEATURE_RXINVERTRX論理反転
UART_ADVFEATURE_DATAINVERTデータビット論理反転
UART_ADVFEATURE_SWAPTX、RX入れ替え
UART_ADVFEATURE_RXOVERRUNDISABLE受信エラー無効
UART_ADVFEATURE_DMADISABLEONERRORDMA受信エラー無効
UART_ADVFEATURE_AUTOBAUDRATEオートボーレート有効
UART_ADVFEATURE_MSBFIRSTMSB有効


UART拡張機能の定義はstm32XX_hal_uart.hで下記のように定義されています。

/*!< No advanced feature initialization */
#define UART_ADVFEATURE_NO_INIT 0x00000000U

/*!< TX pin active level inversion */
#define UART_ADVFEATURE_TXINVERT_INIT 0x00000001U

/*!< RX pin active level inversion */
#define UART_ADVFEATURE_RXINVERT_INIT 0x00000002U

/*!< Binary data inversion */
#define UART_ADVFEATURE_DATAINVERT_INIT 0x00000004U

/*!< TX/RX pins swap */
#define UART_ADVFEATURE_SWAP_INIT 0x00000008U

/*!< RX overrun disable */
#define UART_ADVFEATURE_RXOVERRUNDISABLE_INIT 0x00000010U

/*!< DMA disable on Reception Error */
#define UART_ADVFEATURE_DMADISABLEONERROR_INIT 0x00000020U

/*!< Auto Baud rate detection initialization */
#define UART_ADVFEATURE_AUTOBAUDRATE_INIT 0x00000040U

/*!< Most significant bit sent/received first */
#define UART_ADVFEATURE_MSBFIRST_INIT 0x00000080U


実際に使用する場合はCubeMXで設定するか、下記のコードをUART初期化関数MX_USARTX_UART_Initに追記して使用します。CubeMXで設定する場合は下記のようにUARTの設定項目のAdvanced Featuresから有効/無効を設定します。

uart.jpg

コード上から修正する場合はデフォルトでUART_ADVFEATURE_NO_INITとなっているため、必要な項目を追加して各項目を有効化して使用します。

デフォルト
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

追加例
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_TXINVERT_INIT | UART_ADVFEATURE_SWAP_INIT;
huart1.AdvancedInit.TxPinLevelInvert = UART_ADVFEATURE_TXINV_ENABLE;
huart1.AdvancedInit.Swap = UART_ADVFEATURE_SWAP_ENABLE;

STM32F7、L4、H7シリーズのみ対応しているのが残念ですが、UART拡張機能の中でもTXとRXの入れ替え機能は非常に便利だと思いました。TXとRXをクロスさせて回路設計することを忘れていたり、クロスさせたはずが回路上で間違えていたり、クロスケーブルがなく、ストレートケーブルしか準備できていなかったり、UARTのTX、RX絡みでよくあるトラブルがソフトウェア上で解決できるのは非常に便利です。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2021年04月10日

PIC32MX + Harmony3 + MSD(USB Host) 設定ポイント

ここ5年くらいはSTM32マイコンを中心に開発、展開していました。しかし、昨今の半導体供給不足で主要なSTM32マイコンが入手困難となっています。運よく在庫がある場合でも価格が上がっている場合が多々あります。STM32マイコンがこれまで通りに安定して入手可能になるには少なくとも半年(2021年末)、長くて数年(2022~23年以降)は要すると思われます。

このような状況を受けて、STM32マイコンの代替として今更ながら古巣のPICマイコンに少し戻ってきました。PICマイコンも半導体供給不足の影響を多少受けていますが、STM32マイコンほど長納期化していません。主にdsPIC33F、30Fを使用していた10年近く前に比べると自動コード生成ツール(Harmony Configurator)、内部可視化(Data Visualizer)等のツール群が充実してきています。

今回はPIC32MX250F128BをターゲットにMPLAB X v5.45+Harmony3を使用してUSBメモリへの書き込み(MSD:Mass Strage Device)を行いました。その際にポイントとなる設定について紹介します。なお、ターゲットへの書き込みはPickit3を使用しました。


全体の手順については既にMicrochipのgithubサイトに詳しく書かれているため、設定のポイントに絞って紹介します。
MPLAB Xには予め、MPLAB Harmony 3 Launcher(旧名称 MPLAB Harmony Configurator 3)をインストールしてあります。


@File System設定
Use File System Auto Mount Featureにチェックを入れます。また、Media TypeにSYS_FS_MEDIA_TYPE_MSDを選択します。この設定を忘れるとSYS_FS_EventHandlerSet関数やSYS_FS_MEDIA_MANAGER_EventHandlerSet関数が生成されず、app.cのサンプルプログラムのビルドで失敗します。


filesystem_setting.jpg


AHeap Size設定
こちらのMicrochipのgithubサイトでは500byte以上とありましたが、500byteでは動作しませんでした。1024byte程度が良さそうです。

system_heap_setting.jpg


BCrystal設定
PIC32MX2XXの場合はこちらのMicrochipのgithubサイトとは異なり、クロック設定箇所はシンプルです。一方でUSBを使用する場合は外付け発振子が必須となります。最終的に設定上部のUSB Clockが48000000Hz(48MHz)になっていればOKです。USB Clockが0Hzといった48MHz以外の場合は設定を見直す必要があります。

crystal_setting.jpg


以上の設定を終えた段階で、プロジェクトフォルダsrc内のapp.c、app.hを下記のサンプルコードに置き換えます。
Harmony3\usb_apps_host\apps\msd_basic\firmware\src

置き換え後、USBメモリをPIC32マイコンに接続し、ファームを書き込むとUSBメモリにサンプルファイルが保存されれば成功です。

result.jpg

今回のコード、プロジェクトファイルは
です。

STM32マイコンのCubeMXのようにMPLAB Harmonyによって最初のセットアップの敷居が下がっていることを実感できました。一方でMPLAB Harmonyの情報が少なく、バージョンによってUIや設定項目が異なるため、情報収集に苦労する面がありました。今後、CubeMXの様に洗練されたUIになることに期待です。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2021年03月13日

VinculumU SPIパフォーマンス

以前にFTDIのVinculumUを紹介しました。VinculumUはUSBホスト機能を備えたマイコンで最大2つのUSBポートを使用することができます。開発環境のVinculum II Toolchainを使用することで書き込むプログラムによって様々な機能のUSBホストを実現することが可能です。

今回はVinculumU を用いてSPIマスタのパフォーマンスを評価してみました。最終的にはUSBから取得したデータをVinculumU のSPIマスタを介して外付けメモリに転送することを検討しています。検討に際して想定よりもパフォーマンスが出ないことが分かったため、設定による違いをまとめてみました。

前提条件としてvos_initではVOS_Q=10、VOS_TICK=1、NUMBER_OF_DEVICES=4、VOS_48MHZ_CLOCK_FREQUENCY、VOS_IOCTL_SPI_MASTER_SET_DATA_DELAY=0で実験しています。また、CSとCLKを測定して1回のSPI通信サイクルを確認しました。

まず、DMAを無効化した状態で8byteのデータをSPIマスタから書き込む操作を行いました。

vos_dev_write(hSPI_MASTER, wcmd, 4, &num);
vos_dev_read(hSPI_MASTER, dummy, 4, &num);
vos_dev_write(hSPI_MASTER, data, 4, &num);
vos_dev_read(hSPI_MASTER, dummy, 4, &num);

■DMA未使用
VOS_IOCTL_COMMON_DISABLE_DMA、クロック3MHz

1_No_DMA_3MHz_8byte.png

黄色がCLK、赤がCSです。CSが0の期間は約820usecとなりました。1byte毎に分かれて送出されていることが分かります。また、各byte毎に50usec程度の間をおいてから次のbyteが送出されています。また、4byteの書き込み後、次の4byteを書き込むまでに200usec以上要していることが分かりました。

■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック3MHz
DMA転送を有効にしてDMAモードをDMA_ACQUIRE_AS_REQUIREDで同様に書き込みを行いました。

2_DMA_AS_3MHz_8byte.png

DMAを有効にすると1byte毎でなく、4byteまとめて送出されてるようになりました。CSが0の期間は約750usecとなりました。


■DMA使用DMA_ACQUIRE_AND_RETAINモード、クロック3MHz
DMAモードをDMA_ACQUIRE_AND_RETAINで同様に書き込みを行いました。

3_DMA_AND_3MHz_8byte.png

DMA_ACQUIRE_AND_RETAINモードでは4byteと次の4byteとの間隔が短くなり、CSが0の期間は約500usecとなりました。

■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック20MHz
SPI通信のクロックを上げてDMA_ACQUIRE_AS_REQUIREDモードで同様に書き込みを行いました。

4_DMA_AS_20MHz_8byte.png

クロックを上げると4byteと次の4byteとの間隔が短くなり、CSが0の期間は約380usecとなりました。

■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック20MHz、まとめて書き込み

4Byteを2回書き込みでなく、8byteを1回の書き込みに変更してみました。
vos_dev_write(hSPI_MASTER, data, 8, &num);
vos_dev_read(hSPI_MASTER, dummy, 8, &num);

5_DMA_AS_20MHz_8byteOnce.png

CSが0の期間は約200usecとなりました。

■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック20MHz、まとめて書き込み、Writeのみ
VinculumUのSPIマスタは書き込み関数と読み込み関数がそれぞれ分かれています。通常は書き込み関数と読み込み関数の2つを使用してSPI通信の読み書きをします。書き込みのみの場合はvos_dev_write関数のみで構いませんが、読み込みの場合はvos_dev_write関数を実行してからvos_dev_read関数で値を読み込む必要があります。今回はメモリ書き込みのみを想定した場合、厳密には読み込み処理は不要です。書き込み関数のみにして同様に測定しました。

vos_dev_write(hSPI_MASTER, data, 8, &num);
//vos_dev_read(hSPI_MASTER, dummy, 8, &num);

6_DMA_AS_20MHz_8byteOnceWriteOnly.png

CSが0の期間は約100usecとなりました。

■結果まとめ
以上の結果からSPI通信を短時間で実行するためにはDMA転送の有効化、DMA_ACQUIRE_AS_REQUIREDよりもDMA_ACQUIRE_AND_RETAIN、クロックを高速にすることが重要であることが分かりました。また、vos_dev_write関数、vos_dev_read関数を細切れに呼び出すよりも分けずにまとめて呼び出すことが同様に短時間化に重要だと分かりました。

VinculumUは独自RTOSで実装されており、各処理の切り替え、関数呼び出しのオーバーヘッドが大きいようです。最後の結果でもCSが下がってからクロックが出るまで約40usec要しています。同様にクロックがで終わってからCSが上がるまでに約50usec要しています。VOS_Q、VOS_TICKの値を様々に変更してタイムスライスを小さくしても劇的な変化はありませんでした。VinculumU のSPIマスタは関数呼び出しのオーバーヘッドが非常に大きいことを考慮する必要があることが分かりました。

なお、今回の結果とは別に書き込みのみで書き込みデータを増やしてCSが0の区間を測定すると下記のような結果になりました。

書き込みデータ8byte192byte384byte512byte640byte800byte944byte
処理時間100usec200usec260usec310usec350usec410usec460usec

CS変化前後の処理オーバーヘッドの時間は変わらず、データ数の増加に合わせて処理時間が長くなる結果となりました。

これらのことからVinculumU のSPIマスタは高速な読み書き用途としてあまり向いていないことが分かりました。実装する際は関数呼び出しのオーバーヘッドを考慮してコーディングする必要があると分かりました。特にUSBのIsochronous転送の場合、最短1msecごとにデータが転送されます。少なくとも1msecより短い時間で1回の転送データを書き込む必要があり、SPI通信の処理速度が求められます。今後はIsochronous転送でどれくらいのデータ処理ができるか検討したいと思います。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2021年01月16日

QSPI通信を用いたSRAM読み書き

STM32マイコンのペリフェラル機能の1つ、QSPIがあります。今回はQSPIでNOR Flashではなく、SRAM(IS62WVS5128FB)を読み書きする方法を紹介します。データ削除等が必要なNOR FlashよりもSRAMは処理がシンプルで、読み書きのみです。

SPIは4つの信号線 (CS:Cable Select、SCK:Serial Clock、MISO:Master In Slave Out、MOSI:Master Out Slave In) で構成されています。一方、QSPIは6つの信号線(CS、SIO0、SIO1、SIO2、SIO3、SCK)で構成されています。SPIはMISO、MOSIの2本の通信バスに対して、QSPIはSIO0、SIO1、SIO2、SIO3の4本の通信バスに拡張されています。そのため、1クロックで送受信できるデータが2倍となり、より高速に通信できるようになっています。QSPIは主にNOR Flash、SRAM等のメモリ向けのインタフェースとして多く採用されています。

QSPI通信はSPI通信と互換があり、多くのQSPI対応デバイスは起動直後はSPIデバイスとして動作します。初期化や設定が完了してからQSPIモードに切り替えて高速に通信します。また、SPIのMISO、MOSIの2本のバスは通信方向が固定されていますが、QSPIは通信状態に応じて通信方向が変化します。通信状態をやり取りするためにSPIと異なり、インストラクションを送ってからアドレスやデータのやり取りを行います。多くの場合はインストラクション+アドレス+データの3つで構成されています。

STM32マイコンのHALライブラリでは、HAL_QSPI_Commandでインストラクション+アドレス+データ設定を行い、送信の場合のデータはHAL_QSPI_Transmitで送信し、受信の場合はHAL_QSPI_Receiveで受信します。

具体的にデータをメモリから読み込む場合は下記のような流れで設定します。
QSPI_CommandTypeDef sCommand;
HAL_StatusTypeDef res=0;
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;//インストラクションのバス数 1~4
sCommand.Instruction = READ_CMD;//インストラクション
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;//アドレスのバス数 1~4
sCommand.Address = address;//アドレス
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;//アドレス長
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;//オルタネイトバイト(拡張用、通常は未使用)
sCommand.DataMode = QSPI_DATA_1_LINE;//データのバス数 1~4
sCommand.DummyCycles = 0;//アドレスを設定してからデータの送受信までに待機が必要な場合に設定
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;//DDRモード設定
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;//DDRモード時遅延設定
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;//コマンドモード
sCommand.NbData = read_length;//データ長さ
res+=HAL_QSPI_Command(&QSPIHandle, &sCommand, 0xFFF);//インストラクション+アドレス+データ設定
res+=HAL_QSPI_Receive(&QSPIHandle, read_data, 0xFFF);//受信処理

上記の例では一般的なインダイレクトモードの例を紹介しました。STM32マイコンのQSPIではインダイレクトモード、ステータスポーリングモード、メモリマップモードの3種類あります。

インダイレクトモード:インストラクション+アドレス+データで送受信する一般的処理モードです。
ステータスポーリングモード:メモリのフォーマット等、時間を要する処理の場合に処理の完了有無を定期的に自動で確認することができます。
メモリマップモード:アドレスで直接、データを読み込み可能なモードです。ポイントは読み込み専用で書き込み不可。フォントや画像といった固定のデータを読み出す場合に向いています。

SRAM(IS62WVS5128FB)はDDRモードに対応していませんが、DDRモードに対応しているメモリの場合、クロックの立上がりと立下りの両方でデータのやり取りができるため、さらに倍のデータをやり取りできます。今回は読み込みのみ紹介しましたが、SRAM(IS62WVS5128FB)とQSPIで読み書きする全体コードはこちらにアップしました。


最近のSTM32L5等ではQSPIの代わりにOctalSPIが搭載されています。OctalSPIはバスが8本となりさらに高速に通信することが可能です。残念ながらQSPIのメモリマップモードは読み込み専用ですが、OctalSPIのメモリマップモードはFMCやFSMCのメモリマップモード同様に読み書き可能です。OctalSPIも今後紹介したいと思います。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2021年01月09日

C言語FFTライブラリ

今回はC言語ベースのFFTライブラリについて紹介します。音や画像などを処理する場合に欠かせない処理としてFFTがあります。1次元の場合はFFT処理で時間毎の信号を周波数ごとの信号に変換できます。1からFFT処理を実装するよりも多くの場合はライブラリを活用すると思います。今回は代表的なFFTライブラリを紹介したいと思います。

・ライセンス
 GPL、商用ライセンス

・メリット
 多次元対応
 CPUの拡張命令によってより高速な処理が可能
 マルチスレッド対応

・デメリット
 GPLライセンス
 専用ライブラリを組み込む必要がある
 fotranコンパイラが必要
 malloc使用
 →組み込み系には向かない

・ライセンス
 修正 BSD

・メリット
 BSDライセンス
 FFTWと互換インタフェース
 多次元対応
 fotranコンパイラ不要

・デメリット
 全てのFFTW関数と互換があるわけではない
 コード構成が複雑
 malloc使用
 →組み込み系には向かない

・ラインセンス
 フリーソフトウェア

・メリット
 コード構成がシンプルで移植が容易
 CPUの拡張命令未使用で移植性が高い
 マルチスレッド対応
 malloc使用/未使用選択可能
 組み込み系にも移植可能

・デメリット
 CPUの拡張命令未使用で速度は期待できない

・ライセンス
  Apache2.0

・メリット
 ARM DSPを活用した高速処理

・デメリット
 ARMDSP搭載マイコンのみ使用可能
 ARMDSP専用で移植性が低い
 サイズ最大4096点

PCアプリケーションで使用する場合はFFTSSやFFTSGがお勧めです。組み込み系の場合はFFTSGがお勧めです。

STM32マイコンでFPU搭載の場合、FFTSGとCMSIS-DSPライブラリで同じ処理点数で速度差はほとんどありませんでした。DSPを使用するCMSIS-DSPライブラリの方がハードウェア演算を利用するため、若干速くなります。

ただ、最適化されたFFTとFPUによってFFTSGも高速に処理できるため、あまり差がなくなっています。一方、CMSIS-DSPライブラリは最大4096点と用意されている関数の点数に制約があります。また、事前にVisualStudio等のコンソールアプリケーションとして単体テストしてからマイコンに移植するといった用途も考えるとFFTSGの一択となります。FFTSGのソースコードはdoubleとなっているため、STM32マイコン等に移植する際にはソースコード内のdoubleを丸ごとfloatに置換させるとFPUで高速に処理できるようになります。なお、FFTSGはサイズ最大4096点の制約がないものの、4096点以上の場合に膨大なRAMメモリが必要となります。高性能マイコンや外部RAM搭載マイコンが必要となります。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする