クラッシクサイズ マイクロマウス まとめ

あけましておめでとうございます。

前年度のマシンの設計のまとめについて書いていきたいと思います。

先日、WMMCでDCモーターを初めてやる際にはまった点について話した内容をしっかりとまとめていきます。

 

クラッシクマウスをDCで始めるにあたって。

・辛くても諦めないようにする心を持つ

・回路図を最初に引いて部品を購入して作らざるを得ない状況を作る

マイコンなどは先に評価基板などで動作確認をしておく)

・マイクロマウスをやっている方のブロブをたくさんあさる。

・機械設計や電子回路設計は周りに知っている人がいれば聞く。

→わからないことは聞く!

・進捗は目に見える形で残す(モチベーションアップやどこまで進んでいたか確認が取れるため。)

・プログラムはバージョン管理をする。

githubなどを使うとプログラムの一行ごとの変更ポイントがわかるので自分がプログラムを変えておかしくなったとき、古いプログラム焼きなおしてみてハードウェアが悪いのか、ソフトウェアが悪いのかの確認が可能になる。)

・調整・走り込みは大切

(走り込みをしなかった結果、毎回大会会場で長く走らせていたらマシンが壊れるということをやり、前日の夜または大会当日の朝に動かないといいながらはんだ付けやらなんやらを毎回やる羽目になりました。)

 

機械設計

2DCADで設計を行いました。3DCADで設計はしていないので画像はありません。

設計図は上、横から見た図を描きました。

ギアのバックラッシはM0.5で約0.1mmピッチ円から離してギアの回転が軽くなるようにしました。(力の伝達効率は落ちているとおもいます。)

 

電子回路設計

回路図

 pdfファイルでリンクを張りました。

モーターグラウンドとその他のグラウンドは分離して一点接地をしたほうがいいと思います。私は今年度ノイズに苦しめられました。

 

最後に

全日本大会出場マシンデータ

length : 100mm

width : 72mm

high : 20mm

MCU : stm32f405rgt

MotorDriver : DRV8835

Sensor ST-1KL3A, SFH-4550

Power :  OK Tahmazo REシリーズ リポバッテリー LP2S1P250RE

    2Cell 250mah

 

 

f:id:sora_siro:20190101132130j:plain

マシンの画像

 

これしか画像がなかった・・・

こんな感じです。

 

その他

迷路探索はほとんどがシミュレーターで動作チェックをして実際のマシンに組み込むということを行っています。

使用しているのはVisual Studio Community 2017 + DXライブラリです。

最短経路まで出せると迷路アルゴリズムがただしく動いているかどうかの確認が楽でいいです!

シミュレーター - YouTube

 

 

 

 

 

 

 

 

 

stm32f405rgtとhalライブラリを使用してエンコーダモードを使ってみる

 

今回は stm32f4 + hal(stm32cube)でtimをエンコーダモードに設定してエンコーダの値を取得の仕方をかいていきます。

例によって、stm32cubeを開き、timをエンコーダモードに設定しましょう!
次に、configurationのタブのエンコーダモードに設定したtimの設定を行います。
periodを16bitの最大値である65535に設定します

f:id:sora_siro:20181210113157p:plain

Pin設定

f:id:sora_siro:20181210113224p:plain

設定

あとは、エンコーダの値を確認するためにusartを有効にしてprintfを表示できるようにしました。

 printfに関してはこちらのエントリに書いています

stm32 halライブラリ、makefileでprintf(float型)を使えるようにする! - sora blog

 

そしたらcubeからソースコードを作成してプログラムを書いていきます。

私は、tim.c内のusercode begin - end 内にこのような関数を実装しました。

