2016年10月13日

SPI/I2C シリアル通信

今回はSTM32でのSPI/I2C シリアル通信について紹介します。

環境はこれまで同様、
・STM32F303K8
 +SW4STM32(System Workbench for STM32)
 +STM32CubeMX
です。


◆HALライブラリを使用したI2C通信
HALライブラリを使用したI2C通信でSTM32側がマスタの場合、
PICマイコンなどのようにACKとかRepeatStartなど考える必要はありません。
下記の読み込みか書き込みかの関数を使い分けるだけです!

HAL_I2C_Mem_Read( I2C_HandleTypeDef *hi2c,
                  uint16_t DevAddress,
                  uint16_t MemAddress,
                  uint16_t MemAddSize,
                  uint8_t *pData,
                  uint16_t Size,
                  uint32_t Timeout);

HAL_I2C_Mem_Write( I2C_HandleTypeDef *hi2c,
                  uint16_t DevAddress,
                  uint16_t MemAddress,
                  uint16_t MemAddSize,
                  uint8_t *pData,
                  uint16_t Size,
                  uint32_t Timeout);



非接触赤外線センサMLX90614を読みだした場合
#define DevAddress  (0xB4)
⇒0x5A
として読み書きされます。
R/Wを含めてアドレスを指定するようです。

環境温度読み込み時の例は下記の通り。


HAL_I2C_Mem_Read( hi2c,
                  (uint16_t)DevAddress,
                  0x06,
                  I2C_MEMADD_SIZE_8BIT,
                  (uint8_t*) ret,
                  3,
                  100);

res=(float)(ret[0]+(ret[1]<<8))/100.0;
resに環境温度が格納されます。

MLX90614_i2c-STM32.png

LabToolを使用してデータ通信状態。
直接LabToolをI2Cラインへ接続するとインピーダンスが変わってしまうため、
1k~10kの抵抗を挟んでロギングしました。

I2Cはアドレスの表記が7bitアドレスでR/Wを含めるか、含めないか
チップメーカによってまちまちなのでそこがいつも引っかかるところです。

また、マイコンがいつもと違うと同様にまちまちなので
今回のような地味な検証が後々役立ちます。


思った以上にすんなり動いてくれました。



◆HALライブラリを使用したSPI通信
I2C同様、SPIも思った以上にシンプルでした。
デバイスのデータシートと睨めっこしながら、
main.c内のMX_SPI1_Initの設定を確認してください。
通信できない時はSPIのクロック極性やサンプル位置設定が
間違っていることがほとんどです。

hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;//SPI_POLARITY_HIGH//?!
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;//SPI_PHASE_1EDGE//?!


HAL_SPI_TransmitReceive( SPI_HandleTypeDef *hspi,
                      uint8_t *pTxData,
                      uint8_t *pRxData,
                      uint16_t Size,
                      uint32_t Timeout);

実際にあるデバイスで通信した場合
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,0);//CS
HAL_SPI_TransmitReceive(&hspi1,sData,rData,1,100);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,1);//CS


送受信を想定してTransmitReceiveを使用していますが、
受信専用の関数
HAL_SPI_Receive( SPI_HandleTypeDef *hspi,
               uint8_t *pData,
               uint16_t Size,
               uint32_t Timeout);
送信専用関数
HAL_SPI_Transmit( SPI_HandleTypeDef *hspi,
                uint8_t *pData,
                uint16_t Size,
                uint32_t Timeout);
もあります。
ただ、実際に実験してみてはいませんが、
どちらかの場合でも送受信関数TransmitReceiveで
空データを使うことで同じ関数でいけそうな気がします。



SPIについても思った以上にすんなり動いてくれました。

PICの時はRepeatStartのタイミングなど色々苦労させられましたが、
STM32のHALライブラリのシリアル通信は思った以上に考えることが少なく、
すんなり動いてくれました。



posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 電子工作 | このブログの読者になる | 更新情報をチェックする

2016年10月05日

PrintfのFloat出力

以前にSTM32マイコンでPrintfを出力する方法を紹介させて頂きました。

だた、紹介した方法だけではfloatの出力ができないという問題があります。
設定せずにfloat出力すると空欄になってしまいます。

そのため、今回はPrintfでFloat出力する方法をご紹介します。



PrintfでFloat出力する方法を調べると既にいくつか紹介されていました。




ただ、開発環境が異なるため、
今回はSystem Workbench for STM32 (SW4STM32)での
PrintfでFloat出力する方法を紹介します。



結論から言うとプロジェクト内のプロパティから、
「C/C++ Build」->[Settings]->
[Tool Settings]->[MCU GCC Linker]->[Miscellaneous]
でLinker flagsの
「-specs=nosys.specs -specs=nano.specs」
から
「-u _printf_float」
を追加して
「-specs=nosys.specs -specs=nano.specs  -u _printf_float」
にすることです。


