2020年4月16日木曜日

Lチカ最速を求めて STM32F446RE

久々にcubeMXまで引っ張り出してSTM32をいじっているのには理由があって、ちょっと短かいパルスのゲート信号を好きなように生成したいのです。クロック生信号やPWM出力とかなら簡単に高周波を出せますが、1発だけとか、少しずつディレイを変えながら2発とか、そういったちまちましたことをやるのにマイコンは向いています。

そう考えると、単なるベンチマークみたいなIOトグルのLチカ最速周波数が、自由に出力できるパルスの最短を示しているわけで、どうでもいい数字ではないわけです。

arduino勢の速度を丁寧に計ってくれているひとがいて、それによると矩形波の周波数でarduino UNOが500Hz, DUEが17.85Mhz, ESP8266が6.25Mhzだそうです。やっぱりDUEは速いです。

STM32F446のハードウェアを振り返ると、まずCPUクロックが168Mhz~180Mhzです。そしてGPIOはAH1Bに繋がっています。そしてなんとAH1Bの上限はCPUと同じ180Mhzなのです!

あとは、ポートアクセスで無駄なくたたけば1クロックで状態が変わるはず。ということでcubeMXの助けを借りて下のように書いてみました。

IO初期化
  /*Configure GPIO pins : LD2_Pin D7_Pin */
  GPIO_InitStruct.Pin = LD2_Pin|D7_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

IO出力部
  while (1)
  {
    /* USER CODE END WHILE */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);   //LED
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);   //D7
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
   
    GPIOA->ODR = 65535;
    GPIOA->ODR = 0;
    GPIOA->ODR = 65535;
    GPIOA->ODR = 0;
    GPIOA->ODR = 65535;
    GPIOA->ODR = 0;
    GPIOA->ODR = 65535;
    GPIOA->ODR = 0;

    /* USER CODE BEGIN 3 */
  }
その結果がこちら。HALでトグルした遅いパルス2発と、ポートたたきで出した高速パルス4発が見えます。負荷の影響有無も確認したかったのでLEDポートと空きポートD7の2か所に出しています。(特に違い無かったです)

高速パルス4発の拡大がこれ。パルス数で88Mhzということは、確かに2倍の180MhzでIOの上げ下げができているということです。STM32F4すげー。波形はほぼsin波にしか見えないほどなまってるけど、そもそも立ち上がり設定の最速が100Mhzとされてるので文句は言えません。
ちなみにレジスタ操作のところを "GPIOA->ODR ^= GPIO_ODR_5" みたいにオシャレに書く方法がありますが、これはコンパイルするとIO状態リード→論理演算→ライトの3工程に分かれるので数倍遅くなります。

Lチカ速度を調べたいだけだったのに、がんばってググってもいまいちぴったりの例が無くて実演する羽目になりました。でもすっきりして良かった。STM43F4は速いですよ。

0 件のコメント:

コメントを投稿