void update_encoder( t_enc_value *enc )
{

uint16_t enc_l_buff = TIM4->CNT;
uint16_t enc_r_buff = TIM3->CNT;
TIM3->CNT = 0;
TIM4->CNT = 0;

if( enc_l_buff > 32767 ){
enc->left = -1 * (int16_t)enc_l_buff;
} else {
enc->left = -1 * enc_l_buff;
}
 
if ( enc_r_buff > 32767 ){
enc->right = (int16_t)enc_r_buff;
} else {
enc->right = enc_r_buff;
}

 エンコーダのカウントはTIM構造体のCNTにカウントされいていくので、毎回値を確保した後に0にリセットをしています。そのため、定期的に値を取得するということを行うためにこの関数を割り込み内で動かしています。

また、カウントの最大値は先ほど設定した値になります。(詳しくはstm32のマニュアルを読んでください。)

したがって、65535が最大値となっています。

ここで、左側にマイナスがついている理由についてですが、マイクロマウスの場合マシンが直進する際にはモーターの主軸の回転方向が逆になるためです。

if 文についてはint16_tがたの最大値より大きいかどうかを判断して正方向か逆方向化判断して値を取得できるようにしています。

また、t_enc_valueは次のように定義しています。

// enc value
typedef struct {
int16_t left;
int16_t right;
}t_enc_value;

 

そしたら、ちゃんと動いているかどうかを確認していきます。

stm32f4xx_it.cのvoid SysTick_Handler(void)

内でこの関数をよび、int mainのwhileループの前に

HAL_TIM_Encoder_Start( &htim1, TIM_CHANNEL_ALL ); // encoder
HAL_TIM_Encoder_Start( &htim8, TIM_CHANNEL_ALL ); // encoder

 を読んでからprintfで確認をしてみてください。

 

マイクロマウスの場合はここから速度をだして使われることが多いです。私は角速度に直してから速度に変換しています。

方法はいくつかあるのでちゃんと正しい値が返ってくればいいのではないかと考えています。

 

最後に

知見のあるかたでここがおかしいといったことがあれば教えていただきたいです。

 

ところどころ適当になってしまって申し訳ないです。

疲れました・・・

 

stm32f405rg + hal ライブラリ を使用してmpu6500とお話する 

こんばんわ!

先日Twitterでアンケートを取ったところ需要があるという意見を多数いただいたので書いていこうと思います。

実際私自身もはまったのでそれも踏まえて書いていきたいと思います。

最初のstm32 cubeでの設定などに関しては下記のリンクなどを参照してください。

 

sora-siro.hatenablog.com

 

まず初めにmpu 6500 のデータシートを見て設定をするうえで必要そうなことが書いてある場所を探します。この記事では必要そうなところを大まかにピックアップして載せていきます。

いきなりこうだよねみたいな書き方をしていたらデータシートを各自でみて確認してみてください。データシートを読む練習?になると思います。

間違ってたらごめんなさい。ご指摘いただければと思います。

まずは、MPU-6500 Product Specification Revision 1.1 のデータシートから読んでいきます!

f:id:sora_siro:20180915214208p:plain

このページを見ると、2000deg/s にするためには FS_SEL = 3, スケール調整をするために 16.4 で割ればいいということがわかりました。

f:id:sora_siro:20180915214628p:plain

ここをみるとspiの書き込み時は1MHz,読み込みだけなら20MHzまで対応していることがわかります。

先ほど設定したSPIの通信速度をみて間違っている場合は各自直しておきましょう。

f:id:sora_siro:20180915221511p:plain

パワーモードはこんな感じらしいです。

f:id:sora_siro:20180915215244p:plain

この前に通信の際にこのデバイスを指定するときはこのデバイスにつないでるcsPinをLowにしてあげて、このようにすればいいみたいです。

8bit 送って 8bit 送るという16bit 刻みでの通信を行う必要があるそうです。

まずは、アドレスを指定する8bitを送ります。

ただし、最上位ビットでR(Read)/W(Write) : bit 1 / 0 + アドレス、書き込みなら書き込む内容、読み込みならダミーを送信すればいいようです。

ここまでの内容から通信に必要なソースコードを書いてみると以下のようになりました。

読み込みは以下のようになります。

uint8_t read_byte( uint8_t reg )
{
uint8_t ret,val;
HAL_GPIO_WritePin( gyro_cs_GPIO_Port, gyro_cs_Pin, GPIO_PIN_RESET ); //cs = 0;
ret = reg | 0x80;
HAL_SPI_Transmit( &hspi2, &ret,1,100 ); // 読み込みアドレス
HAL_SPI_Receive( &hspi2,&val,1,100 );
HAL_GPIO_WritePin( gyro_cs_GPIO_Port,gyro_cs_Pin, GPIO_PIN_SET ); //cs = 1;
return val;
}

HAL ライブラリには SPI_Receive という便利な関数があったのでそれを使っちゃいました!

続いて書き込みです。

///////////////////////////////////////////////////////////////////////
// spi write 1 byte
// [argument] Register
// [Substitutiong] write data
// [return] nothong
///////////////////////////////////////////////////////////////////////
void write_byte( uint8_t reg, uint8_t val )
{
uint8_t ret;
ret = reg & 0x7F ;
HAL_GPIO_WritePin( gyro_cs_GPIO_Port, gyro_cs_Pin, GPIO_PIN_RESET ); //cs = 0;
HAL_SPI_Transmit( &hspi2, &ret,1,100 ); // 書き込みアドレス
HAL_SPI_Transmit( &hspi2, &val,1,100 );
HAL_GPIO_WritePin( gyro_cs_GPIO_Port,gyro_cs_Pin, GPIO_PIN_SET ); //cs = 1
}

書き込みのときは書き込みのアドレスが上位ビットだけ送信になるので ret = reg & 0x7Fとして最上位ビットは絶対に0になるようにしてます

これで書き込み、読み込みができました。続いてお話しするためには設定が必要になるみたいなのでそれを見ていきたいと思います。

 

次に、MPU-6500 Register Map and Descriptions Revision 2.1を見ていきましょう!

私はこのページに載っているアドレスで必要なものだけマクロ定義をしています。

すべてマクロ定義をしてもOKだと思います。

そうじゃないと確認する際に面倒だと思います。

 

さて、レジスタの詳しい内容を見ていきましょう。

今回設定やチェックをする必要がありそうな内容は

Who Am I ( 君の名は(映画は関係ありません) ) 0x70

2000deg/secに設定する

Z Axis を読み込む

パワー(ジャイロモード)をOnにする

データの出力を許可する

といったところだと思うのでこれらをできるようにそれぞれのレジスタに書き込んだり読み込んだりをできるようにしましょう

 

順番的には

Who Am I

パワーをON

データの出力を許可する

2000 deg / sに設定する

Z 軸のデータを読み込むといったところでしょうか?

 

まずは who am i からいきます。

who am i のレジスタを読みこむ。 以上

はい簡単ですね。

つづいてパワーをON にしましょう

adder 0x6B  PWR_MGMT_1

f:id:sora_siro:20180915222825p:plain

よし、すべてに0をいれれば動くということで0x00を代入します。

ソフトで表すと

write_byte( MPU6500_PWR_MGMT_1, 0x00 );

こんな感じです。

 データの出力を許可するの設定も同様にデータシートを見ていきます。

f:id:sora_siro:20180915223440p:plain

FIFO,LPFは使用する必要がないのですべてに0を代入してしまいましょう!

write_byte( MPU6500_CONFIG, 0x00 );

 

2000 deg / sec の設定の仕方も同様にして

f:id:sora_siro:20180915223725p:plain

2000 deg / sec にするためには 4:3 に 11 をたてればいいみたいです。

書き込む内容は0x18 ですね。

write_byte(MPU6500_GYRO_CONFIG, 0x18);

さて、ここまでで書き込みができたので次は読み込みをしましょう。

ジャイロのデータは16bit で一つのデータになりますが、なんどmpu 6500 は上位と下位でレジスタが分かれてしまっているためなんとかして16bitのデータにまとめる必要があります。なのでビットシフトとキャストを使用してデータの結合、取得を行います!

float MPU6500_read_gyro_z( void )
{
int16_t gyro_z;
float omega;

gyro_z = (int16_t)( ( read_byte(MPU6500_RA_GYRO_ZOUT_H) << 8 )
| read_byte(MPU6500_RA_GYRO_ZOUT_L) );
 
omega = (float)( gyro_z / GYRO_FACTOR);

return omega;
}

こんな感じになります。

gyro_z でジャイロのデータを読み込んで、omegaではdeg/sに直すために定数で割っています。

あとは割り込み関数内で

prev_omega, machine_degree は global変数なり,static でそのファイル内でのみの静的な変数なり毎回リセットされないようにして

now_omega = MPU6500_read_gyro_z();

machine_degree += ( now_omega + prev_omega ) / 2.0f * dt;

prev_omega = now_omega;

とでもすればマシンの角度が取得できると思います。

ただし、この生のデータの値を使用すると0点ドリフトに角度が影響を受けてすごい勢いで大きくなることや小さくなるといった現象に見舞われる可能性があるのでその場合はオフセットを入れましょう。

これは各自考えてみてください。

ヒントはデータをある一定周期で取得してそのデータを足し合わせて・・・です。

 

最後に

データシートはしっかり読みましょう( 自分への戒め )

 

知見のあるかたで、ここをこうしたほうがいいということがあればご指摘していただきたいです。よろしくお願いします。

 

 

マイクロマウス東日本地区大会報告

マイクロマウス東日本地区大会に参加してきました。

これまでマイクロマウスの話は一切出していませんでしたが、stm32マイコンを使うきっかけになった競技がマイクロマウス、ロボットトレーサーでした!

とても楽しかったです!

結果報告になりますが、ロボトレ、マイクロマウスともに完走をすることができ全日本大会の切符(認定証)を手に入れることができました!!

今後はマイクロマウスのことも書いていけたらと思っています。

次は学生大会に参加をする予定です。

また、マイクロマウスの迷路探索シュミレーターを作ってみました。動画を挙げておきます。まだまだ製作途中という感じですが今後の進化を楽しみに!!

まだまだ探索の効率が悪い、最短経路のパスを作ることができてないのでここからが正念場かなと思ってます。

youtu.be

それではまた。

 

youtu.be

迷路探索シミュレーターいろいろと進化!

2018 11/19追記

最短経路の線を近日中に引く予定!

stm32 cube に作成してもらった makefile を使用して c++ のプログラムをコンパイルできるようにする ( memo )

こんにちは。

最近毎日外に出ると蒸し風呂かって言いたくなるくらいの暑さですが、皆様いかがお過ごしでしょうか?

体調管理はしっかり気を付けてやっていきましょう。(自戒)

 

最近、マイクロマウスの迷路のソフトをc++で少し書いていたので、マイコンでもc++が動くようにしたいというところからこの話はスタートしました。

今回の記事では私がnone-eabi-g++,makefile を使用してすべての.c,.cppファイルをコンパイルするまでのやり方を書き残しておこうと思い書くものになります。

所々抜けている点や間違えている点があるかもしれません。ご愛顧でお願いします。また、ご指摘していただけるばと思います。

さて、まずはstm32cube からコードをはいてもらいましょう!

 

そしたら makefile を開いてください。

今回はすべてのファイルを一括でg++でコンパイルをしてしまうということなので

#######################################
# binaries
#######################################
BINPATH =
PREFIX = arm-none-eabi-
CC = $(PREFIX)g++
AS = $(PREFIX)g++ -x assembler-with-cpp
CP = $(PREFIX)objcopy
AR = $(PREFIX)ar
SZ = $(PREFIX)size
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S

のようにしてgccのところをg++に変えてしまいます。

その後、ソース管理のところに

CPP_SOURCES = \

というものを作成してcppソース置き場を作りましょう。

そしたら次にコンパイルオプションの追加を行います。

CFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall
-fdata-sections -ffunction-sections -std=c++11

std=c++11でコンパイルをしたかったためこのようにしました。必要なもののオプションを通せば大丈夫だと思います。

続いてobjectに追加して

# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(CPP_SOURCES:.cpp=.o)))
vpath %.cpp $(sort $(dir $(CPP_SOURCES)))
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))
 
