内蔵DACを使う(Nucleo-F446RE)Nucleo-F446REの内蔵DACからSIN波を出力しました。2.8.1.201903050911STM32CubeMXの設定STM32CubeMXに[Report]という機能があったので出力してみました。*/}位相角を0.01ずつ増やしてsinの値を求め、12bit値に変換して2chある内蔵DACから出力しています。ch2:DAC2(PA5)DAC2はNucleoボード上でLEDに接続されているため、上側がクリップしています。DAC1も上下の最大振幅付近で若干クリップしています。ADCのMCP3208を使う(Nucleo-F446RE)SPIのマスター側が読み取る必要があるA-DコンバーターのMCP3208を動作させました。128プリスケーラ-で分周しやすいようにHCLKを128MHz。64MCP3208はVdd=2.7Vのときクロック周波数は最大1.0MHzなのでそれに合わせてプリスケーラ-を設定。GPIOの設定SPI1のNSS(CS)をソフトウェア制御するために、GPIOで[SPI1_CS]を割り当て。*/MCP3208のデータシートを見ると、SPIで8bit単位で送受信すると、RXデータ(12bit)の上位3ビットはHI-Zで不定になり、4ビット目は0になるようです。このためRXデータ(aRxBuffer[])の2バイト目の上位4ビットはプログラムで読み捨てています。↑DOUTがNucleo-F446側から見るとRXデータになります。*/メインループでMCP3208をポーリングして、値をprintf(UART出力)しています。ch2:SCKPuttyで受信しているようすメモ3連POTのch0(黄色)が動作不良。DACのMCP4922でノコギリ波を2ch出力しました。Master」でOKです。GPIOは、SPIのNSS(CS)をソフトウェアで制御するのに1つ、2ch分ラッチして出力するのでLDAC1つで計2本です。*/ノコギリ波の非反転、反転を出力しました。SPIをPollingとDMAで使う(Nucleo-F446RE)SPI通信を、ポーリングとDMA経由でテストしました。2.8.1.201903050911SPI通信(ポーリング)STM32CubeのExampleはボードを2枚使って互いに通信させていますが、SPI送信波形を見るだけにして一番シンプルな形でテストしました。viewでPB3にSPI1_SCKを割り当ててやれば、有効化できます。Master」にしました。MISOが割り当てられず、SCKとMOSIの2線です。viewでPB4をGPIO_Outputに指定しました。D5クロック設定SPIクロックをちょうど1MHzにしたかったので、HCLKを2のN乗の128MHzにしました。Mux)を内蔵RCのHSIではなく、NucleoボードのST-Link側に乗っている8MHzの水晶から取るために、HSEに切り替えています。0xAAを送信しています。ビット列にすると「01010101:10101010」になります。Master)にしました。Masterの場合より1ピン増えて、MISOが追加されます。viewでPB10をGPIO_Outputに指定しました。SettingsSPIとDMAを紐付ける設定です。Request]で[SPI1_TX][SPI1_RX]を追加します。Normalクロックの設定はポーリングの場合と同じです。*/DMA転送の状態を示すフラグです。*/こちらも0x55、0xAAを送信しています。ソースのコメントにもありますが、DMA転送の完了をWhileループでフラグを見て待機していますが、本来はうまいことやってDMA転送完了待ち中は他の処理をするべきです。*/DMA転送完了の割り込みハンドラです。wTransferStateに状態を代入しているだけです。ch2:SCK(D3)printf()でUART通信しているので(ブロッキングされる)、SPI通信ごとの間隔が広がっています。Puttyで受信しているようすスレーブがつながっていないので受信データは0:0です。Writeしてやれば用は済みます。NSSのハードウェア制御の使い方はしばし保留。Convertするテストをしました。STM32CubeMXの設定[Analog]-[ADC1]で、[Mode]の[IN0]をチェックします。PA0がADC1-IN0に割り当てられます。これはNucleoボードのArduinoヘッダのA0に接続されています。CyclesのままだとDMAの割り込み処理でCPU時間を消費しつくしてしまい、他の処理が行えません。Cyclesを指定しました。実用的には、DMAの処理と他の処理との兼ね合いで値を調整することになると思います。HAL_ADC_Start_DMA()\r\n");に処理が移らず、メッセージが表示されません。*/ADC変換後のDMA転送完了時の割り込み処理です。Nucleoボード上のLEDを点滅させています。点滅の間隔が短すぎて視認できないのでオシロで測定しました。*/メインループ内で、printf()でADCの読み取り値をUART送信し、その前後で処理時間計測用にGPIOをH/Lさせています。ch2:D2(CHK1)メインループ処理中(黄色)にも非同期にADCのDMA転送割り込み(赤色)が行われています。Puttyで受信しているようすマルチチャンネル2ch分ADC読み取りを行いました。プロジェクト:https://github.com/ryood/STM32Cube_Test/tree/master/SW4STM32/Nucleo-F446_ADC_DMA_Multi_Test1STM32CubeMXの設定[Analog]-[ADC1]で、[Mode]の[IN0]、[IN1]をチェックします。PA0がADC1-IN0、PA1がADC1-IN1に割り当てられます。これはNucleoボードのArduinoヘッダのA0、A1に接続されています。Mode]は[Enable]しか選べなくなります。Timeはひとまず480Cyclesを指定しました。*2ch分のバッファを確保しています。*/メインループでは、ADCの読み取り値をUART送信しています。*/DMA転送割り込みハンドラではLEDを点滅させています。ADCをInterruptで使う(Nucleo-F446RE)ADCを1チャネル、割り込みでテストしました。2.8.1.201903050911プロジェクト:https://github.com/ryood/STM32Cube_Test/tree/master/SW4STM32/Nucleo-F446_ADC_Interrupt_Test1STM32CubeMXの設定[Analog]-[ADC1]で[IN0]を有効化。*/HAL_ADC_ConvCpltCallback()は割り込みハンドラで名前は固定です。printf()を使っていますが、ブロッキングされるので本当は割り込みハンドラ内で使ってはいけません。DISABLE;となっています。DISABLEは、stm32f4xx.hで「0U」と定義されています。*/と定義されています。よって「ADC_EOC_SEQ_CONV」(0U)を指定しました。「ADC_EOC_SINGLE_CONV」(1U)の場合は、ポーリングの場合と同様に、起動時に1回割り込みがかかってそれっきりで、連続変換になりません。これはADC_CR2レジスタのEOCSビットの仕様だと思います。ADCをPollingで使う(Nucleo-F446RE)STM32のADCを一番簡単そうな、1チャネルのポーリングで使ってみました。(簡単そうでしたがハマったところがあります。)STM32のADCはポーリングの他に、割り込みやDMAを使う事もでき、こちらのほうがCPU時間を節約できそうです。DISALBE)」で動作させました。Enable)」である点が異なります。STM32CubeMXの設定ADC1のIN0を有効化します。PinoutビューでPA0がADC入力に割り当てられます。HeaderのA0につながっています。Configurationはデフォルトのままです。*/<stdio.h>をインクルード。*/printf()を使えるようにする。*/メインループでADCの読み取りを行う。シングル変換のため、毎回HAL_ADC_Start()を呼んだあと、ADCの値を読み取っています。ADCの初期化コードはSTM32CubeMXによって生成されています。conversion」と指定する必要がありました。調べるとUM1725の6.2.7の「HAL_ADC_PollForConversion」の項に以下の記述がありました。こんなのマニュアル読み込まないとわからない・・・。conversion」のままだと、起動後1回だけADC変換が行われそれ以降は同じ値が返ってくるようです。*/連続変換モードにしてHAL_ADC_Start()をメインループの外に追い出せました。メモ:STM32CubeF4はSTM32CubeF3とはADCの仕様が結構異なり、「HAL_ADCEx_Calibration」がない模様。UARTでprintfを使う(浮動小数点型あり)STM32のUARTでprintf関数を使ってみました。2.8.1.201903050911プロジェクト:https://github.com/ryood/STM32Cube_Test/tree/master/SW4STM32/UART_printf_test1UART自体の基本的な使い方は「STM32CubeとTrueSTUDIOでUART通信」にあります。*/<stdio.h>をインクルードします。__io_putchar()で、HAL_UART_Transmit()をラッピングするコードです。これによってprintf()内部でHAL_UART_Transmit()が呼ばれるようになります。0.01;」は無駄な演算です。_printf_float」せよと、IDEでアラートが表示されます。_printf_float」を指定します。Codeすると「syscalls.c」は<projectフォルダ>/Srcに入っています。Functionsの処理速度を測定しました。関数が用意されています。その1」を参考にしました。「<STM32Cube>\Repository\STM32Cube_FW_F4_V1.24.0\Drivers\CMSIS\Lib\GCC\libarm_cortexM4lf_math.a」を「<workspace>\CMSIS_DSP_test1\」(プロジェクトのルート)にコピー。ファイル名の"l"はリトル・エンディアン、"f"はfpuの意味のようです。path(-L)"${workspace_loc:/${ProjName}}"Libraryの指定は、接頭辞の"lib"及び接尾辞の".a"を抜きます。Preprocessorで「ARM_MATH_CM4」を指定。「__FPU_PRESENT」はもともと定義されているようで、Preprocessorで指定すると「redefined」のアラートが出ます。Libraryの関数(sinf()など)と、CMSIS-DSPの関数(arm_sqrt_f32()など)をコメントアウトしたり外したりしてビルドし直して計測しました。GPIOをH/Lさせてオシロで処理時間を測定しました。APIを使用しました。i);」でvolatile修飾に対して警告が出ましたが無視しています。cosineはCMSIS-DSPを使うとかなり高速化できるようです。メモ:STM32CubeMXとSW4STM32を行ったり来たりすると、「STM32F446RETx_FLASH.ld」が空(0Byte)になってビルドできなくなることがあります。Codeし直せば良いようです。