2017年09月24日

ソフトリセット

今回はSTM32マイコンでソフトリセットの使用方法について紹介します。


I2Cのデバイスが検出できない場合や何かしらの異常が発生した場合に
電源投入時の状態に初期化したい場合があります。

その場合に便利な機能がソフトリセットです。



使用するSTM32マイコンのコアに応じて、
ヘッダが異なります。

CortexM0の場合は#include "core_cm0.h"
CortexM3の場合は#include "core_cm3.h"
CortexM4の場合は#include "core_cm4.h"
必要に応じて、変更します。

ソフトリセットを行う関数は
NVIC_SystemReset();
です。

何かしらの異常が発生した後に
上記の関数を入れておくと、
ソフトリセットが掛かります。

異常が連続して起きた場合に変な挙動にならないように
ソフトリセットの使い方には要注意ですが、
比較的簡単に実装できました。

続きを読む
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2017年09月15日

BOOT0切替なし書き換え

今回はSTM32マイコンでBOOT0切替なしで
書き換えを行う方法を紹介します。

CubeMXでNucleo等を選択すると
BOOT0切替なしでファームの書き換えができます。

一方で、マイコン単体を選択して
最低限の設定でCubeMXで生成したコードを一度書き込むと、
次回の書き換え等でBOOT0をHighにして電源を入れないと
SWD端子に接続したSTLinkからマイコンが認識されず、
ファームの書き込みや削除ができない現象が発生しました。


原因としてはシリアルデバッグを有効化せずにCubeMXで生成したコードを書き込むと、
シリアルが無効化されてプログラムが動いてしまうことです。
書き換える場合はBoot0をHighにして電源を入れて
bootをシステムメモリに変更することで書き換えできます。

意図しない書き換え防止やセキュリティ強化になりますが、
Boot0のジャンパやスイッチの切り替えが面倒です。


ここで、BOOT0切替なしで書き換えを行う方法を紹介します。
CubeMXの設定でシリアルデバッグを有効化します。

serial-debug.jpg


この状態で生成したファームを書き込むと次回以降の書き換えは
BOOT0切替なしで書き換えできます。


製品としてファームを書き込む以外の実験用途では
意図しない書き換え防止やセキュリティ強化が不要なため、
CubeMXの設定でシリアルデバッグを有効化するのが
Boot0切替の手間がなく便利です。



posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2017年04月13日

FreeRTOS TICK RATE 調査

今回はSTM32 CubeMXで自動生成できる
FreeRTOSについて紹介させて頂きます。

CubeMXでFreeRTOSにチェックを入れるだけで
簡単にFreeRTOSを導入することが可能です。

ロボット制御やモータ制御を専門としていると
リアルタイム性や高速制御周期が制御性能や制御安定性に
効いてくるため気になるポイントです。


今回は将来的に加速度制御系にFreeRTOSを導入する場合を考え、
標準のFreeRTOSのconfigTICK_RATE_HZをデフォルト1000から
10000~60000まで変更してリアルタイム性やスレッドが動作するかテストしてみました。

FreeRTOSはconfigTICK_RATE_HZをデフォルト1000となっていますが、
この場合、最小スレッド切替が1msとなってしまいます。
加速度制御系や電流制御系を構築する場合、
20us~200us程度の最小スレッド切替が欲しいところです。



環境は
・STM32F303K8
 +SW4STM32(System Workbench for STM32)
 +STM32CubeMX(HAL ライブラリ、F3 ver. 1.7.0)
です。


CubeMXの設定は下記の通りです。
MPU周波数は内臓RCで最大周波数の64MHzに設定しました。
ポイントはデフォルトでは無効のosDelayUntil関数を有効化する点です。

rtos-setting1.png

rtos-setting2.png



作成するスレッドは3つ。

void StartDefaultTask(void const * argument)
{
  uint32_t PreviousWakeTime = osKernelSysTick();
  for(;;)
  {
      HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
      osDelayUntil (&PreviousWakeTime, 1);
  }
}