$(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR)
  $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.cpp=.lst)) $< -o $@

また、c言語と同じように、コンパイルをするときのルール?も決めましょう。

 

ここまでやったらcpp_sourseのところにc++のソースファイルを置いてあげればコンパイルをすることが可能になりました。

以上でmakefileの操作は終了になります。

 

ここから先はまった点になります。

一つ目 printf が使えなくなった。

先日の記事で記載した方法でそのまま使用をしようとしたところ使うことができずになぜかと考えたり調べたりしたところ、

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
void __io_putchar(uint8_t ch) {
HAL_UART_Transmit(&huart1, &ch, 1, 1);
}
 

はだめじゃん、__GNUC__はgccに定義されているものじゃんということになり、

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
void __io_putchar(uint8_t ch) {
HAL_UART_Transmit(&huart1, &ch, 1, 1);
}
#ifdef __cplusplus
}
#endif

のようにc言語としてコンパイルしろというマクロを使うことで使用可能にしました。

 

次にerror_handler()のwarningがたくさんおきました。

それはchar*型の関数の引数は関数内で値の変更ができるから推奨しないよということでした。これにはすべてのhファイル,関数の引数を const char*とすることで解決します。

また、main.hも上記に挙げたマクロが使用されていないため自分で書いておくと安全かもしれないです。

 

