2017年6月25日日曜日
りはびり:03
さて、話しは前後して、作ったプログラムを動かすマイコンボードの話。
パソコンプログラムと違って、組み込みプログラムはビルドしただけでは動かせない。
組み込みマイコンも市販品は数多くあるので何を使うかは迷うところだけれど、今回はストロベリー・リナックスさんのSTBee F4miniを使うことにする。
特にこれと言って理由はないけれど、あえて言えば、
・小さいこと
・手元にあること
・あまりネットに情報がないこと
、が選定理由でしょうか。
STBee Miniとはまた別の製品なので注意が必要です。
STBee F4miniの製品ページはこちら(https://strawberry-linux.com/catalog/items?code=32405)を参照。
使用マイコン:STM32F405RGT
メインクロック:12MHz
プッシュスイッチ:ポートA-0
ユーザLED:ポートD-2
ひとまず直近のプログラムでは、この情報がわかっていればいいです。
プログラムのライターソフトは、マイコンメーカのSTマイクロのDfuSeというソフトを使います。
リンクはこちら(http://www.st.com/ja/development-tools/stsw-stm32080.html)。
DfuSeを使ったプログラムの書き込み手順は、ストロベリー・リナックスのこちらのページ(http://strawberry-linux.com/stbee/dfuse)が詳しい。
※紹介ページのマイコンボードはSTBeeです。STBee F4miniとは違いますので注意です。
さて、DfuSeで書き込めるファイル形式は、*.dfuです。
前回gccで生成したmain.elfはそのままでは書き込めませんので、変換作業が必要です。
dfu形式のファイルを作るには、DFU File Managerを使いますが、このソフトで扱えるのはS19形式、HEX形式、BIN形式です。今回は、以下のコマンドでHEX形式のファイルを生成します。
> arm-none-eabi-objcopy -O ihex main.elf main.hex
他の作業はストロベリー・リナックスのサイトのやり方と同じです。
※GUI操作なので、超面倒です。
コマンドライン操作の方法は次回。
2017年6月21日水曜日
りはびり:02
前回の続き。
main.cをコンパイルしたらエラーになる話。
> arm-none-eabi-gcc.exe main.c -o main
arm-none-eabi/lib\libc.a(lib_a-exit.o): In function `exit':
exit.c:(.text.exit+0x2c): undefined reference to `_exit'
collect2.exe: error: ld returned 1 exit status
この_exitは参照した覚えがない。
C言語の勉強をすると、ほぼ必ず、「C言語はmain関数から始まります」と教えられる。
基本的にはそれで正しいのだと思うけれど、組み込みC言語の目線では正しくない。
組み込みの世界ではmain関数を呼び出すためのスタートアップルーチンという裏方さんに、どんな仕事をしてほしいか、きっちり教えて上げる必要がある。
教育の機会に恵まれない裏方さんは、とりあえず万人向けの仕事をしようとする。その仕事の一つが_exitという処理なのだ(難しい話なので抽象化して書いてます)。
ひとまず、裏方さんには大人しくしていて貰いたいので、「-nostartfiles」というオプションをつけてコンパイルしてみます。このオプションについてはgccの公式ページを見てください。
>arm-none-eabi-gcc main.c -o main.o -nostartfiles
arm-none-eabi/bin/ld.exe: warning: cannot find entry symbol _start; defaulting to 00008000
今度はwarningが発生しています。_startのエントリがないので、デフォルトの00008000にするよ、というメッセージです。
何を言っているのか、分かりませんね。
うまく説明できないので強引に対策だけいうと、リンカスクリプトをオプションで指定します。
「-T ./STM32F405RGT6.ld」です。
STM32F405RGT6.ld ファイルは、ねむいさんが公開されているサンプルコードから流用させてもらいました。STマイクロのサンプルコード集にも別マイコン用のリンカスクリプトがあるので、それをもとに自分で作れる人は頑張ってください。
ちなみに、「STM32F405RGT6.ld」は内部で「STM32F40_41xxx_FLASH.ld」を呼び出しているので、同じフォルダにおいておきます。
>arm-none-eabi-gcc main.c -o main.o -nostartfiles -T ./STM32F405RGT6.ld
ひとまずエラーはでなくなった。
最後に、main.oをgccが出力する実行形式のelf形式に変換します。
>arm-none-eabi-gcc -nostartfiles -T ./STM32F405RGT6.ld main.o -o main.elf
今日はここまで。
エラーが出なくなったからって、動くものが出来たわけではないのが、組み込みの怖いところ。(笑)
main.cをコンパイルしたらエラーになる話。
> arm-none-eabi-gcc.exe main.c -o main
arm-none-eabi/lib\libc.a(lib_a-exit.o): In function `exit':
exit.c:(.text.exit+0x2c): undefined reference to `_exit'
collect2.exe: error: ld returned 1 exit status
この_exitは参照した覚えがない。
C言語の勉強をすると、ほぼ必ず、「C言語はmain関数から始まります」と教えられる。
基本的にはそれで正しいのだと思うけれど、組み込みC言語の目線では正しくない。
組み込みの世界ではmain関数を呼び出すためのスタートアップルーチンという裏方さんに、どんな仕事をしてほしいか、きっちり教えて上げる必要がある。
教育の機会に恵まれない裏方さんは、とりあえず万人向けの仕事をしようとする。その仕事の一つが_exitという処理なのだ(難しい話なので抽象化して書いてます)。
ひとまず、裏方さんには大人しくしていて貰いたいので、「-nostartfiles」というオプションをつけてコンパイルしてみます。このオプションについてはgccの公式ページを見てください。
>arm-none-eabi-gcc main.c -o main.o -nostartfiles
arm-none-eabi/bin/ld.exe: warning: cannot find entry symbol _start; defaulting to 00008000
今度はwarningが発生しています。_startのエントリがないので、デフォルトの00008000にするよ、というメッセージです。
何を言っているのか、分かりませんね。
うまく説明できないので強引に対策だけいうと、リンカスクリプトをオプションで指定します。
「-T ./STM32F405RGT6.ld」です。
STM32F405RGT6.ld ファイルは、ねむいさんが公開されているサンプルコードから流用させてもらいました。STマイクロのサンプルコード集にも別マイコン用のリンカスクリプトがあるので、それをもとに自分で作れる人は頑張ってください。
ちなみに、「STM32F405RGT6.ld」は内部で「STM32F40_41xxx_FLASH.ld」を呼び出しているので、同じフォルダにおいておきます。
>arm-none-eabi-gcc main.c -o main.o -nostartfiles -T ./STM32F405RGT6.ld
ひとまずエラーはでなくなった。
最後に、main.oをgccが出力する実行形式のelf形式に変換します。
>arm-none-eabi-gcc -nostartfiles -T ./STM32F405RGT6.ld main.o -o main.elf
今日はここまで。
エラーが出なくなったからって、動くものが出来たわけではないのが、組み込みの怖いところ。(笑)
2017年6月15日木曜日
りはびり:01
しばらく組み込みから離れていたので、リハビリがてらARMマイコンで動くプログラムをコマンドラインでコンパイル・ビルドする方法を勉強しなおす。
基本的な開発環境は「ねむいさんのぶろぐ(http://nemuisan.blog.bai.ne.jp/?eid=188089)」を参考に構築しています。
コーディングに使うエディタは秀丸エディタを使用します。
coreutilsとかlaunchpadとかへのパスはwindowsの環境変数にセットしています。
まずは、とてもシンプルなプログラムを作ってみます。
main.c
int main(void)
{
return 10;
}
これをコンパイルしてみます。
> arm-none-eabi-gcc.exe hello.c -o hello arm-none-eabi/lib\libc.a(lib_a-exit.o): In function `exit': exit.c:(.text.exit+0x2c): undefined reference to `_exit' collect2.exe: error: ld returned 1 exit status
なにやらエラーになりました。
未定義の_exitを参照していると言われています。そんなの参照している覚えはないのですけどね。
続きは次回。
2016年7月8日金曜日
ST-Linkの種類
現在、ねむいさんの環境でSTM32F4のデバッグを行なっている。
STM32F4-discoveryを使ってGDB+inghtは正常に動くのだけれど、STM32F4-nucleo のST-LINK回路+STbeeF4miniだと上手くいかない。
target setting の画面を表示しようとするとフリーズしてしまう。
似たような環境だけれど、細かい部分は全然違うので、どこから手をつけたらいいか。
まず、OpenOCDとはJTAGではなく、SWDで接続しているつもり。
STM32F4-discoveryはST-Link/V2の回路になっていて、ねむいさんのサンプルcfgファイルで接続できる。
STM32F4-nucleoもST-Link/V2の回路になって・・・・、あれ、紹介ページにはST-Link/V2-1になっている。-1ってなんだ?
ねむいさんのこのブログでは、ST-Link/V2とST-Link/V2-1は明確に使い分けされている。
なるほど。
ST-Link/V2-1用のcfgファイルも用意されているので、なんとか解決の糸口を見つけた。
STM32F4-discovery用のcfgファイルを編集するのは嫌なので、STbeeF4mini用にコピー&編集してST-Link/V2-1を使ったOpenOCDアクセス環境を作って接続!・・・・失敗。
ねむいさんのブログでは、 ST-Link/V2-1を使うときはVCPドライバ必須とある。
すでに私の環境ではWindows7からはSTM32F4-nucleoとVCPで繋がっているように見える。
けれど、手元のダウンロード保管庫には ST-Link/V2用のVCPドライバは保管してあるけれど、ST-Link/V2-1用のVCPドライバは保管されていない。
わずかな望みを掛けてST-Link/V2-1用のVCPドライバをインストールしてみた。
結果、 target setting の画面が表示されて、設定をすることもできた。
ターゲットと接続することが出来て、ステップ実行も出来た。
これで万事解決!
と思ったけれど、もう一度つなごうとしたら、やはりtarget setting の画面でフリーズする。
惜しいところまで行っていると思うのだけれど。
ST-Link/V2-1用のVCPドライバはこちら。
STM32F4-discoveryを使ってGDB+inghtは正常に動くのだけれど、STM32F4-nucleo のST-LINK回路+STbeeF4miniだと上手くいかない。
target setting の画面を表示しようとするとフリーズしてしまう。
似たような環境だけれど、細かい部分は全然違うので、どこから手をつけたらいいか。
まず、OpenOCDとはJTAGではなく、SWDで接続しているつもり。
STM32F4-discoveryはST-Link/V2の回路になっていて、ねむいさんのサンプルcfgファイルで接続できる。
STM32F4-nucleoもST-Link/V2の回路になって・・・・、あれ、紹介ページにはST-Link/V2-1になっている。-1ってなんだ?
ねむいさんのこのブログでは、ST-Link/V2とST-Link/V2-1は明確に使い分けされている。
なるほど。
ST-Link/V2-1用のcfgファイルも用意されているので、なんとか解決の糸口を見つけた。
STM32F4-discovery用のcfgファイルを編集するのは嫌なので、STbeeF4mini用にコピー&編集してST-Link/V2-1を使ったOpenOCDアクセス環境を作って接続!・・・・失敗。
ねむいさんのブログでは、 ST-Link/V2-1を使うときはVCPドライバ必須とある。
すでに私の環境ではWindows7からはSTM32F4-nucleoとVCPで繋がっているように見える。
けれど、手元のダウンロード保管庫には ST-Link/V2用のVCPドライバは保管してあるけれど、ST-Link/V2-1用のVCPドライバは保管されていない。
わずかな望みを掛けてST-Link/V2-1用のVCPドライバをインストールしてみた。
結果、 target setting の画面が表示されて、設定をすることもできた。
ターゲットと接続することが出来て、ステップ実行も出来た。
これで万事解決!
と思ったけれど、もう一度つなごうとしたら、やはりtarget setting の画面でフリーズする。
惜しいところまで行っていると思うのだけれど。
ST-Link/V2-1用のVCPドライバはこちら。
2016年6月15日水曜日
STM Studio
STbee F4mini にMPU6500基板を取り付けて、動作確認。
デバッグしやすいように、変数のモニタ用にSTM Studio をインストールした。
XYZ各軸の加速度と角加速度を表示させてみた。上の図は、MPU6500基板を平らなところに置いて、Z軸をまわしてみたところ。
Z軸の加速度は常に重力が加わっているのでプラスの値をとる。Z軸の角加速度は時計回り、反時計回りにまわしたので、値がプラスとマイナスに振れている。
ソースコードデバッグより、変数デバッグのほうが直感的でいい。
デバッグしやすいように、変数のモニタ用にSTM Studio をインストールした。
XYZ各軸の加速度と角加速度を表示させてみた。上の図は、MPU6500基板を平らなところに置いて、Z軸をまわしてみたところ。
Z軸の加速度は常に重力が加わっているのでプラスの値をとる。Z軸の角加速度は時計回り、反時計回りにまわしたので、値がプラスとマイナスに振れている。
ソースコードデバッグより、変数デバッグのほうが直感的でいい。
2016年3月18日金曜日
STM32 Nucleo Board STM32F401のST-LINK v2
昔に買って、眠ったままになっていたSTM32 Nucleo Board STM32F401があったので、ST-Linkとして使おうと思ってみた。
この基板は、ST-Link部分とマイコンボード部分が割りやすいようになっていて、割ることでST-Link部分が単体のST-Linkとして使えるようになっている。
なので、割ってみた。
そして、STbee F4miniと以下のように接続してみた。
1.Vtarget(ST-Link) ->VDD(STbee F4mini)
2.SWCLK(ST-Link) ->PA14(STbee F4mini)
3.GND(ST-Link) ->GND(STbee F4mini)
4.SWDIO(ST-Link) ->PA13(STbee F4mini)
5.nRST(ST-Link) ->nRESET(STbee F4mini)
6.SWO(ST-Link) ->未接続
STbee F4miniとST-Linkの両方にUSBケーブルをつないでみる。
この状態では、まだSWDは有効になっていないので、STbee F4miniのユーザプログラムが動くはずだが動かない。
スイッチの押下を検出してLEDを光らせるだけの簡単なプログラムが書き込まれているはずなのに、それが動かない。
ST-Link側のUSBケーブルを抜いて、STbee F4miniの動きを見る。
動かない。
STbee F4miniとST-Linkの接続をはずしてみる。とたんにSTbee F4miniが動き始める。
ということは、ST-Link側の回路が悪さをしているようだ。
回路図をじっくり眺めて、気付いた。
Vtargetの電圧を監視している抵抗R9が未実装(N/A)になっている。
きっとそのせいでST-Linkがリセットを解除していないのであろう。
実装したからといって壊れる回路にも見えないので、手持ちの100Ω抵抗を半田付けしてから、もう一度全てのケーブルを接続した。
STbee F4miniのユーザプログラムは動く。よしよし。
続いて、ST-Link Utilityを使ってプログラムの書き換えを行なう。
シンプルに確認ができるように、LEDの光る論理を逆にしたプログラムを書き込む。
書き換え成功。よしよし。
スイッチを押して、LEDの光り方を確認する。期待通り。よしよし。
これでSTbee F4miniのブートモードを切り替えずにプログラム書き換えができる。
この基板は、ST-Link部分とマイコンボード部分が割りやすいようになっていて、割ることでST-Link部分が単体のST-Linkとして使えるようになっている。
なので、割ってみた。
そして、STbee F4miniと以下のように接続してみた。
1.Vtarget(ST-Link) ->VDD(STbee F4mini)
2.SWCLK(ST-Link) ->PA14(STbee F4mini)
3.GND(ST-Link) ->GND(STbee F4mini)
4.SWDIO(ST-Link) ->PA13(STbee F4mini)
5.nRST(ST-Link) ->nRESET(STbee F4mini)
6.SWO(ST-Link) ->未接続
STbee F4miniとST-Linkの両方にUSBケーブルをつないでみる。
この状態では、まだSWDは有効になっていないので、STbee F4miniのユーザプログラムが動くはずだが動かない。
スイッチの押下を検出してLEDを光らせるだけの簡単なプログラムが書き込まれているはずなのに、それが動かない。
ST-Link側のUSBケーブルを抜いて、STbee F4miniの動きを見る。
動かない。
STbee F4miniとST-Linkの接続をはずしてみる。とたんにSTbee F4miniが動き始める。
ということは、ST-Link側の回路が悪さをしているようだ。
回路図をじっくり眺めて、気付いた。
Vtargetの電圧を監視している抵抗R9が未実装(N/A)になっている。
きっとそのせいでST-Linkがリセットを解除していないのであろう。
実装したからといって壊れる回路にも見えないので、手持ちの100Ω抵抗を半田付けしてから、もう一度全てのケーブルを接続した。
STbee F4miniのユーザプログラムは動く。よしよし。
続いて、ST-Link Utilityを使ってプログラムの書き換えを行なう。
シンプルに確認ができるように、LEDの光る論理を逆にしたプログラムを書き込む。
書き換え成功。よしよし。
スイッチを押して、LEDの光り方を確認する。期待通り。よしよし。
これでSTbee F4miniのブートモードを切り替えずにプログラム書き換えができる。
2016年2月29日月曜日
2016年2月4日木曜日
STbeeF4mini到着
2月2日の夜に注文したストロベリーリナックスのSTbeeF4miniが到着。
シンプルながらコンパクトでいい。
ストロベリーリナックス:https://strawberry-linux.com/
商品紹介ページ:https://strawberry-linux.com/catalog/items?code=32405
オンボードのUSBコネクタ経由でVCPのprintfデバッグができたら便利だなぁ。無理ならStlinkのSWDデバッグか。
開発環境はいつもの、ねむいさんのを使わせてもらう。
ねむいさん:http://nemuisan.blog.bai.ne.jp/?eid=188089
シンプルながらコンパクトでいい。
ストロベリーリナックス:https://strawberry-linux.com/
商品紹介ページ:https://strawberry-linux.com/catalog/items?code=32405
オンボードのUSBコネクタ経由でVCPのprintfデバッグができたら便利だなぁ。無理ならStlinkのSWDデバッグか。
開発環境はいつもの、ねむいさんのを使わせてもらう。
ねむいさん:http://nemuisan.blog.bai.ne.jp/?eid=188089
2015年8月27日木曜日
MPU6500 動く
3軸ジャイロ+3軸加速度センサMPU-6500をSTM32F4のSPI接続で動作確認をした。
・・・と書くと簡単に動いたみたいだけれど、かなり試行錯誤した。おもわず勢いでロジアナを買ってしまいたくなるくらい苦労した。
だけれど、オシロスコープだけで頑張った。
近いうちにAnalogDiscoveryを買いたいな。
さて、SPIの設定はこんな感じ。
MPU6500からのデータが正しく読めたかを確認するには、0x75番地のWHO_AM_Iレジスタを読み込めばよい。MPU6500の場合、その結果は0x70になる。
SPIの読み込みは、こんな感じ。
・・・と書くと簡単に動いたみたいだけれど、かなり試行錯誤した。おもわず勢いでロジアナを買ってしまいたくなるくらい苦労した。
だけれど、オシロスコープだけで頑張った。
近いうちにAnalogDiscoveryを買いたいな。
さて、SPIの設定はこんな感じ。
// SPI2 設定 SPI_InitTypeDef SPI_InitStructure; SPI_StructInit(&SPI_InitStructure); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI2 , &SPI_InitStructure); SPI_Cmd(SPI2,ENABLE);
MPU6500からのデータが正しく読めたかを確認するには、0x75番地のWHO_AM_Iレジスタを読み込めばよい。MPU6500の場合、その結果は0x70になる。
SPIの読み込みは、こんな感じ。
/*
MPU6500 リード
*/
uint16_t mpu6500_rd(SPI_TypeDef *SPIx , uint16_t reg){
volatile uint16_t ret=0;
MPU6500_CS_ON();
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET); // 送信バッファが空
SPI_I2S_SendData(SPIx,(reg|0x80));
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET); // 受信完了待ち
ret = SPI_I2S_ReceiveData(SPIx); // dummy read
SPI_I2S_SendData(SPIx,0xFF); // dummy write
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET); // 受信完了待ち
ret = SPI_I2S_ReceiveData(SPIx);
MPU6500_CS_OFF();
return ret;
}
2015年8月16日日曜日
ADC1とADC2とADC3
STM32F405とSTM32F407の64ピン版と100ピン版のADCについて一覧にしてみた。
ADC3が思いのほか、使えるチャンネルが少ない。
ADC3が思いのほか、使えるチャンネルが少ない。
| ADC1 | ADC2 | ADC3 | |
| ADC_ch0 | ○ | ○ | ○ |
| ADC_ch1 | ○ | ○ | ○ |
| ADC_ch2 | ○ | ○ | ○ |
| ADC_ch3 | ○ | ○ | ○ |
| ADC_ch4 | ○ | ○ | × |
| ADC_ch5 | ○ | ○ | × |
| ADC_ch6 | ○ | ○ | × |
| ADC_ch7 | ○ | ○ | × |
| ADC_ch8 | ○ | ○ | × |
| ADC_ch9 | ○ | ○ | × |
| ADC_ch10 | ○ | ○ | ○ |
| ADC_ch11 | ○ | ○ | ○ |
| ADC_ch12 | ○ | ○ | ○ |
| ADC_ch13 | ○ | ○ | ○ |
| ADC_ch14 | ○ | ○ | × |
| ADC_ch15 | ○ | ○ | × |
2015年7月20日月曜日
STM32のクロック設定の自動生成
stm32f40xのクロックの設定は「system_stm32f4xx.c」で定義されている。
標準では、外部クロック8MHzが接続されている前提で168MHzで動作するように設定されている。
マウスでは、外部クロックではなく、内部クロック16MHzを使うので、設定を変更する必要がある。
これは普通にやると非常に面倒だ。
そこで、以下のページにあるエクセルファイルを使って自分の環境に即した「system_stm32f4xx.c」を生成する。エクセルのマクロを有効化してGenerateボタンで生成できる。
STSW-STM32091のページ
マウスの基板にマイコンを実装した。半田ブリッジがないことを目視で確認してから、電源-グランド間の抵抗値がおかしくないことを確認した。具体的には1MΩくらいあれば十分だと思う。
まだLEDを実装していないので、シリアルで通信できることが出来れば良しとする。
ちょっと反省は、プッシュスイッチと、電源用LEDが近すぎた。プログラム書き込みモードにするときに、プッシュスイッチを押しながらスライドスイッチをオンする必要があるのだけれど、プッシュスイッチを押す指でLEDが隠れてしまうのだ。それほど実害はないのだけれど、次回の課題とする。
もうひとつ。今は電源LEDの電流制限抵抗に2.2kΩを使っているのだけれど、まだ値が小さいようで少し明るい。明るいということは、電流を喰っているということなので、もう少し大きくしてもいいかもしれない。10kΩくらいかな?これは、適当にいらない基板で試してみればいいと思う。
電源周りで少し気になる点が。バッテリ駆動なので、電圧が少しずつ下がるのは仕方ないと思うけれど、レギュレータを通した後の電圧も、時間とともに低下するのだ。リポ電池の電圧は約3.8Vで、使って言うレギュレータは入出力間電圧は0.1Vの3.3V出力なので3.3Vは低下しないと思うのだけれど。
使っているレギュレータは秋月で購入したNJM2863F33。
確認したプログラムは以下。
2015年6月5日金曜日
STM32F4のADC3をDMA転送02
以前に書いた「STM32のAD変換01」では、AD変換した結果は右詰されていた。
しかし、その後に書いた記事、「STM32のAD変換結果をDMA転送」では、AD変換の結果が右詰されないで左詰で変数に格納されていた。
DMA関連の何かが悪いのだと思ったので、じっくり眺めたけれど分からなかった。
そこで、AD変換の初期化まわりを眺めなおしたら、少し気がついた。ADC_InitTypeDef構造体でADCを初期化する前に、ADC_StructInit関数を使って構造体自体の初期化をしているサンプルがある。それを真似して、ADC_StructInit関数で初期化してから構造体に値をセットして、ADC_Init関数で初期化してみた。
うまくいった。
なるほどね、構造体の初期値が不定だから、自分で設定しなかったメンバーが悪さをしていたのかな。だけれど、それだと、最初の「STM32のAD変換01」で期待通りの右詰で値を取得できた理由が分からない。
まぁ、とりあえず今はいいか。
それと、各種の関数の実体をソースで呼んでいるときに、ADC_DeInit関数の中身をみたらADC1のリセットをしているだけだったので、ADC3のリセット処理に変えてみた。
一度に色々と変更したせいで、どの変更がどう反映されたか分からなくなってしまったが、望んだ結果が得られたから、今日のところは良しとしよう。
ソースは以下。
2015年6月4日木曜日
STM32のTIM5でPWM出力
先日、TIM1でPWM出力が出来たので、TIM5でも楽勝と思っていたけれど、またまた上手くいかなかった。
結果としては、TIM5の設定は間違えてはおらず、GPIOの初期設定の間違えだった。
GPIOをオルタネート・ファンクションとして使う場合、GPIO_OTypeやGPIO_PuPdの設定は必要ないと思ったけれど、必要だった。
ごくごく初歩的な設定例だけれど、TIM5のPWM出力をする際のGPIO設定をさらします。
結果としては、TIM5の設定は間違えてはおらず、GPIOの初期設定の間違えだった。
GPIOをオルタネート・ファンクションとして使う場合、GPIO_OTypeやGPIO_PuPdの設定は必要ないと思ったけれど、必要だった。
ごくごく初歩的な設定例だけれど、TIM5のPWM出力をする際のGPIO設定をさらします。
// PA0,PA1,PA2,PA3 : GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // この行がないとPWM出力されない GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA,&GPIO_InitStructure);
2015年6月3日水曜日
STM32のAD変換スキャンモード不発
調子に乗って、AD変換のスキャンモードにチャレンジしてみたが、うまく結果を得られなかった。
//ADC3の変換モード設定。
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
// ↓ ENABLE(スキャンモード)、DISABLE(分割スキャンモード)
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
// ↓ ENABLE(連続変換モード)、DISABLE(シングル変換モード)
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// ↓ AD変換開始トリガなし
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
// ↓ AD変換後のデータ右詰
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// ↓ 入力を4本(チャネルを増やしたらここを変える)
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC3, &ADC_InitStructure);
変換モードをENABLEにしただけなんだけれど、駄目でした。
//ADC3の変換モード設定。
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
// ↓ ENABLE(スキャンモード)、DISABLE(分割スキャンモード)
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
// ↓ ENABLE(連続変換モード)、DISABLE(シングル変換モード)
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// ↓ AD変換開始トリガなし
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
// ↓ AD変換後のデータ右詰
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// ↓ 入力を4本(チャネルを増やしたらここを変える)
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC3, &ADC_InitStructure);
変換モードをENABLEにしただけなんだけれど、駄目でした。
2015年5月31日日曜日
STM32のAD変換01
今回からF4 discoveryではなくて、 自作F4基板でプログラムの評価をする。discoveryは周辺機能が盛りだくさんである一方で、使えるポートに制限があるので、ピッチ変換基板的な基板を作った。
詳しい話は、また別の機会に。
とりあえず、ポートの制限がなくなった。
さて本題。情報としては知っていたのだけれど、STM32のAD変換で、はまった。
STM32の12bitAD変換は変換結果を左詰にするか、右詰にするかを選べるのだけれど、右詰に設定しても、それが有効化されないのだ。
花岡ちゃんに花束を(STM32F4のAD変換トラブル(その2))
このページで、ADCの初期化でADC_DeInit();を実行すれば良いとされているが、それだけでは解決されなかった。
試行錯誤の結果、ADCの初期化処理の最後にウェイト処理を追加することで解決したので、ADCの初期化が完了する前に、ADCを使い始めてしまったのだろうか?
おそらく、データシートには書いてあるのだろうけれど、詳しく見てないので分からない。
ソースコードは以下。
詳しい話は、また別の機会に。
とりあえず、ポートの制限がなくなった。
さて本題。情報としては知っていたのだけれど、STM32のAD変換で、はまった。
STM32の12bitAD変換は変換結果を左詰にするか、右詰にするかを選べるのだけれど、右詰に設定しても、それが有効化されないのだ。
花岡ちゃんに花束を(STM32F4のAD変換トラブル(その2))
このページで、ADCの初期化でADC_DeInit();を実行すれば良いとされているが、それだけでは解決されなかった。
試行錯誤の結果、ADCの初期化処理の最後にウェイト処理を追加することで解決したので、ADCの初期化が完了する前に、ADCを使い始めてしまったのだろうか?
おそらく、データシートには書いてあるのだろうけれど、詳しく見てないので分からない。
ソースコードは以下。
2015年5月16日土曜日
STM32でモータ制御1
STM32F4でコアレスモータmk06を回してみた。
PB4、PB5にロータリーエンコーダを接続して、TIM3の位相計数でカウントしています。
モータはPE9、PE11に接続したモータドライバBD6211を介して行ないます。PE9、PE11はTIM1のPWM出力で動作します。
すんなりとはいかなかったところは以下。
1.符号なし変数から符号あり変数へのキャスト。
ロータリーエンコーダを使って、カウント動作させてみたのだけれど、STM32のレジスタは符号なしで定義されているので、負の値がそのまま使えない。
そこで、何も考えずにC言語の型のキャストを使ってみたのだけれど、うまくはいかなかった。
int16_t counter = (int16_t) TIM3->CNT;
これで、符号なし16bitデータを符号付16bitデータに出来たと思って、printfデバッグしてみた。
printf("counter : %d " , counter);
この値が、常に正の数で、デクリメントしても負の数にならない。0の下が65535になってしまう。
仕方ないので、最上位bitが1の時は、2の補数を取ることで、負の数にしている。
本当はもっときれいな方法があるのだろうけれど・・・。
2.TIM1(高機能タイマ)の動作
汎用タイマのTIM3などを使うときは必要ないのだけれど、高機能タイマのTIM1を出力で使用するときは、以下のコマンドが必要。
TIM_CtrlPWMOutputs(TIM1,ENABLE); // 高機能タイマ専用
詳しく追いかけていないけれど、必要だということで書いておく。
3.BD6211の制御論理
説明の前に、まずはモータドライバICのBD6211のデータシートを紹介(秋月リンク)。
このドライバを使ってPWM制御する際には、PWM制御モードAとPWM制御モードBというのがある。詳しいことはデータシートを見てほしいのだけれど、真理値表を見るとPWMで制御しないほうのピンをH固定するか、Lこてするかの違いに見えた。
その程度の違いなら、PWMモードAでいいかなと思い、ソフトのコーディングをした。
コンパイルエラーもなくしたところで、もう一度データシートを見ていたら、PWM制御モードAだと、PWM周期が20kHz以下だと途中でスタンバイモードになるため、理想どおりの制御にならないことがあると書かれている。
今回は、84kHz周期で使う予定なので、問題ないのだけれど、やはり気になるので、PWM制御モードBに変更した。
といっても、この段階では使っていないほうのピンをH固定からL固定にしただけ。
そして通電。
リセット直後は、信号を出していないのでモータは空転状態。そして、ロータリーエンコーダを一回まわすと、勢いよく回り始めた。なんだか全力で。これがコアレスモータの性能なのかと思いながらもロータリーエンコーダをまわし続けたら、次第にモータの元気がなくなってきた。
・・・あれ?
熱か電流でモータにダメージでも与えてしまったのかと思い、リセット。
気を取り直してエンコーダを回すと勢いよく回る。
ここで一呼吸おいて、よく考えてみたら当然のことだった。PWM制御モードをAからBに変更したときに、PWM制御してないほうの端子の論理を反転したのに、PWM信号自体はそのままだったので、最小幅のPWMで制御しているつもりが、最大幅になっていたのだ。すぐにTIM1のPWM出力の論理も反転することで、思ったとおりにゆっくりスタートのモータ制御が出来た。
ソースコードの表示は、以下をクリック。(書きなぐりでまとめてないので、汚いです。)
PB4、PB5にロータリーエンコーダを接続して、TIM3の位相計数でカウントしています。
モータはPE9、PE11に接続したモータドライバBD6211を介して行ないます。PE9、PE11はTIM1のPWM出力で動作します。
すんなりとはいかなかったところは以下。
1.符号なし変数から符号あり変数へのキャスト。
ロータリーエンコーダを使って、カウント動作させてみたのだけれど、STM32のレジスタは符号なしで定義されているので、負の値がそのまま使えない。
そこで、何も考えずにC言語の型のキャストを使ってみたのだけれど、うまくはいかなかった。
int16_t counter = (int16_t) TIM3->CNT;
これで、符号なし16bitデータを符号付16bitデータに出来たと思って、printfデバッグしてみた。
printf("counter : %d " , counter);
この値が、常に正の数で、デクリメントしても負の数にならない。0の下が65535になってしまう。
仕方ないので、最上位bitが1の時は、2の補数を取ることで、負の数にしている。
本当はもっときれいな方法があるのだろうけれど・・・。
2.TIM1(高機能タイマ)の動作
汎用タイマのTIM3などを使うときは必要ないのだけれど、高機能タイマのTIM1を出力で使用するときは、以下のコマンドが必要。
TIM_CtrlPWMOutputs(TIM1,ENABLE); // 高機能タイマ専用
詳しく追いかけていないけれど、必要だということで書いておく。
3.BD6211の制御論理
説明の前に、まずはモータドライバICのBD6211のデータシートを紹介(秋月リンク)。
このドライバを使ってPWM制御する際には、PWM制御モードAとPWM制御モードBというのがある。詳しいことはデータシートを見てほしいのだけれど、真理値表を見るとPWMで制御しないほうのピンをH固定するか、Lこてするかの違いに見えた。
その程度の違いなら、PWMモードAでいいかなと思い、ソフトのコーディングをした。
コンパイルエラーもなくしたところで、もう一度データシートを見ていたら、PWM制御モードAだと、PWM周期が20kHz以下だと途中でスタンバイモードになるため、理想どおりの制御にならないことがあると書かれている。
今回は、84kHz周期で使う予定なので、問題ないのだけれど、やはり気になるので、PWM制御モードBに変更した。
といっても、この段階では使っていないほうのピンをH固定からL固定にしただけ。
そして通電。
リセット直後は、信号を出していないのでモータは空転状態。そして、ロータリーエンコーダを一回まわすと、勢いよく回り始めた。なんだか全力で。これがコアレスモータの性能なのかと思いながらもロータリーエンコーダをまわし続けたら、次第にモータの元気がなくなってきた。
・・・あれ?
熱か電流でモータにダメージでも与えてしまったのかと思い、リセット。
気を取り直してエンコーダを回すと勢いよく回る。
ここで一呼吸おいて、よく考えてみたら当然のことだった。PWM制御モードをAからBに変更したときに、PWM制御してないほうの端子の論理を反転したのに、PWM信号自体はそのままだったので、最小幅のPWMで制御しているつもりが、最大幅になっていたのだ。すぐにTIM1のPWM出力の論理も反転することで、思ったとおりにゆっくりスタートのモータ制御が出来た。
ソースコードの表示は、以下をクリック。(書きなぐりでまとめてないので、汚いです。)
STM32F4 エンコーダ入力
秋月で売っている、このロータリーエンコーダーを使って、STM32のエンコーダー入力を試してみる。
参考にしたのは、以下のサイト。
・ロータリエンコーダによる角度検出
・Encoder Interfaceについて(ちょろまつ製作記)
以下は、STM32F4 discoveryで試したソース。
エンコーダの1クリックで、カウントが2つ変化するのは、B相の立上がりと立下りの両方でカウントしているのだろうか?ちょっとよく分からない。
ソースコードは以下。
STM32のSPI通信のエッジの設定
2月8日の記事にて、STM32のSPI通信のデータ取り込みエッジの設定を、
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
としていたが、これだと、送信データの8bit目が1のときに、タイムアウトみたいな変な動きをする。
そこで、以下のように変更したところ、まともに動くようになった。
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
時間を見つけて、きちんと波形で確認しないといけないと思った。
2015年1月10日土曜日
STM32F4 でシリアル通信(割込みあり)
前回に引き続き、STM32F4 discoveryのUART2を使って、パソコンにメッセージを表示させてみた。
今回は割込み使用。
uart2_printf(送信文字列)は、割込みなしで送信。
sci2_printf(送信文字列)は、リングバッファ経由で割込みありで送信。
共に、全角文字は駄目かなと思っていたけれど、ターミナルソフトの文字コードをSJISにしたら、全角文字も送れた。
プロジェクトは、こちら(stm32f4_uart02.zip)に保管します。
ソースコードは以下。
今回は割込み使用。
uart2_printf(送信文字列)は、割込みなしで送信。
sci2_printf(送信文字列)は、リングバッファ経由で割込みありで送信。
共に、全角文字は駄目かなと思っていたけれど、ターミナルソフトの文字コードをSJISにしたら、全角文字も送れた。
プロジェクトは、こちら(stm32f4_uart02.zip)に保管します。
ソースコードは以下。
登録:
投稿 (Atom)