void StartTask02(void const * argument)
{
   uint32_t PreviousWakeTime = osKernelSysTick();
  for(;;)
  {
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4);
    osDelayUntil (&PreviousWakeTime, 1);
  }
 }

void StartTask03(void const * argument)
{
   uint32_t PreviousWakeTime = osKernelSysTick();
  for(;;)
  {
      HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
      osDelayUntil (&PreviousWakeTime, 1);
  }
}

スレッドはそれぞれGPIOのトグルを実行し、
トグル実行時間含めて1tick分まで待機します。


スレッドの生成は3段階の優先度で設定しました。
スレッド1つor 2つの場合は2つ目、3つ目のスレッドをコメントアウトして
スレッドを減らして実行しました。

 /* definition and creation of myTask01 */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityRealtime, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* definition and creation of myTask02 */
  osThreadDef(myTask02, StartTask02, osPriorityHigh, 0, 128);
  myTask02Handle = osThreadCreate(osThread(myTask02), NULL);

  /* definition and creation of myTask03 */
  osThreadDef(myTask03, StartTask03, osPriorityAboveNormal, 0, 128);
  myTask03Handle = osThreadCreate(osThread(myTask03), NULL);




最小スレッド切替の定義は
FreeRTOSConfig.h内の
#define configTICK_RATE_HZ                       ((TickType_t)1000*10)
を変更して実験しました。



◆結果
結果一覧は下記の通り

configTICK_RATE  周期       スレッド1つ   スレッド2つ   スレッド3つ
10000           100us       ○           ○        ○
20000           50us        ○           ○        ○
30000           33us        ○           ○        ×
40000           25us        ○           △       ×
50000           20us        △           ×        ×
60000           17us        ×           ×        ×

○:スレッド通りの動作、△:ジッターが多く、時々スレッド通り動作していない
×:スレッド通り動作していない、他のスレッドが全く動作していない


◆スレッド1つ
スレッド1つの場合、configTICK_RATE_HZ 50000 が限界ラインのようです。
configTICK_RATE_HZ 60000 にすると
下記のように周期が一定でなく、非常にジッターが多い感じです。


1ch60t.png



◆スレッド2つ
スレッド2つの場合、configTICK_RATE_HZ 30000 が限界ラインのようです。
configTICK_RATE_HZ 40000 にすると
下記のようにスレッド1は周期一定ですが、
スレッド2の周期が一定でなく、非常にジッターが多い感じです。


2ch40t.png

更に周期を高く設定して、
configTICK_RATE_HZ 50000 にすると
下記のようにスレッド1は周期一定ですが、
スレッド2が全く動作していません。


2ch50t.png


◆スレッド3つ
スレッド3つの場合、configTICK_RATE_HZ 20000 が限界ラインのようです。
configTICK_RATE_HZ 30000 にすると
下記のようにスレッド1、スレッド2は周期一定ですが、
スレッド3は全く動作していません。

3ch30t.png


更に周期を高く設定して、
configTICK_RATE_HZ 40000 にすると
下記のようにスレッド1は周期一定ですが、
スレッド2の周期が安定せず、
スレッド3は全く動作していません。
3ch40t.png



◆スレッド切替時間
スレッド数2や3の場合は11us程度のようです。
厳密には同時にスレッドスタートできないため、
スレッド切替時間というよりも
スタート時の処理時間の差といった方が正しいかもしれません。

taskswitch.png



◆まとめ

スレッド1つ:25us周期、configTICK_RATE_HZ 40000が限界ライン
スレッド2つ:33us周期、configTICK_RATE_HZ 30000が限界ライン
スレッド3つ:50us周期、configTICK_RATE_HZ 20000が限界ライン
という感じです。
スレッド切替時間は11us程度。

ただ、今回のスレッド内のタスクはLEDトグルの最小限の処理のため、
実際に数値計算の処理やAD変換等の処理が入ると
もう少し限界ラインが変わってくると思います。


理想的な加速度制御系を構築するためには
電流制御周期20us程度が理想で
加速制御周期100us程度となると
スレッド2つでFreeRTOS+F3だとちょっと厳しいかなと思いました。