最後に

 なにか質問等ございましたらコメントに書いていただければわかる内容であれば答えます。間違いなどがあれば教えていただければ幸いです。

 

 

stm32f405rg flashに書き込み

こんにちは

今回はstm32f405rgtのフラッシュにデータを書き込み、読み込み方を書いていきます。

ここに書いてあるのはあくまで一例なのでそこのところはご了承ください。いつも通りこれで動きましたという紹介のような形で書いていきます。

 

それでは本文に入っていきたいと思います。

今回はSTMicroelectronicsの公式サイトにあるja.DM00031020.pdfから絶対に必要だと思われる場所を一部抜粋します。f:id:sora_siro:20180525111624p:plain

f:id:sora_siro:20180525111735p:plain

今回はこの中のセクタ11を使いたいと思います。

 

これでセクタとフラッシュメモリにどのように書き込みができるか削除ができるか、メモリの番地がわかりました。

 

それではプログラムに入っていきたいと思います。

まずはSTM32F405RGTx_FLASH.ldファイルを開いてください。そこのだいたい40行目を以下のように追記、変更してください。

/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 896K
DATA (rx) : ORIGIN = 0x80E0000, LENGTH = 128k
}

このこうすることでDATAっていうプログラムを書き込まない部分を作ることができます。*1

 

