HAVRMの空空活動誌

「空空」は「うつらうつら」と読むらしいです.まぁ常に寝不足なもんで...

STM32F105におけるCAN2の利用に関して

こんにちは
HAVRMです.

以前すでにできている基板でのCAN通信によるマイコン間の通信をさせようとしたところ,相当苦労したのでメモ書き程度に書いておく.

なお,有名なHALライブラリやSTM32CubeMXなどは都合上使っていない(だから苦労したともいえる).

細かいコード説明等は後から追記しようとは思うが,とりあえず初期化,受信割り込み,送信のコードを載せておく.

確かどっかのサイトにあったサンプルコードで動いたと思うんだけど,忘れた.思い出したら追加する.

この時使用したのはCAN2で,PB5とPB6をRemapして利用している.
主に受信割り込みと送信を1Mbpsでおこなう.

まず,初期化.

/**
 * @brief Can Initialize using CAN_Init in stm32f10x_can.h
 * @param _mode set CAN mode:CAN_Mode_Normal, CAN_Mode_Silent, CAN_Mode_LoopBack, CAN_Mode_Silent_LoopBack
 */
void Can_Init( uint8_t _mode ){
  
  GPIO_InitTypeDef GPIO_InitStrct;
  CAN_InitTypeDef CAN_InitStrct;
  NVIC_InitTypeDef NVIC_InitStrct, NVIC_InitStrct2;
  CAN_FilterInitTypeDef	CAN_FilterStrct;
  
  /* Periphery clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1 , ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2 , ENABLE);

  GPIO_PinRemapConfig(GPIO_Remap_CAN2, ENABLE);
  
  /* Configure CAN pin: RX */
  GPIO_InitStrct.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStrct.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOB, &GPIO_InitStrct);

  /* Configure CAN pin: TX */
  GPIO_InitStrct.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStrct.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStrct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStrct);
  
  /* CAN register init */
  CAN_DeInit(CAN2);
  CAN_StructInit(&CAN_InitStrct);

  /* CAN cell init */
  CAN_InitStrct.CAN_TTCM = DISABLE;
  CAN_InitStrct.CAN_ABOM = DISABLE;
  CAN_InitStrct.CAN_AWUM = DISABLE;
  CAN_InitStrct.CAN_NART = DISABLE;
  CAN_InitStrct.CAN_RFLM = DISABLE;
  CAN_InitStrct.CAN_TXFP = DISABLE;
  CAN_InitStrct.CAN_Mode = _mode;

  /* CAN Baudrate = 1MBps*/
  CAN_InitStrct.CAN_SJW = CAN_SJW_1tq;
  CAN_InitStrct.CAN_BS1 = CAN_BS1_8tq;
  CAN_InitStrct.CAN_BS2 = CAN_BS2_3tq;
  CAN_InitStrct.CAN_Prescaler = 3;
  CAN_Init(CAN2, &CAN_InitStrct);

  /* CAN Interrput */
  NVIC_InitStrct.NVIC_IRQChannel = CAN2_RX0_IRQn;
  NVIC_InitStrct.NVIC_IRQChannelPreemptionPriority = 0x1;
  NVIC_InitStrct.NVIC_IRQChannelSubPriority = 0x0;
  NVIC_InitStrct.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStrct);
  
  NVIC_InitStrct2.NVIC_IRQChannel = CAN2_RX1_IRQn;
  NVIC_InitStrct2.NVIC_IRQChannelPreemptionPriority = 0x1;
  NVIC_InitStrct2.NVIC_IRQChannelSubPriority = 0x1;
  NVIC_InitStrct2.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStrct2);
  
  CAN_ITConfig(CAN2, CAN_IT_FMP0 , ENABLE);
  CAN_ITConfig(CAN2, CAN_IT_FMP1 , ENABLE);
  
  /* CAN filter */
  /* フィルターは設定しているが,全て通す*/
  CAN_FilterStrct.CAN_FilterNumber = 15;
  CAN_FilterStrct.CAN_FilterMode = CAN_FilterMode_IdMask;
  CAN_FilterStrct.CAN_FilterScale = CAN_FilterScale_32bit;
  CAN_FilterStrct.CAN_FilterIdHigh = 0x0000;
  CAN_FilterStrct.CAN_FilterIdLow = 0x0000;
  CAN_FilterStrct.CAN_FilterMaskIdHigh = 0x0000;
  CAN_FilterStrct.CAN_FilterMaskIdLow = 0x0000;
  CAN_FilterStrct.CAN_FilterFIFOAssignment = CAN_FIFO0;
  CAN_FilterStrct.CAN_FilterActivation = ENABLE;
  CAN_FilterInit(&CAN_FilterStrct);
}

多分下の設定が抜けてたからうまくいかなかったと思われるが急に動いたため定かじゃない.

  //...
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1 , ENABLE);
  //...
  CAN_ITConfig(CAN2, CAN_IT_FMP0 , ENABLE);
  CAN_ITConfig(CAN2, CAN_IT_FMP1 , ENABLE);
  //...

特にCAN2を使うためだけなのにCAN1もやらないといけないのが気付かない.

あとLoopbackモードでデバッグしていたのだが,Normalモードに戻したらできたのだけどなんなんだろう...
オシロで見ていたんだけど,急に波形が出てびっくりした.

次に受信割り込み

/**
 * @brief interrupt function at RX0, colect data and send to Can_IRQfunc
 */
void CAN2_RX0_IRQHandler(void){
  CAN_Receive(CAN2, CAN_FIFO0, &tCAN2_RXMsg);
  Can_IRQfunc(tCAN2_RXMsg);
}

/**
 * @brief interrupt function at RX1, colect data and send to Can_IRQfunc
 */
void CAN2_RX1_IRQHandler(void){
  CAN_Receive(CAN2, CAN_FIFO1, &tCAN2_RXMsg);
  Can_IRQfunc(tCAN2_RXMsg);
}

この時は受信割り込みが発生するとデータを読み込み,そのデータを自分で作成する関数に送るようにしている.

最後に送信

/**
 * @brief send data function using CAN_Transmit in stm32f19x_can.h
 * @param _data data to send
 */
void Can_send_data(uint8_t* gsend_data){
  int i = 0;
  CanTxMsg _msg_data;
  
  _msg_data.StdId = 5;
  _msg_data.ExtId = 5;
  _msg_data.IDE = CAN_Id_Standard;
  _msg_data.DLC = 8;
  _msg_data.RTR = 0;
  for(i=0; i<8; i++)_msg_data.Data[i] = gsend_data[i];
  
  CAN_Transmit(CAN2, &_msg_data);
}

まぁ,初期化以外は特に問題はなかったんだけど.

っていうか,CAN2の失敗談は多いけど,成功談についての記述が見つからなくて大変だった…