float.png


これでビルドするとPrintfでfloat出力ができるようになります!



他の開発環境では別に色々設定変更が必要なようですが、
SW4STM32ではデフォルトのままで大丈夫でした。

float2.png

一応確認すると既にFPU等の設定は設定済みでした。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 電子工作 | このブログの読者になる | 更新情報をチェックする

2016年09月15日

UART設定とPrintf

STM32で使用可能な開発環境の1つのSW4STM32を使用して、
Nucleoボード版STM32F303K8のUartについて、
戸惑った点含めて備忘録として軽くまとめます。


STM32CubeMXでUART1を有効にして、
ボーレートを9600で自動でコードを生成したコードを使用。
ライブラリはHAL。

ここで注意!
自動生成する際のUart設定のWord Lengthで初期値がなぜか7bit!!

これに気付かず、なぜかUartが文字化けるという不具合に遭遇。
クロック系やボーレートがおかしいのかと色々調査したところ、
オシロスコープで確認するとビットが欠けていることを発見!

結局、Word Lengthを8bitにするとビット欠けずにUARTの送信ができました。
7bitなんて普通では使わないので、なぜデフォルトが7bitなのか不明。
不親切だなあと思いました。


UART送信ができると、
次にやりたいのはPrintf。


メイン関数内で
色々宣言するとUARTに出力できるとかできないとか...
「STM32 printf」で検索するといろいろなやり方が出てきて、
古いやり方だったり、環境が違ったりとうまくできない感じでした。

#ifdef __GNUC__
 /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
    set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
を宣言するとかしないとか。上記のやり方はうまくいかなかった。


当方のSW4STM32とHAL、STM32CubeMXという環境では、
下記の関数をmain関数の手前で宣言することで、
UART1へ出力されることを確認しました。

int _write( int file, char *ptr, int len )
{
   HAL_UART_Transmit(&huart1, ptr, len, 1000);
  return len;
}
他にももっとよいやり方があったら教えてください。


STM32やARM系の場合、開発環境やコンパイラの組み合わせが1種類ではないため、
なかなかGoogle先生に聞いてもジャストな回答を得られないのが難点ですね。

posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 電子工作 | このブログの読者になる | 更新情報をチェックする

2016年09月10日

Lチカできない原因

STM32で使用可能な開発環境の1つのSW4STM32(System Workbench for STM32)を使用して、
Nucleoボード版STM32F303K8のLチカから始めようとしたが...


普通は数時間もかからずにLチカできるはずが、
何時間もLチカに時間がかかってしまいました。


結論から先に言うと
「設定ツールやファームのバージョンは同時期のものを使用する」
ということです。


STM32の設定を簡単に実現する
STM32CubeMXを使用して生成したコードでSW4STM32でコンパイル、
DebugするとLチカも何も起こらず...

Debugを停止するとなぜか「b    Infinite_Loop」という場所で停止し、
This is the code that gets called when the processor receives an unexpected interrupt.
という説明がありました。
つまり、処理しきれない何かが発生した例外のようです。


その例外がなぜ発生するのか、分からず色々試行錯誤。

そして、STM32CubeMXで生成したコードを使用せずに、
SW4STM32で新規作成でLチカすると問題なく、Lチカできることが判明。

原因はSTM32CubeMXにありそうと、
バージョン確認したところ、ファームのバージョンが古いものになっていました。

最新にアップするとSTM32CubeMXでもLチカできました...

IMG_3735.JPG

設定ツールやファームのバージョンは同時期のものを使用するというのは鉄則ですね。
Lチカでここまで苦労したのは初めてです笑


posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 電子工作 | このブログの読者になる | 更新情報をチェックする

2016年08月06日

組立ワークショップ開催しました!

IMG_2960_.jpg

ご支援して頂いたサポータの皆様、本プロジェクトにご協力頂いた皆様、
本当にありがとうございます!

先日、7/31(日)にご支援して頂いた方を対象に
組立ワークショップを秋葉原のハンダ付けカフェで実施しました。

2組の支援者の方にご参加頂き、
組立て頂きました。

IMG_2956_.jpg

IMG_2959_.jpg

ハンダ付けが中学校以来という方もいらっしゃいましたが、
40分程度の組立作業後には皆さん完成して描画できました!


今後の開催はCore基板(単体版)を含めて希望者に応じて、
開催する予定です。


今回、会場としてお貸し頂いたはんだ付けカフェは10月中旬に閉店が決まっており、
今後は「はんだづけカフェ@神楽坂」として月1回のペースで利用できるようです。
プロ向けの機材が無料で利用できる貴重な場所であり、
利用者としてはちょっと残念です。

posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 電子工作 | このブログの読者になる | 更新情報をチェックする