それではプログラムにはいっていきたいと思います。

私が実装したソフトは以下のようになりました。

///////////////////////////////////////////////////////////////////////
// ereaseFlash
// [argument] nothing
// [Substitutiong] nothing
// [return] nothing
///////////////////////////////////////////////////////////////////////
void eraseFlash( void )
{
  FLASH_EraseInitTypeDef erase;
  erase.TypeErase = FLASH_TYPEERASE_SECTORS;  // セクタを選ぶ
  erase.Sector = FLASH_SECTOR_11;       // セクタ11を指定
  erase.NbSectors = 1;    // 消すセクタの数(今回はひとつ)
  erase.VoltageRange = FLASH_VOLTAGE_RANGE_3; // 3.3Vで消去

  uint32_t pageError = 0;

  HAL_FLASHEx_Erase(&erase, &pageError);  // HAL_FLASHExの関数で消去
}

///////////////////////////////////////////////////////////////////////
// writeFlash
// [argument] address, *data, size
// [Substitutiong] nothing
// [return] nothing
///////////////////////////////////////////////////////////////////////
void writeFlash(uint32_t address, uint8_t *data, uint32_t size )
{
  HAL_FLASH_Unlock();   // フラッシュをアンロック
  eraseFlash();     // セクタ11を消去
  while ( size > 0 ){
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, *data); // 1byteずつフラッシュに書き込む
++address;
++data;
--size;
  }

  HAL_FLASH_Lock();   // フラッシュをロック
}

///////////////////////////////////////////////////////////////////////
// loadFlash
// [argument] address, *data, size
// [Substitutiong] struct
// [return] nothing
///////////////////////////////////////////////////////////////////////
void loadFlash(uint32_t address, uint8_t *data, uint32_t size )
{
  memcpy(data, (uint8_t*)address, size); // addressの内容をコピー
 
}

 

私は構造体自体で書き込み・読み込みをするようにしています。

 理由としてはフラシュに書き込みするためには1byteずつ書き込みになるので構造体だと都合がよかったため使いました。

また、書き込む構造体を増やしたいときは次のように改造すればできます。

 

///////////////////////////////////////////////////////////////////////
// writeFlash
// [argument] address, *data, size
// [Substitutiong] nothing
// [return] nothing
///////////////////////////////////////////////////////////////////////
void writeFlash(uint32_t address, uint8_t *data, uint32_t size, uint8_t *data2, uint32_t size2 )
{
  HAL_FLASH_Unlock();   // フラッシュをアンロック
  eraseFlash();     // セクタ11を消去
  while ( size > 0 ) {
    // 1byteずつフラッシュに書き込む
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, *data);
++address;
++data;
--size;
  };
 
