STM32 + レジスタをたたいてCAN通信を実装する その3 CANのフィルタの初期化
こんにちは。今回は、CAN通信のフィルタの初期化のための実装をしていきます。
前回の記事↓
Contents
データシートを確認
設定の流れなどを確認
例に則ってデータシートを確認していきたいと思います。
RM0316より引用
データシートをもとに、CANフィルタの設定の流れを以下に記載します。
- フィルターの初期化モードにする
- 使用するフィルターを一度無効にする
- フィルターのスケールが16bit/32bitに設定
- フィルターバンクレジスタの設定
- フィルターのモード設定
- FIFOの選択
- フィルターの有効化および初期化モードからの脱却
この流れをもとにレジスタの確認をしていきたいと思います。
レジスタの確認
使用するレジスタの確認をしておきます。
CAN_FMR, CAN_FM1R
CAN_FS1R, FFA1R
CAN_FA1R
CAN_FiRx
実装編
初期化用の構造体および関数
ここまでの内容をもとに実装をしていきたいと思います。
can_driver.hに初期化用構造体を定義しました。
typedef struct {
uint32_t FilterIdHigh; // フィルタの識別番号Highを設定(MSBs)
uint32_t FilterIdLow; // フィルタの識別番号Lowを設定(LSBs)
uint32_t FilterMaskIdHigh; // フィルタの識別番号Highのマスクを設定(MSBs)
uint32_t FilterMaskIdLow; // フィルタの識別番号Lowのマスクを設定(LSBs)
uint8_t FilterFIFOAssignment; // CAN_filter_FIFOの設定を行う
uint32_t FilterBank; // フィルタバンクの設定(0~13)
uint8_t FilterMode; // CAN_filter_modeの設定を行う
uint8_t FilterScale; // CAN_filter_scaleの設定(16bit or 32bit)
FunctionalState FilterActivation; // filterの有効化or無効化を設定
} CAN_FilterTypeDef;
// FILTER用マクロ
#define CAN_FILTER_SCALE_16BIT 0x00U
#define CAN_FILTER_SCALE_32BIT 0x01U
#define CAN_FILTER_MODE_IDMASK 0x00U
#define CAN_FILTER_MODE_IDLIST 0x01U
#define CAN_FILTER_FIFO0 0x00U
#define CAN_FILTER_FIFO1 0x01U
void CAN_Filter_Reg_Init(CAN_TypeDef* CANx, CAN_FilterTypeDef* filterConfig);
続いてcan_driver.cに追加
void CAN_Filter_Reg_Init(CAN_TypeDef* CANx, CAN_FilterTypeDef* filterConfig) {
uint32_t filternbrbitpos;
// フィルターの初期化モードにする
SET_BIT(CANx->FMR, CAN_FMR_FINIT);
// 使用するフィルタを一度無効にする
filternbrbitpos = (uint32_t)1 << (filterConfig->FilterBank & 0x1FU);
CLEAR_BIT(CANx->FA1R, filternbrbitpos);
// フィルターのスケールが16bitのときと32bitのときで設定方法を変える
if (filterConfig->FilterScale == CAN_FILTER_SCALE_16BIT) {
// フィルターのスケール設定を行う
CLEAR_BIT(CANx->FS1R, filternbrbitpos);
// CAN フィルタバンク i レジスタ x
// CAN_FIR[2:1]から構成されているのでそれぞれ設定する必要がある。
CANx->sFilterRegister[filterConfig->FilterBank].FR1 =
((0x0000FFFFU & (uint32_t)filterConfig->FilterMaskIdLow) << 16U) |
(0x0000FFFFU & (uint32_t)filterConfig->FilterIdLow);
CANx->sFilterRegister[filterConfig->FilterBank].FR2 =
((0x0000FFFFU & (uint32_t)filterConfig->FilterMaskIdHigh) << 16U) |
(0x0000FFFFU & (uint32_t)filterConfig->FilterIdHigh);
}
if (filterConfig->FilterScale == CAN_FILTER_SCALE_32BIT) {
// フィルターのスケール設定を行う
SET_BIT(CANx->FS1R, filternbrbitpos);
// CAN フィルタバンク i レジスタ x
// CAN_FIR[2:1]から構成されているのでそれぞれ設定する必要がある。
CANx->sFilterRegister[filterConfig->FilterBank].FR1 =
((0x0000FFFFU & (uint32_t)filterConfig->FilterIdHigh) << 16U) |
(0x0000FFFFU & (uint32_t)filterConfig->FilterIdLow);
CANx->sFilterRegister[filterConfig->FilterBank].FR2 =
((0x0000FFFFU & (uint32_t)filterConfig->FilterMaskIdHigh) << 16U) |
(0x0000FFFFU & (uint32_t)filterConfig->FilterMaskIdLow);
}
// filterのモードに対しての設定
if (filterConfig->FilterMode == CAN_FILTER_MODE_IDMASK) {
// 識別子マスクモード
CLEAR_BIT(CANx->FM1R, filternbrbitpos);
} else {
// 識別子リストモード
SET_BIT(CANx->FM1R, filternbrbitpos);
}
// FIFOの設定
if (filterConfig->FilterFIFOAssignment == CAN_FILTER_FIFO0) {
// フィルタが FIFO 0 に割り当てられる
CLEAR_BIT(CANx->FFA1R, filternbrbitpos);
} else {
// フィルタが FIFO 1 に割り当てられる
SET_BIT(CANx->FFA1R, filternbrbitpos);
}
// FILTERを有効にするかどうか
if (filterConfig->FilterActivation == ENABLE) {
// 最初に無効にしたものを、有効にし直す
SET_BIT(CANx->FA1R, filternbrbitpos);
}
// 初期化モードから通常モードに変更する
CLEAR_BIT(CANx->FMR, CAN_FMR_FINIT);
}
リファレンスマニュアルとレジスタで確認したところを全て設定しました。
can.cに追加
void CAN_FilterParam_Init(void) {
CAN_FilterTypeDef filterConfig;
filterConfig.FilterBank = 0;
filterConfig.FilterMode = CAN_FILTER_MODE_IDLIST;
filterConfig.FilterScale = CAN_FILTER_SCALE_16BIT;
filterConfig.FilterIdHigh = 0x123 << 5; // or 0x456 << 5
filterConfig.FilterIdLow = 0x123 << 5; // or 0x456 << 5
filterConfig.FilterMaskIdHigh = 0x123 << 5; // or 0x456 << 5
filterConfig.FilterMaskIdLow = 0x123 << 5; // or 0x456 << 5
filterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
filterConfig.FilterActivation = ENABLE;
CAN_Filter_Reg_Init(CAN, &filterConfig);
}
フィルタの初期化パラメータについて
今回は、フィルタバンク0を用いて、モードはリストを使用しました。リストモードの場合は一致したIDの通信データのみ受け入れ、それ以外のIDははじくということを行うようです。その他は16bitにしてIDの設定およびFIFO0にデータを格納、フィルターを有効化にするということを行いました。
さいごに
次回は、送受信の関数の実装までいく予定です。後2回くらいお付き合いいただければと思います。CANは設定をすることや確認をすることが多いですね。