ということで理想的な加速度制御系を実現するには
MPU周波数が高いF4、F7、H7 を使ってみるか
今まで通り、RTOSなしでタイマ処理で分けるのが良さそうです...

続きを読む
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2017年03月27日

STM32 Studio

今回はSTMマイコンで便利なツールについて紹介します。

マイコンのツールというと、
開発環境と書込みソフトの2つがあれば十分という感じですが、
STMマイコンではSTM32 Studioというツールがあります。


STM32 Studioでは
・グローバル変数のモニタリング
・グローバル変数のグラフ化
・グローバル変数の値書き換え
などができます。

つまりprintfやLCDなどで出力しなくとも簡単に
デバッグを進められます。



使い方は
1. STM32 Studioのダウンロードとインストール

2. ソフト立ち上げ
 ※javaの関連付けができていない場合は
   java binaryへ開くプログラムを変更する

3. マイコン書込み
 マイコンにプログラムを書き込み
 ※書き込み後は接続を解除してください。

4. 設定ファイル読込
  開発環境で生成したバイナリファイルの1つ.elfファイルを読込ます。

set1.png

5. 設定
 「Expand table elements」にチェックを入れて、
 「select all」、「Import」をクリックして、変数をインポートします。
 ※「Expand table elements」にチェックで配列の先頭以外も表示できます。


set3.png

6. 接続先設定
 画面上のプルダウンメニューから
 「STLink SWD」を選択して、
 横の「Start」ボタンを押すと取り込みが開始されます。
 ※書込みツールの接続が維持されていると取り込みでエラーが出ます。
   接続を解除してから「Start」してください。 

set5.png

7. グラフ表示
 左の窓から変数を右の窓へドラッグ&ドロップすると
 変数の変化がほぼリアルタイムに表示されます。

set4.png



ロボット制御のゲイン調整など
Uartや可変抵抗を利用して何度も設定し直すことが一般的でしたが、
これで簡単にリアルタイムに調整ができます。


パラメータ調整やゲイン調整などをSTMマイコンで行う際は
STM32Studioは必須ツールだと思いました。


posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2017年03月22日

I2C Device Search サンプルコード

今回はI2Cデバイスのアドレスを検索して、
一覧を表示するデバイスサーチについて紹介します。


環境はこれまで同様、
・STM32F303K8
 +SW4STM32(System Workbench for STM32)
 +STM32CubeMX(HAL ライブラリ、F3 ver. 1.60)
です。


raspberryPIやArduinoなどでは
I2Cデバイスサーチのコードが公開されており、
I2Cデバイスのアドレス確認や正常動作の確認に使えるので
非常に便利です。

ただ、STM32のHALライブラリで書かれたものがなかったので、
作成してみました。


void I2C_Dev_Search(){

    uint8_t FindNum=0;
    uint8_t FindDev[128];

    printf("*** I2C Device Search Start! ***\n\r");
    for(int i=0; i<0xff;i=i+2){

        uint8_t res=HAL_I2C_Master_Transmit(&hi2c1, i,(uint8_t*)0x00,0,50);
        if(res==HAL_OK){
            FindDev[FindNum]=i;
            FindNum++;
            printf("[0x%X] \t",i);
        }
        else{
            printf("0x%X \t",i);
        }

        if((i+2)%10==0)printf("\n");
        HAL_Delay(1);
    }
    printf("\nDevice Found: %d \n",FindNum);
    for(int i=0; i<FindNum; i++){
        printf("Device No. %d  Address: 0x%X (0x%X)\n",i+1,FindDev[i],FindDev[i]>>1);
    }
    printf("*** I2C Device Search Finished! ***\n\r");
    HAL_Delay(100);

}


上記の関数をmain関数内で実行するとデバイス名が一覧で表示されます。

i2c-search.png

上記では加速度、ジャイロセンサが一体の
MPU6050を接続した際のアドレスが表示されています。

0xD0がHALライブラリで使用するアドレスとなります。
データシートでは読込書込みビットを除いた0x68が
アドレスとして説明されています。

Githubにプロジェクトファイル含めてアップしました。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする