STM32 + レジスタをたたいてCAN通信を実装する その1 GPIOの初期化と割り込み設定

2021年2月16日

こんにちは。
STM32のLLAPIを使用してCAN通信ができるかなと思いつつSTM32CubeMXのAdvancedSettingを見に行ったところ、HALしかありませんでした。これは、レジスタをたたいて実装するしかないといことでやっていきたいと思います。
今回、使用するマイコンはSTM32F303K8、CANトランシーバーはMCP2562です。
回路図は以下の通りです。VIOはPA11,PA12がトレラントピンなので5V,3.3Vのどちらでも大丈夫です。私は、3.3V,5Vの両方で動作確認をしました。
下に示す回路は接続例の一つとして扱っていただければと思います。詳しくはMCP2562のデータシートを参照をお願いします。

実際にブレッドボード上では以下のようになりました。(上記の参考回路で組んだ時のもの)

実装を行っていくにあたって、データシートとリファレンスマニュアルを確認していきたいと思います。




実装前の下準備

リファレンスマニュアルでGPIOの設定方法を確認する

GPIOの機能説明と設定について確認をしていきます。

RM0316より引用

GPIOの設定を行うにあたって、CANオルタネート機能設定をデバイスシートで確認する必要があることがわかりました。また、オルタネート機能設定の図よりピン設定はプッシュプルで設定をしていきます。MCP2562の内部でプルアップ抵抗がついているようなので、オープンドレイン設定でも動きそうですね。

AF機能の設定のために、データシートを確認する

Alternate functionsでCANの設定がどこになるのかの確認をしたいと思います。

DS9866 Rev 8より引用

AF9に設定すればいいということがわかりました。

割り込みの設定の仕方を確認する

GPIOの設定がわかったので、続いてCANの割り込みの設定方法の確認をしていきたいと思います。

RM0316より引用

優先順位の設定が可能であることと、アドレスの位置がわかりました。続いて、NVICのレジスタの確認をしていきます。
PM0214

PM0214より引用

CMSISの関数が用意されているようです。LLAPIのEnableIRQ,NVIC_SetPriorityが定義されているため、それを使用すればよさそうだということがわかりました。

実装編

ここまでの内容をもとにLLAPIのコードをもとに実装をしていきたいと思います。

STM32CubeMXの設定

STM32CubeMXの設定をしていきます。

プロジェクト名およびプロジェクトの出力は各自の開発環境にあったもので設定をしてください。USARTはprintf用に用意をしました。

↑printfの設定は上記の記事と同じようにしました。

CANのGPIOおよびNVICの実装

STM32CubeMXから出力されたプロジェクトを用いて実装をしていきます。CANのモジュールに分割されたファイルが存在しないため、can.c/can.hなどのファイルを作成した上で書いていきます。

can.h

#ifndef __CAN_H__
#define __CAN_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "main.h"

void CAN_Init(void);

void CAN_RX0_IRQHandler(void);
void CAN_RX1_IRQHandler(void);

#ifdef __cplusplus
}
#endif
#endif /*__ CAN_H__ */

can.c

GPIOの初期化にはLLAPIで提供されているGPIO_InitStructとLL_GPIO_Init関数を用いて実装をしました。このようにすることで、他のLLAPIとの実装の共通化を図りました。割り込みハンドラーの関数名はstartup_stm32f303x8.sに書いてありました。

#include "can.h"
void CAN_MspInit(void) {
  // CANのクロックを有効にする
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_CAN);
  // GPIOAのクロックを有効にする
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);

  // GPIO Init
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = LL_GPIO_PIN_11 | LL_GPIO_PIN_12; // Pin選択
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; // alternate function mode
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; // SPEED FREQUENT HIGH
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; // OUTPUT PUSH PULL
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; // not PULL
  GPIO_InitStruct.Alternate = LL_GPIO_AF_9; // CAN Alternate Function
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 初期化する

  // CANの割り込みを設定する
  // RX0の割り込みを有効にする
  NVIC_SetPriority(CAN_RX0_IRQn,NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
  NVIC_EnableIRQ(CAN_RX0_IRQn);

  // RX1の割り込みを有効にする
  NVIC_SetPriority(CAN_RX1_IRQn,NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
  NVIC_EnableIRQ(CAN_RX1_IRQn);
}
void CAN_RX0_IRQHandler(void) {}
void CAN_RX1_IRQHandler(void) {}

おわりに

GPIOの初期化と割り込みの有効化だけでもかなり疲れました。次回はCAN機能の初期化などをやっていきます。

参考文献

PM0214

RM0316

MCP2562データシート