while ( size2 > 0 ) {
    // 1byteずつフラッシュに書き込む
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, *data2);
++address;
++data;
--size;
  };

  HAL_FLASH_Lock();   // フラッシュをロック
}

///////////////////////////////////////////////////////////////////////
// loadFlash
// [argument] address, *data, size
// [Substitutiong] struct
// [return] nothing
///////////////////////////////////////////////////////////////////////
void loadFlash(uint32_t address, uint8_t *data, uint32_t size, uint8_t *data2, uint32_t size2 )
{
  memcpy(data, (uint8_t*)address, size);
address = address + size;
memcpy(data2, (uint8_t*)address, size2);
address = address + size2;
}

ただ単に引数を増やしてアドレスの更新をしてあげるだけです。

実際に動作確認をした際のソフトは以下のようになりました。*2

 

#include <string.h>
// flash use address ( sector11 )
const uint32_t start_address = 0x80E0000; //sentor11 start address
const uint32_t end_adress = 0x80FFFFF;
 
typedef struct {
int x;
int y;
int dir;
float angle;
float distance;
}POSITION;

POSITION position;

int main()
{
loadFlash( start_address,(uint8_t*)&position, sizeof(POSITION) );
printf("%d,%d,%f,%f\r\n",
position.x, position.y,position.angle, position.distance);

position.x = 100;
position.y = 150;
position.angle = 1.52;
position.distance = 0.18;

writeFlash( start_address,(uint8_t*)&position, sizeof(POSITION) );

}
 

こうしてprintfで構造体positionのメンバの値の変化を一度目の電源を入れたときと二度目で見比べてあげれば書き込まれているかどうかがわかると思います。

 

まとめ

私の勉強不足によりこまかい動作に対しての説明ができず申し訳ないです。

HALの関数の動作に関してはSTMicroelectronicsの公式サイトにある関数をまとめたドキュメントから参照していただければと思います。

 

最後に

知見のあるかたで、ここをこうしたほうがいいということがあればご指摘していただきたいです。よろしくお願いします。

 

更新履歴

2018.5/16

writeFlash関数の中のdo while文の条件式が分かりづらいとの指摘をいただいたので訂正しました。

2018.6/9 

誤字を指摘していただいたため訂正しました。

2018 9/28

書き込みのdo while Loopにミスがあったためwhile Loopにしてミスを訂正。

 

 

 

*1:リンカファイルに関して勉強不足なので間違っているかもしれないです。知見のある方で何か問題があれば指摘をしていただきたいです。

*2:一部抜粋で書きます。

stm32f405rgt,makefileでFPUを使う

arm_mathi.hを使いたいと思い使えるようにしたいということでいろいろと試してみたところできなかったのでTwitterでそのようなことをつぶやいたところosabohさんに教えていただき解決することができました。

ありがとうございました。

 

実装の仕方をここにメモしておきます。

 

まず、stm32cubeのファームウェアからCMISのLibディレクトリを自分のプロジェクトのCMISの直下に置きます。

cubeの初期設定のままなら以下のディレクトリにあると思います。参考までに私は以下のディレクトリにありました。

「C:\Users\alcne\STM32Cube\Repository\STM32Cube_FW_F4_V1.16.0\Drivers\CMSIS」  *1

そしたら、makefileを開き次のように編集します。

# C defines
C_DEFS = \
-DUSE_HAL_DRIVER \
-DARM_MATH_CM4 \
-DSTM32F405xx

 

# libraries
LIBS = -lc -lm -lnosys -larm_cortexM4lf_math
LIBDIR = -L Drivers/CMSIS/Lib/GCC/

 

あとはarm_math.hをよべば使えるはずです。

 

最後に

途中から雑になってしまい申し訳ないです。

知見のあるかたでここをこうしたほうがいいということがあればご指摘していただきたいです。よろしくお願いします。

 

訂正

*1 2018/5/7 F3xxと記載ミスがあったため訂正しました

osabohさん,指摘していただきありがとうございます。